.Net技术中心
===========================================================
dotnet中使用嵌入资源
===========================================================

最近打算做一个将excel文件转为xmlpipeline component,过程中需要给这个组件做个ICON,就需要处理位图和把icon作为资源嵌入到程序集中,使用时在程序集中找到icon的资源还原成icon。嵌入资源部分以前一直没做过,这回借机把嵌入资源部分的内容学习一下。

Dotnet中嵌入资源(位图、图标或光标等)有两种方式,一是直接把资源文件加入到项目,作为嵌入资源,在代码中通过AssemblyGetManifestResourceStream方法获取资源的Stream。另一种方法是在项目中加入. resx资源文件,在资源文件中添加资源,由ResourceManager类统一管理其中的资源。

下面分别详述这两种方法

一、 使用GetManifestResourceStream读取嵌入资源

1、 加入资源文件

直接把要嵌入到程序集的资源文件加入到项目中,可以加在项目的根目录,可以加在项目的任何目录中。

2、 设置资源文件的“BuildAction”属性

将嵌入资源文件的“BuildAction”属性设置为“Embedded Resource

3、 代码中使用嵌入资源

//获得正在运行类所在的名称空间

Type type = MethodBase.GetCurrentMethod().DeclaringType;

string _namespace = type.Namespace;

//获得当前运行的Assembly

Assembly _assembly = Assembly.GetExecutingAssembly();

//根据名称空间和文件名生成资源名称

string resourceName = _namespace + ".directory.BitmapManifest.bmp";

//根据资源名称从Assembly中获取此资源的Stream

Stream stream = _assembly.GetManifestResourceStream(resourceName);

Image myImage = Image.FromStream(stream);

注意资源名称的组成规则:

项目默认名称空间.资源在项目中所在目录.资源文件名

上面代码中BitmapManifest.bmp位图就在项目的directory目录下。如果资源文件直接在项目根目录,则为项目默认名称空间.资源文件名

再给一个xml资源的例子:

//获得正在运行类所在的名称空间

Type type = MethodBase.GetCurrentMethod().DeclaringType;

string _namespace = type.Namespace;

//获得当前运行的Assembly

Assembly _assembly = Assembly.GetExecutingAssembly();

//根据名称空间和文件名生成资源名称

string resourceName = _namespace + ".XMLFileTest.xml";

//根据资源名称从Assembly中获取此资源的Stream

Stream stream = _assembly.GetManifestResourceStream(resourceName);

XmlDocument xmlDoc = null;

xmlDoc = new XmlDocument();

xmlDoc.Load(stream);

二、 使用. resx资源文件嵌入资源

1、 新建资源文件

在项目中新建一个资源文件,资源文件以.resx为后缀,同时还会新建一个跟资源文件同名的Designer.cs文件。

其实资源文件最大的用处是用来做多语言版本的软件时保存不同语言的资源,比如不同语言的菜单文本,可以把不同语言的字符串放在同一个资源类型下的不同资源包中,程序运行时根据运行时系统的culture选择不同的包显示不同语言的字符串。这里我们不关心多语言的资源的应用,所有略过这部分。

新建了资源文件后就能往资源文件中添加资源文件:

clip_image001

Figure.1 .resx资源文件可嵌入的资源类型

资源中可以添加字符串、位图、图标、音频、文件等等的资源。

添加的资源都会被保存在项目的Resources文件夹中。

2、 设置资源文件的“BuildAction”属性

Resources文件夹中的所有资源文件的“BuildAction”属性设置为“Embedded Resource”。

3、 资源存在方式

.resx资源文件管理的资源可以用两种存在形式,一种是以一般的文件形式存在于Resources文件夹中,另一个是经过Base64编码后嵌入到.resx资源文件中。

clip_image002

Figure.2 .resx资源文件中资源存在方式

打开.resx资源文件,选择资源,在属性中Persistence属性决定资源的存在形式。资源的两种存在形式,在代码中调用都是一样的。

4、 代码中使用嵌入资源

