[Memcached]Memcached (Distributed Cache) ASP.net P

mikel阅读(916)

转载:http://www.codeproject.com/KB/aspnet/memcached_aspnet.aspx

Introduction

Currently I am working on a web-based project that will be hosted in a web farm. Among the several issues, we faced the issue of having a distributed cache. As we know the current cache in ASP.NET is an in-process cache and can't be used in a web farm. After doing some research found a few solutions on the web but at the end all of them had scalability issues. We found a few third party implementations but they were quite expensive. Then I came across memcahced implemented by Danga Interactive. This is a high performance distributed memory cache initially implemented for http://www.LiveJournal.com. The original implementation runs on *nix system. Luckily there is win32 port available at http://jehiah.cz/projects/memcached-win32/ for those who want to run it in a windows environment. For more detail on the working of Memcached, please read the following article http://www.linuxjournal.com/article/7451.

There is a C# client for memcached available and can be downloaded from the following location https://sourceforge.net/projects/memcacheddotnet/. For coding this provider, I have used the clientlib 1.1.5.

Using the code

Following is the interface for the Cached Provider.

Collapse
public abstract class CacheProvider : ProviderBase
{
// Currently returns -1 as this property is not implemented
public abstract long Count { get;}
// Returns the server names with port in the memcached cluster
public abstract string[] Servers { get;}
// Default expiration time in milli seconds
public abstract long DefaultExpireTime { get;set;}
// Adds object to the cache for the max amount of time
public abstract bool Add(string strKey, object objValue);
// Adds object to the cache for Default Expire time if bDefaultExpire
// is set to true otherwise for max amount of time
public abstract bool Add(string strKey, object objValue,bool bDefaultExpire);
// Add objects for specified about of time. Time is specified in milli seconds        
public abstract bool Add(string strKey, object objValue, long lNumofMilliSeconds);
// Return the object from memcached based on the key otherwise 
// just returns null
public abstract object Get(string strKey);
// Clears everything from the cache on all servers
public abstract bool RemoveAll();
// Removes the an object from cache
public abstract object Remove(string strKey);
// Release resources and performs clean up
public abstract void Shutdown();
// Checks if the key exists in memory
public abstract bool KeyExists(string strKey);
// Return all servers stats
public abstract Hashtable GetStats();
}

Following is how to configure Cache Provider in a web.config or app.config file

Collapse
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="cacheProvider" type="CacheProvider.CacheProviderSection, CacheProvider"
allowDefinition="MachineToApplication" restartOnExternalChanges="true"/>
</configSections>
<cacheProvider defaultProvider="MemcachedCacheProvider">
<providers>
<add name="MemcachedCacheProvider" type="CacheProvider.MemcachedCacheProvider,CacheProvider"
servers="127.0.0.1:11211" socketConnectTimeout="1000" socketTimeout="1000"/>
<!�To add more servers use comma to separate servernames and ports
eg. servers="127.0.0.1:11211,192.168.0.111:11211"
-->
</providers>
</cacheProvider>
</configuration>

Following parameters can be specified for initializing the cache provider

  • socketConnectTimeout � Timeout for Socket connection with memcached servers
  • socketTimeout � Timeout for Socket read-write operations
  • defaultExpireTime � Default expire time in milliseconds

To use Cache Provider in a project add a reference to the CacheProvider.dll and access the methods using DistCache static class. When creating keys for storing data, avoid using spaces in keys e.g. "My Key". This is an issue with C# memcached client. To close the provider gracefully please add a call to DistCache.Shutdown() in Global.asax file's Application_End event.
Update Dec 24, 2007
To report any issues and enhancements please go to the following link http://www.codeplex.com/memcachedproviders. I have started working on the Session State Provider for Memcached. I will be releasing it very soon on codeplex.com.

Update Dec 31, 2007I have released Session State Provider for memcached. Please go to the following link to download
http://www.codeplex.com/memcachedproviders

References

  1. http://www.danga.com/memcached/
  2. http://jehiah.cz/projects/memcached-win32/
  3. https://sourceforge.net/project/showfiles.php?group_id=152153
  4. Sample Project Provider by Memcached C# client 1.1.5
  5. http://www.infoq.com/news/2007/07/memcached
  6. http://msdn2.microsoft.com/en-US/library/aa479038.aspx
  7. http://www.linuxjournal.com/article/7451

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0

About the Author

Fahad Azeem

Member
My name is Fahad Azeem. I am interested in distributed software development. Currently I am working for a software consulting company in Chicago which developes software in .NET platform.
My Blog: http://fahadaz.blogspot.com

Occupation: Web Developer
Location: United States United States

[ASP.NET]超级简单:ASP.NET Localization (本地化,多语言)

mikel阅读(778)

      有很多讨论ASP.NET localization(本地化,多语言)的文章,这篇文章是不会的深入讨论ASP.NET Localization (本地化,多语言)。相反,它将给你有关ASP.NET页面中通常使用的内容的localization的一个快速参考,这些内容包括:ASP.NET服 务端控件,html内容,SiteMap,一些其他资源。

      这篇文章包括以下内容:

      1、 如何本地化的ASP.NET服务器控件?

      2、如何本地化HTML内容?

      3、如何本地化站点地图?

      4、如何动态改变文化环境?

     如何本地化的ASP.NET服务器控件?

     ASP.NET服务器控件的localization是所有类型中最简单的一种。一旦你添加一个服务器控件到你的页面上,您可以简单地切换网页到“Design”,然后进入菜单 “Tools”->“Generate Local Resource”。

     它将会为页面上的每个asp.net服务器控件产生一段字符串资源。在这个例子中,创建一个名字为Default.aspx.resx 的文件。它包含了Default.aspx页面所有的资源的name/value对。

   切换回"Source",你将看到在你的html里面添加了如下的代码:

<asp:Button ID="Button1" runat="server" Text="Hello" 
    meta:resourcekey
="Button1Resource1" />

     然后,您可以复制/粘贴,为了创建另一个文化资源文件。例如,您可以为法国用户创建一个Default.aspx.fr.resx。 

 

     下面的截图是当Internet Explorer的语言设置为英语。

 

      通过Internet Explorer->Tools->Internet Options->Languages更改语言为法语. 

 

     下面是为法语版本的页面:

 

   如何本地化HTML内容?

    为了本地化普通的HTML内容,您可以使用<asp:Localize>控件。让我们用一个例子来解释。

    在您的网页,你有一个标题和段落。

<h1>Localization Page Header</h1>
<p>This is a demo page to show you how to do localization in ASP.NET</p>

     为了本地化,您需要给他们添加<asp:Localize>。

