在WEB场中,动态网页往往会因为几台主机做了负载而产生SESSION丢失的问题,网上也有很多的介绍,我这里只将我经历的过程给大家分享一下:
系统要运行在负载平衡的 Web 场环境中,而系统配置文件web.config中的Session状态却设置为InProc(即在本地存储会话状态),导至在用户访问量大时,Session常经超时的情况。引起这个现象的原因主要是因为用户通过负载平衡IP来访问WEB应用系统,某段时候在某台服务器保存了Session 的会话状态,但在其它的WEB前端服务器中却没有保存Session的会话状态,而随着并发量的增大,负载平衡会当作路由随时访问空闲的服务器,结果空闲的服务器并没有之前保存的Session会话状态。
解决办法: 
1.当您在负载平衡的 Web 场环境中运行 ASP.NET Web 应用程序时,一定要使用 SqlServer 或 StateServer 会话状态模式,在项目中我们基于性能考虑并没有选择SqlServer模式来存储Session状态,而是选择一台SessionStateServer 服务器来用户的Session会话状态。我们要在系统配置文件web.config中设置如下: 
<sessionState mode="StateServer" cookieless="false" timeout="240" stateConnectionString="tcpip=192.168.0.1:42424" stateNetworkTimeout="14400" />
这里的红字体的IP一定要是同域的一台机器,在这台机器上进行第二步的操作,同时将其注册表中HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Servi ces\aspnet_state\Parameter
s\AllowRemoteConnection的键值改为1,然后重启本机的ASP.NET State Service服务
还要添加一项 
<machineKey validationKey="78AE3850338BFADCE59D8DDF58C9E4518E7510149C46142D7AAD7F1AD49D95D4" decryptionKey="5FC88DFC24EA123C" validation="SHA1"/>
如何生成machineKey?
按照MSDN的标准说法:“对密钥进行配置,以便将其用于对 Forms 身份验证 Cookie 数据和视图状态数据进行加密和解密,并将其用于对进程外会话状态标识进行验证。”也就是说Asp.Net的很多加密,都是依赖于machineKey里面的值,例如Forms 身份验证 Cookie、ViewState的加密。默认情况下,Asp.Net的配置是自己动态生成,如果单台服务器当然没问题,但是如果多台服务器负载均衡,machineKey还采用动态生成的方式,每台服务器上的machinekey值不一致,就导致加密出来的结果也不一致,不能共享验证和ViewState,所以对于多台服务器负载均衡的情况,一定要在每台站点配置相同的machineKey
machineKey生成的算法:
validationKey = CreateKey(20);
decryptionKey = CreateKey(24);
     protected string CreateKey(int len)
     {
             byte[] bytes = new byte[len];
             new RNGCryptoServiceProvider().GetBytes(bytes);
               StringBuilder sb = new StringBuilder();
               for(int i = 0; i < bytes.Length; i++)
               {   
                   sb.Append(string.Format("{0:X2}",bytes[i]));
               }
               return sb.ToString();
     }
附参考的matchineKey配置:
<?xml version="1.0"?>
<configuration>
<system.web>
     <machineKey validationKey="3FF1E929BC0534950B0920A7B59FA698BD02DFE8" decryptionKey="280450BB36319B474C996B506A95AEDF9B51211B1D2B7A77" decryption="3DES" validation="SHA1"/>
     </system.web>
</configuration>