//获得正在运行类所在的名称空间

Type type = MethodBase.GetCurrentMethod().DeclaringType;

string _namespace = type.Namespace;

//获取当前主程序集

Assembly currentAssembly = Assembly.GetExecutingAssembly();

//资源的根名称

string resourceRootName = _namespace + ".ResourceTest";

//实例化资源管理类

ResourceManager resourceManager = new ResourceManager(resourceRootName, currentAssembly);

//根据资源名获得资源对象

Icon myIcon = (Icon)resourceManager.GetObject("IconTest");

注意资源的根名称的规则:

资源的根名称就是这个资源文件类的全名称。打开.resx资源文件相应的Designer.cs文件能看到资源类的全名称:名称空间.资源类名

资源名:

资源名就是某个资源在.resx资源文件中的名称,打开.resx资源文件可以看到各个资源的名称。上面图中图标文件IconTest.ico的名称是IconTest


dotnet 发表于:2007.09.14 10:40 ::分类: ( .NET技术开发 ) ::阅读:(1354次) :: 评论 (2)
===========================================================
C#的方法的参数修饰符详解
===========================================================

方法参数修饰
如果参数的修饰是啥也没有,那么其参数传递的方式是值传递,接受方收到的是原始数据的拷贝。
out 说明了参数是引用传递。
params 可变参,注意了这种修饰符针对的参数一定是最后一个参数
ref 引用传递,参数的内容会改变。

// 缺省是传值
public static int Add(int x, int y)
{
int ans = x + y;
x = 10000;
y = 88888;
return ans;
}

static void Main(string[] args)
{
int x = 9, y = 10;
Console.WriteLine("调用前: X: {0}, Y: {1}", x, y);
Console.WriteLine("结果: {0}", Add(x, y));
Console.WriteLine("调用后: X: {0}, Y: {1}", x, y);
}

// 输出修饰
public static void Add(int x, int y, out int ans)
{
ans = x + y;
}

static void Main(string[] args)
{
// 不需要进行本地赋值
int ans;
Add(90, 90, out ans);
Console.WriteLine("90 + 90 = {0} ", ans);
}

// 多个输出修饰
public static void FillTheseValues(out int a, out string b, out bool c)
{
a = 9;
b = "Enjoy your string.";
c = true;
}

static void Main(string[] args)
{
int i;
string str;
bool b;
FillTheseValues(out i, out str, out b);
Console.WriteLine("Int is: {0}", i);
Console.WriteLine("String is: {0}", str);
Console.WriteLine("Boolean is: {0}", b);
}

//引用修饰
public static void SwapStrings(ref string s1, ref string s2)
{
string tempStr = s1;
s1 = s2;
s2 = tempStr;
}
This method can be called as so:
static void Main(string[] args)
{
string s = "第一个字符串";
string s2 = "其他字符串";
Console.WriteLine("之前: {0}, {1} ", s, s2);
SwapStrings(ref s, ref s2);
Console.WriteLine("之后: {0}, {1} ", s, s2);
}

//可变参
static double CalculateAverage(params double[] values)
{
double sum = 0;
for (int i = 0; i < values.Length; i++)
sum += values[i];
return (sum / values.Length);
}

static void Main(string[] args)
{
// Pass in a comma-delimited list of doubles...
double average;
average = CalculateAverage(4.0, 3.2, 5.7);
Console.WriteLine("4.0, 3.2, 5.7 的平均数是: {0}",
average);
double[] data = { 4.0, 3.2, 5.7 };
average = CalculateAverage(data);
Console.WriteLine("Average of data is: {0}", average);
Console.ReadLine();
}


dotnet 发表于:2007.09.13 09:14 ::分类: ( .NET技术开发 ) ::阅读:(440次) :: 评论 (0)
===========================================================
理解.NET中的数据库连接池
===========================================================

摘要:

连接池能在程度上提高数据库访问性能。本文讨论到底何为连接池,它如何提高数据库访问性能,以及如何在.NET中创建连接池并增加或移除连接。