代码

<h1><asp:Localize ID="Header" runat="server">Localization Page Header</asp:Localize></h1>
<p><asp:Localize ID="Localize1" runat="server">This is a demo 
   page to show you how to do localization in ASP.NET
</asp:Localize></p>

 

      然后,您可以手动创建一个资源文件并添加meta:resourcekey =“HeaderResource1”到您的网页。您可以利用Visual Studio,它自动生成。切换页面到“Design”,进入菜单“Tools”->“Generate Local Resource”。

      它将为您生成以下代码和资源文件(例如:yourfile.aspx.resx)。

      下面是它更改的代码:

代码

<h1><asp:Localize ID="Header" runat="server" 
   meta:resourcekey
="HeaderResource1" 
   Text
="Localization Page Header"></asp:Localize></h1>
<p><asp:Localize ID="Localize1" runat="server" 
   meta:resourcekey
="Localize1Resource1" Text="This is a demo page to show you 
      how to do localization in ASP.NET"
></asp:Localize></p>

     在其余步骤是与如何本地化ASP.NET服务器控件相同。

   如何本地化SiteMap?

     本文将给你关于SiteMap的本地化更多的细节。

     1、通过加入enableLocalization =“true”,启用站点地图文件网站地图本地化。例如:在Web.sitemap文件。

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0"
    enableLocalization
="true">

   2、 在SiteMapNode中使用这种格式: “$resources:ClassName,KeyName,DefaultValue”,更改你要本地化的资源字符串的属性的值。

<siteMapNode url="Default.aspx" 
  title
="$resources:SiteMapLocalizations,HomePageTitle" 
  description
="$resources:SiteMapLocalizations,HomePageDescription">

    3、 添加 global resource 文件夹和文件。右键单击在解决方案资源管理器的web site 。点击“添加ASP.NET文件夹”。从子菜单点击“添App_GlobalResources文件”。这将增加一个 “App_GlobalResources文件”文件夹到根目录。

然后,添加一个资源文件,例如,SiteMapLocalizations.resx。在文件中,您将有资源字符串的 name/value 对。例如:

Name             Value
HomePageTitle    Home

 4、为每一种你需要的文化,添加资源文件。例如,您可能有一个名字为SiteMapLocalizations.fr.resx法语版的文件。下面是英文和法文的菜单屏幕截图:

 

如何编程本地化字符串?

有时您可能需要显示一个字符串,例如,在运行时错误信息。您需要编程将它本地化。下面是如何做到这一点:

1、在App_GlobalResources 文件夹下面添加一个资源文件。例如,我们能添加一个名字为“CommonResource.resx”文件和一个法语版的“CommonResource.fr.resx”。

2、有很多其他很好的方法来获取资源字符串。

你能从 ~\App_GlobalResources\MyMessages.resx 得到的资源通过:

1、产生的封装代码 :

string message = Resources.MyMessages.Hello;

 2、资源表达式

<asp:Label Text="<%$ Resources: MyMessages, Hello %>" />

3、GetGlobalResourceObject方法

string message = GetGlobalResourceObject("MyMessages""Hello");

你能从 ~\App_LocalResources\default.aspx.resx 得到的资源通过: 

1、资源表达式:

<asp:Label Text="<%$ Resources: Hello %>" />

2、meta:resourceKey :

<asp:Label meta:resourceKey="labelResourceKey" />

 3、GetLocalResourceObject方法:

string message = GetLocalResourceObject("Hello"); "

 这有个截图:

  

 如何动态改变文化?

    在示例代码中,我们增加了两个LinkButtons控件。当您点击“English”,该网页将切换到英语文化,点击 “Français”, 将切换到法国文化。为了检测的哪个LinkButtons被点击,我们使用Request.Form [“__EventTarget”]。它能实现,但可能不是最好的方式。

    我们覆盖页面InitializeCulture方法,这样就会对我们作出的选择显示正确的文化。

<asp:LinkButton ID="LanguageEnglish" Text="English" runat="server"></asp:LinkButton>
<asp:LinkButton ID="LanguageFrench" Text="Français" runat="server"></asp:LinkButton>

 

代码

protected override void InitializeCulture()
{
    
string language = Request.Form["__EventTarget"];
    
string languageId = "";
    
if (!string.IsNullOrEmpty(language))
    {
        
if (language.EndsWith("French"))
            languageId 
= "fr-FR";
        
else languageId = "en-US";
        Thread.CurrentThread.CurrentCulture 
= 
        CultureInfo.CreateSpecificCulture(languageId);
        Thread.CurrentThread.CurrentUICulture 
= new CultureInfo(languageId);
    }
    
base.InitializeCulture(); 
}

 

   除了menu之外,其它一切控件都有效。如果在网页中你有一个menu使用Sitemap,您可能需要在Page_Load事件调用 menu.DataBind()或设置的EnableViewState为false。否则,但其他内容更改为新的文化,你的menu上仍会显示以前的文 化字符串。

   当我们动态改变文化,最有可能的是我们需要将它存储在某个地方,当我们从页面到页面跳转时,这样就不会丢失。在示例应用程序,我们使用了Session。

源代码:

/Files/zhuqil/Localization.zip

原文:http://www.codeproject.com/KB/aspnet/AspNetLocalization.aspx

朱祁林

[Linq]非常简单的实现LINQ通用分页绑定方法

mikel阅读(907)

转载:http://www.cnblogs.com/ejiyuan/archive/2009/12/22/1629806.html

在LINQ中,IQueryable <T>接口和IEnumerable <T>接口都分别提供了Skip方法和Take方法,用来做分页非常合适.因此我就想用他们做一个分页控件,因为IQueryable <T> 是继承自 IEnumerable <T> 的。因此使用接口仅需要针对后者就可以了。使用的时候只需提供数据源、绑定的GridView的、每页大小即可。现在问题就出了在数据源上,要求用户提供 一个数据源类型,即IQueryable <T>接口和IEnumerable <T>接口? T是可确定类型(已知类型)的话还可以,若T是匿名类型,如 

var list = from it in de.Customers where it.City == "abc" select new { it.City, it.Country }; 

 

 list的类型只有在运行时才能得到,怎么办呢!其实很简单我,我们可以使用 “参数推导泛型类型”的方法来实现:
看下面的代码(因为重点不在这里所以 代码写的比较粗糙):

代码