2. 我们同时还要在SessionStateServer 服务器中启动ASP.NET State Service服务,具体设置:控制面板>>管理工具>>服务>>ASP.NET State Service,把它设为自动启动即可。
3. 每台前端WEB服务的Microsoft“Internet 信息服务”(IIS)设置 
             要在 Web 场中的不同 Web 服务器间维护会话状态,Microsoft“Internet 信息服务”(IIS) 配置数据库中 Web 站点的应用程序路径(例如,\LM\W3SVC\2)与 Web 场中所有 Web 服务器必须相同。大小写也必须相同,因为应用程序路径是区分大小写的。在一台 Web 服务器上,承载 ASP.NET 应用程序的 Web 站点的实例 ID 可能是 2(其中应用程序路径是 \LM\W3SVC\2)。在另一台 Web 服务器上,Web 站点的实例 ID 可能是 3(其中应用程序路径是 \LM\W3SVC\3)。因此,Web 场中的 Web 服务器之间的应用程序路径是不同的。我们必须使Web 场Web 站点的实例 ID 相同即可。你可以在IIS中把某一个WEB配置信息保存为一个文件,其他Web 服务器的IIS配置可以来自这一个文件。您如果想知道具体的设置请访问Microsoft Support网站:http://support.microsoft.com/default.aspx?scid=kb;zh-cn;325056
补充一些相关资料:
PRB: Session Variables Are Lost If You Use FRAMESET in Internet Explorer 6.0
http://support.microsoft.com/kb/323752/EN-US/#
PRB: Session Data Is Lost When You Use ASP.NET InProc Session State Mode
http://support.microsoft.com/?id=324772
PRB:如果您使用 SqlServer 或 StateServer 会话模式 Web 场中会丢失会话状态
http://support.microsoft.com/default.aspx?scid=kb;zh-cn;325056

ASP.NET Session State FAQ
http://www.eggheadcafe.com/articles/20021016.asp


参考来自:http://hi.baidu.com/panshuaiyang


应用程序如何用两种方式存储Session信息
以下的各种操作主要是针对这一段配置展开。让我们先看看这一段配置中所包含的内容的意思。sessionState节点的语法是这样的: 

<sessionState mode="Off|InProc|StateServer|SQLServer" 
cookieless="true|false" 
timeout="number of minutes" 
stateConnectionString="tcpip=server:port" 
sqlConnectionString="sql connection string" 
stateNetworkTimeout="number of seconds" 
/> 


必须有的属性是 

属性 选项 描述 
mode 设置将Session信息存储到哪里 
Off 设置为不使用Session功能 
InProc 设置为将Session存储在进程内,就是ASP中的存储方式,这是默认值。 
StateServer 设置为将Session存储在独立的状态服务中。 
SQLServer 设置将Session存储在SQL Server中。 

可选的属性是: 

属性 选项 描述 
cookieless 设置客户端的Session信息存储到哪里 
ture 使用Cookieless模式 
false 使用Cookie模式,这是默认值。 
timeout 设置经过多少分钟后服务器自动放弃Session信息。默认为20分钟 
stateConnectionString 设置将Session信息存储在状态服务中时使用的服务器名称和端口号,例如:"tcpip=127.0.0.1:42424”。当mode的值是StateServer是,这个属性是必需的。 
sqlConnectionString 设置与SQL Server连接时的连接字符串。例如"data source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"。当mode的值是SQLServer时,这个属性是必需的。 
stateNetworkTimeout 设置当使用StateServer模式存储Session状态时,经过多少秒空闲后,断开Web服务器与存储状态信息的服务器的TCP/IP连接的。默认值是10秒钟。 
ASP.NET中客户端Session状态的存储 
在我们上面的Session模型简介中,大家可以发现Session状态应该存储在两个地方,分别是客户端和服务器端。客户端只负责保存相应网站的 SessionID,而其他的Session信息则保存在服务器端。在ASP中,客户端的SessionID实际是以Cookie的形式存储的。如果用户在浏览器的设置中选择了禁用Cookie,那末他也就无法享受Session的便利之处了,甚至造成不能访问某些网站。为了解决以上问题,在ASP.NET中客户端的Session信息存储方式分为:Cookie和Cookieless两种。 

ASP.NET中,默认状态下,在客户端还是使用Cookie存储Session信息的。如果我们想在客户端使用Cookieless的方式存储Session信息的方法如下: 

找到当前Web应用程序的根目录,打开Web.Config文件,找到如下段落: 

