Asp.Net底层解析(四)——应用程序生命周期与HttpModule

ASP.NET中HttpHandler与HttpModule的本质区别与选型指南 HttpHandler和HttpModule是ASP.NET请求生命周期中的两个核心扩展机制,分别承担资源处理与横切干预职责。其设计根植于IIS请求管道的阶段化模型:HttpHandler作为请求的唯一终点执行器,专注生成响应内容;HttpModule则是全程监听的事件订阅者,用于日志、认证、压缩等通用逻辑。理解二者在执行时机、作用范围、状态共享及线程安全上的根本差异,是避免Session丢失、响应乱码、CPU飙升等线上故障的关键。本文结合IIS集成模式、ASP.NET生命周期、请求处理阶段等实战要素,为. 阅读详情

    前言:一般ASP.NET开发者对页面生命周期(PageLife Cycle)是比较熟悉的,在开发ASP.NET应用程序中经常需要从页面周期的角度去思考问题。实际上在页面生命周期的背后,还存在着一个不太为人所熟知的更广义的周期——应用程序生命周期(Application Life Cycle)。本篇文章将详细对其进行说明(IIS6.0)。

    一,应用程序生命周期综述

    所谓应用程序生命周期指的是:从客户端向Web服务器发出资源请求开始,到Web服务器反馈结果返回给客户端的整个在服务器端执行的过程。

    ASP.NET是Web 服务器下的 ISAPI 扩展,Web 服务器接收到请求时,会对所请求的文件的扩展名进行检查,确定应由哪个 ISAPI 扩展处理该请求,然后将该请求传递给合适的 ISAPI 扩展。ASP.NET处理已映射到其上的文件扩展名,如.aspx、.ascx、.ashx和.asmx。因此,aspx页面的请求是首先提交给IIS,然后由IIS通过文件扩展名查找ISAPI最终交给ASP.NET(aspnet_isapi.dll进程)进行处理,再经过一系列规范化的步骤最终生成对应的html编码返回给浏览器。综上可知,ASP.NET的页面生命周期是应用程序生命周期的一部分,而且仅仅当请求文件为aspx页面时才能触发该页面的生命周期。

    下面分阶段描述ASP.NET 应用程序生命周期(这里假设请求资源文件类型为aspx页面,下面的内容大部分是从bitfan前辈的博客文章和MSDN中复制而来):

    1,  用户请求aspx页面:
        A, 当此请求到达Web服务器时,由HTTP.SYS(Windows进行http协议信息通讯的核心组件)负责接收,根据ISAPI扩展设置,将其传递给此ASP.NET应用程序所对应的应用程序池,在此应用程序池中运行的工作者进程负责处理请求。
       B, 工作者进程接收到这个请求之后,装载专用于处理ASP.NET页面的一个ISAPI扩展“aspnet_isapi.dll”,并将HTTP请求传给它。
       C, 工作者进程加载完aspnet_isapi.dll后,由aspnet_isapi.dll负责加载ASP.NET应用程序的运行环境――CLR
       D, 工作者进程工作于非托管环境(指Windows操作系统本身)之中,而.NET中的对象则工作于托管环境(指CLR)之中,aspnet_isapi.dll起到了一个沟通两者的桥梁作用,将收到的HTTP请求(由非托管环境传来)转发给相应.NET对象(处于托管环境中)处理。
   2,  ASP.NET 应用程序(通常意义上的网站)接收第一个请求:
       A, 说明:同一个ASP.NET应用程序只在第一次请求时才会执行该阶段。
       B, 加载CLR之后,由System.Web.Hosting.ApplicationManager类负责创建一个应用程序域。
       C, 每个ASP.NET应用程序都运行于自己的应用程序域中,且对应着一个ApplicationManager类的实例对象,该对象负责对该应用程序进行管理,包括:激活和初始化 ASP.NET 应用程序、管理应用程序生存期和在应用程序中注册的对象的生存期、公开宿主环境使用的对象以处理 ASP.NET 应用程序请求、提供任意给定时刻运行于宿主进程中的应用程序的列表。
       D, 接着在应用程序域中创建一个System.Web.Hosting.HostingEnvironment实例对象,该对象提供对有关应用程序的信息(如存储该应用程序在服务器中的目录等等信息)的访问。
       E,关系图表示为:

   3,  为每个请求创建 ASP.NET 核心对象:
        A, 当应用程序域创建完成之后,一个ISAPIRuntime对象被创建,并自动调用它的ProcessRequest()方法。在此方法中,ISAPIRuntime对象根据传入的HTTP请求创建一个HttpWorkerRequest对象,此对象以面向对象的方式包装了HTTP请求的各种信息(这就是说,原始的HTTP请求信息被封装为HttpWorkerRequest对象)
       B, 然后,调用ISAPIRuntime对象的StartProcessing()方法启动整个HTTP请求处理过程(此即“HTTP管线:HTTP Pipeline”),在这个处理过程的开端,一个HttpRuntime类型的对象被创建,前面创建好的HttpWorkerRequest对象作为方法参数被传送给此HttpRuntime对象的ProcessRequest()方法。
       C, HttpRuntime类的ProcessRequest()方法根据HttpWorkerRequest对象中所提供的HTTP请求信息,创建了一个HttpContext对象。HttpContext 类包含特定于当前应用程序请求的对象,如HttpRequest 和 HttpResponse 对象。
       D, HttpRequest 对象包含有关当前请求的信息,包括 Cookie 和浏览器信息。HttpResponse 对象包含发送到客户端的响应,包括所有呈现的输出和 Cookie。
       E,  在整个HTTP处理过程中,HttpContext对象都是可以访问的,也就是说这个阶段之后的应用程序生命周期内所有使用的HttpContext实际上都是这个HttpContext对象的引用,如aspx页面后台常用的Context属性。
   4,  分配一个HttpApplication 对象用于处理请求:
       A, HttpRuntime 类的 ProcessRequest() 方法除了创建 HttpContext 对象之外,还完成了另一个很重要的工作——向 HttpApplicationFactory 类的一个实例申请分配一个 HttpApplication 对象用于管理整个 HTTP 请求处理管线中的各种事件。
       B, HttpApplicationFactory对象负责管理一个HttpApplication对象池,当有HTTP请求到来时,如果池中还有可用的 HttpApplication对象,就直接分配此对象用于处理HTTP请求,否则,创建一个新的HttpApplication对象。
       C, 如果ASP.NET应用程序无 Global.asax 文件,使用原始的System.Web.HttpApplication类,如果ASP.NET应用程序中有使用在Global.asax中定义的继承于System.Web.HttpApplication的类,作为创建HttpApplication对象的类。
    5,  HttpApplication对象启动HTTP管线:
       A, HttpApplication对象负责装配出整个“HTTP请求处理管线(HTTP Pipeline)”,可以将HttpContext看成是订单(HttpRequest)与产品(HttpResponse)的打包,而将HTTP请求处理管线看做是产品生成流程。在这个流程中,各个模块将根据订单(HttpRequest)提供的信息,将特定的内容添加到产品(HttpResponse)中。
       B, HttpContext对象经过“生产流水线”的不同部分时,HttpApplication对象会先后激发出一连串的事件。一些特定的组件——HTTP模块(HTTP Module)可以响应这些事件,在此事件响应代码中可以对HttpContext对象进行“加工和处理”。从这个意义上说,HTTP模块可以看成是“生产流水线”中的工人。
       C, HTTP模块对象是在HttpApplication对象的InitModules()方法中被创建的,一般在HTTP模块对象的Init方法内对HttpApplication对象所激发的特定事件进行绑定,在这些事件中,各个HTTP模块可以对HttpContext对象进行操作,主要是对HttpResponse进行添加内容,也能够直接将本次请求终止(这里需要注意的是,这里的终止并不会完全将HttpResponse返回空,而是跳过HttpApplication中的一些处理步骤,直接引发EndRequest事件)。
       D, ASP.NET提供了一些预定义的HTTP模块响应特定的事件,开发者也可以编写自己的HTTP模块并将其插入到“HTTP请求处理管线”中(可通过Web.Config配置)。
       E,  在HttpApplication对象触发PreRequestHandlerExecute事件之后,会根据请求调用合适的 IHttpHandler(或由IHttpHandlerFactory确定目标IHttpHandler)类的 ProcessRequest 方法,处理过程临时交给已配置的HttpHandler。这里只考虑aspx页面请求的话,那么本阶段将会调用aspx页面对应后台的继承于Page的类的ProcessRequest方法,从而触发页面生命周期开始执行。调用执行完成目标页面的生命周期之后,得到页面周期内呈现(Render)的html编码将加入到HttpContext对象的HttpResponse中。
       F,  调用请求页面的ProcessRequest 方法之后将会触发HttpApplication的PostRequestHandlerExecute事件,处理过程又交还给HttpApplication,直到触发PreSendRequestHenaders及PreSendRequestConternt。这时HttpApplication的任务算是完成了,HttpContext内的HttpResponse产品就是最终版了。

       G, HttpContext对象带着最后的处理结果来到了“HTTP请求处理管线”的未端,其信息被取出来,再次以aspnet_isapi.dll为桥梁传送给工作者进程。工作者进程再将HTTP请求的处理结果转给HTTP.SYS,由它负责将结果返回给浏览器。

    下面用流程图来直观地展示应用程序周期模型:


    以生产个性化面包对上述过程打个简单的比喻(仅参考,部分细节可能不符):

    1,  IIS就是整个面包店,所有参与的成员都是在IIS的环境下进行的。
    2,  HTTP.SYS是前台收费员,负责收集客户对产品的需求信息,包括请求资源的类型、地址等。
    3,  ISAPI负责联系各个面包房,有些负责生产ASP.NET面包,有些负责htm、shtml面包,还有其他生成各种类型面包的面包房。
    4,  工作者进程是大堂小二,负责前台收费员与面包房内沟通,还负责将面包房生成出来的面包交给前台收费员。
    5,  ASP.NET 应用程序是其中一种面包房,它可以生产aspx、asmx等类型的面包,由它根据前台收费员(HTTP.SYS)接到的订单进行生产。ASP.NET 面包房可以有多个,它们之间是独立运营的,如果其中某个ASP.NET面包房从来没有过客户订单,就没有配备相应的面点师傅了;只有当第一个订单来了,面包房才开始招师傅来干活了。
    6,  ApplicationManager对象是ASP.NET面包房的总负责人,他有对这个面包房的总控制权,包括什么时候开工,什么时候干脆关闭得了。
    7,  由ApplicationManager创建的应用程序域就是面包房内部的工作场所,所有的人员及设置都在里面。
    8,  HostingEnvironment对象是对这个面包房的说明书,各个设备在哪,怎么用等等信息,当然包括卫生合格证明啦,要不然就是违法生产了。
    9,  ISAPIRuntime对象及HttpRuntime对象就看做面包房负责人的命令吧,ISAPIRuntime是初步动员令,而HttpRuntime更是正式命令。
    10, HttpWorkerRequest对象是负责人在发布ISAPIRuntime命令的同时根据前台收费员提供的订单信息而组织的使面包房内部更容易理解的简要需求说明书。
    11, HttpContext对象则是负责人在发布HttpRuntime正式命令时,觉得HttpWorkerRequest还不太规范,因此将其修改为HttpContext对象。HttpContext是打包好的,里面有根据HttpWorkerRequest修改后的更详细的面包需求说明书HttpRequest,还有一个包装盒HttpResponse,里面是“基本”是空的,要求在剩下的步骤里将这个包装盒按照说明书的要求制作出准确的面包。
    12, HttpApplicationFactory是所有面包房的人力资源经理,由他分配由哪个师傅来接手面包房负责人的HttpContext打包。如果店里有手艺的师傅不够了,就再招一个;如果有师傅有闲余时间了,那得了,您上吧。
    13, HttpApplication对象就是人力资源经理分配的师傅了,这里称为“主师傅”,他相当于一个小工头。拿到HttpContext打包之后就开始在面包房了吼嗓子了:“我开始工作了!有谁要在HttpResponse中添加内容的赶紧了,过了就不候着了啊!”、“我要加载初始化Session了,之后Session就可以随便用了!”、“雏形师傅,该你大显身手了!”等等。主师傅的每次吼嗓子都代表着HttpApplication的每个事件,所有主师傅是最累最辛苦的角色了,因为他要吼二十几个嗓子,而且嗓门要大,好让HTTP模块对象们都能听见。
    14, HTTP模块对象的是装点师,装点师有多个,各个师傅的作用都不同;每个装点师在HttpApplication主师傅每次吼嗓子的时候都可以往HttpResponse中添加内容,撒点糖、加点装饰品什么的。装点师有一个很大的权利,他可以要求主师傅直接跳过一些步骤,直接吼“我的任务马上就要结束了!”。这里要注意的是,每次主师傅吼嗓子,装点师往HttpResponse加东西的顺序是固定的,谁来店里来早(就是在Web.config中的配置顺序),谁是前辈,谁就先操作;这一嗓子吼完之后,所有想要往HttpResponse加东西的的装点师都操作过之后,主师傅才会吼下一嗓子;各个装点师可以在主师傅吼完一嗓子之后不理他,等到他吼另一个嗓子的时候再行动,也就是说装点师傅的行动完全是自主的。
    15, IHttpHandler对象是特殊的一类师傅,是专业人才,这里称为雏形师傅(而IHttpHandlerFactory则是这些专业人才的介绍人什么的)。每个IHttpHandler对象只负责一种面包,他会按照自己的理解将这个面包做出来,然后放在主师傅的HttpResponse中。
    16, 这里有个流程需要特别注意,在吼完“雏形师傅,该你大显身手了!”之后,主师傅会将HttpContext打包临时交给IHttpHandler对象,等IHttpHandler对象的工作完成之后再交还给主师傅,之后主师傅会吼“雏形师傅的工作完成了!”。