导言

连接数据库是应用程序中耗费大量资源且相对较慢的操作,但它们又是至关紧要的。连接池是已打开的及可重用的数据库连接的一个容器。连接池在所有的数据库连接都关闭时才从内存中释放。使用连接池最基本的好处是提高应用程序的性能及可伸缩性,而其主要缺点是会有一个或多个数据库连接将一直保持打开状态,即使当前不在使用。ADO.NETData Providers将默认情况下将使用连接池,如果你不想使用连接池,必须在连接字符串中指定”Polling=false”。连接池中为你提供了空闲的打开的可重用的数据库连接,而不再需要每次在请求数据库数据时新打开一个数据库连接。当数据库连接关闭或释放时,将返回到连接池中保持空闲状态直到新的连接请求到来。如果我们有效地使用连接池,打开和关闭数据库将不再很耗费资源。本文讨论连接池的相关内容以及如何有效的使用连接池来提高应用程序的效率及可伸缩性。

连接池如何工作

连接池中包含打开的可重用的数据库连接。在同一时刻同一应用程序域中可以有多个连接池,但连接池不可以跨应用程序域共享。注意:一个连接池是通过一个唯一的连接字符串来创建。连接池是根据第一次请求数据库连接的连接字符串来创建的,当另外一个不同的连接字符串请求数据库连接时,将创建另一个连接池。因此一个连接字符中对应一个连接池而不是一个数据库对应一个连接池。如以下代码所示

代码1

// 新建一个连接池

SqlConnection sqlConnection = new SqlConnection();

sqlConnection.ConnectionString = 

"Server=localhost;Database=test;User ID=joydip;Password=joydip;Trusted_Connection=False";

sqlConnection.Open();      

代码2

// 因为连接字符串不同,新建另一个连接池

SqlConnection conn = new SqlConnection();

sqlConnection.ConnectionString = 

"Server=localhost;Database=test;User ID=test;Password=test;Trusted_Connection=False";

sqlConnection.Open();   

代码3

// 因为连接字符串与代码1相同,不再创建连接池.

SqlConnection conn = new SqlConnection();

sqlConnection.ConnectionString = 

"Server=localhost;Database=test;User ID=joydip;Password=joydip;Trusted_Connection=False";

sqlConnection.Open();      

当有新的数据库连接请求到来时,连接池中连接进行了响应而不用创建一个新的数据库连接,也就是说数据库连接可以被重用,而不需要重新新建连接。因此这提高了应用程序的效率和可伸缩性。当你在应用程序中关闭一个打开的数据库连接时,该连接返回到连接池中等待重新连接直到等待超时。在这个时间内等待同一数据库相同连接信息的连接请求。如果这个时间内没有连接请求,这个数据库连接将被关闭,并从连接池中移除这个连接实例。

当一个新的连接池创建后,数据库连接被添加到池中,连接池和池中的连接立即可被使用。连接池中将填满连接字个串中指定的最小连接数量的连接。连接池中连接在长时间不活动或超出指定的生存期时将被移除。

连接池由连接池管理器维护。当后续的连接请求到来,连接池管理器在连接池中寻找可用的空闲的连接,如果存在就交给应用程序使用。以下描述了当一个新的连接请求到来时连接管理器如何工作

· 如果有未用连接可用,返回该连接

· 如果池中连接都已用完,创建一个新连接添加到池中

· 如果池中连接已达到最大连接数,请求进入等待队列直到有空闲连接可用

通过连接字符串中传递的参数可以控制连接池。基本的参数包括:

· Connect Timeout

· Min Pool Size

· Max Pool Siz

· Pooling

为了有效的使用连接池,记住数据库操作完成后马上关闭连接,这样连接才能返回连接池中。

提高连接池性能