<sessionState 
mode="InProc" 
stateConnectionString="tcpip=127.0.0.1:42424" 
sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" 
cookieless="false" 
timeout="20" 
/> 

这段话中的cookieless="false"改为:cookieless="true",这样,客户端的Session信息就不再使用 Cookie存储了,而是将其通过URL存储。关闭当前的IE,打开一个新IE,重新访问刚才的Web应用程序,就会看到类似下面的样子: 


其中,http://localhost/MyTestApplication/(ulqsek45heu3ic2a5zgdl245) /default.aspx中黑体标出的就是客户端的Session ID。注意,这段信息是由IIS自动加上的,不会影响以前正常的连接。 

ASP.NET中服务器端Session状态的存储 
准备工作 

为了您能更好的体验到实验现象,您可以建立一个叫做SessionState.aspx的页面,然后把以下这些代码添加到<body></body>中。 


<scriptrunat="server"> 
Sub Session_Add(sender As Object, e As EventArgs) 
Session("MySession") = text1.Value 
span1.InnerHtml = "Session data updated! <P>Your session contains: <font color=red>" & \ 
Session("MySession").ToString() & "</font>" 
End Sub 

Sub CheckSession(sender As Object, eAs EventArgs) 
If (Session("MySession")Is Nothing) Then 
span1.InnerHtml = "NOTHING, SESSION DATA LOST!" 
Else 
span1.InnerHtml = "Your session contains: <font color=red>" & \ 
Session("MySession").ToString() & "</font>" 
End If 
End Sub 
</script> 
<formrunat="server"id="Form2"> 
<inputid="text1"type="text"runat="server"name="text1"> 
<inputtype="submit"runat="server"OnServerClick="Session_Add" 
value="Add to Session State" id="Submit1"name="Submit1"> 
<inputtype="submit"runat="server"OnServerClick="CheckSession" 
value="View Session State" id="Submit2"name="Submit2"> 
</form> 
<hrsize="1"> 
<fontsize="6"><spanid="span1"runat="server" /></font> 

这个SessionState.aspx的页面可以用来测试在当前的服务器上是否丢失了Session信息。 

将服务器Session信息存储在进程中 
让我们来回到Web.config文件的刚才那段段落中: 

<sessionState 
mode="InProc" 
stateConnectionString="tcpip=127.0.0.1:42424" 
sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" 
cookieless="false" 
timeout="20" 
/> 
当mode的值是InProc时,说明服务器正在使用这种模式。 