后续流程:等到主师傅吼完“面包已经完成了,我要把面包放到面包房的产品架上了!”,这时主师傅的工作已经结束了,这时大堂小二会到面包房的产品架去面包交给前台收费员,前台拿到面包后交个客户。这样,一次面包的定制过程就完成了。
    17,  后续流程:等到主师傅吼完“面包已经完成了,我要把面包放到面包房的产品架上了!”,这时主师傅的工作已经结束了,这时大堂小二会到面包房的产品架去面包交给前台收费员,前台拿到面包后交个客户。这样,一次面包的定制过程就完成了。

    下面的表格列举了HttpApplication在启动HTTP管线阶段依次触发的事件

BeginRequest

在 ASP.NET 响应请求时作为 HTTP 执行管线链中的第一个事件发生

AuthenticateRequest

当安全模块已建立用户标识时发生。

PostAuthenticateRequest

当安全模块已建立用户标识时发生。

AuthorizeRequest

当安全模块已验证用户授权时发生。

PostAuthorizeRequest

在当前请求的用户已获授权时发生。

ResolveRequestCache

在 ASP.NET 完成授权事件以使缓存模块从缓存中为请求提供服务后发生,从而绕过事件处理程序(例如某个页或 XML Web services)的执行。

PostResolveRequestCache

在 ASP.NET 跳过当前事件处理程序的执行并允许缓存模块满足来自缓存的请求时发生。

PostMapRequestHandler

在 ASP.NET 已将当前请求映射到相应的事件处理程序时发生。

AcquireRequestState

当 ASP.NET 获取与当前请求关联的当前状态(如会话状态)时发生。

PostAcquireRequestState

在已获得与当前请求关联的请求状态(例如会话状态)时发生。

PreRequestHandlerExecute

恰好在 ASP.NET 开始执行事件处理程序(例如,某页或某个 XML Web services)前发生。

PostRequestHandlerExecute

在 ASP.NET 事件处理程序(例如,某页或某个 XML Web service)执行完毕时发生。

ReleaseRequestState

在 ASP.NET 执行完所有请求事件处理程序后发生。 该事件将使状态模块保存当前状态数据。

PostReleaseRequestState

在 ASP.NET 已完成所有请求事件处理程序的执行并且请求状态数据已存储时发生。

UpdateRequestCache

当 ASP.NET 执行完事件处理程序以使缓存模块存储将用于从缓存为后续请求提供服务的响应时发生。

PostUpdateRequestCache

在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件。

EndRequest

在 ASP.NET 响应请求时作为 HTTP 执行管线链中的最后一个事件发生。

PreSendRequestHeaders

恰好在 ASP.NET 向客户端发送 HTTP 标头之前发生。

PreSendRequestContent

恰好在 ASP.NET 向客户端发送内容之前发生。

二,HttpModule编程

HTTP模块(HttpModule)在应用程序生命周期中的作用在于HttpApplication对象启动HTTP管线阶段,这时所有的HttpModule都可以进行以下操作:

1,  在HttpApplication的各个事件中往HttpResponse添加内容。
2,  当HttpApplication执行出现异常时,执行异常处理机制。
3,  直接终止本次请求,这里需要注意的是,这里的终止并不会完全将HttpResponse返回空,而是跳过HttpApplication中的一些处理步骤,直接引发EndRequest事件,实际上是终结本次HTTP管线。

    利用操作1,我们可以很自由地“影响”最终生成的请求结果,包括实现很猥琐的功能,比如在页面正文之前或之后添加小广告等等。操作2功能很明确,当出现异常时,可以收集异常信息记录错误日志等等。操作3也很好理解,比如今天某个页面我不想对外公开了,直接添加一个HttpModule,如果有访问该页面请求,则直接终止掉就行了;明天又要恢复公开了,那好,把之前那个HttpModule配置给删除就行了。

    下面给出一下实现操作1的简单示例,新建一个Web应用程序,添加一个类库,命名为HttpModules,并且为Web应用程序添加对该类库的引用,解决方案截图如下:


    HttpModules类库添加对System.Web程序集的引用,该类库用于编写各个测试用的HttpModule。这里先编写FullEvents.cs,用于测试Application的所有事件,该HttpModule会在Application的每个事件中都往HttpResponse添加文本(每次添加的文本都会记录本次Application的事件),FullEvents.cs代码如下:

using System;
using System.Web;
namespace HttpModules
{
    public class FullEvents : IHttpModule
    {
        public void Dispose()
        { }  //这里没有什么要释放的资源,所以这里为空
        public void Init(HttpApplication application)
        {
            application.BeginRequest += (sender, e) => { application.Context.Response.Write("Application_BeginRequest<br/>"); };
            application.AuthenticateRequest += (sender, e) => { application.Context.Response.Write("Application_AuthenticateRequest<br/>"); };
            application.PostAuthenticateRequest += (sender, e) => { application.Context.Response.Write("Application_PostAuthenticateRequest<br/>"); };
            application.AuthorizeRequest += (sender, e) => { application.Context.Response.Write("Application_AuthorizeRequest<br/>"); };
            application.PostAuthorizeRequest += (sender, e) => { application.Context.Response.Write("Application_PostAuthorizeRequest<br/>"); };
            application.ResolveRequestCache += (sender, e) => { application.Context.Response.Write("Application_ResolveRequestCache<br/>"); };
            application.PostResolveRequestCache += (sender, e) => { application.Context.Response.Write("Application_PostResolveRequestCache<br/>"); };
            application.PostMapRequestHandler += (sender, e) => { application.Context.Response.Write("Application_PostMapRequestHandler<br/>"); };
            application.AcquireRequestState += (sender, e) => { application.Context.Response.Write("Application_AcquireRequestState<br/>"); };
            application.PostAcquireRequestState += (sender, e) => { application.Context.Response.Write("Application_PostAcquireRequestState<br/>"); };
            application.PreRequestHandlerExecute += (sender, e) => { application.Context.Response.Write("Application_PreRequestHandlerExecute<br/>"); };
            //这里正在执行页面生命周期
            application.PostRequestHandlerExecute += (sender, e) => { application.Context.Response.Write("Application_PostRequestHandlerExecute<br/>"); };
            application.ReleaseRequestState += (sender, e) => { application.Context.Response.Write("Application_ReleaseRequestState<br/>"); };
            application.PostReleaseRequestState += (sender, e) => { application.Context.Response.Write("Application_PostReleaseRequestState<br/>"); };
            application.UpdateRequestCache += (sender, e) => { application.Context.Response.Write("Application_UpdateRequestCache<br/>"); };
            application.PostUpdateRequestCache += (sender, e) => { application.Context.Response.Write("Application_PostUpdateRequestCache <br/>"); };
            application.EndRequest += (sender, e) => { application.Context.Response.Write("Application_EndRequest<br/>"); };
            application.PreSendRequestHeaders += (sender, e) => { application.Context.Response.Write("Application_PreSendRequestHeaders<br/>"); };
            application.PreSendRequestContent += (sender, e) => { application.Context.Response.Write("Application_PreSendRequestContent<br/>"); };
        }
    }
}

    要想在Web应用程序中使用该HttpModule就必须先对其进行注册,可以在Web.config中注册,代码如下:

<system.web>
    <compilation debug="true" targetFramework="4.0" />
  <httpModules>
    <!--只有测试完整Application事件时才使用下面的配置,否则请注释下面的配置-->
    <add name="FullEvents" type="HttpModules.FullEvents,HttpModules"/>
  </httpModules>
</system.web>

    使用页面AspxForFullEvents.aspx用于本次测试,该页面的前台代码为(仅含Form内标签):

<form id="form1" runat="server">
这是页面前台文本<br/><asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</form>

    后台代码如下:

protected void Page_Load(object sender, EventArgs e)
{
    Label1.Text = "这是后台服务器控件生成文本";
}
    运行该页面,得到结果如下:

   

    下面给出一个实现操作2的简单示例,沿用测试1的解决方案,在类库HttpModules中添加文件ErrorHandler.cs用于在HttpModule中进行错误处理,ErrorHandler.cs代码如下:

using System;
using System.Web;
namespace HttpModules
{
    public class ErrorHandler : IHttpModule
    {
        public void Dispose()
        { }  //这里没有什么要释放的资源,所以这里为空
        public void Init(HttpApplication application)
        {
            application.Error += new EventHandler(application_Error);
            application.BeginRequest += new EventHandler(application_BeginRequest);
        }
        private void application_BeginRequest(object sender, EventArgs e)
        {
            throw new Exception("这里故意抛出一个异常,用于测试!"); //Application在运行时可能会出现异常,但是这是小概率事件,所以这里主动抛出异常以便进行测试
        }
        private void application_Error(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            //这里可以设置断点进行监视
            Exception LastError = application.Context.Server.GetLastError();    //这里获取异常信息
            //这里利用LastError,添加任意代码进行错误处理,一般操作是记录错误日志,以便后续查错修正
        }
    }
}

    在Web应用程序中添加AspxForErrorHandler.aspx空页面,且将Web.config中的配置内容修改为:

<httpModules>
  <!--只有测试完整Application事件时才使用下面的配置,否则请注释下面的配置-->
  <!--<add name="FullEvents" type="HttpModules.FullEvents,HttpModules"/>-->
  <!--只有测试错误处理时才使用下面的配置,否则请注释下面的配置-->
  <add name="ErrorHandler" type="HttpModules.ErrorHandler,HttpModules"/>
</httpModules>

    运行AspxForErrorHandler.aspx页面(实际上运行AspxForFullEvents.aspx也是一样的,因为HttpModule是针对每次请求都执行一遍的,不管这次请求的具体页面是什么),因为在Application的BeginRequest中主动抛出一个异常,所以会触发Application的Error事件,执行application_Error方法;后通过ExceptionLastError = application.Context.Server.GetLastError()可获取出错异常的Exception的实例,接下来就可以利用这个LastError进行错误日志记录了,当然你也可以做其他任何你需要的操作。


    下面给出一个实现操作3的简单示例,同样沿用测试1的解决方案,在类库HttpModules中添加文件ErrorHandler.cs用于在HttpModule中进行错误处理,ErrorHandler.cs代码如下:

using System;
using System.Web;
namespace HttpModules
{
    public class CompleteRequest : IHttpModule
    {
        public void Dispose() { }
        public void Init(HttpApplication application)
        {
            application.BeginRequest += new EventHandler(Application_BeginRequest);
            //下面两个是从剩下的近20个事件中随机选择的两个,可以发现这两个事件都不会触发,因为在BeginRequest中调用了CompleteRequest方法,导致直接跳到EndRequest事件。
            application.PostResolveRequestCache += (sender, e) => { application.Context.Response.Write("Application_PostResolveRequestCache<br/>"); };
            application.PostMapRequestHandler += (sender, e) => { application.Context.Response.Write("Application_PostMapRequestHandler<br/>"); };
            //EndRequest事件会被执行,PreSendRequestHeaders与PreSendRequestContent因为在EndRequest之后,因此也会被执行
            application.EndRequest += (sender, e) => { application.Context.Response.Write("Application_EndRequest<br/>"); };
            application.PreSendRequestHeaders += (sender, e) => { application.Context.Response.Write("Application_PreSendRequestHeaders<br/>"); };
            application.PreSendRequestContent += (sender, e) => { application.Context.Response.Write("Application_PreSendRequestContent<br/>"); };
        }
        public void Application_BeginRequest(object sender, EventArgs e)
        {
            HttpApplication application = sender as HttpApplication;
            application.CompleteRequest();
            application.Context.Response.Write("请求被终止<br/>");
        }
    }
}

    在Web应用程序中添加AspxForCompleteRequest.aspx空页面(就算不是空页面也不会显示页面内容,因为已经HttpModule中终止请求,不会再去执行页面生命周期),且将Web.config中的配置内容修改为:

<httpModules>
  <!--只有测试“完整Application事件”时才使用下面的配置,否则请注释下面的配置-->
  <!--<add name="FullEvents" type="HttpModules.FullEvents,HttpModules"/>-->
  <!--只有测试“错误处理”时才使用下面的配置,否则请注释下面的配置-->
  <!--<add name="ErrorHandler" type="HttpModules.ErrorHandler,HttpModules"/>-->
  <!--只有测试“直接终止请求”时才使用下面的配置,否则请注释下面的配置-->
  <add name="CompleteRequest" type="HttpModules.CompleteRequest,HttpModules"/>