public void BindBoundControl<TSource>(IEnumerable<TSource> DataSource, GridView BoundControl, int PageSize)
        {
            
//获取总记录数(这里可以使用参数传入总页数 就不必每次都执行下面方法)
            int totalRecordCount = DataSource.Count();
            
//计算总页数
            int totalPageCount = 0;
            
if (PageSize == 0)
            {
                PageSize 
= totalRecordCount;
            }
            
if (totalRecordCount % PageSize == 0)
            {
                totalPageCount 
= totalRecordCount / PageSize;
            }
            
else
            {
                totalPageCount 
= totalRecordCount / PageSize + 1;
            }
            
//从参数中获取当前页码
            int CurrentPageIndex = 1;
            
//如果从参数中获取页码不正确 设置页码为第一页
            if (!int.TryParse(HttpContext.Current.Request.QueryString["Page"], out CurrentPageIndex) || CurrentPageIndex <= 0 || CurrentPageIndex > totalPageCount)
            {
                CurrentPageIndex 
= 1;
            }
            
//绑定数据源
            BoundControl.DataSource = DataSource.Skip((CurrentPageIndex  1* PageSize).Take(PageSize);
            BoundControl.DataBind();
        }

 

        调用

 

代码

        protected void Page_Load(object sender, EventArgs e)
        {
            NorthwindEntities de 
= new NorthwindEntities();
            BindingUtils bind 
= new BindingUtils();
            
//先排序与一下再绑定
            bind.BindBoundControl<Customers>(de.Customers.OrderBy(v=>v.CustomerID), this.GridView1, 10);  
        }

 

下面我们只是需要重载一下我们的分页方法实现“参数推导泛型类型”就可以了 代码如下:

代码

        public void BindBoundControl<TSource>(IEnumerable<TSource> DataSource, TSource type, GridView BoundControl, int PageSize)
        {
            
this.BindBoundControl(DataSource, BoundControl, PageSize);
        }

 

调用

代码

        protected void Page_Load(object sender, EventArgs e)
        {
            NorthwindEntities de 
= new NorthwindEntities();
            var list 
= from it in de.Customers where it.City == "abc" select new { it.City, it.Country };
            BindingUtils bind 
= new BindingUtils();
            bind.BindBoundControl(list.OrderBy(c
=>c.City), list.FirstOrDefault(), this.GridView1, 10);  
        }

 

这个方法很简单的 只是通过 list.FirstOrDefault() 做参数 来推导 方法中 BindBoundControl<TSource> 的TSource 就可以了,当然因为每次分页时都会执行 list.FirstOrDefault() 会损失一点点的效率。

 

[C#]动软代码生成器源码下载地址

mikel阅读(1610)

动软代码生成器源码下载页面
http://www.maticsoft.com/download.aspx

动软.Net代码生成器(.Net 2.0版)源码

软件版本: 2.41
最后更新: 2009-12-22
软件大小: 13M
软件性质: 简体中文/免费软件
运行环境: .Net 2.0
下载次数: 194
软件描述:

        动软.Net代码生成器2.41版最新全部源码开放!

        转眼间,动软经历了几年的风风雨雨,得到了众多网友们的支持和厚爱。同时也结识了很多的朋友,虽然几年的update很辛苦,但有这么多朋友的支持和鼓励,也甚感欣慰。
为 感谢众多网友对该软件的支持,现在正式开放源码。希望它能带给大家和更多的朋友更大的帮助,也不枉这么多年开发动软的心血。虽然对动软有着深厚的感情,但 为了更好的发挥动软.NET代码生成器更大的社会价值,也为更多的程序员提供更大的便利性和灵活性。也当作我对同行朋友们新年的一点贺礼,希望大家在未来 的工作生活中,快乐工作,享受生活!

    本地免费下载

动软.Net代码生成插件源码

软件版本: 2.4
最后更新: 2009-7-19
软件大小: 69K
软件性质: 简体中文/免费软件
运行环境: Codematic 2.19
下载次数: 28405
软件描述:

动软.Net代码生成器2.1以上版本支持代码插件机制,支持可扩展的代码生成插件,用户可以定制自己的代码生成的插件,根据接口开发自己的代码生成方式,按用户需求进行代码生成。详见插件接口开发帮助和源码。
这里提供了几种典型的代码生成方式的组件源码供参考。
包括组件:
1.BuilderBLLComm  BLL层代码模板组件源码。
2.BuilderDALELParam  DAL层代码构造器(基于企业库方式)
3.BuilderDALParam  DAL数据访问层代码构造器(Parameter方式)
4.BuilderDALSQL  DAL数据访问层代码构造器(基于SQL方式)
5.BuilderModel  Model代码生成组件源码。
6.BuilderWeb  Web层代码生成组件源码。
7.Lib  需要引用的库。

同时希望大家把自己开发的代码生成插件在网上共享,别的网友也可使用已经开发好的插件覆盖安装目录下的插件库文件通过插件管理增加新插件。尽量避免重复开发。借此也可以让大家有个交流的机会。
全部源码下载

    本地免费下载

[C#].NET 中的对象序列化

mikel阅读(1270)

转载:http://www.cnblogs.com/wayfarer/articles/4759.html

Piet Obermeyer

Microsoft Corporation

 

2001 8

 

摘要:为什么要使用序列化?最重要的两个原因是:将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本;按值将对象从一个应用程序域发送至另一个应用程序域。例如,序列化可用于在 ASP.NET 中保存会话状态,以及将对象复制到 Windows 窗体的剪贴板中。它还可用于按值将对象从一个应用程序域远程传递至另一个应用程序域。本文简要介绍了 Microsoft .NET 中使用的序列化。

 

目录

简介

持久存储

按值封送

基本序列化

选择性序列化

自定义序列化

序列化过程的步骤

版本控制

序列化规则

 

简介

序列化是指将对象实例的状态存储到存储媒体的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。

 

在面向对象的环境中实现序列化机制时,必须在易用性和灵活性之间进行一些权衡。只要您对此过程有足够的控制能力,就可以使该过程在很大程度上自动进行。例如,简单的二进制序列化不能满足需要,或者,由于特定原因需要确定类中那些字段需要序列化。以下各部分将探讨 .NET 框架提供的可靠的序列化机制,并着重介绍使您可以根据需要自定义序列化过程的一些重要功能。

 

持久存储

我 们经常需要将对象的字段值保存到磁盘中,并在以后检索此数据。尽管不使用序列化也能完成这项工作,但这种方法通常很繁琐而且容易出错,并且在需要跟踪对象 的层次结构时,会变得越来越复杂。可以想象一下编写包含大量对象的大型业务应用程序的情形,程序员不得不为每一个对象编写代码,以便将字段和属性保存至磁 盘以及从磁盘还原这些字段和属性。序列化提供了轻松实现这个目标的快捷方法。

 

公共语言运行时 (CLR) 管理对象在内存中的分布,.NET 框架则通过使用反射提供自动的序列化机制。对象序列化后,类的名称、程序集以及类实例的所有数据成员均被写入存储媒体中。对象通常用成员变量来存储对其他实例的引用。类序列化后,序列化引擎将跟踪所有已序列化的引用对象,以确保同一对象不被序列化多次。.NET 框架所提供的序列化体系结构可以自动正确处理对象图表和循环引用。对对象图表的唯一要求是,由正在进行序列化的对象所引用的所有对象都必须标记为 Serializable(请参阅基本序列化)。否则,当序列化程序试图序列化未标记的对象时将会出现异常。

 

当反序列化已序列化的类时,将重新创建该类,并自动还原所有数据成员的值。

 

按值封送

对象仅在创建对象的应用程序域中有效。除非对象是从 MarshalByRefObject 派生得到或标记为 Serializable,否则,任何将对象作为参数传递或将其作为结果返回的尝试都将失败。如果对象标记为 Serializable,则该对象将被自动序列化,并从一个应用程序域传输至另一个应用程序域,然后进行反序列化,从而在第二个应用程序域中产生出该对象的一个精确副本。此过程通常称为按值封送。

 

如果对象是从 MarshalByRefObject 派生得到,则从一个应用程序域传递至另一个应用程序域的是对象引用,而不是对象本身。也可以将从 MarshalByRefObject 派生得到的对象标记为 Serializable。远程使用此对象时,负责进行序列化并已预先配置为 SurrogateSelector 的格式化程序将控制序列化过程,并用一个代理替换所有从 MarshalByRefObject 派生得到的对象。如果没有预先配置为 SurrogateSelector,序列化体系结构将遵从下面的标准序列化规则(请参阅序列化过程的步骤)。

 

基本序列化

要使一个类可序列化,最简单的方法是使用 Serializable 属性对它进行标记,如下所示:

 

[Serializable]

public class MyObject {

  public int n1 = 0;

  public int n2 = 0;

  public String str = null;

}

以下代码片段说明了如何将此类的一个实例序列化为一个文件:

 

MyObject obj = new MyObject();

obj.n1 = 1;

obj.n2 = 24;

obj.str = "一些字符串";

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Create,

FileAccess.Write, FileShare.None);

formatter.Serialize(stream, obj);

stream.Close();

本例使用二进制格式化程序进行序列化。您只需创建一个要使用的流和格式化程序的实例,然后调用格式化程序的 Serialize 方法。流和要序列化的对象实例作为参数提供给此调用。类中的所有成员变量(甚至标记为 private 的变量)都将被序列化,但这一点在本例中未明确体现出来。在这一点上,二进制序列化不同于只序列化公共字段的 XML 序列化程序。

 

将对象还原到它以前的状态也非常容易。首先,创建格式化程序和流以进行读取,然后让格式化程序对对象进行反序列化。以下代码片段说明了如何进行此操作。

 

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Open,

FileAccess.Read, FileShare.Read);

MyObject obj = (MyObject) formatter.Deserialize(fromStream);

stream.Close();

 

// 下面是证明

Console.WriteLine("n1: {0}", obj.n1);

Console.WriteLine("n2: {0}", obj.n2);

Console.WriteLine("str: {0}", obj.str);

上面所使用的 BinaryFormatter 效率很高,能生成非常紧凑的字节流。所有使用此格式化程序序列化的对象也可使用它进行反序列化,对于序列化将在 .NET 平 台上进行反序列化的对象,此格式化程序无疑是一个理想工具。需要注意的是,对对象进行反序列化时并不调用构造函数。对反序列化添加这项约束,是出于性能方 面的考虑。但是,这违反了对象编写者通常采用的一些运行时约定,因此,开发人员在将对象标记为可序列化时,应确保考虑了这一特殊约定。

 

如果要求具有可移植性,请使用 SoapFormatter。所要做的更改只是将以上代码中的格式化程序换成 SoapFormatter,而 Serialize Deserialize 调用不变。对于上面使用的示例,该格式化程序将生成以下结果。

 

<SOAP-ENV:Envelope

  xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance

  xmlns:xsd="http://www.w3.org/2001/XMLSchema"

  xmlns:SOAP- ENC=http://schemas.xmlsoap.org/soap/encoding/

  xmlns:SOAP- ENV=http://schemas.xmlsoap.org/soap/envelope/

  SOAP-ENV:encodingStyle=

  "http://schemas.microsoft.com/soap/encoding/clr/1.0

  http://schemas.xmlsoap.org/soap/encoding/"

  xmlns:a1="http://schemas.microsoft.com/clr/assem/ToFile">

 

  <SOAP-ENV:Body>

    <a1:MyObject id="ref-1">

      <n1>1</n1>

      <n2>24</n2>

      <str id="ref-3">一些字符串</str>

    </a1:MyObject>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

需要注意的是,无法继承 Serializable 属性。如果从 MyObject 派生出一个新的类,则这个新的类也必须使用该属性进行标记,否则将无法序列化。例如,如果试图序列化以下类实例,将会显示一个 SerializationException,说明 MyStuff 类型未标记为可序列化。

 

public class MyStuff : MyObject

{

  public int n3;

}

使用序列化属性非常方便,但是它存在上述的一些限制。有关何时标记类以进行序列化(因为类编译后就无法再序列化),请参考有关说明(请参阅下面的序列化规则)。

 

选择性序列化

类通常包含不应被序列化的字段。例如,假设某个类用一个成员变量来存储线程 ID。当此类被反序列化时,序列化此类时所存储的 ID 对应的线程可能不再运行,所以对这个值进行序列化没有意义。可以通过使用 NonSerialized 属性标记成员变量来防止它们被序列化,如下所示:

 

[Serializable]

public class MyObject

{

  public int n1;

  [NonSerialized] public int n2;

  public String str;

}

自定义序列化

可以通过在对象上实现 ISerializable 接口来自定义序列化过程。这一功能在反序列化后成员变量的值失效时尤其有用,但是需要为变量提供值以重建对象的完整状态。要实现 ISerializable,需要实现 GetObjectData 方法以及一个特殊的构造函数,在反序列化对象时要用到此构造函数。以下代码示例说明了如何在前一部分中提到的 MyObject 类上实现 ISerializable

 

[Serializable]

public class MyObject : ISerializable

{

  public int n1;

  public int n2;

  public String str;

 

  public MyObject()

  {

  }

 

  protected MyObject(SerializationInfo info, StreamingContext context)

  {

    n1 = info.GetInt32("i");

    n2 = info.GetInt32("j");

    str = info.GetString("k");

  }

 

  public virtual void GetObjectData(SerializationInfo info,

StreamingContext context)

  {

    info.AddValue("i", n1);

    info.AddValue("j", n2);

    info.AddValue("k", str);

  }

}

在序列化过程中调用 GetObjectData 时,需要填充方法调用中提供的 SerializationInfo 对象。只需按名称/值对的形式添加将要序列化的变量。其名称可以是任何文本。只要已序列化的数据足以在反序列化过程中还原对象,便可以自由选择添加至 SerializationInfo 的成员变量。如果基对象实现了 ISerializable,则派生类应调用其基对象的 GetObjectData 方法。

 

需要强调的是,将 ISerializable 添加至某个类时,需要同时实现 GetObjectData 以及特殊的构造函数。如果缺少 GetObjectData,编译器将发出警告。但是,由于无法强制实现构造函数,所以,缺少构造函数时不会发出警告。如果在没有构造函数的情况下尝试反序列化某个类,将会出现异常。在消除潜在安全性和版本控制问题等方面,当前设计优于 SetObjectData 方法。例如,如果将 SetObjectData 方法定义为某个接口的一部分,则此方法必须是公共方法,这使得用户不得不编写代码来防止多次调用 SetObjectData 方法。可以想象,如果某个对象正在执行某些操作,而某个恶意应用程序却调用此对象的 SetObjectData 方法,将会引起一些潜在的麻烦。

 

在反序列化过程中,使用出于此目的而提供的构造函数将 SerializationInfo 传递给类。对象反序列化时,对构造函数的任何可见性约束都将被忽略,因此,可以将类标记为 publicprotectedinternal private。一个不错的办法是,在类未封装的情况下,将构造函数标记为 protect。如果类已封装,则应标记为 private。要还原对象的状态,只需使用序列化时采用的名称,从 SerializationInfo 中检索变量的值。如果基类实现了 ISerializable,则应调用基类的构造函数,以使基础对象可以还原其变量。

 

如果从实现了 ISerializable 的类派生出一个新的类,则只要新的类中含有任何需要序列化的变量,就必须同时实现构造函数以及 GetObjectData 方法。以下代码片段显示了如何使用上文所示的 MyObject 类来完成此操作。

 

[Serializable]

public class ObjectTwo : MyObject

{

  public int num;

 

  public ObjectTwo() : base()

  {

  }

 

  protected ObjectTwo(SerializationInfo si, StreamingContext context) :

base(si,context)

  {

    num = si.GetInt32("num");

  }

 

  public override void GetObjectData(SerializationInfo si,

StreamingContext context)

  {

    base.GetObjectData(si,context);

    si.AddValue("num", num);

  }

}

切记要在反序列化构造函数中调用基类,否则,将永远不会调用基类上的构造函数,并且在反序列化后也无法构建完整的对象。

 

对象被彻底重新构建,但是在反系列化过程中调用方法可能会带来不良的副作用,因为被调用的方法可能引用了在调用时尚未反序列化的对象引用。如果正在进行反序列化的类实现了 IDeserializationCallback,则反序列化整个对象图表后,将自动调用 OnSerialization 方法。此时,引用的所有子对象均已完全还原。有些类不使用上述事件侦听器,很难对它们进行反序列化,散列表便是一个典型的例子。在反序列化过程中检索关键字/值对非常容易,但是,由于无法保证从散列表派生出的类已反序列化,所以把这些对象添加回散列表时会出现一些问题。因此,建议目前不要在散列表上调用方法。

 

序列化过程的步骤

在格式化程序上调用 Serialize 方法时,对象序列化按照以下规则进行:

 

检查格式化程序是否有代理选取器。如果有,检查代理选取器是否处理指定类型的对象。如果选取器处理此对象类型,将在代理选取器上调用 ISerializable.GetObjectData

如果没有代理选取器或有却不处理此类型,将检查是否使用 Serializable 属性对对象进行标记。如果未标记,将会引发 SerializationException

如果对象已被正确标记,将检查对象是否实现了 ISerializable。如果已实现,将在对象上调用 GetObjectData

如果对象未实现 Serializable,将使用默认的序列化策略,对所有未标记为 NonSerialized 的字段都进行序列化。

版本控制

.NET 框架支持版本控制和并排执行,并且,如果类的接口保持一致,所有类均可跨版本工作。由于序列化涉及的是成员变量而非接口,所以,在向要跨版本序列化的类中添加成员变量,或从中删除变量时,应谨慎行事。特别是对于未实现 ISerializable 的类更应如此。若当前版本的状态发生了任何变化(例如添加成员变量、更改变量类型或更改变量名称),都意味着如果同一类型的现有对象是使用早期版本进行序列化的,则无法成功对它们进行反序列化。

 

如果对象的状态需要在不同版本间发生改变,类的作者可以有两种选择:

 

实现 ISerializable。这使您可以精确地控制序列化和反序列化过程,在反序列化过程中正确地添加和解释未来状态。

使用 NonSerialized 属性标记不重要的成员变量。仅当预计类在不同版本间的变化较小时,才可使用这个选项。例如,把一个新变量添加至类的较高版本后,可以将该变量标记为 NonSerialized,以确保该类与早期版本保持兼容。

序列化规则

由 于类编译后便无法序列化,所以在设计新类时应考虑序列化。需要考虑的问题有:是否必须跨应用程序域来发送此类?是否要远程使用此类?用户将如何使用此类? 也许他们会从我的类中派生出一个需要序列化的新类。只要有这种可能性,就应将类标记为可序列化。除下列情况以外,最好将所有类都标记为可序列化:

 

所有的类都永远也不会跨越应用程序域。如果某个类不要求序列化但需要跨越应用程序域,请从 MarshalByRefObject 派生此类。

类存储仅适用于其当前实例的特殊指针。例如,如果某个类包含非受控的内存或文件句柄,请确保将这些字段标记为 NonSerialized 或根本不序列化此类。

某些数据成员包含敏感信息。在这种情况下,建议实现 ISerializable 并仅序列化所要求的字段。

[MVC]分页存储过程,ASP.NET MVC中的Linq分页

mikel阅读(954)

转载:http://www.cnblogs.com/sonven/archive/2009/07/27/1531836.html
分页存储过程 


Alter procedure [dbo].[sys_getPagerData]
    
@pageSize int数据条数,注意从1开始
    @pageIndex int,页数索引
    @fields nvarchar(100),选取字段
    @Conditions nvarchar(50),选择条件
    @Chart nvarchar(50), 要选取的表
    @recordCount int output, 记录总数
    @pageCount int output 页面条数
AS
declare @SQL nvarchar(300)SQL语句
declare @SkipCount int要跳过查询的记录数

/* 获取记录总数 */
declare @getRecordSql nvarchar(100
set @getRecordSql='select @recordcount=count(1) from '+@chart
exec sp_executesql @getRecordSql,N'@recordCount int output',@recordCount output
/* 计算总页数 */
select @pagecount=floor(@recordCount/@pageSize);
if(@recordCount%@pageSize!=0)set @pagecount=@pageCount+1
/* 计算要跳过查询的数目 */
if(@pagecount=1 or @pagecount=0)set @skipCount=0
else set @skipCount=@pageSize*(@pageCount1);
set @sql='select top '+convert(nvarchar,@pageSize)+' '+
    
@fields+' from '+@Chart
+' where(id not in(select top '+
    
convert(nvarchar,(@skipCount))+' id from '+@Chart+
' order by id desc))'
/*附加查询条件*/
if(@Conditions is not null and @Conditions!='')
    
set @sql=@sql+' and '+@Conditions
添加 print @sql可以监视执行的Sql语句–

execute(@sql)

 

广告:http://www.cnyolee.com/(讲述有理的网站)
      http://www.rsion.com/

ASP.NET MVC中分页

 public ActionResult CateList(string page)
        
{
            
//分页大小
            int pageSize = 15;
            
//总页数
            int recordCount = (int)Helper.DataControl.FactoryCommand("select count(0) from articles where",CommandType.Text).ExecuteScalar();
            
int pageCount = recordCount / pageSize + (recordCount % pageSize == 0 ? 0 : 1);

            
//当前页数
            int currentPage = page == null ? 0 :Convert.ToInt32(page);
            
if (currentPage <1) currentPage = 1;
            
else if (currentPage > pageCount) currentPage = pageCount;
            
//分页信息
            TempData["pagedInfo"= "<a href=\"" + Request.Path + "?page=" + (currentPage == 1 ? 1 : currentPage – 1) +
                "\">上一页</a> | <a href=\"" + Request.Path + "?page=" + (currentPage == pageCount ? pageCount : currentPage + 1+
                
"\">下一页</a> <input type=\"text\" size=\"3\" id=\"tbpage\"> <a href=\"#\" onclick=\"location.href='" + Request.Path +
                
"?page='+tbpage.value;\">跳页</a> "+
                
                
"" + (currentPage) + "页/共" + pageCount + "页&nbsp;每页" + pageSize +
                
"条记录/共" + recordCount + "条!";

            
//计算要跳过的页
            int skipCount =recordCount<=pageSize?0:pageSize * (currentPage 1);

            IEnumerable
<Models.Article> articles = Common.DataContext.Articles.Skip(skipCount).Take(pageSize).OrderByDescending(a=>a.AddDate);
      
//注意:要先使用Skip(int)后再使用Take(int)
            return View(articles);
        }

 

[Linq]LINQ可视化查询编辑器: VLinq

mikel阅读(880)

转载:http://www.cnblogs.com/lyj/archive/2008/04/02/1135120.html

大家学习LINQ是不是寻思写LINQ to SQL语句没有一个可视化的编程环境。Mitsu和他们的团队用了近一年的工作在今天发布了VLinq(Visual Linq Query Builder,LINQ可视化查询编辑器)。

Visual Linq Query Builder(LINQ可视化查询编辑器)作为Visual Studio 2008的一个插件,可以帮助我们在程序中创建LINQ to SQL查询表达式,支持C#和VB两种语言。

Linq可视化查询编辑器

VLinq使用Visual Studio 2008 (betas then RTM) 和Expression Blend开发的。在下载页中提供了整个工程项目和一个安装文件。下载文件:

  • msi安装文件
  • 快速参考指南
  • 用户说明文件
  • 2分钟的开发视频。
  • 源代码

下面是摘自Mitsu博客中的描述的快速开发指南:

1.创建一个新程序

创建一个新程序

2.添加LINQ to SQL class

添加LINQ to SQL class

3.添加VLinq queries

添加VLinq queries

4.设置VLINQ连接

设置VLINQ连接

5.创建新的查询语句

创建新的查询语句

6.在可视化编辑器中编辑查询语句

在可视化编辑器中编辑查询语句

可以收缩和展开查询节点

可以收缩和展开查询节点

7.预览查询结果

预览查询结果

8.查看自动生成的代码

查看自动生成的代码

更多使用可以参考开发视频和快速开发指南。

注意:Visual Linq Query Builder目前好像只支持英文版,我目前电脑安装的是中文版不可以使用,没有给大家介绍详细开发实例。抱歉!大家可以去试试,分享一下!

[框架]Shuttler.Net2.0圣诞开源发布

mikel阅读(951)

转载:http://www.cnblogs.com/overred/archive/2009/12/20/Shuttler_Net_2.html

Shuttler.Net(开源)
Shuttler.Net是一个高性能分布式框架,如果你在使用老去的remoting,webservices分布式架构,或在使用新生的wcf,那么你也可以尝试下Shuttler.Net。
如果你想开发自己的IM服务端和客户端(或游戏大厅),你也可以使用Shuttler.Net,只需你制定报文协议即可,其他传输层Shuttler帮你搞定。
Shuttler.Net核心组件Artery正如她的名字一样:脉,基于Tcp的应用栈,可以帮你传输任何能量,使你想唱就唱。

主要功能点包括:
1,分布式RPC,目前支持Tcp和Http(类REST风格)双通道(见Demo:TcpRpcTest和HttpRpcTest):
可以多个RpcServer端和多个RpcClient端,其中client通过HashingAlgorithm根据Key计算出server。
2,分布式缓存系统(Memcached),包括MemcachedServer和MemcachedClient(见Demo:MemcachedTest):
可以多个MemcachedServer端和多个MemcachedClient端,其中client通过HashingAlgorithm根据Key计算出server。
3,IM协议栈,使用Shuttler.Net的Artery组件可以轻松实现一个IMServer端和IMClient端(见Demo:IMTest):
IMTest中实现IM的登录密码校验,通讯协议自己定义即可,协议Demo见Shuttler_Artery_Protocol。

其中Shuttler.Net使用内存Pool概念和Socket增强SocketAsyncEventArgs,使你的所有操作Buffer始终在一块固定的内存区中进行,避免了内存泄漏问题。
值得一提的是,里面还有一个高效的CompactHeap,使你可以在12s内把数亿条数据缓存到800MB内存中(根据sizeof大小而定),如果使用对象级的托管堆,你是难以办到的。
总之里面更精彩!

Shuttler.Net核心组件Artery和Rpc结构图:


Rpc性能计数器相关(不同机器可能有出入):

 

Shuttler.Net开源主页:

http://shuttler.codeplex.com

 

源码(含Demo)下载地址:
Shuttler.Net

 

PS:这个框架是我花了无数个周末时间打造而成!尤其是Tcp流的包完整性解析,曾尝试了无数个算法! 对性能也进行了无数次调优!尽管如此还是不尽我意,那就先这样吧,我会使她一直进化下去。

 

希望两块布子做的是花衣裳!

有问题请留言或联系:overred@gmail.com

[HTML]10个你需要了解的不常见的Html标签(译)

mikel阅读(874)

原文地址:http://net.tutsplus.com/articles/web-roundups/10-rare-html-tags-you-really-should-know/

      如今,Web开发工程师在学习和工作中通常都使用了不止一门语言。因此,对一门语言的方方面面我们很难说得上都去了解,要精通一门语言也是相当有难度,比如语言中一些生僻但可能很有用处的关键字用法。

      虽然我们以前可能对这些非常少见的HTML标签并不了解或没能完全用好他们,不过亡羊补牢,为时未晚,现在开始了解并能在以后的开发中正确的用上这些以前没用过的标签也不算太晚。

      这里我给出了10个最不常见并且常被人误用的HTML标签。虽然可能并不像其他HTML标签那么常见,但在某些特殊的情景下,他们仍然相当有用。

1. <cite>

     相信大家都对<blockquote>不陌生吧,但你知道<blockquote>其实有个小弟叫<cite> 不?<cite>允许在一个元素中定义一段文本作为引用。一般情况下,浏览器会把<cite>标签下的文本设置为斜体字,不过这 可能会根据CSS有所改变。

      <cite>标签在书籍目录和其他站点地址引用的时候非常有用。这里给出一个如何在一段文字中使用<cite>标签的例子:

       张三的突破性专著张三自传给网络带来一股新气象.

2. <optgroup>

     当你想在一个下拉框中对根据不同类型分组的选项添加一些定义时,<optiongroup>标签将会非常有用。例如,如果你想根据时间对电影进行分组,代码可以这样写:

1 <LABEL for=showtimes>Showtimes</LABEL><br><Select id=showtimes name=showtimes><OPTGROUP label=1PM></OPTGROUP> <OPTION selected value=titanic>Twister</OPTION> <OPTION value=nd>Napoleon Dynamite</OPTION><OPTION value=wab>What About Bob?</OPTION><OPTGROUP label=2PM></OPTGROUP> <OPTION value=bkrw>Be Kind Rewind</OPTION> <OPTION value=stf>Stranger Than Fiction</OPTION></Select>

例子:

3. <acronym>

     <acronym>标签通常用于对一句话(词组)添加定义或者更详细的解释。当用户将鼠标停留在添加了<acronym>标签的文字上面,添加的注释或定义会在文字下方显示。如:

1 微博网站 <ACRONYM title="Founded in 2006"> Twitter</ACRONYM> 最近引起了互联网上的一股新的风潮!

例子:

微博网站 Twitter最近引起了互联网上的一股新的风潮!

4. <address>

     <address>标签是个相当少见的标签,不过这并不代表它没什么用处。望文生义,<address>允许你在HTML中根据 语义来标记地址。这个很好用的标签同样会把它内部的数据用斜体字标识,不过,这个样式很容易通过CSS修改。

1 <address><br>中国,上海市,闵行区,XX路,XX小区,XXX室<br></address>

例子:

中国,上海市,闵行区,XX路,XX小区,XXX室

 

5. <ins> 和 <del>

     如果你想通过标记来显示文档编辑样式,<ins>和<del>刚好可以用到。就像它们的名字,<ins>通过一个下划线来突出那些被添加进文档的内容,而<del>则通过删除线来显示那些从中删除的文字。

1 没有了驴子,我们的日子还要怎么<DEL>过下去</DEL> <INS>活下去</INS>?

例子:没有了驴子,我们的日子还要怎么过下去 活下去?

6. <label>

     当标记文档时,表格元素很容易被遗忘。在表格元素中,最容易被遗忘的元素之一怕要数<label>标签了。但对<label>标 签来说,它不仅可以相当方便的表示一段文字,同时,它更能通过for属性来指定标签被用于哪个元素。这些<label>不仅很容易被定义样 式,它们还允许你将标签的文字设计成像按钮一样可以被用户点击。

1 <LABEL for="username">用户名</LABEL>  <br><INPUT id="username" type="text">

7. <fieldset>

     <fieldset>是一个相当好用的标签,它可将表单内的相关元素按逻辑分组。一旦这些元素通过<fieldset>标签放到一起,另外通过将<label>标签和fieldset绑定可以为分组定义标题。

1 <FORM><FIELDSET>  <br><LEGEND>你觉得自己牛X么?</LEGEND>  <br>Yes<INPUT value=yes type=radio name=yes>  <br>No <INPUT value=no type=radio name=no>  <br></FIELDSET>  <br></FORM>

例子:

你觉得自己牛X么?

Yes No

8. <abbr>

     <abbr>和<acronym>是一类的标签,只是<abbr>标签只用于定义缩写的词组。就 像<acronym>,相当于你给元素添加了一个标题或称号。当用户将鼠标悬停在缩写词上面,它的全称会在下方显 示。<abbr>标签很少被用到,不过它对屏幕阅读器,拼写检查程序和搜索引擎很有用。

1 他<ABBR title="妈">文明用语</ABBR>的

例子:文明用语的!

9. rel

    Rel是一个相当有用的属性,基本上任何一个HTML元素都可以应用Rel属性(注1)。它可以为那些没有别的方式提供详细信息的元素提供额外的信息。这 在JavaScript和HTML一起工作时尤其有用。如果你有一个你可能想在内部编辑,你可以这样添加代码:

 

代码

<html> <body> <p><a id="myAnchor" rel="index" href="http://www.w3school.com.cn">Visit W3School.com.cn</a></p> <script type="text/javascript"> x=document.getElementById("myAnchor"); document.write(x.rel); </script> </body> </html>

 

     JavaScript会找到rel属性为clickable的link元素,然后它可以接着通过ajax内部改变元素。当然,这个只是你可以应用rel属性的无数种情况中的一种,你可以用其他方式来很好的使用rel属性。

10. <wbr>

     <wbr>(注2)是个基本已经销声匿迹的标签。坦诚的说,我怀疑读者中的大多数都没接触过这个标签,毕竟它太少用到了(真的,在写这篇文章 之前,我自己都没见过这个标签)。这个标签允许你指定一块区域来强制使用换行符,但仅仅是确实必要的时候。该元素很特殊因为它定义在浏览器中添加换行符, 如果需要的话,它可以在你极力避免浏览器中出现横向的滚动条时实现符合要求的界面。

如果你想在不必使用<wbr>标签的情况下达到相同的效果,你也可以尝试&#8203;或&shy; 。但千万注意,这三个标签中没有一个可以完全支持所有浏览器的。如果你想看看哪些浏览器支持这三种标签可以看看这篇文章

 

译者注:

注1,实际上rel通常用在a和link标签中,它常和rev一起出现。

注2,wbr不是标准的html标签,它最开始是网景公司添加的,但随后被移除掉了。

 

附注:

      这篇文章仅仅是一个参考,实际上,由于一些地方使用和解释得并不清楚, 它也引起了比较多的争论,建议如果确实对这些标签有兴趣研究的朋友,可以参看下原文地址并仔细的查看文章的一些回复。

      另外有朋友认为这些少见的标签兼容性会很差,所以我们应少用。然而恰恰相反,上面列举的标签,除了最后一个不符合标准不推荐使用之外,其他都符合W3C标 准,它们兼容目前任何主流浏览器。当然,由于<acronym>和<abbr>功能基本一样,在新的html 5标准中不推荐使用<acronym>,w3c推荐用<abbr>代替<acronym>。

       最后有人可能认为这里的一些标签都可以用其他一些常见标签实现相同功能,因此没必要使用。不过正如回复中沉默杨仔所说:“w3c就是要语义化页面内容”,对用户说,可能你可以通过普通标签实现一样的功能,但对机器(e.g.屏幕阅读器,单词拼写检查程序,搜索引擎等)来说,这种标签它们更容易懂。所以我认为,如果你的网页中真有这些标签可以应用的场合,最好还是使用这些标签来实现相应的功能。

 

Always There, Always Ready!

[IIS]用一行代码让w3wp进程崩溃,如何查找w3wp进程崩溃的原因

mikel阅读(800)

转载:http://www.cnblogs.com/yukaizhao/archive/2009/12/19/iis_w3wp_crash.html

W3wp进程崩溃了,在系统日志中留下了一个错误,而留下的错误信息却很少,如何才能快速查找w3wp崩溃的原因呢?

首先,我们来写一行代码让w3wp崩溃:

1 protected void Page_Load(object sender, EventArgs e)
2 {
3     ThreadPool.QueueUserWorkItem(delegate(object noUse) { throw new Exception("go to hell w3wp!"); });
4 }

这一行代码就会让w3wp进程崩溃,因为ASP.NET 2.0之后,微软处理多线程操作异常的默认方式发生了变化,如果在Thread,或者ThreadPool,或者 System.Threading.Timer中执行方法中出现未处理异常,则当前执行进程会停止执行崩溃。

 

当然实际情况中我们不会故意写这么一行代码让w3wp崩溃,也许你会说,我一般情况下不在web程序中使用Thread,或者 ThreadPool,即便如此,出现崩溃也是有可能的,因为数据库的连接池,HttpRuntime管理请求队列等系统方法中也会用到Thread,或 者System.Threading.Timer类,或者ThreadPool。我曾经亲身遭遇到系统方法导致崩溃,是因为SQL server的数据库连接池被耗尽,取不出新的数据库连接而导致崩溃,这和以上一行代码导致崩溃的原理是一样的。

 

可以这么说这种崩溃是一种微软设计的应该崩溃的情况,微软认为如果在多线程中执行过程中发生异常就应该让进程崩溃。而这种崩溃发生之后留下的系统日 志往往很少,我们只能看到崩溃的错误,而得不到崩溃的具体点或者崩溃发生的调用堆栈。俗话说:“办法总比苦难多”,虽然系统没有记录,但是我们可以通过代 码来让系统记录崩溃原因。我们有两种办法来得到崩溃原因。

 

第一种办法是利用反射在Global的Application_End事件中记录HttpRuntime的退出堆栈和退出原因。如果你手头有反编译的工具,你可以反编译一下System.Web.HttpRuntime类,你可以看到此类有两个私有的字段:

1 private string _shutDownMessage;
2 private string _shutDownStack;

他们记录了w3wp进程的退出消息和退出堆栈,通常我们在Application_End事件中记录这两个变量的值,就可以看到崩溃的堆栈。具体怎么做请看代码

01 protected void Application_End(object sender, EventArgs e)
02 {
03     HttpRuntime runtime = (HttpRuntime)typeof(System.Web.HttpRuntime).InvokeMember("_theRuntime",
04         BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField,
05         null,
06         null,
07         null);
08  
09     if (runtime == null)
10         return;
11  
12     string shutDownMessage = (string)runtime.GetType().InvokeMember("_shutDownMessage",
13         BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
14         null,
15         runtime,
16         null);
17  
18     string shutDownStack = (string)runtime.GetType().InvokeMember(
19         "_shutDownStack",
20         BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
21         null,
22         runtime,
23         null);
24  
25     if (!EventLog.SourceExists(".NETRuntime"))
26     {
27  
28         EventLog.CreateEventSource(".NETRuntime", "Application");
29  
30     }
31  
32     EventLog log = new EventLog();
33  
34     log.Source = ".NET Runtime";
35  
36     log.WriteEntry(String.Format("\r\n\r\n_shutDownMessage={0}\r\n\r\n_shutDownStack={1}", shutDownMessage, shutDownStack), EventLogEntryType.Error);
37 }

以上代码主要使用了反射,本文不做详细解释。

上面的这种方法通常情况可以得到w3wp崩溃的调用堆栈,我们还有另一种方法来获得。利用AppDomain.CurrentDomain.UnhandledException 事件来记录未处理异常的发生原因,代码也很简单:

01 protected void Application_Start(object sender, EventArgs e)
02 {
03     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
04 }
05  
06 void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
07 {
08     Exception ex = e.ExceptionObject as Exception;
09     string msg = ex.Message;
10     string stack = ex.StackTrace;
11 }

以上代码的是在Application Start的时候给AppDomain的UnhandleException时间加处理方法,来记录未处理异常的发生原因。


请尊重作者的劳动,转载请保留链接 玉开的技术博客