这种方式和以前ASP中的模式一样,就是服务器将Session信息存储在IIS进程中。当IIS关闭、重起后,这些信息都会丢失。但是这种模式也有自己最大好处,就是性能最高。应为所有的Session信息都存储在了IIS的进程中,所以IIS能够很快的访问到这些信息,这种模式的性能比进程外存储 Session信息或是在SQL Server中存储Session信息都要快上很多。这种模式也是ASP.NET的默认方式。  
好了,现在让我们做个试验。打开刚才的SessionState.aspx页面,随便输入一些字符,使其存储在 Session中。然后,让我们让IIS重起。注意,并不是使当前的站点停止再开始,而是在IIS中本机的机器名的节点上点击鼠标右键,选择重新启动 IIS。(想当初使用NT4时,重新启动IIS必须要重新启动计算机才行,微软真是@#$%^&)返回到SessionState.aspx页面中,检查刚才的Session信息,发现信息已经丢失了。 

将服务器Session信息存储在进程外 
首先,让我们来打开管理工具->服务,找到名为:ASP.NET State Service的服务,启动它。实际上,这个服务就是启动一个要保存Session信息的进程。启动这个服务后,你可以从Windows任务管理器 ->进程中看到一个名为aspnet_state.exe的进程,这个就是我们保存Session信息的进程。 

然后,回到Web.config文件中上述的段落中,将mode的值改为StateServer。保存文件后的重新打开一个IE,打开 SessionState.aspx页面,保存一些信息到Session中。这时,让我们重起IIS,再回到SessionState.aspx页面中查看刚才的Session信息,发现没有丢失。 

实际上,这种将Session信息存储在进程外的方式不光指可以将信息存储在本机的进程外,还可以将Session信息存储在其他的服务器的进程中。这时,不光需要将mode的值改为StateServer,还需要在stateConnectionString中配置相应的参数。例如你的计算你是 192.168.0.1,你想把Session存储在IP为192.168.0.2的计算机的进程中,就需要设置成这样:stateConnectionString="tcpip=192.168.0.2:42424"。当然,不要忘记在192.168.0.2的计算机中装上.NET Framework,并且启动ASP.NET State Services服务。 

将服务器Session信息存储在SQL Server中 
首先,还是让我们来做一些准备工作。启动SQL Server和SQL Server代理服务。在SQL Server中执行一个叫做InstallSqlState.sql的脚本文件。这个脚本文件将在SQL Server中创建一个用来专门存储Session信息的数据库,及一个维护Session信息数据库的SQL Server代理作业。我们可以在以下路径中找到那个文件: 

[system drive]\winnt\Microsoft.NET\Framework\[version]\ 
然后打开查询分析器,连接到SQL Server服务器,打开刚才的那个文件并且执行。稍等片刻,数据库及作业就建立好了。这时,你可以打开企业管理器,看到新增了一个叫ASPState的数据库。但是这个数据库中只是些存储过程,没有用户表。实际上Session信息是存储在了tempdb数据库的ASPStateTempSessions表中的,另外一个ASPStateTempApplications表存储了ASP中Application 对象信息。这两个表也是刚才的那个脚本建立的。另外查看管理->SQL Server代理->作业,发现也多了一个叫做ASPState_Job_DeleteExpiredSessions的作业,这个作业实际上就是每分钟去ASPStateTempSessions表中删除过期的Session信息的。 

接着,我们返回到Web.config文件,修改mode的值改为SQLServer。注意,还要同时修改sqlConnectionString的值,格式为: 

sqlConnectionString="data source=localhost; Integrated Security=SSPI;" 
其中data source是指SQL Server服务器的IP地址,如果SQL Server与IIS是一台机子,写127.0.0.1就行了。Integrated Security=SSPI的意思是使用Windows集成身份验证,这样,访问数据库将以ASP.NET的身份进行,通过如此配置,能够获得比使用 userid=sa;password=口令的SQL Server验证方式更好的安全性。当然,如果SQL Server运行于另一台计算机上,你可能会需要通过Active Directory域的方式来维护两边验证的一致性。 

同样,让我们做个试验。向SessionState.aspx中添加Session信息,这时发现Session信息已经存在SQL Server中了,即使你重起计算机,刚才的Session信息也不会丢失。现在,你已经完全看见了Session信息到底是什么样子的了,而且又是存储在SQL Server中的,能干什么就看你的发挥了,哈哈。 

总结 
通过这篇文章,你可以看到在Session的管理和维护上,ASP.NET比ASP有了很大的进步,我们可以更加随意的挑选适合的方法了。对于企业级的应用来说,这无疑对于服务器的同步、服务器的稳定性、可靠性都是有利的。相信在强大的微软支持下,新一代的电子商务平台将会搭建的更好!
来自:http://topic.csdn.net/t/20050314/17/3850093.html

 

转自:http://hi.baidu.com/sai5d/blog/item/5b481d16d5f69d1f962b436c.html

posted @ 2011-10-31 17:31 chenzhaohf 阅读(338) 评论(0) 编辑

HttpModule与HttpHandler详解

ASP.NET对请求处理的过程:
当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给ASPNET_ISAPI.dll,ASPNET_ISAPI.dll会通过http管道(HttpPipeLine)将请求发送给ASPNET_WP.exe进程,在ASPNET_WP.exe进程中通过HttpRuntime来处理这个请求,处理完毕将结果返回客户端。
     inetinfo.exe进程:是www服务的进程,IIS服务和ASPNET_ISAPI.DLL都寄存在此进程中。
     ASPNET_ISAPI.DLL:是处理.aspx文件的win32组件。其实IIS服务器是只能识别.html文件的,当IIS服务器发现被请求的文件是.aspx文件时,IIS服务器将其交给aspnet_isapi.dll来处理。
     aspnet_wp.exe进程:ASP.NET框架进程,提供.net运行的托管环境,.net的CLR(公共语言运行时)就是寄存在此进程中。
ASP.NET Framework处理一个Http Request的流程:
   HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNET_WP.exe-->HttpRuntime-->HttpApplicationFactory-->HttpApplication-->HttpModule-->HttpHandlerFactory-->HttpHandler-->HttpHandler.ProcessRequest()

ASP.NET请求处理过程是基于管道模型的,这个管道模型是由多个HttpModule和HttpHandler组成,ASP.NET把http请求依次传递给管道中各个HttpModule,最终被HttpHandler处理,处理完成后,再次经过管道中的HTTP模块,把结果返回给客户端。我们可以在每个HttpModule中都可以干预请求的处理过程。


注意:在http请求的处理过程中,只能调用一个HttpHandler,但可以调用多个HttpModule。 
当请求到达HttpModule的时候,系统还没有对这个请求真正处理,但是我们可以在这个请求传递到处理中心(HttpHandler)之前附加一些其它信息,或者截获的这个请求并作一些额外的工作,也或者终止请求等。在HttpHandler处理完请求之后,我们可以再在相应的HttpModule中把请求处理的结果进行再次加工返回客户端。
HttpModule
     HTTP模块是实现了System.Web.IhttpModule接口的类。
     IHttpModule接口的声明:
         public interface IHttpModule
         {
             void Init (HttpApplication context);
             void Dispose ();
         }
       Init 方法:系统初始化的时候自动调用,这个方法允许HTTP模块向HttpApplication 对象中的事件注册自己的事件处理程序。
         Dispose方法: 这个方法给予HTTP模块在对象被**收集之前执行清理的机会。此方法一般无需编写代码。
     
     HTTP模块可以向System.Web.HttpApplication对象注册下面一系列事件:
         AcquireRequestState 当ASP.NET运行时准备好接收当前HTTP请求的对话状态的时候引发这个事件。 
         AuthenticateRequest 当ASP.NET 运行时准备验证用户身份的时候引发这个事件。 
         AuthorizeRequest 当ASP.NET运行时准备授权用户访问资源的时候引发这个事件。 
         BeginRequest 当ASP.NET运行时接收到新的HTTP请求的时候引发这个事件。 
         Disposed 当ASP.NET完成HTTP请求的处理过程时引发这个事件。 
         EndRequest 把响应内容发送到客户端之前引发这个事件。 
         Error 在处理HTTP请求的过程中出现未处理异常的时候引发这个事件。 
         PostRequestHandlerExecute 在HTTP处理程序结束执行的时候引发这个事件。 
         PreRequestHandlerExecute 在ASP.NET开始执行HTTP请求的处理程序之前引发这个事件。在这个事件之后,ASP.NET 把该请求转发给适当的HTTP处理程序。 
         PreSendRequestContent 在ASP.NET把响应内容发送到客户端之前引发这个事件。这个事件允许我们在内容到达客户端之前改变响应内容。我们可以使用这个事件给页面输出添加用于所有页面的内容。例如通用菜单、头信息或脚信息。 
         PreSendRequestHeaders 在ASP.NET把HTTP响应头信息发送给客户端之前引发这个事件。在头信息到达客户端之前,这个事件允许我们改变它的内容。我们可以使用这个事件在头信息中添加cookie和自定义数据。 
         ReleaseRequestState 当ASP.NET结束所搜有的请求处理程序执行的时候引发这个事件。 
         ResolveRequestCache 我们引发这个事件来决定是否可以使用从输出缓冲返回的内容来结束请求。这依赖于Web应用程序的输出缓冲时怎样设置的。 
         UpdateRequestCache 当ASP.NET完成了当前的HTTP请求的处理,并且输出内容已经准备好添加给输出缓冲的时候,引发这个事件。这依赖于Web应用程序的输出缓冲是如何设置的。
     上面这么多的事件,我们看起来可能会有些眼晕,但没关系,下面一步一步地看。
     HttpModule生命周期示意图

     下面是事件的触发顺序:

     BeginRequest和PreRequestHandlerExecute之间的事件是在服务器执行HttpHandler处理之前触发。
     PostRequestHandlerExecute和PreSendRequestContent之间的事件是在服务器执行Handler处理之后触发。
     
     下面我们看一下如何使用HttpModule来实现我们日常的应用:
         HttpModule通过在某些事件中注册,把自己插入ASP.NET请求处理管道。当这些事件发生的时候,ASP.NET调用对相应的HTTP模块,这样该模块就能处理请求了。
        1、向每个页面动态添加一些备注或说明性的文字:
             有的网站每一个页面都会弹出一个广告或在每个页面都以注释形式(<!-- -->)加入网站的版权信息。如果在每个页面教编写这样的JS代码的话,对于大一点的网站,这种JS代码的编写与维护可是一个很繁琐枯燥的工作。
           有了HttpModule我们就可以很简单地解决这个问题了。HttpModule是客户端发出请求到客户端接收到服务器响应之间的一段必经之路。我们完全可以在服务器处理完请求之后,并在向客户端发送响应文本之前这段时机,把这段注释文字添加到页面文本之后。这样,每一个页面请求都会被附加上这段注释文字。
             这段代码究竟该在哪个事件里实现呢? PostRequestHandlerExecute和PreSendRequestContent之间的任何一个事件都可以,但我比较喜欢在EndRequest事件里编写代码。
             第一步:创建一个类库ClassLibrary831。
             第二步:编写一个类实现IHttpModule接口
               class TestModule:IHttpModule
                 {
                     public void Dispose()
                     {
                     }
                     public void Init(HttpApplication context)
                     {
                     }
                 } 
             第三步:在Init事件中注册EndRequest事件,并实现事件处理方法
                class TestModule:IHttpModule
                 {
                     public void Dispose(){}
                     public void Init(HttpApplication context)
                     {
                         context.EndRequest += new EventHandler(context_EndRequest);
                     }
                     void context_EndRequest(object sender, EventArgs e)
                     {
                         HttpApplication ha = (HttpApplication)sender;
                         ha.Response.Write("<!--这是每个页面都会动态生成的文字。--grayworm-->");
                     }
                 } 
             第四步:在Web.Conofig中注册一下这个HttpModule模块
          
<httpModules>
          <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
           </httpModules> 
           name:模块名称,一般是类名
           type:有两部分组成,前半部分是命名空间和类名组成的全名,后半部分是程序集名称,如果类是直接放在App_Code文件夹中,那程序名称是App_Code。
                 这样在Web站点是添加该类库的引用后,运行每个页面,会发现其源文件中都会加入“<!--这是每个页面都会动态生成的文字。--grayworm-->”这句话。同样的方法你也可以在其中加入JS代码。
        2、身份检查
             大家在作登录时,登录成功后,一般要把用户名放在Session中保存,在其它每一个页面的Page_Load事件中都检查Session中是否存在用户名,如果不存在就说明用户未登录,就不让其访问其中的内容。
             在比较大的程序中,这种做法实在是太笨拙,因为你几乎要在每一个页面中都加入检测Session的代码,导致难以开发和维护。下面我们看看如何使用HttpModule来减少我们的工作量
           由于在这里我们要用到Session中的内容,我们只能在AcquireRequestState和PreRequestHandlerExecute事件中编写代码,因为在HttpModule中只有这两事件中可以访问Session。这里我们选择PreRequestHandlerExecute事件编写代码。
             第一步:创建一个类库ClassLibrary831。
             第二步:编写一个类实现IHttpModule接口
                 class TestModule:IHttpModule
                 {
                     public void Dispose()
                     {
                     }
                     public void Init(HttpApplication context)
                     {
                     }
                 } 
             第三步:在Init事件中注册PreRequestHandlerExecute事件,并实现事件处理方法
                class AuthenticModule:IHttpModule
                 {
                     public void Dispose(){}
                     public void Init(HttpApplication context)
                     {
                         context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
                     }
                     void context_PreRequestHandlerExecute(object sender, EventArgs e)
                     {
                         HttpApplication ha = (HttpApplication)sender;
                         string path = ha.Context.Request.Url.ToString();
                         int n = path.ToLower().IndexOf("Login.aspx"); 
                         if (n == -1) //是否是登录页面,不是登录页面的话则进入{}
                         {
                             if (ha.Context.Session["user"] == null) //是否Session中有用户名,若是空的话,转向登录页。
                             {
                                 ha.Context.Response.Redirect("Login.aspx?source=" + path);
                             }
                         }
                     }
                 } 
             第四步:在Login.aspx页面的“登录”按钮中加入下面代码
                 protected void Button1_Click(object sender, EventArgs e)
                 {
                     if(true)     //判断用户名密码是否正确
                     { 
                         if (Request.QueryString["source"] != null)
                         {
                             string s = Request.QueryString["source"].ToLower().ToString();    //取出从哪个页面转来的
                             Session["user"] = txtUID.Text;
                             Response.Redirect(s); //转到用户想去的页面
                         }
                         else
                         {
                             Response.Redirect("main.aspx");     //默认转向main.aspx
                         }
                     } 
                 } 
             第五步:在Web.Conofig中注册一下这个HttpModule模块
          
<httpModules>
            <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
           </httpModules> 
        3、多模块的操作 
             如果定义了多个HttpModule,在web.config文件中引入自定义HttpModule的顺序就决定了多个自定义HttpModule在处理一个HTTP请求的接管顺序。
            
HttpHandler
     HttpHandler是HTTP请求的处理中心,真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。
     HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。
     IHttpHandler接口声明
    public interface IHttpHandler
     {
         bool IsReusable { get; }
         public void ProcessRequest(HttpContext context); //请求处理函数
     }
     
     示例:把硬盘上的图片以流的方式写在页面上
       class TestHandler : IHttpHandler
         {
             public void ProcessRequest(HttpContext context)
             {
                 FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                 byte[] b = new byte[fs.Length];
                 fs.Read(b, 0, (int)fs.Length);
                 fs.Close();
                 context.Response.OutputStream.Write(b, 0, b.Length);
             }
             public bool IsReusable
             {
                 get
                 {
                     return true;
                 }
             }
         }
         Web.Config配置文件
      <httpHandlers>
        <add verb="*" path="*" type="ClassLibrary831.TestHandler,ClassLibrary831"></add>
       </httpHandlers> 
            Verb属性:指定了处理程序支持的HTTP动作。*-支持所有的HTTP动作;“GET”-支持Get操作;“POST”-支持Post操作;“GET, POST”-支持两种操作。 
  Path属性:指定了需要调用处理程序的路径和文件名(可以包含通配符)。“*”、“*.aspx”、“showImage.aspx”、“test1.aspx,test2.aspx”
  Type属性:用名字空间、类名称和程序集名称的组合形式指定处理程序或处理程序工厂的实际类型。ASP.NET运行时首先搜索bin目录中的DLL,接着在GAC中搜索。 
       这样程序运行的效果是该网站的任何一个页面都会显示worm.jpg图片。如何只让一个页面(default21.aspx)执行HttpHandler中的ProcessRequest方法呢?最简单的办法是在Web.Config文件中把path配置信息设为default21.aspx。
         根据这个例子大家可以考虑一下如何编写“验证码”了。
IHttpHandler工厂
     IHttpHandlerFactory的作用是对IHttpHandler进行管理。工厂的作用请见[url]http://hi.baidu.com/grayworm/blog/item/4a832160f8c9de46eaf8f8c1.html[/url]"
     IHttpHandlerFactory接口的声明:
         public interface IHttpHandlerFactory
         {
             IHttpHandler GetHandler (HttpContext context,string requestType,string url,string pathTranslated);
             void ReleaseHandler (IHttpHandler handler);
         }
        GetHandler返回实现IHttpHandler接口的类的实例,ReleaseHandler使工厂可以重用现有的处理程序实例。
     示例:两个用IHttpHandlerFactory来实现对不同HttpHandler的调用。
     有两个HttpHandler:将图片显示在页面上的HttpHandler和生成验证码的Handler
         //将图片显示在页面上的Handler
         class TestHandler : IHttpHandler
         {
             public void ProcessRequest(HttpContext context)
             {
                 FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                 byte[] b = new byte[fs.Length];
                 fs.Read(b, 0, (int)fs.Length);
                 fs.Close();
                 context.Response.OutputStream.Write(b, 0, b.Length);
             }
             public bool IsReusable
             {
                 get
                 {
                     return true;
                 }
             }
         }
         //生成验证码的Handler 
         class CodeHandler:IHttpHandler
         {
             public bool IsReusable
             {
                 get
                 {
                     return true;
                 }
             }
             public void ProcessRequest(HttpContext context)
             {
                 Image b = new Bitmap(50,20);
                 Graphics g = Graphics.FromImage(b);
                 SolidBrush sb = new SolidBrush(Color.White);
                 Font f = new Font("宋体", 12);
                 string str = "";
                 Random r = new Random();
                 for (int i = 0; i < 4; i++)
                 {
                     str += r.Next(10);
                 }
                 g.DrawString(str,f,sb,0,0);
                 b.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
             }
         } 
          IHttpHandler工厂
          class TestHandlerFactory : IHttpHandlerFactory
          {
             public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
             {
                 
                 string fname = url.Substring(url.IndexOf('/') + 1);
                 while (fname.IndexOf('/') != -1)
                     fname = fname.Substring(fname.IndexOf('/') + 1);
                 string cname = fname.Substring(0, fname.IndexOf('.'));
                 string className ="";

                 className = "ClassLibrary831.CodeHandler";
                 object h = null;
                 try
                 {
                     //h = new TestHandler();
                     h = Activator.CreateInstance(Type.GetType(className));
                 }
                 catch (Exception e)
                 {
                     throw new HttpException("工厂不能为类型" + cname + "创建实例。", e);
                 }
                 return (IHttpHandler)h;
             }
             public void ReleaseHandler(IHttpHandler handler)
             {
             }
          }(车延禄)
         配置文件
     <httpHandlers>
    <add verb="*" path="default21.aspx,default22.aspx"type="ClassLibrary831.TestHandlerFactory,ClassLibrary831"></add>
    </httpHandlers>

    这样TestHandlerFactory就会根据请求的不同页面执行不同的HttpHandler处理程序了。
HttpHandler使用会话
     如果要在处理程序中使用Session,那必须把该HttpHandler实现IRequiresSessionState接口,,IRequiresSessionState接口是个空接口,它没有抽象方法,只是一个标记。此处就不作例子验证了。
 

http://lidup.blog.51cto.com/426277/139695

posted @ 2011-09-22 13:38 chenzhaohf 阅读(14) 评论(0) 编辑

今天博客开通了,这是个helloworld.haha.

posted @ 2011-09-13 10:00 chenzhaohf 阅读(6) 评论(0) 编辑