我们应该在最晚时刻打开连接并在最早时刻释放连接,即在使用完成后立即释放。数据库连接应该在真正请求数据时才打开,而不应在使用之前就请求连接,这会减少池中可用连接的数量,因此有害于连接池的操作及应用程序性能。数据库连接应使用完成后立即释放,这能促进连接池更好的使用,因为连接可以返回池中被重新使用。以下代码展示如何在应用程序中有效地打开和关闭连接

代码4

SqlConnection sqlConnection = new SqlConnection(connectionString);

try

{

  sqlConnection.Open();

  //Some Code

}

 

finally

{

  sqlConnection.Close();

}

代码4可以使用”using”关键字进一步简化如以下代码所示

代码5

using(SqlConnection sqlConnection = new SqlConnection(connectionString))

{

  sqlConnection.Open();

  //Some Code

}

注:以上代码5中的”using”关键字将隐含地生成try-finally

以下列举了更好地使用连接池的几个可参考要点

· 在需要使用时才打开连接,并在完成操作后马上关闭

· 在关闭连接时先关闭相关用户定义的事务

· 确保维持连接池中至少有一个打开的连接

· 在使用集成身份验证的情况下避免使用连接池

连接池可以通过以下途径进行监控

· 使用sp_whosp_who2存储过程

· 使用SQL ServerProfiler

· 使用性能监视器的性能计数器

参考文献

Tuning Up ADO.NET Connection Pooling in ASP.NET Applications

Connection Pooling for the .NET Framework Data Provider for SQL Server

The .NET Connection Pool Lifeguard

ADO.NET Connection Pooling Explained

结语

连接池是数据库连接对象的容器,只要其中存在活动的或打开的连接它维持活动状态。当使用一个连接字符串来请求数据库连接时,将分配一个新的连接池。通过在应用程序中使用相同的连接字符串我们可以提高应用程序的性能和可伸缩性。然而如果我们不正确地使用连接池可能给我们的应用程序带来负效果。MSDN中说“连接是提高应用程序性能的有力工具,但如果使用不当连接池非但不是有益的而且是害的”。本文讨论了连接池的相关内容以及如何有效的使用连接池来提高应用程序的效率及可伸缩性。


dotnet 发表于:2007.09.11 16:39 ::分类: ( .NET技术开发 ) ::阅读:(678次) :: 评论 (2)
===========================================================
深入解析ASP.NET架构
===========================================================
MSDN的WEBCAST,感觉单纯看一遍意义不大,做个笔记,以备不时只需查找方便。代码部分本人在XP+VS2005+SQL2005测试通过。

首先我们来说一下Asp.net工作原理。
具体描述下这样的:首先客户请求WEB页。然后WEB服务寻找指令文件(.aspx),而这时就是aspnet_isapi.dll这个动态连接库来处理。接着Asp.net代码被发送到公共语言运行时进行编译。接着HTML流返回给浏览器和令。最后由浏览器处理HTML并显示页面。

什么是ISAPI呢?
在Internet时代的开端,客户端的需求非常有限;.htm文件就可以满足他们的需求。但是,随着时间的流逝,客户端需求的扩充超越了.htm文件或静态文件所包含的功能。
开发者需要扩充或扩展Web服务器的功能。Web服务器厂商设计了不同的解决方案,但是都遵循同一个主题“向Web服务器插入某些组件”。所有的Web服务器补充技术都允许开发者建立并插入组件以增强Web服务器的功能。微软公司提出了ISAPI(Internet服务器API),网景公司提出了NSAPI(网景服务器API)等等。ISAPI是一种重要的技术,它允许我们增强与ISAPI兼容的Web服务器(IIS就是一种与ISAPI兼容的Web服务器)的能力。我们使用下面的组件达到这个目的:
1,ISAPI扩展:ISAPI扩展是使用Win32动态链接库来实现的。你可以把ISAPI扩展看作是一个普通的应用程序。ISAPI扩展的处理目标是http请求。
2,ISAPI过滤器:客户端每次向服务器发出请求的时候,请求要经过过滤器。客户端不需要在请求中指定过滤器,只需要简单地把请求发送给Web服务器,接着Web服务器把请求传递给相关的过滤器。接下来过滤器可能修改请求,执行某些登录操作等等。