</httpModules>

    运行AspxForCompleteRequest.aspx得到结果如下:


    可以看到,Application在BeginRequest中调用了CompleteRequest方法,终止了本次请求,跳过PostResolveRequestCache等等中间事件(包括执行目标页面的生命周期)而直接跳到EndRequest事件。

    可以选择在任意HttpModule的EndRequest之前的任意事件中调用CompleteRequest方法,这里要注意的是:如果HttpModuleA在BeginRequest中调用了CompleteRequest方法,那么HttpModuleB、HttpModuleC的BeginRequest事件都不会执行,而直接转到依次执行三个HttpModule(A、B、C)的EndRequest事件。


    本篇博客的测试代码下载地址: 点击打开链接







asp.NET生命周期图文解释 通过图文详细阐述了asp.net页面的生命周期,让初学者对页面生命周期的了解有一个大致的认识。 立即下载

相关推荐

ASP.NET的网页代码模型及生命周期

第4章 ASP.NET的网页代码模型及生命周期 从本章开始,就进入了ASP.NET应用程序开发的世界。在了解了C#的结构,以及面向对象的概念后,就可以从面向对象的思想开发ASP.NET应用程序。在ASP.NET中,能够使用面向对象的思想和软件开发中的一些思想,例如封装、派生、继承以及高级的设计模式等。本章首先介绍ASP.NET中最重要的概念---网页代码模型。 4.1 ASP.NET的网页代码模型 在ASP.NET应用程序开发中,微软提供了大量的控件,这些控件能够方便用户的开发以及维护。这些控件具有很强的扩展能力,在开发过程中无需自己手动编写。不仅如此,用户还能够创建自定义控件进行应用程序开发以扩展现有的服务器控件的功能。 4.1.1 创建ASP.NET网站 在ASP.NET中,可以创建ASP.NET网站和ASP.NET应用程序,ASP.NET网站的网页元素包含可视元素和页面逻辑元素,并不包含designer.cs文件。而ASP.NET应用程序包含designer.cs文件。创建ASP.NET网站,首先需要创建网站,单击【文件】按钮,在下拉菜单中选择【新建网站】选项,单击后会弹出对话框用于ASP.NET网站的创建,如图4-1所示。 图4-1 新建ASP.NET网站 在【位置】选项中,旁边的【下拉菜单】可以按照开发的需求来写,一般选择文件系统,地址为本机的本地地址。语言为.NET网站中使用的语言,如果选择Visual C#,则默认的开发语言为C#,否则为Visual Basic。创建了ASP.NET网站后,系统会自动创建一个代码隐藏页模型页面Default.aspx。ASP.NET网页一般由三部分组成,这三个部分如下所示。 q 可视元素:包括HTML,标记,服务器空间。 q 页面逻辑元素:包括事件处理程序和代码。 q designer.cs页文件:用来为页面的控件做初始化工作,一般只有ASP.NET应用程序(Web Application)才有。 ASP.NET页面中包含两种代码模型,一种是单文件页模型,另一种是代码隐藏页模型。这两个模型的功能完全一样,都支持控件的拖拽,以及智能的代码生成。 4.1.2 单文件页模型 单文件页模型中的所有代码,包括控件代码、事物处理代码以及HTML代码全都包含在.aspx文件中。编程代码在script标签,并使用runat=“server”属性标记。创建一个单文件页模型,在【文件】按钮中选择【新建文件】选项,在弹出对话框中选择【Web窗体】或在右击当前项目,在下拉菜单中选择【添加新建项】选项即可创建一个.aspx页面,如图4-2所示。 图4-2 创建单文件页模型 在创建时,去掉【将代码放在单独的文件中】复选框的选择即可创建单文件页模型的ASP.NET文件。创建后文件会自动创建相应的HTML代码以便页面的初始化,示例代码如下所示。 <%@ Page Language=“C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=“server”> </script> <html xmlns=“http://www.w3.org/1999/xhtml”> <head runat=“server”> <title>无标题页</title> </head> <body> <form id=“form1” runat=“server”> <div> </div> </form> </body> </html> 编译并运行,即可看到一个空白的页面被运行了。ASP.NET单文件页模型在创建并生成时,开发人员编写的类将编译成程序集,并将该程序集加载到应用程序域,并对该页的类进行实例化后输出到浏览器。可以说,.aspx页面的代码也即将会生成一个类,并包含内部逻辑。在浏览器浏览该页面时,.aspx页面的类实例化并输出到浏览器,反馈给浏览者。ASP.NET单文件页模型运行示例图如图4-3所示。 图4-3 单文件页模型 4.1.3 代码隐藏页模型 代码隐藏页模型与单文件页模型不同的是,代码隐藏页模型将事物处理代码都存放在cs文件中,当ASP.NET网页运行的时候,ASP.NET类生成时会先处理cs文件中的代码,再处理.aspx页面中的代码。这种过程被成为代码分离。 代码分离有一种好处,就是在.aspx页面中,开发人员可以将页面直接作为样式来设计,即美工人员也可以设计.aspx页面,而.cs文件由程序员来完成事务处理。同时,将ASP.NET中的页面样式代码和逻辑处理代码分离能够让维护变得简单,同时代码看上去也非常的优雅。在.aspx页面中,代码隐藏页模型的.aspx页面代码基本上和单文件页模型的代码相同,不同的是在script标记中的单文件页模型的代码默认被放在了同名的.cs文件中,.aspx文件示例代码如下所示。 <%@ Page Language=“C#” AutoEventWireup=“true” CodeFile=“Default.aspx.cs” Inherits=“_Default” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=“http://www.w3.org/1999/xhtml”> <head runat=“server”> <title>无标题页</title> </head> <body> <form id=“form1” runat=“server”> <div> </div> </form> </body> </html> 从上述代码中可以看出,在头部声明的时候,单文件页模型只包含Language=“C#”,而代码隐藏页模型包含了CodeFile=“Default.aspx.cs”,说明被分离出去处理事物的代码被定义在Default.aspx.cs中,示例代码如下所示。 using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; //使用HtmlControls using System.Web.UI.WebControls; //使用WebControls using System.Web.UI.WebControls.WebParts; //使用WebParts public partial class _Default : System.Web.UI.Page //继承自System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } 上述代码为Default.apx.cs页面代码。从上述代码可以看出,其格式与类库、编写类的格式相同,这也说明了.aspx页面允许使用面向对象的特性,如多态、继承等。但是ASP.NET代码隐藏页模型的运行过程比单文件页模型要复杂,运行示例图如图4-4所示。 图4-4 代码隐藏页模型 上述描述了代码隐藏类模型的页面生成模型。当页面被呈现之前,ASP.NET应用程序会解释并编译相应的cs文件中的代码,与此同时,ASP.NET应用程序还会将.aspx页面进行编译并生成.aspx页面对应的类。生成.aspx页面对应的类后会将该类与cs文件中的类进行协调生成新的类,该类会通过IIS在用户浏览页面时呈现在用户的浏览器中。 4.1.4 创建ASP.NET Web Application ASP.NET网站有一种好处,就是在编译后,编译器将整个网站编译成一个DLL(动态链接库),在更新的时候,只需要更新编译后的DLL(动态链接库)文件即可。但是ASP.NET网站却有一个缺点,编译速度慢,并且类的检查不彻底。 相比之下,ASP.NET Web Application不仅加快了速度,只生成一个程序集,而且可以拆分成多个项目进行管理。创建Application,首先需要新建项目用于开发Web Application,单击菜单栏上的【文件】按钮,在下拉菜单中选择【新建项目】选项,在弹出窗口中选择【ASP.NET应用程序】选项,如图4-5所示。 图4-5 创建ASP.NET应用程序 在创建了ASP.NET应用程序后,系统同样会默认创建一个Default.aspx页面,不同的是,多出了一个Default.aspx.designer.cs,用来初始化页面控件,一般不需要修改。 4.1.5 ASP.NET网站和ASP.NET应用程序的区别 在ASP.NET中,可以创建ASP.NET网站和ASP.NET应用程序,但是ASP.NET网站和ASP.NET应用程序开发过程和编译过程是有区别的。ASP.NET应用程序主要有以下特点: q 可以将ASP.NET应用程序拆分成多个项目以方便开发,管理和维护。 q 可以从项目中和源代码管理中排除一个文件或项目。 q 支持VSTS的Team Build方便每日构建。 q 可以对编译前后的名称,程序集等进行自定义。 q 对App_GlobalResources 的Resource强类支持。 ASP.NET WebSite编程模型具有以下特点: q 动态编译该页面,而不用编译整个站点。 q 当一部分页面出现错误不会影响到其他的页面或功能。 q 不需要项目文件,可以把一个目录当作一个Web应用来处理。 总体来说,ASP.NET网站适用于较小的网站开发,因为其动态编译的特点,无需整站编译。而ASP.NET应用程序适应大型的网站开发、维护等。 4.2 代码隐藏页模型的解释过程 在ASP.NET的代码隐藏页模型中,一个完整的.aspx页面包含两个页面,分别是以.aspx和.cs文件为后缀的文件,这两个文件在形成了整个Web窗体。在编译的过程中都被编译成由项目生成的动态链接库(.DLL),同时,.aspx页面同样也会编译。但是与.cs页面编译过程不同的是,当浏览者第一次浏览到.aspx页面时,ASP.NET自动生成该页的.NET类文件,并将其编译成另一个.DLL文件。 当浏览者再一次浏览该页面的时候,生成的.DLL就会在服务器上运行,并响应用户在该页面上的请求或响应,ASP.NET应用程序的解释过程图如4-6所示。 图4-6 代码隐藏页模型页面的执行过程 在客户端浏览器访问该页面时,浏览器会给IIS发送请求消息,IIS则会开始执行ASP.NET编译过程,如果不存在编译过后的DLL文件,则加载编译的类并创建对象。当创建对象完成,生成创建对象后的代码并生成一个ASPX页面代码,该页面代码反馈给IIS,IIS再反馈成HTML页面的形式给客户端。 4.3 代码隐藏页模型的事件驱动处理 在传统的ASP开发中,ASP的事件都是按照网页的顺序来处理的,一般情况下,ASP页面的事件都是从上到下处理事件,可以说ASP的开发是一个线性的处理模型。在用户的浏览操作中,每一次用户的操作都会导致页面重新被发送到服务器。因此,重复的操作必然导致客户端和服务器的往返过程,服务器必须重新创建页面,当创建页面后,服务器再按照原来的从上到下的顺序进行事件处理。 在ASP.NET中,通过使用模拟事件驱动模型的行为代替了ASP的线性处理模型。ASP.NET页框架模型隐式的为用户建立了事件和事件处理程序的关联。ASP.NET让用户可以为从浏览器传递的事件在服务器代码中设置相应的处理程序。假设某个用户正在浏览网站并与页面之间产生了某种交互,用户的操作就会引发事件,事件通过HTTP被传输到服务器。在服务器中,ASP.NET框架解释信息,并触发事件与之对应的处理程序。该程序可以是.aspx页面中的处理程序,也可以是开发者自定义的类库,或者COM组件等。事件驱动处理如图4-7所示。 图4-7 页面框架的事件驱动处理模型 上图则说明了当一个浏览者通过浏览器触发ASPX页面时,浏览器、服务器和服务器返回页的过程。 4.4 ASP.NET客户端状态 Web开发不像软件开发,Web应用实际上是没有状态的,这就说明Web应用程序不自动指示序列中的请求是否来自相同的浏览器或客户端,也无法判断浏览器是否一直在浏览一个页面或者一个站点,也无法判断用户执行了哪个操作并统计用户的喜好。 4.4.1 视图状态 从上面的章节中可以知道,当服务器每次的往返过程,都将销毁页面并重新创建新的页面。如果一个页面中的信息超出了页面的生命周期,那么这个页面中的相关信息就不存在了。如果注销了页面的信息,那么用户的一些信息可能就不存在了。 在ASP.NET中,网页包含视图状态来保存用户的信息,视图状态在页面发回到自身时,跨页过程存储和用户自己的页面的特定值,视图状态的优点如下所示。 q 不需要任何服务器资源。 q 在默认情况下,对控件启用状态的数据进行维护,不会被破坏。 q 视图状态的值经过哈希运算和压缩保护,安全性更高。 视图状态同样有一些缺点,缺点如下所示。 q 视图状态会影响性能,如果页面存储较大较多的值,则性能会有较大的影响。 q 在手机,移动终端上,可能无法保存视图状态中使用的值。 q 视图状态虽然安全性较高,但是还是有风险,如果直接查看页面代码,可以看到相应代码。 4.4.2 控件状态 ASP.NET中还提供了控件状态属性作为在服务器往返过程中存储自定义控件中的数据的方法。在页面控件中,如果有多个自定义控件使用多个不同的控件来显示不同的数据结构,为了让这些页面控件能够在在页面上协调的工作,则需要使用控件状态来保护控件,同时,控件状态是不能被关闭的。同样,控件状态也有它的优点,优点如下所示。 q 与视图状态相同的是,不需要任何服务器资源。 q 控件状态是不能被关闭的,提供了控件管理的更加可靠的方法。 q 控件状态具有通用性。 4.4.3 隐藏域 在ASP中,通常使用隐藏域保存页面的信息。在ASP.NET中,同样具有隐藏域来保存页面的信息,作为维护页面状态的一种形式,但是隐藏域的安全性并不高,最好不要在隐藏域保存过多的信息。隐藏域具有以下优点。 q 不需要任何服务器资源。 q 支持广泛,任何客户端都支持隐藏域。 q 实现简单,隐藏域属于HTML控件,无需像服务器控件那样有需要编程知识。 而隐藏域具有一些不足,如下所示。 q 具有较高的安全隐患。 q 存储结构简单。 q 同样,如果存储了较多的较大的值,则会导致性能问题。 q 如果隐藏域过多,则在某些客户端中被禁止。 q 隐藏域将数据存储在服务器上,而不存储在客户端。 注意:如果开发中,页面的隐藏域过多,这些隐藏域被存储在服务器。当客户端浏览页面的时候,会有一些防火墙扫描页面,以保证操作系统的安全,如果页面的隐藏域过多,那么这些防火墙可能会禁止页面的某些功能。 4.4.4 Cookie Cookie在客户端用户保存网站的少量的用户信息,服务器可以通过编程的方法获取用户信息,Cookie信息和页面请求通常一起发送到服务器,服务器对客户端传递过来的Cookie信息做处理。通常Cookie保存用户的登录状态、用户名等基本信息等等,在后面的章节会详细介绍使用ASP.NET操作Cookies。 4.4.5 客户端状态维护 虽然使用某些客户端状态并不使用服务器资源,但是这些状态都具有潜在的安全隐患,如Cookie。非法用户可以使用Cookie欺骗来攻击网站进行用户信息的获取,不过使用客户端状态能够使用客户端的资源从而提高服务器性能。使用客户端状态,虽然有安全隐患,但是具有良好的编程能力,以及基本的安全知识,能够较好的解决安全问题,同时也能够提高服务器性能。下面小结了一些客户端状态的优缺点。 q 视图状态:推荐当存储少量挥发到自身的页面的信息时使用。 q 控件状态:不需要任何服务器资源,控件状态是不能被关闭的,提供了控件管理的更加可靠和更通用的方法。 q 隐藏域:实现简单,但是在应用程序中会造成一些安全隐患。 q Cookie:实现简单,同样也能够简单的获取用户的信息,但是Cookie有大小的限制,不适宜存储大量的代码。 4.5 ASP.NET页面生命周期 ASP.NET页面运行时,也同类的对象一样,有自己的生命周期。ASP.NET页面运行时,ASP.NET页面将经历一个生命周期,在生命周期内,该页面将执行一系列的步骤,包括控件的初始化,控件的实例化,还原状态和维护状态等,以及通过IIS反馈给用户呈现成HTML。 ASP.NET页面生命周期是ASP.NET中非常重要的概念,了解ASP.NET页面的生命周期,就能够在合适的生命周期内编写代码,执行事务。同样,熟练掌握ASP.NET页面的生命周期,可以开发高效的自定义控件。ASP.NET生命周期通常情况下需要经历几个阶段,这几个阶段如下所示。 q 页请求:页请求发生在页生命周期开始之前。当用户请求一个页面,ASP.NET将确定是否需要分析或者编译该页面,或者是否可以在不运行页的情况下直接请求缓存响应客户端。 q 开始:发生了请求后,页面就进入了开始阶段。在该阶段,页面将确定请求是发回请求还是新的客户端请求,并设置IsPostBack属性。 q 初始化:在页面开始后,进入了初始化阶段。初始化期间,页面可以使用服务器控件,并为每个服务器控件进行初始化。 q 加载:页面加载控件。 q 验证:调用所有的验证程序控件的Vailidate方法,来设置各个验证程序控件和页的属性。 q 回发事件:如果是回发请求,则调用所有事件处理的程序。 q 呈现:在呈现期间,视图状态被保存并呈现到页。 q 卸载:完全呈现页面后,将页面发送到客户端并准备丢弃时,将调用卸载。 4.6 ASP.NET生命周期中的事件 在页面周期的每个阶段,页面将引发可运行用户代码进行处理事件。对于控件产生的事件,通过声明的方式执行代码,并将事件处理程序绑定到事件。不仅如此,事件还支持自动事件连接,最常用的就是Page_Load事件了,除了Page_Load事件以外,还有Page_Init等其他事件,本节将会介绍此类事件。 4.6.1 页面加载事件(Page_PreInit) 每当页面被发送到服务器时,页面就会重新被加载,启动Page_PreInit事件,执行Page_PreInit事件代码块。当需要对页面中的控件进行初始化时,则需要使用此类事件,示例代码如下所示。 protected void Page_PreInit(object sender, EventArgs e) //Page_PreInit事件 { Label1.Text = “OK”; //标签赋值 } 在上述代码中,当触发了Page_PreInit事件时,就会执行该事件的代码,上述代码将Lable1的初始文本值设置为“OK”。Page_PreInit事件能够让用户在页面处理中,能够让服务器加载时只执行一次而当网页被返回给客户端时不被执行。在Page_PreInit中可以使用IsPostBack来实现,当网页第一次加载时IsPostBack属性为false,当页面再次被加载时,IsPostBack属性将会被设置为true。IsPostBack属性的使用能够影响到应用程序的性能。 4.6.2 页面加载事件(Page_Init) Page_Init事件与Page_PreInit事件基本相同,区别在于Page_Init并不能保证完全加载各个控件。虽然在Page_Init事件中,依旧可以访问页面中的各个空间,但是当页面回送时,Page_Init依然执行所有的代码并且不能通过IsPostBack来执行某些代码,示例代码如下所示。 protected void Page_Init(object sender, EventArgs e) //Page_Init事件 { if (!IsPostBack) //判断是否第一次加载 { Label1.Text = “OK”; //将成功信息赋值给标签 } else { Label1.Text = “IsPostBack”; //将回传的值赋值给标签 } } 4.6.3 页面载入事件(Page_Load) 大多数初学者会认为Page_Load事件是当页面第一次访问触发的事件,其实不然,在ASP.NET页生命周期内,Page_Load远远不是第一次触发的事件,通常情况下,ASP.NET事件顺序如下所示。 q 1. Page_Init()。 q 2. Load ViewState。 q 3. Load Postback data。 q 4. Page_Load()。 q 5. Handle control events。 q 6. Page_PreRender()。 q 7. Page_Render()。 q 8. Unload event。 q 9. Dispose method called。 Page_Load事件是在网页加载的时候一定会被执行的事件。在Page_Load事件中,一般都需要使用IsPostBack来判断用户是否进行了操作,因为IsPostBack指示该页是否正为响应客户端回发而加载,或者它是否正被首次加载和访问,示例代码如下所示。 protected void Page_Load(object sender, EventArgs e) //Page_Load事件 { if (!IsPostBack) { Label1.Text = “OK”; //第一次执行的代码块 } else { Label1.Text = “IsPostBack”; //如果用户提交表单等 } } 上述代码使用了Page_Load事件,在页面被创建时,系统会自动在代码隐藏页模型的页面中增加此方法。当用户执行了操作,页面响应了客户端回发,则IsPostBack为true,于是执行else中的操作。 4.6.4 页面卸载事件(Page_Unload) 在页面被执行完毕后,可以通过Page_Unload事件用来执行页面卸载时的清除工作,当页面被卸载时,执行此事件。以下情况会触发Page_Unload事件。 q 页面被关闭。 q 数据库连接被关闭。 q 对象被关闭。 q 完成日志记录或者其他的程序请求。 4.6.5 页面指令 页面指令用来通知编译器在编译页面时做出的特殊处理。当编译器处理ASP.NET应用程序时,可以通过这些特殊指令要求编译器做特殊处理,例如缓存、使用命名空间等。当需要执行页面指令时,通常的做法是将页面指令包括在文件的头部,示例代码如下所示。 <%@ Page Language=“C#” AutoEventWireup=“true” CodeBehind=“Default.aspx.cs” Inherits=“MyWeb._Default” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> 上述代码中,就使用了@Page页面指令来定义ASP.NET页面分析器和编译器使用的特定页的属性。当代码隐藏页模型的页面被创建时,系统会自动增加@Page页面指令。 ASP.NET页面支持多个页面指令,常用的页面指令如下所示。 q @ Page:定义ASP.NET页分析器和编译器使用的页特定(.aspx文件)属性,可以编写为<%@ Page attribute=“value” [attribute=“value”…]%>。 q @ Control:定义ASP.NET页分析器和编译器使用的用户控件(.ascx文件)特定的属性。该指令只能为用户控件配置。可以编写为<%@ Control attribute=“value” [attribute=“value”…]%>。 q @ Import:将命名空间显示导入到页中,使所导入的命名空间的所有类和接口可用户该页。导入的命名空间可以是.NET Framework类库或用户定义的命名空间的一部分。可以编写为<%@ Import namespace=“value” %>。 q @ Implements:提示当前页或用户控件实现制定的.NET Framework接口。可以编写为<%@ Implements interface=“ValidInterfaceName” %>。 q @ Reference:以声明的方式指示,应该根据在其中声明此指令的页对另一个用户控件或页源文件进行动态编译和链接。可以编写为<%@ Reference page | control=“pathtofile” %>。 q @ Output Cache:以声明的方式空间ASP.NET页或页中包含的用户控件的输出缓存策略。可以编写为<%@ Output Cache Duration=“#ofseconds” Location=“Any | Client | Downstream | Server | None” Shared=“True |False” VaryByControl=“controlname” VaryByCustom=“browser | customstring” VaryByHeader=“headers” VaryByParam=“parametername” %> q @ Assembly:在编译过程中将程序集链接到当前页,以使程序集的所有类和接口都可用在该页上。可以编写为<%@ Assembly Name=“assemblyname” %>或<%@ Assembly Src=“pathname” %>的方式。 q @ Register:将别名与命名空间以及类名关联起来,以便在自定义服务器控件语法中使用简明的表示法。可以编写为<%@ Register tagprefix=“ tagprefix” Namespace=“namepace” Assembly=“assembly” %>或<%@ Register tagprefix=“ tagprefix” Tagname=“tagname” Src=“pathname” %>的方式。 4.7 ASP.NET网站文件类型 在ASP.NET中包含诸多的文件类型,这些类型的文件由ASP.NET支持和管理,而除了这些文件以外,其他的文件都由IIS托管。使用VS2008能够创建大部分可以使用ASP.NET托管运行的程序。同时,使用应用程序映射可以将文件类型映射到应用程序。当需要伪静态时,很可能需要将.html后缀托管到IIS中的应用扩展,因为默认情况下ASP.NET不会处理HTML的操作。 技巧:现在的网站构架中,生成静态是一种降低网站压力的一种很好的解决方案。在某些情况下,服务器可能需要伪静态支持,就是将.aspx页面后缀显式成.html后缀,让搜索引擎能够更好的搜录。 1.ASP.NET管理的文件类型 ASP.NET管理的文件类型能够在ASP.NET应用程序中被ASP.NET应用程序的不同模块进行访问和调用,这些文件可能是用户能够直接访问的,也有可能是用户无法直接访问的。ASP.NET管理的文件类型如表4-1所示。 表4-1 ASP.NET管理的文件类型 文件类型 保存位置 描述 .asax 根目录。 Global.asax 文件。包含 HttpApplication 对象的派生代码,用于重新展示 Application 对象。 .ascx 根目录或子目录。 可重用的自定义 Web 控件。 .ashx 根目录或子目录。 处理器文件。包含实现 IHttpHandler 接口的代码,用于处理输入请求。 .asmx 根目录或子目录。 XML Web Services 文件。包含由 SOAP 提供给其他 Web 应用的类对象和功能。 .aspx 根目录或子目录。 ASP.NET Web 窗体。包含 Web 控件和其他业务逻辑。 .axd 根目录。 跟踪视图文件。通常是 Trace.axd。 .browser App_Browsers 目录。 浏览器定义文件。用于识别客户端浏览器的可用特征。 .cd 根目录或子目录。 类图文件。 .compile Bin 目录。 定位于适当汇编集中的预编译文件。可执行文件(.aspx,.ascx,.master,theme)预编译后放在 Bin 目录。 .config 根目录或子目录。 Web.config 配置文件。包含用于配置 ASP.NET 若干特征的 XML 元素集。 .cs,.jsl,vb App_Code 目录。有些是 ASP.NET 的代码分离文件,位于与 Web 页面相同的目录。 运行时被编译的类对象源代码。类对象可以是 HTTP 模块,HTTP 处理器,或 ASP.NET 页面的代码分离文件。 .csproj,vbproj,vjsproj Visual Studio 工程目录。 Visual Studio 客户工程文件。 .disco,.vsdisco App_WebReferences 目录。 XML Web Services Discovery 文件。用于定位可用 Web Services。 .dsdgm,dsprototype 根目录或子目录。 分布式服务图表(DSD)文件。可添加到 Visual Studio 方案中,为反向引擎提供消耗 Web Services 时的交互性图表。 .dll Bin 目录。 已编译类库文件。作为替代,可将类对象源代码保存到 App_Code 目录。 .licx,.webinfo 根目录或子目录。 许可协议文件。许可协议有助于保护控件开发者的知识产权,并对控件用户的使用权进行验证。 .master 根目录或子目录。 模板文件定义 Web 页面的统一布局,并在其他页面中得到引用。 .mdb,.ldb App_Data 目录。 Access 数据库文件。 .mdf App_Data 目录。 SQLServer 数据库文件。 .msgx,.svc 根目录或子目录。 Indigo Messaging Framework(MFx)服务文件。 .rem 根目录或子目录。 远程处理器文件。 .resources App_GlobalResources 或 App_LocalResources 目录。 资源文件。包含图像,本地化文本,或其他数据的资源引用串。 .resx App_GlobalResources 或 App_LocalResources 目录。 资源文件。包含图像,本地化文本,或其他数据的资源引用串。 .sdm,.sdmDocument 根目录或子目录。 系统定义模型(SDM)文件。 .sitemap 根目录。 网站地图文件。包含网站的结构。ASP.NET 通过默认的网站地图提供者,简化导航控件对网站地图文件的使用。 .skin App_Themes 目录。 皮肤定义文件。用于确定显示格式。 .sln Visual Web Developer 工程目录。 Visual Web Developer 工程的项目文件。 .soap 根目录或子目录。 SOAP 扩展文件。 注意:ASP.NET 管理的文件类型映射到 IIS 的 Aspnet_isapi.dll。 2.IIS 管理的文件类型 在ASP.NET应用程序中,有些动态的文件如asp文件就不被ASP.NET应用程序框架管理,这些文件由IIS进行管理,由IIS管理的文件类型如表4-2所示。 表4-2 IIS管理的文件类型 文件类型 保存位置 描述 .asa 根目录。 Global.asa 文件。包含 ASP 会话对象或应用程序对象生命周期中的各种事件处理。 .asp 根目录或子目录. ASP Web 页面。包含 @ 指令和使用 ASP 内建对象的脚本代码。 .cdx App_Data 目录. Visual FoxPro 的混合索引文件。 .cer 根目录或子目录。 证明文件。用于对网站的授权。 .idc 根目录或子目录。 Internet Database Connector(IDC)文件。被映射到 httpodbc.dll。 注意:由于无法为数据库连接提供足够的安全性,IDC 将不再被继续使用。IIS 6.0 是最后一个支持 IDC 的版本。 .shtm,.shtml,.stm 根目录或子目录。 包含文件。被映射到 ssinc.dll。 注意:IIS管理的文件类型被映射到IIS的asp.dll 3.静态文件类型 IIS仅提供已注册MIME类型的静态文件服务,注册信息保存在Mime Map IIS元数据库中。如果某种文件类型已经映射到指定应用程序,在不需要作为静态文件的情况之下,无需再在MIME类型列表中进行包含。默认的静态文件类型如表4-3所示。 表4-3 静态文件类型 文件类型 保存位置 描述 .css 根目录或子目录,以及 App_Themes 目录。 样式表文件。用于确定 HTML 元素的显示格式。 .htm,.html 根目录或子目录。 静态网页文件。由 HTML 代码编写。 注意:虽然ASP.NET的代码页面也能够手动添加到MIME类型列表中,但是这样操作浏览者就能够看到页面源代码,从而暴露ASP.NET页面源代码,相对于服务器而言是非常不安全的。 4.8 小结 本章介绍了ASP.NET页面生命周期,以及ASP.NET页面的几种模型。ASP.NET页面生命周期是ASP.NET中非常重要的概念,熟练掌握ASP.NET生命周期能对ASP.NET开发,自定义控件开发起到促进作用。本章还介绍了: q 代码隐藏页模型的解释过程。 q 代码隐藏页模型的事件驱动处理。 q ASP.NET网页的客户端状态。 q ASP.NET页面生命周期。 q ASP.NET生命周期中的事件。 q ASP.NET 网站文件类型。 上面的章节都分开的讲解了ASP.NET运行中的一些基本机制,在了解了这些基本运行机制后,就能够在.NET框架下做ASP.NET开发了。虽然这些都是基本概念,但是在今后的开发中,会起到非常重要的作用。

