处理管道,就是处理复杂问题的时候,将处理的过程分解为多个处理步骤,我们将这种经过多个步骤的处理方式称为处理管道。在.Net中,借助于事件的强大威力,我们可以通过处理管道将复杂的处理步骤封装起来,通过事件将处理过程的多个步骤暴露给程序员,以便于程序员对管理管道进行扩展。
简单描述一下Asp.net处理管道流程:
- Asp.net处理管道的第一步是创建HttpWorkerRequest对象,它包含于当前请求有关的所有信息
- HttpWorkerRequest把请求传递给HttpRuntime类的静态ProcessRequest方法。HttpRuntime首先要做的事是创建HttpContext对象,并用HttpWorkerRequest进行初始化
- 创建了HttpContext实例之后,HttpRuntime类就通过调用HttpApplicationFactory的静态GetApplicationInstance()方法,为该应用程序请求HttpApplication派生类的一个实例。GetApplicationInstance()方法要么创建一个HttpApplication类的一个新实例,要么从应用程序对象池中取出一个实例
- 在创建完成HttpApplication实例之后,就对它进行初始化,并在初始化期间分配应用程序定义的所有模块
- 模块式实现IHttpModule接口的类,作用就是为了实现经典的标准处理事件
- 在创建了模块之后,HttpRuntime类通过调用它的BeginProcessRequest方法,要求最新检索到的HttpApplication类对当前请求提供服务。然后,为当前请求找到合适的处理程序工厂
- 创建处理程序,传递当前HttpContext,一旦ProcessRequest方法返回,请求完成
HttpApplication初始化
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) {
Debug.Assert(context != null, "context != null");
// Remember state
_state = state;
PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
try {
try {
// Remember context for config lookups
_initContext = context;
_initContext.ApplicationInstance = this;
// Set config path to be application path for the application initialization
context.ConfigurationPath = context.Request.ApplicationPathObject;
// keep HttpContext.Current working while running user code
using (new DisposableHttpContextWrapper(context)) {
// Build module list from config
if (HttpRuntime.UseIntegratedPipeline) {//使用集成管道
Debug.Assert(_moduleConfigInfo != null, "_moduleConfigInfo != null");
Debug.Assert(_moduleConfigInfo.Count >= 0, "_moduleConfigInfo.Count >= 0");
try {
context.HideRequestResponse = true;
_hideRequestResponse = true;
InitIntegratedModules();//初始化集成模块
}
finally {
context.HideRequestResponse = false;
_hideRequestResponse = false;
}
}
else {
InitModules();//初始化模块
// this is used exclusively for integrated mode
Debug.Assert(null == _moduleContainers, "null == _moduleContainers");
}
// Hookup event handlers via reflection
if (handlers != null)
HookupEventHandlersForApplicationAndModules(handlers);//注册handles
// Initialization of the derived class
_context = context;
if (HttpRuntime.UseIntegratedPipeline && _context != null) {
_context.HideRequestResponse = true;
}
_hideRequestResponse = true;
try {
Init();
}
catch (Exception e) {
RecordError(e);
}
}
if (HttpRuntime.UseIntegratedPipeline && _context != null) {
_context.HideRequestResponse = false;
}
_hideRequestResponse = false;
_context = null;
_resumeStepsWaitCallback= new WaitCallback(this.ResumeStepsWaitCallback);//设置恢复步骤等待回调
// Construct the execution steps array
if (HttpRuntime.UseIntegratedPipeline) {
_stepManager = new PipelineStepManager(this);
}
else {
_stepManager = new ApplicationStepManager(this);
}
_stepManager.BuildSteps(_resumeStepsWaitCallback);//设置应用程序事件执行步骤
}
finally {
_initInternalCompleted = true;
// Reset config path
context.ConfigurationPath = null;
// don't hold on to the context
_initContext.ApplicationInstance = null;
_initContext = null;
}
}
catch { // Protect against exception filters
throw;
}
}
为应用程序和模块注册事件
private void HookupEventHandlersForApplicationAndModules(MethodInfo[] handlers) {
_currentModuleCollectionKey = HttpApplicationFactory.applicationFileName;
if(null == _pipelineEventMasks) {
Dictionary<string, RequestNotification> dict = new Dictionary<string, RequestNotification>();
BuildEventMaskDictionary(dict);
if(null == _pipelineEventMasks) {
_pipelineEventMasks = dict;
}
}
for (int i = 0; i < handlers.Length; i++) {
MethodInfo appMethod = handlers[i];
String appMethodName = appMethod.Name;
int namePosIndex = appMethodName.IndexOf('_');
String targetName = appMethodName.Substring(0, namePosIndex);
// Find target for method
Object target = null;
if (StringUtil.EqualsIgnoreCase(targetName, "Application"))
target = this;
else if (_moduleCollection != null)
target = _moduleCollection[targetName];
if (target == null)
continue;
// Find event on the module type
Type targetType = target.GetType();
EventDescriptorCollection events = TypeDescriptor.GetEvents(targetType);
string eventName = appMethodName.Substring(namePosIndex+1);
EventDescriptor foundEvent = events.Find(eventName, true);
if (foundEvent == null
&& StringUtil.EqualsIgnoreCase(eventName.Substring(0, 2), "on")) {
eventName = eventName.Substring(2);
foundEvent = events.Find(eventName, true);
}
MethodInfo addMethod = null;
if (foundEvent != null) {
EventInfo reflectionEvent = targetType.GetEvent(foundEvent.Name);
Debug.Assert(reflectionEvent != null);
if (reflectionEvent != null) {
addMethod = reflectionEvent.GetAddMethod();
}
}
if (addMethod == null)
continue;
ParameterInfo[] addMethodParams = addMethod.GetParameters();
if (addMethodParams.Length != 1)
continue;
// Create the delegate from app method to pass to AddXXX(handler) method
Delegate handlerDelegate = null;
ParameterInfo[] appMethodParams = appMethod.GetParameters();
if (appMethodParams.Length == 0) {
// If the app method doesn't have arguments --
// -- hookup via intermidiate handler
// only can do it for EventHandler, not strongly typed
if (addMethodParams[0].ParameterType != typeof(System.EventHandler))
continue;
ArglessEventHandlerProxy proxy = new ArglessEventHandlerProxy(this, appMethod);
handlerDelegate = proxy.Handler;
}
else {
// Hookup directly to the app methods hoping all types match
try {
handlerDelegate = Delegate.CreateDelegate(addMethodParams[0].ParameterType, this, appMethodName);
}
catch {
// some type mismatch
continue;
}
}
// Call the AddXXX() to hook up the delegate
try {
addMethod.Invoke(target, new Object[1]{handlerDelegate});//依次添加委托(事件)
}
catch {
if (HttpRuntime.UseIntegratedPipeline) {
throw;
}
}
if (eventName != null) {
if (_pipelineEventMasks.ContainsKey(eventName)) {
if (!StringUtil.StringStartsWith(eventName, "Post")) {
_appRequestNotifications |= _pipelineEventMasks[eventName];
}
else {
_appPostNotifications |= _pipelineEventMasks[eventName];
}
}
}
}
}
private void BuildEventMaskDictionary(Dictionary<string, RequestNotification> eventMask) {
eventMask["BeginRequest"] = RequestNotification.BeginRequest;
eventMask["AuthenticateRequest"] = RequestNotification.AuthenticateRequest;
eventMask["PostAuthenticateRequest"] = RequestNotification.AuthenticateRequest;
eventMask["AuthorizeRequest"] = RequestNotification.AuthorizeRequest;
eventMask["PostAuthorizeRequest"] = RequestNotification.AuthorizeRequest;
eventMask["ResolveRequestCache"] = RequestNotification.ResolveRequestCache;
eventMask["PostResolveRequestCache"] = RequestNotification.ResolveRequestCache;
eventMask["MapRequestHandler"] = RequestNotification.MapRequestHandler;
eventMask["PostMapRequestHandler"] = RequestNotification.MapRequestHandler;
eventMask["AcquireRequestState"] = RequestNotification.AcquireRequestState;
eventMask["PostAcquireRequestState"] = RequestNotification.AcquireRequestState;
eventMask["PreRequestHandlerExecute"] = RequestNotification.PreExecuteRequestHandler;
eventMask["PostRequestHandlerExecute"] = RequestNotification.ExecuteRequestHandler;
eventMask["ReleaseRequestState"] = RequestNotification.ReleaseRequestState;
eventMask["PostReleaseRequestState"] = RequestNotification.ReleaseRequestState;
eventMask["UpdateRequestCache"] = RequestNotification.UpdateRequestCache;
eventMask["PostUpdateRequestCache"] = RequestNotification.UpdateRequestCache;
eventMask["LogRequest"] = RequestNotification.LogRequest;
eventMask["PostLogRequest"] = RequestNotification.LogRequest;
eventMask["EndRequest"] = RequestNotification.EndRequest;
eventMask["PreSendRequestHeaders"] = RequestNotification.SendResponse;
eventMask["PreSendRequestContent"] = RequestNotification.SendResponse;
}
设置应用程序事件执行步骤
internal override void BuildSteps(WaitCallback stepCallback ) {
ArrayList steps = new ArrayList();
HttpApplication app = _application;
bool urlMappingsEnabled = false;
UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
urlMappingsEnabled = urlMappings.IsEnabled && ( urlMappings.UrlMappings.Count > 0 );
steps.Add(new ValidateRequestExecutionStep(app));
steps.Add(new ValidatePathExecutionStep(app));
if (urlMappingsEnabled)
steps.Add(new UrlMappingsExecutionStep(app)); // url mappings
app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
steps.Add(new MapHandlerExecutionStep(app)); // map handler
app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
steps.Add(app.CreateImplicitAsyncPreloadExecutionStep()); // implict async preload step
steps.Add(new CallHandlerExecutionStep(app)); // execute handler
app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
steps.Add(new CallFilterExecutionStep(app)); // filtering
app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
_endRequestStepIndex = steps.Count;
app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
steps.Add(new NoopExecutionStep()); // the last is always there
_execSteps = new IExecutionStep[steps.Count];
steps.CopyTo(_execSteps);
// callback for async completion when reposting to threadpool thread
_resumeStepsWaitCallback = stepCallback;
}
HttpApplication对象是Asp.net中处理请求的重要对象,但是,这种类型的对象实例不是由程序员来创建,而是由Asp.net帮助我们创建。为了便于扩展处理,Asp.net暴露了大量的事件给程序员,这些事件按照固定的处理顺序依次触发,程序员通过编写事件处理方法就可以自定义每一个请求的扩展处理过程。
HttpApplication的标准事件
事件名称 | 说明 |
---|---|
BeginRequest | Asp.net处理的第一个事件,表示处理的开始 |
AuthenticateRequest | 验证请求,一般用来取得请求用户的信息 |
PostAuthenticateRequest | 已经获取请求用户的信息 |
AuthorizeRequest | 授权,一般用来检查用户的请求是否获得权限 |
PostAuthorizeRequest | 用户请求已经得到授权 |
ResolveRequestCache | 获取以前处理缓存的处理结果,如果以前缓存过,那么,不必再进行请求的处理工作,直接返回缓存结果 |
PostResolveRequestCache | 已经完成缓存的获取操作 |
PostMapRequestHandler | 已经根据用户的请求,创建了处理请求的处理器对象 |
AcquireRequestState | 取得请求的状态,一般用于Session |
PostAcquireRequestState | 已经取得了Session |
PreRequestHandlerExecute | 准备执行处理程序 |
PostRequestHandlerExecute | 已经执行了处理程序 |
ReleaseRequestState | 释放请求的状态 |
PostReleaseRequestState | 已经释放了请求的状态 |
UpdateRequestCache | 更新缓存 |
PostUpdateRequestCache | 已经更新了缓存 |
LogRequest | 请求的日志操作 |
PostLogRequest | 已经完成了请求的日志操作 |
EndRequest | 本次请求处理完成 |
IHttpModule
HttpApplication提供了基于事件的扩展机制,允许程序员借助于处理管道中的事件进行处理过程扩展。由于HttpApplication对象是由Asp.net基础架构来创建和维护的,那么,如何才能获取这个对象的引用,以便于注册HttpApplication对象的事件处理,在Asp.net中,提供了两种方式来解决这个问题:IHttpModule方式和golbal.asax方式。这两种方式的核心都是IHttpModule接口。
/// <devdoc>
/// <para>Provides module initialization and tear-down events to the inheriting class.</para>
/// </devdoc>
public interface IHttpModule
{
/// <devdoc>
/// <para>Invoked by ASP.NET to enable a module to set itself up to handle
/// requests.</para>
/// </devdoc>
void Init(HttpApplication context);
/// <devdoc>
/// <para>Invoked by ASP.NET to enable a module to perform any final cleanup work prior to tear-down.</para>
/// </devdoc>
void Dispose();
}
IHttpModule接口,仅仅包含两个成员:
- Dispose方法用于回收Module所使用的非托管资源,如果没有的话,直接返回即可。
- 重要的是Init方法,这个方法接收一个HttpApplication类型的参数,在Asp.net中,每当创建一个HttpApplication对象实例,将遍历注册的HttpModule类型,通过反射,依次每个注册HttpModule类型的一个实例对象,并将这个HttpApplication实例通过Init方法传递给各个HttpModule,这样HttpModule就可以在第一时间完成针对HttpApplication对象的事件注册了。
HttpModule源码
class HttpModule : IHttpModule
{
static bool disabled;
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called outside PermitOnly context.")]
public void Dispose()
{
}
[Fx.Tag.SecurityNote(Critical = "Entry-point from asp.net, accesses ProcessRequest which is SecurityCritical.")]
[SecurityCritical]
public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += new EventHandler(ProcessRequest);
}
[Fx.Tag.SecurityNote(Critical = "Entry-point from asp.net, called outside PermitOnly context. ASP calls are critical." +
"HostedHttpRequestAsyncResult..ctor is critical because it captures HostedImpersonationContext." +
"(and makes it available later) so caller must ensure that this is called in the right place.")]
[SecurityCritical]
static void ProcessRequest(object sender, EventArgs e)
{
if (HttpModule.disabled)
{
return;
}
try
{
ServiceHostingEnvironment.SafeEnsureInitialized();
}
catch (SecurityException exception)
{
HttpModule.disabled = true;
DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning);
// If requesting a .svc file, the HttpHandler will try to handle it. It will call
// SafeEnsureInitialized() again, which will fail with the same exception (it is
// idempotent on failure). This is the correct behavior.
return;
}
HttpApplication application = (HttpApplication)sender;
// Check to see whether the extension is supported
string extension = application.Request.CurrentExecutionFilePathExtension;
if (string.IsNullOrEmpty(extension))
{
return;
}
ServiceHostingEnvironment.ServiceType serviceType = ServiceHostingEnvironment.GetServiceType(extension);
// do extension check first so that we do not need to do it in aspnetrouting/configurationbasedactivation
if (serviceType == ServiceHostingEnvironment.ServiceType.Unknown)
{
return;
}
// check for AspNetcompat
if (ServiceHostingEnvironment.AspNetCompatibilityEnabled)
{
// remap httphandler for xamlx in CBA, since there is No physical file and
// the xamlx httphandlerfactory will do file exist checking
if (serviceType == ServiceHostingEnvironment.ServiceType.Workflow && ServiceHostingEnvironment.IsConfigurationBasedService(application))
{
application.Context.RemapHandler(new HttpHandler());
}
return;
}
else if (serviceType == ServiceHostingEnvironment.ServiceType.WCF)
{
HostedHttpRequestAsyncResult.ExecuteSynchronous(application, false, false);
}
else if (serviceType == ServiceHostingEnvironment.ServiceType.Workflow)
{
HostedHttpRequestAsyncResult.ExecuteSynchronous(application, false, true);
}
}
}
新建一个项目,模拟HttpModule创建一个自定义模块
public class CustomHttpModule : IHttpModule
{
public void Dispose()
{
Console.WriteLine();
}
public event EventHandler CustomHttpModuleHandler;
/// <summary>
/// 注册动作
/// </summary>
/// <param name="context"></param>
public void Init(HttpApplication application)
{
application.BeginRequest += (s, e) =>
{
this.CustomHttpModuleHandler?.Invoke(application, null);
};
//application.EndRequest += (s, e) =>
//{
// HttpContext.Current.Response.Write("CustomHttpModule.EndRequest");
//};
#region 为每一个事件,都注册了一个动作,向客户端输出信息
application.AcquireRequestState += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "AcquireRequestState "));
application.AuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "AuthenticateRequest "));
application.AuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "AuthorizeRequest "));
application.BeginRequest += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "BeginRequest "));
application.Disposed += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "Disposed "));
application.EndRequest += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "EndRequest "));
application.Error += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "Error "));
application.LogRequest += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "LogRequest "));
application.MapRequestHandler += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "MapRequestHandler "));
application.PostAcquireRequestState += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostAcquireRequestState "));
application.PostAuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostAuthenticateRequest "));
application.PostAuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostAuthorizeRequest "));
application.PostLogRequest += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostLogRequest "));
application.PostMapRequestHandler += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostMapRequestHandler "));
application.PostReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostReleaseRequestState "));
application.PostRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostRequestHandlerExecute "));
application.PostResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostResolveRequestCache "));
application.PostUpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PostUpdateRequestCache "));
application.PreRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PreRequestHandlerExecute "));
application.PreSendRequestContent += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PreSendRequestContent "));
application.PreSendRequestHeaders += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "PreSendRequestHeaders "));
application.ReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "ReleaseRequestState "));
application.RequestCompleted += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "RequestCompleted "));
application.ResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "ResolveRequestCache "));
application.UpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h6 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h6><hr>", DateTime.Now.ToString(), "UpdateRequestCache "));
#endregion
}
}
注册HttpModule
在Asp.net中,实现IHttpModule接口只是实现HttpModule的第一步,在Asp.net中所使用的HttpModule还必须在网站配置文件中进行注册才能真正生效
对于IIS7.0来说,需要在配置文件的system.webServer配置节中注册HttpModule。注意此时的配置元素名称变为了modules。在IIS7.0中,可以为MapRequestHandler,LogRequest和PostLogRequest事件添加处理程序。
只要在IIS7.0集成模式下运行并且与.Net Framework3.0或更高版本一起运行的应用程序,才可以支持这些事件。
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
<add name="CustomHttpModule" type="TestMeb.Utility.CustomHttpModule,TestMeb"/>
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
运行程序我们可以看到效果如下
我们看到HttpApplication各个事件执行顺序
常见的HttpModule
系统文件夹C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.config中看到已经注册的HttpModule如下:
<httpModules>
<add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/>
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule"/>
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"/>
<add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule"/>
<add name="RoleManager" type="System.Web.Security.RoleManagerModule"/>
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule"/>
<add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule"/>
<add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule"/>
<add name="Profile" type="System.Web.Profile.ProfileModule"/>
<add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule"/>
<add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>
模块 | 说明 | 描述 |
---|---|---|
OutputCacheModule | 完成Asp.net的输出缓存管理工作 | OutputCacheModule的配置参数通过system.web配置元素的caching子元素的outputCache元素进行定义。当启用输出缓存之后(启用还是通过配置文件,下同),OutputCacheModule将注册HttpApplication的ResolveRequestCache和UpdateRequestCache两个事件完成输出缓存的管理 |
SessionStateModule | 完成Session的管理工作 | 这个Module的配置参数通过配置文件中的system.web配置元素的sessionState子元素进行配置。当启用Session状态管理之后,SessionStateModule将注册HttpApplication的AcquireRequestState、ReleaseRequestState、EndRequest三个事件完成Session状态的管理工作 |
ProfileModule | 提供个性化数据管理 | 这是一个自定义的类似于Session的会话状态管理,但是,个性化数据的读取和保存可以由程序员完全控制,并且提供了强类型的数据访问方式。这个Module的配置参数在system.web的子元素profile中进行说明。当启用了个性化数据管理之后,Module将注册HttpApplication的AcquireRequestState和EndRequest事件处理 |
AnonymousIdentificationModule | 提供匿名用户的标志 | 是否启用匿名用户标志在配置文件的system.web配置元素的子元素anonymousIdentification中定义,还可以配置匿名标识的管理方式。由于在AuthenticateRequest事件中将验证用户,获取用户名,所以这个Module注册了PostAuthenticateRequest的事件处理,当用户没有经过验证的时候,为用户分配一个唯一的匿名标识 |
WindowsAuthenticationModule FormsAuthenticationModule PassportAuthenticationModule |
用来完成用户的验证 | 工作它们通过配置文件中system.web的子元素authentication子元素定义,mode属性用来指定网站当前使用的验证方式,也就是哪一个Module将被用来完成验证工作。在启用验证的情况下,FormsAuthenticationModule和PassportAuthenticationModule将注册HttpApplication的AuthenticateRequest和EndRequest事件进行用户的验证处理。WindowsAuthenticationModule将注册AuthenticateRequest的事件处理 |
RoleManagerModule UrlAuthorizationModule FileAuthorizationModule |
用来完成用户的授权管理 | 授权管理的配置参数来自system.web的authorization子元素。UrlAuthorizationModule和FileAuthorizationModule注册了HttpApplication的AuthorizeRequest事件处理,用来检查Url和文件的访问授权。RoleManagerModule在Url和文件访问授权检查通过之后,通过用户的标识和角色来完成用户的授权检查,RoleManagerModule注册了HttpApplication的PostAuthenticateRequest和EndRequest事件处理 |
通过global.asax创建HttpApplication的事件处理
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
// 在应用程序启动时运行的代码
}
void Application_End(object sender, EventArgs e)
{
// 在应用程序关闭时运行的代码
}
void Application_Error(object sender, EventArgs e)
{
// 在出现未处理的错误时运行的代码
}
void Session_Start(object sender, EventArgs e)
{
// 在新会话启动时运行的代码
}
void Session_End(object sender, EventArgs e)
{
// 在会话结束时运行的代码。
// 注意: 只有在 Web.config 文件中的 sessionstate 模式设置为
// InProc 时,才会引发 Session_End 事件。如果会话模式设置为 StateServer
// 或 SQLServer,则不会引发该事件。
}
}
本文参考文档:
https://www.cnblogs.com/JimmyZhang/archive/2007/11/25/971878.html
https://www.cnblogs.com/kissdodog/p/3527871.html
https://www.cnblogs.com/kissdodog/p/3527922.html