ASP.NET请求的处理过程:
ASP.NET请求处理过程是基于管道模型的,在模型中ASP.NET把http请求传递给管道中的所有模块。每个模块都接收http请求并有完全控制权限。模块可以用任何自认为适合的方式来处理请求。一旦请求经过了所有HTTP模块,就最终被HTTP处理程序处理。HTTP处理程序对请求进行一些处理,并且结果将再次经过管道中HTTP模块。

ISAPI的筛选器:
IIS本身是不支持动态页面的,也就是说它仅仅支持静态html页面的内容,对于如.asp,.aspx,.cgi,.php等,IIS并不会处理这些标记,它就会把它当作文本,丝毫不做处理发送到客户端。为了解决这个问题。IIS有一种机制,叫做ISAPI的筛选器,它是一个标准组件(COM组件)。
Asp.net服务在注册到IIS的时候,会把每个扩展可以处理的文件扩展名注册到IIS里面(如:*.ascx、*.aspx等)。扩展启动后,就根据定义好的方式来处理IIS所不能处理的文件,然后把控制权跳转到专门处理代码的进程中让这个进程开始处理代码,生成标准的HTML代码,生成后把这些代码加入到原有的Html中,最后把完整的Html返回给IIS,IIS再把内容发送到客户端。

HttpModule:
HttpModule实现了ISAPI Filter的功能,是通过对IhttpModule接口的继承来处理。
HTTP模块是实现了System.Web.IhttpModule接口的.NET组件。这些组件通过在某些事件中注册自身,把自己插入ASP.NET请求处理管道。当这些事件发生的时候,ASP.NET调用对请求有兴趣的HTTP模块,这样该模块就能处理请求了。

HttpModule的实现:
1. 编写一个类,实现IhttpModule接口。
2. 实现Init 方法,并且注册需要的方法。
3. 实现注册的方法。
4. 实现Dispose方法,如果需要手工为类做一些清除工作,可以添加Dispose方法的实现,但这不是必需的,通常可以不为Dispose方法添加任何代码。
5. 在Web.config文件中,注册您编写的类。

下边我们来看例子,HttpModule的实现:
首先添加一个类库,然后在引用里引用System.Web和System.Security这两个命名空间。然后写个类,代码如下:

using System;using System.Collections.Generic;using System.Text;using System.Web;using System.Security.Principal;
namespace Httplibrary{
public class SecurityModules:IHttpModule
{
public void Init(HttpApplication r_objApplication)
  
{
// 向Application 对象注册事件处理程序,核心部分。 r_objApplication.AuthenticateRequest += new EventHandler(this.AuthenticateRequest) ;
  }


  
public void Dispose()
  
{
   
  }


  
private void AuthenticateRequest(object r_objSender,EventArgs r_objEventArgs)
  
{
// 鉴别用户的凭证,并找出用户角色。 HttpApplication objApp = (HttpApplication) r_objSender ;
HttpContext objContext
= (HttpContext) objApp.Context ;
if ( (objApp.Request["userid"] == null) ||(objApp.Request["password"] == null) )
{
objContext.Response.Write(
"用户名和密码为空,验证失败!") ;
objContext.Response.End() ;
}

string userid = "" ;
userid
= objApp.Request["userid"].ToString() ;
string password = "" ;
password
= objApp.Request["password"].ToString() ;
string[] strRoles ;
strRoles
= AuthenticateAndGetRoles(userid, password) ;
if ((strRoles == null) || (strRoles.GetLength(0) == 0))
{
objContext.Response.Write(
"用户名或密码错误!") ;
objApp.CompleteRequest() ;
//终止一个Http请求
}

GenericIdentity objIdentity
= new GenericIdentity(userid,"CustomAuthentication") ;
objContext.User
= new GenericPrincipal(objIdentity, strRoles) ;
}

private string[] AuthenticateAndGetRoles(string r_strUserID,string r_strPassword)
{
string[] strRoles = null ;
if ((r_strUserID.Equals("Zhangsan")) && (r_strPassword.Equals("111")))
{
strRoles
= new String[1] ;
strRoles[
0] = "Administrator" ;
}

else if ((r_strUserID.Equals("Lisi")) && (r_strPassword.Equals("222")))
{
strRoles
= new string[1] ;
strRoles[
0] = "User" ;
}

return strRoles ;
  }

}


}