asp.net 生命周期

网上找了一下,然后摘录整理了一下asp.net的生命周期,比较详细的。 一.Asp.Net页面生命周期的概念  当我们在浏览器地址栏中输入网址,回车查看页面时,这时会向服务器端IIS)发送一个request请求,服务器就会判断发送过来的请求页面,当完全识别 TTP页面处理程序类后,ASP.NET运行时将调用处理程序的 ProcessRequest 方法来处理请求、创建页面对象。通常情况下,无需更改...

chencai56的博客 4026

CISSP背书三次失败后的终极解决方案

本文分享了作者CISSP认证三次线上背书审核失败的经历与终极解决方案。针对(ISC)²官方审核的严格性,文章详细剖析了使用公积金证明、工作证明盖章签字等常见材料的误区,并最终提出了通过构建“官方邮件往来”证据链的核心策略,以动态、可验证的方式成功通过审核,为后来者提供了详实的避坑指南和实操清单。

weixin_29219539的博客 154

ASP.NET 生命周期

ASP.NET 生命周期通常情况下需要经历几个阶段,这几个阶段如下所示。    1  页请求:页请求发生在页生命周期开始之前。当用户请求一个页面,ASP.NET将确定是否需要       分析或者编译该页面,或者是否可以在不运行页的情况下直接请求缓存响应客户端。    2  开始:发生了请求后,页面就进入了开始阶段。在该阶段,页面将确定请求是发回请求还是新       的客户端请求

