当客户端向web服务器请求*.aspx的页面文件时,这个http请求也会被inetinfo.exe进程截获(www服务),它判断文件后缀之后,把这个请求转交给ASPNET_ISAPI.DLL而ASPNET_ISAPI.DLL则会通过一个Http PipeLine的管道,将这个http请求发送给ASPNET_WP.EXE进程,当这个HTTP请求进入ASPNET_WP.EXE进程之后,asp.net framework就会通过HttpRuntime来处理这个Http请求,处理完毕后将结果返回给客户端。
大致流程如下:
HttpRequest-->inetinfo.exe->ASPNET_ISAPI.DLL-->Http Pipeline-->ASPNET_WP.EXE-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
通过反编译器,我们来简单看看它是如何实现的(.Net Version=2.0.0.0)
工作进程(IIS5中是ASPNET_WP.EXE,IIS6中是W3WP.EXE)寄宿.NET运行时和ISAPI DLL,它(工作进程)通过调用COM对象的一个小的非托管接口最终将调用发送到ISAPIRuntime类的一个实例上。进入运行时的第一个入口就是这个没有被文档记载的类,这个类实现了IISAPIRuntime接口(对于调用者说明来说,这个接口是一个COM接口)这个基于Iunknown的底层 COM接口是从ISAPI扩展到ASP.NET的一个预定的接口
1. [ComImport, Guid("08a2c56f-7c16-41c1-a8be-432917a1a2d1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
2. public interface IISAPIRuntime
3. {
4. void StartProcessing();
5. void StopProcessing();
6. [return: MarshalAs(UnmanagedType.I4)]
7. int ProcessRequest([In] IntPtr ecb, [In, MarshalAs(UnmanagedType.I4)] int useProcessModel);
8. void DoGCCollect();
9. }
代码展示了IISAPIRuntime接口和它的调用签名代码
以下是ISAPIRuntime类
1. public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IRegisteredObject
2. {
3. // Fields
4. private static int _isThisAppDomainRemovedFromUnmanagedTable;
5. private static string s_thisAppDomainsIsapiAppId;
6. private const int WORKER_REQUEST_TYPE_IN_PROC = 0;
7. private const int WORKER_REQUEST_TYPE_IN_PROC_VERSION_2 = 2;
8. private const int WORKER_REQUEST_TYPE_OOP = 1;
9.
10. // Methods
11. [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Minimal), SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
12. public ISAPIRuntime();
13. public void DoGCCollect();
14. public override object InitializeLifetimeService();
15. public int ProcessRequest(IntPtr ecb, int iWRType);
16. internal static void RemoveThisAppDomainFromUnmanagedTable();
17. internal void SetThisAppDomainsIsapiAppId(string appId);
18. public void StartProcessing();
19. public void StopProcessing();
20. void IRegisteredObject.Stop(bool immediate);
21. }
我们知道了接口,那具体处理,就让我们看一下ISAPIRuntime.ProcessRequest函数
1. public int ProcessRequest(IntPtr ecb, int iWRType)
2. {
3. 。。。。。。
4. 。。。。。。
5. ISAPIWorkerRequest wr = null;
6. try
7. {
8. 。。。。。。
9. wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
10. wr.Initialize();
11. string appPathTranslated = wr.GetAppPathTranslated();
12. string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
13. if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
14. {
15. HttpRuntime.ProcessRequestNoDemand(wr);
16. return 0;
17. }
18. 。。。。
19. return 1;
20. }
21. catch (Exception exception)
22. {
23. 。。。。
24. }
25. }
26.
27.
在这个函数中首先创建了一个ISAPIWorkerRequest实例,即是被.Net`经过一层封装的Http请求,
随后继续调用HttpRuntime.ProcessRequestNoDemand(wr);进行处理
1. internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)
2. {
3. RequestQueue queue = _theRuntime._requestQueue;
4. if (queue != null)
5. {
6. wr = queue.GetRequestToExecute(wr);
7. }
8. if (wr != null)
9. {
10. 。。。。
11. 。。。。
12. ProcessRequestNow(wr);
13. }
14. }
如果请求有多个,则进行请求队列的筛选,取得要处理的请求,继续转交ProcessRequestNow(wr)处理
1. internal static void ProcessRequestNow(HttpWorkerRequest wr)
2. {
3. _theRuntime.ProcessRequestInternal(wr);
4. }
调用当前应用程序域的方法_theRuntime.ProcessRequestInternal(wr)
1. private void ProcessRequestInternal(HttpWorkerRequest wr)
2. {
3. HttpContext context;
4. try
5. {
6. context = new HttpContext(wr, false);
7. }
8. catch
9. {
10. wr.SendStatus(400, "Bad Request");
11. ..........
12. return;
13. }
14. .........
15. try
16. {
17. ........
18. context.Response.InitResponseWriter();
19. IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
20. if (applicationInstance == null)
21. {
22. throw new HttpException(SR.GetString("Unable_create_app_object"));
23. }
24. ........
25. if (applicationInstance is IHttpAsyncHandler)
26. {
27. IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
28. context.AsyncAppHandler = handler2;
29. handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
30. }
31. else
32. {
33. applicationInstance.ProcessRequest(context);
34. this.FinishRequest(context.WorkerRequest, context, null);
35. }
36. }
37. catch (Exception exception)
38. {
39. .........
40. }
41. }
在这个方法内主要完成了
1.HttpContext的创建(非常重要的实例,提供了绝大多数的接口)
2.通过HttpApplicationFactory.GetApplicationInstance(context)生成或回收HttpApplicaiton实例(确切地说实现IHttpAsyncHandler接口或者IHttpHandler接口的实例),并转交请求处理
handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
或者applicationInstance.ProcessRequest(context);
其中,HttpApplicationFactory.GetApplicationInstance(context),若Http请求是第一个到达的时候,将会初始化HttpApplicationFactory
1. internal static IHttpHandler GetApplicationInstance(HttpContext context)
2. {
3. 。。。。。。。。。。。
4. _theApplicationFactory.EnsureInited();
5. _theApplicationFactory.EnsureAppStartCalled(context);
6. return _theApplicationFactory.GetNormalApplicationInstance(context);
7. }
8.
_theApplicationFactory.EnsureInited();中将判断工厂是否被初始化,若没则会先进行ApplicationFactory初始化
_theApplicationFactory.EnsureAppStartCalled(context);创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的 Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。
ApplicationFactory初始化最终调用Init() 方法
1. private void Init()
2. {
3. if (_customApplication == null)
4. {
5. try
6. {
7. try
8. {
9. this._appFilename = GetApplicationFile();
10. this.CompileApplication();
11. }
12. 。。。。。
13. }
14. catch
15. {
16. throw;
17. }
18. }
19. }
20.
21.
this._appFilename = GetApplicationFile();取得global.asax文件路径
1. internal static string GetApplicationFile()
2. {
3. return Path.Combine(HttpRuntime.AppDomainAppPathInternal, "global.asax");
4. }
可见在.Net中global.asax文件名是被规定死的。
this.CompileApplication也是比较重要的
1. private void CompileApplication()
2. {
3. this._theApplicationType = BuildManager.GetGlobalAsaxType();
4. BuildResultCompiledGlobalAsaxType globalAsaxBuildResult = BuildManager.GetGlobalAsaxBuildResult();
5. if (globalAsaxBuildResult != null)
6. {
7. if (globalAsaxBuildResult.HasAppOrSessionObjects)
8. {
9. this.GetAppStateByParsingGlobalAsax();
10. }
11. this._fileDependencies = globalAsaxBuildResult.VirtualPathDependencies;
12. }
13. if (this._state == null)
14. {
15. this._state = new HttpApplicationState();
16. }
17. this.ReflectOnApplicationType();
18. }
19.
20.
this._theApplicationType = BuildManager.GetGlobalAsaxType();
若存在global.asax文件则返回与该文件绑定编译的类型
若不存在则返回HttpApplication类型
05至12的代码则是在存在global.asax文件的情况下,生成文件解分器,应用程序状态就从其中被创建(HttpApplicationState)。
13至16,在不存在global.asax文件的情况下,创建默认HttpApplicationState;
在这里可以看到应用程序状态HttpApplicationState实例其实是HttpApplicationFactory的成员变量,所以其生存周期是整个应用程序域,作用域则是可被所有客户端应用程序(HttpApplication)共享。
this.ReflectOnApplicationType();通过映射theApplicationType,保存theApplicationType中的函数信息(用于之后HttpApplication实例事件函数输出),但是有三个函数是特别的,他们属于HttpApplicationFactory级别,就是应用程序域级别的事件函数输出,它们是Application_OnStart,Application_OnEnd,Session_OnEnd。
首先看一下ReflectOnApplicationType函数
1. private void ReflectOnApplicationType()
2. {
3. ArrayList list = new ArrayList();
4. foreach (MethodInfo info in this._theApplicationType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance))
5. {
6. if (this.ReflectOnMethodInfoIfItLooksLikeEventHandler(info))
7. {
8. list.Add(info);
9. }
10. }
11. Type baseType = this._theApplicationType.BaseType;
12. if ((baseType != null) && (baseType != typeof(HttpApplication)))
13. {
14. 。。。。。。
15. }
16. this._eventHandlerMethods = new MethodInfo[list.Count];
17. for (int i = 0; i < this._eventHandlerMethods.Length; i++)
18. {
19. this._eventHandlerMethods[i] = (MethodInfo) list[i];
20. }
21. }
22.
23.
可以看出theApplicationType中的函数信息是被保存到ArrayList类型中,并最终this._eventHandlerMethods[i] = (MethodInfo) list[i];存入_eventHandlerMethods成员变量中(MethodInfo[]类型 )
接下来看一下ReflectOnMethodInfoIfItLooksLikeEventHandler(info)函数做的处理
1. private bool ReflectOnMethodInfoIfItLooksLikeEventHandler(MethodInfo m)
2. {
3. 。。。。。。。
4. 。。。。。。。
5. 。。。。。。。
6. if (StringUtil.EqualsIgnoreCase(str, "Application_OnStart") || StringUtil.EqualsIgnoreCase(str, "Application_Start"))
7. {
8. this._onStartMethod = m;
9. this._onStartParamCount = parameters.Length;
10. }
11. else if (StringUtil.EqualsIgnoreCase(str, "Application_OnEnd") || StringUtil.EqualsIgnoreCase(str, "Application_End"))
12. {
13. this._onEndMethod = m;
14. this._onEndParamCount = parameters.Length;
15. }
16. else if (StringUtil.EqualsIgnoreCase(str, "Session_OnEnd") || StringUtil.EqualsIgnoreCase(str, "Session_End"))
17. {
18. this._sessionOnEndMethod = m;
19. this._sessionOnEndParamCount = parameters.Length;
20. }
21. return true;
22. }
23.
24.
省略的部分是对theApplicationType中函数的检验(返回值,参数)
如之前所说Application_OnStart函数(或Application_Start),Application_OnEnd函数(或Application_End),Session_OnEnd函数(或Session_End),若theApplicationType中存在这三个函数信息会被存贮在HttpApplicationFactory,并在适当的时机,通过invoke来调用,所以在HttpApplication中事件并不包括此三类。
这样整个HttpApplicationFactory的Init处理就完成了。
回顾上述GetApplicationInstance(HttpContext context) 方法
接下来要做的就是_theApplicationFactory.EnsureAppStartCalled(context); 创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的 Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。
这里不详细分析了,有兴趣可以去找一下:)形如以下操作
_onStartMethod.Invoke(this, new object[] { eventSource, eventArgs })
最后总算可以取HttpApplication实例了,在这之中,我们看一下HttpApplication初始化的实现
1. private HttpApplication GetNormalApplicationInstance(HttpContext context)
2. {
3. HttpApplication application = null;
4. lock (this._freeList)
5. {
6. if (this._numFreeAppInstances > 0)
7. {
8. application = (HttpApplication) this._freeList.Pop();
9. 。。。。。。。
10. }
11. }
12. if (application == null)
13. {
14. application = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
15. using (new ApplicationImpersonationContext())
16. {
17. application.InitInternal(context, this._state, this._eventHandlerMethods);
18. }
19. }
20. return application;
21. }
22.
23.
04到10的操作是在ApplicationFactory池中取空闲的HttpApplication(当客户端程序结束后HttpApplication不会被释放,而是被存在ApplicationFactory池中供其它用户复用,这样显然更有效),如果不存在则进行初始化创建
接下来我们看一下HttpApplication级的初始化操作
1. internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
2. {
3. 。。。。。。。
4. try
5. {
6. try
7. {
8. 。。。。。。。。。。。。
9. using (new HttpContextWrapper(context))
10. {
11. 。。。。。。。。
12. this.InitModules();
13. Label_006B:
14. if (handlers != null)
15. {
16. this.HookupEventHandlersForApplicationAndModules(handlers);
17. }
18. 。。。。。。
19. 。。。。。。。
20. try
21. {
22. this.Init();
23. }
24. catch (Exception exception)
25. {
26. 。。。。。。。。。。。
27. }
28. }
29. 。。。。。。。。。。。
30. if (HttpRuntime.UseIntegratedPipeline)
31. {
32. this._stepManager = new PipelineStepManager(this);
33. }
34. else
35. {
36. this._stepManager = new ApplicationStepManager(this);
37. }
38. this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
39. }
40. finally
41. {
42. 。。。。。。。。
43. }
44. }
45. catch
46. {
47. throw;
48. }
49. }
50.
在这个方法中,首先this.InitModules();这里做的是1.从配置文件中读取节点内容(machine.config web.config) 2.创建HttpModules模块并逐一调用HttpModule的Init初始化方法(HttpModules相关内容这里不作介绍)
this.HookupEventHandlersForApplicationAndModules(handlers);参数handlers其实就是保存在ApplicationFactory中ApplicationType中的函数信息(以上提到过)。根据HttpApplication的事件信息,进行动态的创建委托,并且进行方法的绑定(指针挂钩),但是对函数名有要求
例如:事件BeginRequest 能自动绑定的函数名为 Application_OnBeginRequest 或者 Application_BeginRequest
若函数名不为上述名称,想绑定事件BeginRequest的话,可在this.Init()中通过委托绑定(+=),这是个虚拟函数(多态)
this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
1. internal override void BuildSteps(WaitCallback stepCallback)
2. {
3. ArrayList steps = new ArrayList();
4. 。。。。。。。。。。。
5. app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
6. app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);
7. app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);
8. app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
9. app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);
10. app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
11. app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
12. app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
13. steps.Add(new HttpApplication.MapHandlerExecutionStep(app));
14. app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
15. app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
16. app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
17. app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
18. steps.Add(new HttpApplication.CallHandlerExecutionStep(app));
19. app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
20. app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
21. app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
22. steps.Add(new HttpApplication.CallFilterExecutionStep(app));
23. app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
24. app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
25. this._endRequestStepIndex = steps.Count;
26. app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
27. steps.Add(new HttpApplication.NoopExecutionStep());
28. this._execSteps = new HttpApplication.IExecutionStep[steps.Count];
29. steps.CopyTo(this._execSteps);
30. this._resumeStepsWaitCallback = stepCallback;
31. }
32.
可以看到这个方法创建了事件函数执行顺序,通过不同的类将事件函数封装后,并最终存入_execSteps。
值得注意的是steps.Add(new HttpApplication.MapHandlerExecutionStep(app));和steps.Add(new HttpApplication.CallHandlerExecutionStep(app));
前者读取HttpHandle节点配置,后者则是调用HttpHandle节点中类,进行处理。留意一下它们所处的事件流程的位置
以上的阶段,是HttpApplication的初始化阶段。
取得HttpApplication实例后就是按照上述取得_execSteps来依次执行事件函数的调用了
回顾HttpRuntime类中的ProcessRequestInternal(HttpWorkerRequest wr) 函数,有这么一段
# if (applicationInstance is IHttpAsyncHandler)
# {
# IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
# context.AsyncAppHandler = handler2;
# handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
# }
# else
# {
# applicationInstance.ProcessRequest(context);
# this.FinishRequest(context.WorkerRequest, context, null);
# }
对于取得HttpApplication实例的类型判断,如果实现的是异步接口调用BeginProcessRequest,非异步接口调用ProcessRequest
但实际上HttpApplication的非异步接口会抛出异常,.Net只支持异步的调用
void IHttpHandler.ProcessRequest(HttpContext context)
{
throw new HttpException(SR.GetString("Sync_not_supported"));
}
handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context)实现中
通过调用this.ResumeSteps(null) 并最终调用到HttpApplication的内部类
ApplicationStepManager的 ResumeSteps函数。
1. [DebuggerStepperBoundary]
2. internal override void ResumeSteps(Exception error)
3. {
4. 。。。。。。
5. lock (base._application)
6. {
7. 。。。。。。
8. try
9. {
10. try
11. {
12. Label_0040:
13. if (syncContext.Error != null)
14. {
15. 。。。。。
16. }
17. if (error != null)
18. {
19. 。。。。。。
20. }
21. if (syncContext.PendingOperationsCount > 0)
22. {
23. 。。。。。。。
24. }
25. else
26. {
27. if ((this._currentStepIndex < this._endRequestStepIndex) && ((context.Error != null) || base._requestCompleted))
28. {
29. context.Response.FilterOutput();
30. this._currentStepIndex = this._endRequestStepIndex;
31. }
32. else
33. {
34. this._currentStepIndex++;
35. }
36. if (this._currentStepIndex >= this._execSteps.Length)
37. {
38. flag = true;
39. }
40. else
41. {
42. this._numStepCalls++;
43. context.SyncContext.Enable();
44. error = application.ExecuteStep(this._execSteps[this._currentStepIndex], ref completedSynchronously);
45. if (completedSynchronously)
46. {
47. this._numSyncStepCalls++;
48. goto Label_0040;
49. }
50. }
51. }
52. }
53. finally
54. {
55. 。。。。。。
56. }
57. }
58. catch
59. {
60. throw;
61. }
62. }
63. if (flag)
64. {
65. 。。。。。。
66. }
67.
其中error = application.ExecuteStep(this._execSteps[this._currentStepIndex], ref completedSynchronously);
便是通过_execSteps来依次执行事件函数的调用了,并最终通过step.Execute()调用
以下只对执行HttpHandle的过程做一个了解
之前知道steps.Add(new HttpApplication.CallHandlerExecutionStep(app));已经创建了事件顺序
接下来就是看一下CallHandlerExecutionStep中Execute的实现了
1. void HttpApplication.IExecutionStep.Execute()
2. {
3. HttpContext context = this._application.Context;
4. IHttpHandler handler = context.Handler;
5. 。。。。。。
6. 。。。。。。
7. if (handler is IHttpAsyncHandler)
8. {
9. 。。。。。。
10. IAsyncResult result = handler2.BeginProcessRequest(context, this._completionCallback, null);
11. if (result.CompletedSynchronously)
12. {
13. 。。。。。。。
14. }
15. }
16. else
17. {
18. 。。。。。。。。
19. try
20. {
21. handler.ProcessRequest(context);
22. }
23. finally
24. {
25. 。。。。。。
26. }
27. }
28. }
29.
以上程序可以看出根据HttpHandle所继承的接口,分别调用BeginProcessRequest或者ProcessRequest
另外HttpHandle实例的创建正是之前steps.Add(new HttpApplication.MapHandlerExecutionStep(app))的Execute完成的
Execute中
context.Handler = this._application.MapHttpHandler(。。。。。);取得
值得注意的是MapHttpHandler中通过读取配置文件,首先判断HttpHandle节点是否有自定义IHttpHandlerFactory处理,有的话生成该类实例,如果没有,则生成默认类HandlerFactoryCache
最后通过IHttpHandlerFactory的接口函数GetHandler取得处理句柄(默认句柄情况下就是配置文件HttpHandle节点的处理类,若不存在会报错)
经过几个事件函数的调用后,
在CallHandlerExecutionStep的Execute中被处理(如上)
在所有事件函数被调用完成之后,HttpApplication实例会被回收,ISAPIRuntime.ProcessRequest处理完毕,结果返回给COM,并通过COM的再一次处理,返回给客户端。这样一次请求就至此结束了。
这个文章主要针对的是HttpApplication层面的,下次如果有时间再对aspx文件的HttpHandle层面的重要类Page也做一个分析
睡觉。。。。。
大致流程如下:
HttpRequest-->inetinfo.exe->ASPNET_ISAPI.DLL-->Http Pipeline-->ASPNET_WP.EXE-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
通过反编译器,我们来简单看看它是如何实现的(.Net Version=2.0.0.0)
工作进程(IIS5中是ASPNET_WP.EXE,IIS6中是W3WP.EXE)寄宿.NET运行时和ISAPI DLL,它(工作进程)通过调用COM对象的一个小的非托管接口最终将调用发送到ISAPIRuntime类的一个实例上。进入运行时的第一个入口就是这个没有被文档记载的类,这个类实现了IISAPIRuntime接口(对于调用者说明来说,这个接口是一个COM接口)这个基于Iunknown的底层 COM接口是从ISAPI扩展到ASP.NET的一个预定的接口
1. [ComImport, Guid("08a2c56f-7c16-41c1-a8be-432917a1a2d1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
2. public interface IISAPIRuntime
3. {
4. void StartProcessing();
5. void StopProcessing();
6. [return: MarshalAs(UnmanagedType.I4)]
7. int ProcessRequest([In] IntPtr ecb, [In, MarshalAs(UnmanagedType.I4)] int useProcessModel);
8. void DoGCCollect();
9. }
代码展示了IISAPIRuntime接口和它的调用签名代码
以下是ISAPIRuntime类
1. public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IRegisteredObject
2. {
3. // Fields
4. private static int _isThisAppDomainRemovedFromUnmanagedTable;
5. private static string s_thisAppDomainsIsapiAppId;
6. private const int WORKER_REQUEST_TYPE_IN_PROC = 0;
7. private const int WORKER_REQUEST_TYPE_IN_PROC_VERSION_2 = 2;
8. private const int WORKER_REQUEST_TYPE_OOP = 1;
9.
10. // Methods
11. [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Minimal), SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
12. public ISAPIRuntime();
13. public void DoGCCollect();
14. public override object InitializeLifetimeService();
15. public int ProcessRequest(IntPtr ecb, int iWRType);
16. internal static void RemoveThisAppDomainFromUnmanagedTable();
17. internal void SetThisAppDomainsIsapiAppId(string appId);
18. public void StartProcessing();
19. public void StopProcessing();
20. void IRegisteredObject.Stop(bool immediate);
21. }
我们知道了接口,那具体处理,就让我们看一下ISAPIRuntime.ProcessRequest函数
1. public int ProcessRequest(IntPtr ecb, int iWRType)
2. {
3. 。。。。。。
4. 。。。。。。
5. ISAPIWorkerRequest wr = null;
6. try
7. {
8. 。。。。。。
9. wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
10. wr.Initialize();
11. string appPathTranslated = wr.GetAppPathTranslated();
12. string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
13. if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
14. {
15. HttpRuntime.ProcessRequestNoDemand(wr);
16. return 0;
17. }
18. 。。。。
19. return 1;
20. }
21. catch (Exception exception)
22. {
23. 。。。。
24. }
25. }
26.
27.
在这个函数中首先创建了一个ISAPIWorkerRequest实例,即是被.Net`经过一层封装的Http请求,
随后继续调用HttpRuntime.ProcessRequestNoDemand(wr);进行处理
1. internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)
2. {
3. RequestQueue queue = _theRuntime._requestQueue;
4. if (queue != null)
5. {
6. wr = queue.GetRequestToExecute(wr);
7. }
8. if (wr != null)
9. {
10. 。。。。
11. 。。。。
12. ProcessRequestNow(wr);
13. }
14. }
如果请求有多个,则进行请求队列的筛选,取得要处理的请求,继续转交ProcessRequestNow(wr)处理
1. internal static void ProcessRequestNow(HttpWorkerRequest wr)
2. {
3. _theRuntime.ProcessRequestInternal(wr);
4. }
调用当前应用程序域的方法_theRuntime.ProcessRequestInternal(wr)
1. private void ProcessRequestInternal(HttpWorkerRequest wr)
2. {
3. HttpContext context;
4. try
5. {
6. context = new HttpContext(wr, false);
7. }
8. catch
9. {
10. wr.SendStatus(400, "Bad Request");
11. ..........
12. return;
13. }
14. .........
15. try
16. {
17. ........
18. context.Response.InitResponseWriter();
19. IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
20. if (applicationInstance == null)
21. {
22. throw new HttpException(SR.GetString("Unable_create_app_object"));
23. }
24. ........
25. if (applicationInstance is IHttpAsyncHandler)
26. {
27. IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
28. context.AsyncAppHandler = handler2;
29. handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
30. }
31. else
32. {
33. applicationInstance.ProcessRequest(context);
34. this.FinishRequest(context.WorkerRequest, context, null);
35. }
36. }
37. catch (Exception exception)
38. {
39. .........
40. }
41. }
在这个方法内主要完成了
1.HttpContext的创建(非常重要的实例,提供了绝大多数的接口)
2.通过HttpApplicationFactory.GetApplicationInstance(context)生成或回收HttpApplicaiton实例(确切地说实现IHttpAsyncHandler接口或者IHttpHandler接口的实例),并转交请求处理
handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
或者applicationInstance.ProcessRequest(context);
其中,HttpApplicationFactory.GetApplicationInstance(context),若Http请求是第一个到达的时候,将会初始化HttpApplicationFactory
1. internal static IHttpHandler GetApplicationInstance(HttpContext context)
2. {
3. 。。。。。。。。。。。
4. _theApplicationFactory.EnsureInited();
5. _theApplicationFactory.EnsureAppStartCalled(context);
6. return _theApplicationFactory.GetNormalApplicationInstance(context);
7. }
8.
_theApplicationFactory.EnsureInited();中将判断工厂是否被初始化,若没则会先进行ApplicationFactory初始化
_theApplicationFactory.EnsureAppStartCalled(context);创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的 Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。
ApplicationFactory初始化最终调用Init() 方法
1. private void Init()
2. {
3. if (_customApplication == null)
4. {
5. try
6. {
7. try
8. {
9. this._appFilename = GetApplicationFile();
10. this.CompileApplication();
11. }
12. 。。。。。
13. }
14. catch
15. {
16. throw;
17. }
18. }
19. }
20.
21.
this._appFilename = GetApplicationFile();取得global.asax文件路径
1. internal static string GetApplicationFile()
2. {
3. return Path.Combine(HttpRuntime.AppDomainAppPathInternal, "global.asax");
4. }
可见在.Net中global.asax文件名是被规定死的。
this.CompileApplication也是比较重要的
1. private void CompileApplication()
2. {
3. this._theApplicationType = BuildManager.GetGlobalAsaxType();
4. BuildResultCompiledGlobalAsaxType globalAsaxBuildResult = BuildManager.GetGlobalAsaxBuildResult();
5. if (globalAsaxBuildResult != null)
6. {
7. if (globalAsaxBuildResult.HasAppOrSessionObjects)
8. {
9. this.GetAppStateByParsingGlobalAsax();
10. }
11. this._fileDependencies = globalAsaxBuildResult.VirtualPathDependencies;
12. }
13. if (this._state == null)
14. {
15. this._state = new HttpApplicationState();
16. }
17. this.ReflectOnApplicationType();
18. }
19.
20.
this._theApplicationType = BuildManager.GetGlobalAsaxType();
若存在global.asax文件则返回与该文件绑定编译的类型
若不存在则返回HttpApplication类型
05至12的代码则是在存在global.asax文件的情况下,生成文件解分器,应用程序状态就从其中被创建(HttpApplicationState)。
13至16,在不存在global.asax文件的情况下,创建默认HttpApplicationState;
在这里可以看到应用程序状态HttpApplicationState实例其实是HttpApplicationFactory的成员变量,所以其生存周期是整个应用程序域,作用域则是可被所有客户端应用程序(HttpApplication)共享。
this.ReflectOnApplicationType();通过映射theApplicationType,保存theApplicationType中的函数信息(用于之后HttpApplication实例事件函数输出),但是有三个函数是特别的,他们属于HttpApplicationFactory级别,就是应用程序域级别的事件函数输出,它们是Application_OnStart,Application_OnEnd,Session_OnEnd。
首先看一下ReflectOnApplicationType函数
1. private void ReflectOnApplicationType()
2. {
3. ArrayList list = new ArrayList();
4. foreach (MethodInfo info in this._theApplicationType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance))
5. {
6. if (this.ReflectOnMethodInfoIfItLooksLikeEventHandler(info))
7. {
8. list.Add(info);
9. }
10. }
11. Type baseType = this._theApplicationType.BaseType;
12. if ((baseType != null) && (baseType != typeof(HttpApplication)))
13. {
14. 。。。。。。
15. }
16. this._eventHandlerMethods = new MethodInfo[list.Count];
17. for (int i = 0; i < this._eventHandlerMethods.Length; i++)
18. {
19. this._eventHandlerMethods[i] = (MethodInfo) list[i];
20. }
21. }
22.
23.
可以看出theApplicationType中的函数信息是被保存到ArrayList类型中,并最终this._eventHandlerMethods[i] = (MethodInfo) list[i];存入_eventHandlerMethods成员变量中(MethodInfo[]类型 )
接下来看一下ReflectOnMethodInfoIfItLooksLikeEventHandler(info)函数做的处理
1. private bool ReflectOnMethodInfoIfItLooksLikeEventHandler(MethodInfo m)
2. {
3. 。。。。。。。
4. 。。。。。。。
5. 。。。。。。。
6. if (StringUtil.EqualsIgnoreCase(str, "Application_OnStart") || StringUtil.EqualsIgnoreCase(str, "Application_Start"))
7. {
8. this._onStartMethod = m;
9. this._onStartParamCount = parameters.Length;
10. }
11. else if (StringUtil.EqualsIgnoreCase(str, "Application_OnEnd") || StringUtil.EqualsIgnoreCase(str, "Application_End"))
12. {
13. this._onEndMethod = m;
14. this._onEndParamCount = parameters.Length;
15. }
16. else if (StringUtil.EqualsIgnoreCase(str, "Session_OnEnd") || StringUtil.EqualsIgnoreCase(str, "Session_End"))
17. {
18. this._sessionOnEndMethod = m;
19. this._sessionOnEndParamCount = parameters.Length;
20. }
21. return true;
22. }
23.
24.
省略的部分是对theApplicationType中函数的检验(返回值,参数)
如之前所说Application_OnStart函数(或Application_Start),Application_OnEnd函数(或Application_End),Session_OnEnd函数(或Session_End),若theApplicationType中存在这三个函数信息会被存贮在HttpApplicationFactory,并在适当的时机,通过invoke来调用,所以在HttpApplication中事件并不包括此三类。
这样整个HttpApplicationFactory的Init处理就完成了。
回顾上述GetApplicationInstance(HttpContext context) 方法
接下来要做的就是_theApplicationFactory.EnsureAppStartCalled(context); 创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的 Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。
这里不详细分析了,有兴趣可以去找一下:)形如以下操作
_onStartMethod.Invoke(this, new object[] { eventSource, eventArgs })
最后总算可以取HttpApplication实例了,在这之中,我们看一下HttpApplication初始化的实现
1. private HttpApplication GetNormalApplicationInstance(HttpContext context)
2. {
3. HttpApplication application = null;
4. lock (this._freeList)
5. {
6. if (this._numFreeAppInstances > 0)
7. {
8. application = (HttpApplication) this._freeList.Pop();
9. 。。。。。。。
10. }
11. }
12. if (application == null)
13. {
14. application = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
15. using (new ApplicationImpersonationContext())
16. {
17. application.InitInternal(context, this._state, this._eventHandlerMethods);
18. }
19. }
20. return application;
21. }
22.
23.
04到10的操作是在ApplicationFactory池中取空闲的HttpApplication(当客户端程序结束后HttpApplication不会被释放,而是被存在ApplicationFactory池中供其它用户复用,这样显然更有效),如果不存在则进行初始化创建
接下来我们看一下HttpApplication级的初始化操作
1. internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
2. {
3. 。。。。。。。
4. try
5. {
6. try
7. {
8. 。。。。。。。。。。。。
9. using (new HttpContextWrapper(context))
10. {
11. 。。。。。。。。
12. this.InitModules();
13. Label_006B:
14. if (handlers != null)
15. {
16. this.HookupEventHandlersForApplicationAndModules(handlers);
17. }
18. 。。。。。。
19. 。。。。。。。
20. try
21. {
22. this.Init();
23. }
24. catch (Exception exception)
25. {
26. 。。。。。。。。。。。
27. }
28. }
29. 。。。。。。。。。。。
30. if (HttpRuntime.UseIntegratedPipeline)
31. {
32. this._stepManager = new PipelineStepManager(this);
33. }
34. else
35. {
36. this._stepManager = new ApplicationStepManager(this);
37. }
38. this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
39. }
40. finally
41. {
42. 。。。。。。。。
43. }
44. }
45. catch
46. {
47. throw;
48. }
49. }
50.
在这个方法中,首先this.InitModules();这里做的是1.从配置文件中读取节点内容(machine.config web.config) 2.创建HttpModules模块并逐一调用HttpModule的Init初始化方法(HttpModules相关内容这里不作介绍)
this.HookupEventHandlersForApplicationAndModules(handlers);参数handlers其实就是保存在ApplicationFactory中ApplicationType中的函数信息(以上提到过)。根据HttpApplication的事件信息,进行动态的创建委托,并且进行方法的绑定(指针挂钩),但是对函数名有要求
例如:事件BeginRequest 能自动绑定的函数名为 Application_OnBeginRequest 或者 Application_BeginRequest
若函数名不为上述名称,想绑定事件BeginRequest的话,可在this.Init()中通过委托绑定(+=),这是个虚拟函数(多态)
this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
1. internal override void BuildSteps(WaitCallback stepCallback)
2. {
3. ArrayList steps = new ArrayList();
4. 。。。。。。。。。。。
5. app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
6. app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);
7. app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);
8. app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
9. app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);
10. app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
11. app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
12. app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
13. steps.Add(new HttpApplication.MapHandlerExecutionStep(app));
14. app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
15. app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
16. app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
17. app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
18. steps.Add(new HttpApplication.CallHandlerExecutionStep(app));
19. app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
20. app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
21. app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
22. steps.Add(new HttpApplication.CallFilterExecutionStep(app));
23. app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
24. app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
25. this._endRequestStepIndex = steps.Count;
26. app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
27. steps.Add(new HttpApplication.NoopExecutionStep());
28. this._execSteps = new HttpApplication.IExecutionStep[steps.Count];
29. steps.CopyTo(this._execSteps);
30. this._resumeStepsWaitCallback = stepCallback;
31. }
32.
可以看到这个方法创建了事件函数执行顺序,通过不同的类将事件函数封装后,并最终存入_execSteps。
值得注意的是steps.Add(new HttpApplication.MapHandlerExecutionStep(app));和steps.Add(new HttpApplication.CallHandlerExecutionStep(app));
前者读取HttpHandle节点配置,后者则是调用HttpHandle节点中类,进行处理。留意一下它们所处的事件流程的位置
以上的阶段,是HttpApplication的初始化阶段。
取得HttpApplication实例后就是按照上述取得_execSteps来依次执行事件函数的调用了
回顾HttpRuntime类中的ProcessRequestInternal(HttpWorkerRequest wr) 函数,有这么一段
# if (applicationInstance is IHttpAsyncHandler)
# {
# IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
# context.AsyncAppHandler = handler2;
# handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
# }
# else
# {
# applicationInstance.ProcessRequest(context);
# this.FinishRequest(context.WorkerRequest, context, null);
# }
对于取得HttpApplication实例的类型判断,如果实现的是异步接口调用BeginProcessRequest,非异步接口调用ProcessRequest
但实际上HttpApplication的非异步接口会抛出异常,.Net只支持异步的调用
void IHttpHandler.ProcessRequest(HttpContext context)
{
throw new HttpException(SR.GetString("Sync_not_supported"));
}
handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context)实现中
通过调用this.ResumeSteps(null) 并最终调用到HttpApplication的内部类
ApplicationStepManager的 ResumeSteps函数。
1. [DebuggerStepperBoundary]
2. internal override void ResumeSteps(Exception error)
3. {
4. 。。。。。。
5. lock (base._application)
6. {
7. 。。。。。。
8. try
9. {
10. try
11. {
12. Label_0040:
13. if (syncContext.Error != null)
14. {
15. 。。。。。
16. }
17. if (error != null)
18. {
19. 。。。。。。
20. }
21. if (syncContext.PendingOperationsCount > 0)
22. {
23. 。。。。。。。
24. }
25. else
26. {
27. if ((this._currentStepIndex < this._endRequestStepIndex) && ((context.Error != null) || base._requestCompleted))
28. {
29. context.Response.FilterOutput();
30. this._currentStepIndex = this._endRequestStepIndex;
31. }
32. else
33. {
34. this._currentStepIndex++;
35. }
36. if (this._currentStepIndex >= this._execSteps.Length)
37. {
38. flag = true;
39. }
40. else
41. {
42. this._numStepCalls++;
43. context.SyncContext.Enable();
44. error = application.ExecuteStep(this._execSteps[this._currentStepIndex], ref completedSynchronously);
45. if (completedSynchronously)
46. {
47. this._numSyncStepCalls++;
48. goto Label_0040;
49. }
50. }
51. }
52. }
53. finally
54. {
55. 。。。。。。
56. }
57. }
58. catch
59. {
60. throw;
61. }
62. }
63. if (flag)
64. {
65. 。。。。。。
66. }
67.
其中error = application.ExecuteStep(this._execSteps[this._currentStepIndex], ref completedSynchronously);
便是通过_execSteps来依次执行事件函数的调用了,并最终通过step.Execute()调用
以下只对执行HttpHandle的过程做一个了解
之前知道steps.Add(new HttpApplication.CallHandlerExecutionStep(app));已经创建了事件顺序
接下来就是看一下CallHandlerExecutionStep中Execute的实现了
1. void HttpApplication.IExecutionStep.Execute()
2. {
3. HttpContext context = this._application.Context;
4. IHttpHandler handler = context.Handler;
5. 。。。。。。
6. 。。。。。。
7. if (handler is IHttpAsyncHandler)
8. {
9. 。。。。。。
10. IAsyncResult result = handler2.BeginProcessRequest(context, this._completionCallback, null);
11. if (result.CompletedSynchronously)
12. {
13. 。。。。。。。
14. }
15. }
16. else
17. {
18. 。。。。。。。。
19. try
20. {
21. handler.ProcessRequest(context);
22. }
23. finally
24. {
25. 。。。。。。
26. }
27. }
28. }
29.
以上程序可以看出根据HttpHandle所继承的接口,分别调用BeginProcessRequest或者ProcessRequest
另外HttpHandle实例的创建正是之前steps.Add(new HttpApplication.MapHandlerExecutionStep(app))的Execute完成的
Execute中
context.Handler = this._application.MapHttpHandler(。。。。。);取得
值得注意的是MapHttpHandler中通过读取配置文件,首先判断HttpHandle节点是否有自定义IHttpHandlerFactory处理,有的话生成该类实例,如果没有,则生成默认类HandlerFactoryCache
最后通过IHttpHandlerFactory的接口函数GetHandler取得处理句柄(默认句柄情况下就是配置文件HttpHandle节点的处理类,若不存在会报错)
经过几个事件函数的调用后,
在CallHandlerExecutionStep的Execute中被处理(如上)
在所有事件函数被调用完成之后,HttpApplication实例会被回收,ISAPIRuntime.ProcessRequest处理完毕,结果返回给COM,并通过COM的再一次处理,返回给客户端。这样一次请求就至此结束了。
这个文章主要针对的是HttpApplication层面的,下次如果有时间再对aspx文件的HttpHandle层面的重要类Page也做一个分析
睡觉。。。。。