编译一下,下边做测试页面,很简单,放一个label,text=“测试页面”如果成功则显示测试页面。然后在web.config里面配置,这里很重要。添加 注意注释部分。

<httpModules>
<!--注意我这里的Httplibrary是你添加引用的那个DLL的文件名.Httplibrary.SecurityModules
中前边部分是你那个类的名称空间,后边的是你建的类的名字。
-->
<add name=" Test1 " type="Httplibrary.SecurityModules,Httplibrary"/></httpModules>

然后添加 这个节点,这个大家应该都能明白。
<authorization>
<deny users="?"/>
</authorization>
然后启动测试页面。刚启动开始后页面一定显示“用户名和密码为空,验证失败!”呵呵,别忘记了咱们这就是目的,然后在你的地址栏后边添加?userid=Zhangsan&password=111这行字。然后就会显示“测试页面”这几个字。大家可以多输入几个名字单步调试一下就明白了。
WebConfig设置
<httpModules>
<add type=“classname,assemblyname”
name=“modulename”/>
<remove name=“modulename”/>
<clear/>
</httpModules>
子标记说明:
<add>将HttpModule 类添加到应用程序。请注意,如果以前已指定了相同的谓词/路径组合(例如在父目录的Web.config 文件中),则对的第二个调用将重写以前的设置。
<remove>从应用程序移除HttpModule 类。
<clear>从应用程序移除所有HttpModule 映射。

深入研究HttpModule
HttpModule通过对HttpApplication对象的一系列事件的处理来对HTTP处理管道施加影响,这些事件在HttpModule的Init方法中进行注册,包括:
BeginRequest
AuthenticateRequest
AuthorizeRequest
ResolveRequestCache
AcquireRequestState
PreRequestHandlerExecute
PostRequestHandlerExecute
ReleaseRequestState
UpdateRequestCache
EndRequest
我们都可以对以上事件进行重新定义,注意时重新定义不时覆盖。我们看一个例子,多个HttpModule的实现,建立两个类库,什么都相同就是类名不相同,引入相应的命名空间后我们编写这个类,代码如下:

using System;using System.Collections.Generic;using System.Text;using System.Web;
namespace HttpModuleTest1{
public class Test1Module:IHttpModule
{
public Test1Module()
{

}

public string ModuleName
{
get
{
return "Test1Module";
}

}

public void Init(HttpApplication application)
{
application.BeginRequest
+= new EventHandler(myBeginRequest);
application.EndRequest
+= new EventHandler(myEndRequest);
application.PreRequestHandlerExecute
+= new EventHandler(myPreRequestHandlerExecute);
application.PostRequestHandlerExecute
+= new EventHandler(myPostRequestHandlerExecute);
application.ReleaseRequestState
+= new EventHandler(myReleaseRequestState);
application.AcquireRequestState
+= new EventHandler(myAcquireRequestState);
application.AuthenticateRequest
+= new EventHandler(myAuthenticateRequest);
application.AuthorizeRequest
+= new EventHandler(myAuthorizeRequest);
application.ResolveRequestCache
+= new EventHandler(myResolveRequestCache);
application.PreSendRequestHeaders
+= new EventHandler(myPreSendRequestHeaders);
application.PreSendRequestContent
+= new EventHandler(myPreSendRequestContent);
}

private void myBeginRequest(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Beggining of Request<br>");
}

private void myEndRequest(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:End of Request<br>");
}

private void myPreRequestHandlerExecute(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_RequestHandlerExecute:<br>");
}

private void myPostRequestHandlerExecute(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_PostRequestHandlerExecute:<br>");
}

private void myReleaseRequestState(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_ReleaseRequestState:<br>");
}

private void myAcquireRequestState(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_ReleaseRequestState:<br>");
}

private void myAuthenticateRequest(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_AuthenticateRequest:<br>");
}


private void myAuthorizeRequest(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_AuthorizeRequest:<br>");
}

private void myResolveRequestCache(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_ResolveRequestCache:<br>");
}

private void myPreSendRequestHeaders(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_PreSendRequestHeaders:<br>");
}

private void myPreSendRequestContent(object source, EventArgs e)
{
HttpApplication application
= (HttpApplication)source;
HttpContext context
= application.Context;
context.Response.Write(
"Test1Module:Application_PreSendRequestContent:<br>");
}

public void Dispose()
{
}

}

}