yuyongshenga的专栏 571

从信号到振镜:STM32F103 + XY2-100协议 + AM26LS31芯片的激光打标/雕刻系统信号链搭建指南

本文详细介绍了基于STM32F103微控制器和XY2-100协议的激光打标/雕刻系统信号链搭建方法。从数字振镜控制协议解析、AM26LS31差分驱动电路设计到信号完整性优化,提供了一套完整的解决方案,帮助工程师实现高精度激光控制系统的开发与调试。

weixin_42536058的博客 236

机器学习西瓜书期末复习(2022HENU)

期末复习之机器学习 文章目录期末复习之机器学习第一章 绪论 第一章 绪论 机器学习的定义 机器学习致力于研究如何通过计算的手段,利用经验来改善系统自身的性能。 根据训练数据是否拥有标记信息,将学习任务分为监督学习和无监督学习。 监督学习 :分类和回归 线性回归、对数几率回归、决策树、支持向量机、贝叶斯分类器、神经网络 无监督学习:聚类 聚类算法: 原型聚类:(k均值,学习向量量化,高斯混合聚类);密度聚类(DBSVAN);层次聚类(AGNES)。降维。话题分析。图分

qq_46561559的博客 2万+

ASP.NET 应用程序生命周期概述

本主题概述应用程序生命周期,列出重要的生命周期事件,并描述如何编写适合应用程序生命周期的代码。在 ASP.NET 中,若要对 ASP.NET 应用程序进行初始化并使它处理请求,必须执行一些处理步骤。此外,ASP.NET 只是对浏览器发出的请求进行处理的 Web 服务器结构的一部分。了解应用程序生命周期非常重要,这样才能在适当的生命周期阶段编写代码,达到预期的效果。 应用程序生命周期概述

Leonard的专栏 2193

利用OrthoFinder做泛基因家族聚类分析

这条命令会将 Arabidopsis_thaliana.TAIR10.59_longest_trans.pep.fa 文件中的所有序列ID,去掉ID中的空格后面的部分,只保留 > 后第一个空格之前的基因ID,并将结果保存在 An1.fasta 文件中。muscle 是一种常用的多序列比对工具,用于基因组或蛋白质序列的比对。基因家族(Gene family),是来源于同一个祖先,由一个基因通过基因重复而产生两个或更多的拷贝而构成的一组基因,它们在结构和功能上具有明显的相似性,编码相似的蛋白质产物。

qq_64400864的博客 2750

HTTP请求生命周期

通过网上资料参考结合个人理解,这里对HTTP生命周期进行一个较为全面的介绍,也进一步加深自己的理解吧。 首先还是介绍一下计算机网络模型以及每层对应的设备和协议,如图其中TCP/IP五层模型结合了OSI参考模型和四层模型的优点,在网络模型中使用最广泛。在这里顺便复习一下TCP的三次握手和四次挥手。 传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的全双工的传输层通信协议。Java中通过socket(套接字:IP地址+端口号)编程来建立T

ZeronGod的博客 2977

【学习系列】SAP RAP 20:Unmanaged场景开发示例-调用BAPI、BAPI包装类、BO接口创建标准采购订单