然后在web.config里添加,不明白的看注释部分。


<httpModules>
<!--注意我这里的Httplibrary是你添加引用的那个DLL的文件名.Httplibrary.SecurityModules
中前边部分是你那个类的名称空间,后边的是你建的类的名字。
-->
<add name=" Test1 " type="Httplibrary.SecurityModules,Httplibrary"/>
<add name=" MultiTest1 " type="HttpModuleTest1.Test1Module, HttpModuleTest1" />
<add name=" MultiTest2" type="HttpModuleTest2.Test2Module, HttpModuleTest2" />
</httpModules>

还是用刚才那个测试页面,我们就可以观察到两个test的执行顺序。

我们具体分析一下就是这样的:
HttpRequest开始->进入HttpModule->HttpModule->
首次截获HttpRequest->HttpModule.BeginRequest->
HttpModule.AuthorizeRequest->HttpModule.ResolveRequestCache->
初始化HttpHandler->建立HttpHandler控制点->HttpModule继续处理。HttpHandler已经建立,此后Session可用->HttpModule.AcquireRequestState
->HttpModule.PreRequestHandlerExecute->进入HttpHandler处理HttpRequest
->HttpHandler->HttpHandler.ProcessRequest->返回HttpModule,HttpHandler结束,Session失效->HttpModule.PostRequestHandlerExecute->HttpModule.ReleaseRequestState->
HttpModule.UpdateRequestCache->HttpModule.EndRequest->HttpModule.PreSendRequestHeaders->HttpModule.PreSendRequestContent->
将处理的数据返回客户端,处理结束。


HttpHandler:
HttpHandler实现了ISAPI Extention的功能,他处理请求(Request)的信息和发送响应(Response)。HttpHandler功能的实现通过实现IHttpHandler接口来达到。
HTTP处理程序是实现了System.Web.IHttpHandler接口的.NET组件。任何实现了IHttpHandler接口的类都可以用于处理输入的HTTP请求。HTTP处理程序与ISAPI扩展有些类似。HTTP处理程序和ISAPI扩展的差别在于在URL中可以使用HTTP处理程序的文件名称直接调用它们,与ISAPI扩展类似。

HttpHandler的实现,实现我们的HTTP处理程序包含以下步骤:
编写一个实现IHttpHandler接口的类。
在web.config或machine.config文件中注册这个处理程序。
在Internet服务管理器中把文件扩展(你想要处理的文件扩展名)映射到ASP.NETISAPI扩展DLL(aspnet_isapi.dll)上。


我们来看一个例子,打开IIS服务器,属性,主目录下有个配置,里面你就可以找到你的程序所执行文件所要调用的.dll文件。我们可以看到.aspx就是C:WINDOWSMicrosoft.NETFrameworkv2.0.50727aspnet_isapi.dll这个文件
来执行的。这里还可以添加你自己任意定义任意扩展名文件,定义了后你的服务器就可以认识这些人间,注意只是你的服务器,别人的不认识。这时候大家就会对网络上流行的各式各样的后缀名不奇怪了吧,可以自己定义的。
我们自己定义一个带.xxx后缀的。
添加一个类库,引用的相应的命名空间,