本文介绍了在SAP RAP(Restful ABAP Programming)框架下,通过三种方式实现采购订单创建的方案。首先分析了RAP框架对传统BAPI调用的限制,特别是禁止显式COMMIT语句的要求。随后详细阐述了三种实现方式:1)直接调用传统BAPI(仅支持OP环境);2)使用BAPI包装类(仅支持OP环境);3)调用标准业务对象接口(支持所有环境)。 文章重点说明了在unmanaged场景下的技术实现细节,包括字段控制、缓冲区管理、测试运行与实际调用的分离处理等。针对每种方式都提供了完整的实施步骤

DeveloperMrMeng的博客 598

详解Xilinx FPGA高速串行收发器GTX/GTP(6)--Pattern Generator/Pattern Checker

详解Xilinx FPGA高速串行收发器GTX/GTP(6)--Pattern Generator/Pattern Checker

孤独的单刀 1625

Web.Config配置之---httpRuntime

这对产品环境来说不是必需的,并且可以通过从 Web.config 或 Machine.config 移除该属性,或将该属性设置为空字符串 (versionHeader="") 来将其禁用。ASP.NET 保持的允许执行新本地请求的自由线程的最小数目。该线程数目是为从本地主机传入的请求而保留的,以防某些请求在其处理期间发出对本地主机的子请求。输出缓存的配置和请求的类型决定了是否对内容进行缓存。这是通过自动将不是完全限定的格式的所有重定向转换为完全限定的格式来实现的。允许执行新请求的自由线程的最小数目。

huiguoyuan的博客 1669

Serial RapidIO Gen2 IP 说明(三)

前言 继续接着上篇文章,介绍Serial RapidIO Gen2 IP 的具体端口信息。 一、端口描述 1、缓冲设计接口 2、物理层接口 参考说明 【1】Serial RapidIO Gen2 v4.1https://china.xilinx.com/content/dam/xilinx/support/documentation/ip_documentation/srio_gen2/v4_1/pg007_srio_gen2.pdf ...

记录所学,分享知识,结识挚友 1321

深入理解asp.net里的HttpModule机制

刚工作的时候看《asp.net深入解析》,第一次知道HttpModule和HttpHandler。当时对我而言,它们不过就是两个新名词而已,仅仅知道工作原理但是理解的不深刻。随着经验的累积,逐渐发现它们对开发的重要性。现在回头再看一遍它们的实现机制,顺便参考一下其他资源做个透彻的读书笔记。 1、asp.net的HTTP请求处理过程 说明: (1)、客户端浏览器向服务器发出一个http请求

liuxiao8234240的博客 2501

手把手教你学Simulink——机器人力控场景实例:基于Simulink的永磁同步电机重力补偿力矩控制仿真

本文介绍了基于Simulink的机器人重力补偿力矩控制仿真方法。针对机器人悬停时电机发热、抖动等问题,提出通过前馈补偿重力转矩的解决方案。文章详细阐述了从机器人动力学建模、重力补偿计算、PMSM转矩控制到系统集成的完整实现流程,并以2-DOF机械臂为例验证了补偿效果。结果表明,重力补偿能显著降低电机电流和拖拽力,提高系统柔顺性。文中还提供了高级功能扩展方向,如参数辨识、摩擦补偿等,为实际工程应用提供了参考框架。

MHD0815的博客 154

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

ViewState与HttpModule原理:从ASP.NET底层机制到.NET 8实战迁移

ViewState和HttpModule是ASP.NET经典时代的核心机制,分别代表客户端状态管理与HTTP请求管道干预两大基础能力。其底层原理涉及序列化懒加载、IIS工作进程钩子、线程安全上下文等关键概念,技术价值在于帮助开发者穿透框架封装,实现可调试、可预测的服务端行为控制。典型应用场景包括表单防重放、跨域审计日志、智能路由限流等横切关注点治理。在.NET 8中,这些思想并未消失,而是演进为Minimal API的状态编码、Middleware中间件和RouteConstraint约束——本文即以现代实

dejz8829的专栏 504

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

ASP.NET HttpHandler与HttpModule职责分离原理

HttpHandler和HttpModule是ASP.NET请求管线中两类核心组件,分别承担响应内容生成与横切逻辑处理职责。其设计基于HTTP协议规范与管线事件驱动机制,通过24个标准化事件节点实现精确的执行时机控制。HttpHandler作为唯一拥有ProcessRequest调用权的组件,直接操作Response.OutputStream,决定最终响应体;而HttpModule以事件订阅方式介入各阶段,适用于日志、认证、压缩等全局性功能。这种职责分离架构支撑了高内聚、低耦合的系统演进,也是理解ASP.N

unixboy 638

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【转】Asp.net的生命周期之应用程序生命周期

参考:http://msdn.microsoft.com/zh-cn/library/ms178473(v=vs.100).aspx 参考:http://www.cnblogs.com/JimmyZhang/archive/2007/09/04/880967.html Http请求刚刚到达服务器的时候 当服务器接收到一个 Http请求的时候,IIS (Internet Information Services,互联网信息服务)首先需要决定如何去处理这个请求。 什么是IIS? IIS是一种Web(网

sinolover的专栏 671

ASP.NET 管道事件与HttpModule, HttpHandler简单理解

第一部分:转载自Artech IIS与ASP.NET管道 ASP.NET管道 以IIS 6.0为例,在工作进程w3wp.exe中,利用Aspnet_ispai.dll加载.NET运行时(如果.NET运行时尚未加载)。IIS 6引入了应用程序池的概念,一个工作进程对应着...

chengxiebi6944的博客 280

ASP.NET应用程序生命周期

  没事的时候看看别人的文章,总结了一点小东西,不一定非常全面,希望各位看完能给个参考意见,我会随时更改,谢谢各位大牛的参予!!!   先给大家看个图片。 首先是客户端将用户的操作封装成Http请求报文:string通过socket发送给服务器,是服务器上的HTTP.SYS服务来接收,并解析当前请求地址端口等然后将当前的请求交给IIS来处理。 然后w3svc会根据请求交给asp...

daying0422的博客 125

ASP.NET应用程序生命周期趣谈(一)

这几天一直在看ASP.NET应用程序生命周期,真是太难了,我理解起来费了劲了,但偏偏它又是那么重要,所以我希望能给大家带来一篇容易理解又好用的文章来帮助学习ASP.NET应用程序生命周期。这篇就是了。 当你访问博客园想看我的这篇文章的时候,这个请求就被博客园的WEB SERVER(IIS)接收到了。博客园IIS看了一眼我的请求,“噢,是.aspx啊,给ASP.NET去处理吧,就把...

148

ASP.NET应用程序与页面生命周期

在本文中,我们将了解不同的事件,ASP.NET 应用程序的生命周期以浏览器向 Web 服务器(对于 ASP.NET 应用程序,通常为 IIS)发送请求为起点,直至将请求结果返回至浏览器结束。在这个过程中,首先我们需要了解ASP.NET请求的2个大致的步骤。其次我们将详细了解 'httphandler ',' httpmodule和 asp.net 页面对象(Page)中不同的...

weixin_30824277的博客 187

ASP.NET的必须知道的东东(HttpModule,HttpHandler)之二

在以前的ASP时候,当请求一个*.asp页面文件的时候,这个HTTP请求首先会被一个名为inetinfo.exe进程所截获,这个进程实际上就是www服务。截获之后它会将这个请求转交给asp.dll进程,这个进程就会解释这个asp页面,然后将解释后的数据流返回给客户端浏览器。其实ASP.DLL是一个依附在IIS的ISAPI文件,它负责了对诸如ASP文件,ASA等文件的解释执行,------...

JSGLB61200的博客 543

ASP.NET的生命周期

我主要参考了这些文章 ASP.NET应用程序与页面生命周期,IIS处理Asp.net请求和 Asp.net页面生命周期 asp.net页面的生命周期 页面生命周期开始   (一)页面生命周期的主要阶段包括:  1.页面初始化(Init): 服务器创建服务器控件的实例   2.加载(load): 控件实例被加载到它定义的页面对象中   3.预输出:(PreRender) 对控...

bangweixiao1238的博客 352

ASP.NET运行原理和运行机制

一、ASP.NET运行原理 当一个http请求发送过来并被IIS机收到之后,IIS首先通过你请求的页面类型为其加载相应的dll文件,然后在处理过程中将这条请求发送给能够处理这条请求的模块,而在ASP.NET中这个模块就叫做HttpHandler,为什么aspx这样的文件可以被服务器处理,那是因为在服务器端有默认的HttpHandler专门处理aspx文件,IIS再将这条请求发送给能够处理这条请求的模块之前,还需要经过一些HttpModule,这些都是系统默认的Modules,而且在这个http请求传到Htt

gqk01的博客 4277
上一篇: Asp.Net底层解析(三)——ASPX页面的生命周期详解
下一篇: Asp.Net底层解析(五)——HttpHandler详解
NewClass
博客等级 码龄16年 22粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值