深入ASP.NET MVC 之一:IIS到路由表

关于IIS的介绍,可以参考Introduction to IIS Architecture 。IIS到托管代码的入口点是位于System.Web dll中

双击代码全选

1

public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IISAPIRuntime2, IRegisteredObject

 

的方法

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

public int ProcessRequest(IntPtr ecb, int iWRType)  

    {  

        IntPtr intPtr = IntPtr.Zero;  

        if (iWRType == 2)  

        {  

            intPtr = ecb;  

            ecb = UnsafeNativeMethods.GetEcb(intPtr);  

        }  

        ISAPIWorkerRequest iSAPIWorkerRequest = null;  

        int result;  

        try

        {  

            bool useOOP = iWRType == 1;  

            iSAPIWorkerRequest = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);  

            iSAPIWorkerRequest.Initialize();  

            string appPathTranslated = iSAPIWorkerRequest.GetAppPathTranslated();  

            string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;  

            if (appDomainAppPathInternal == null || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))  

            {  

                HttpRuntime.ProcessRequestNoDemand(iSAPIWorkerRequest);  

                result = 0;  

            }  

            else

            {  

                     //……         

        

            }  

        }  

        catch (Exception ex)  

        {  

                  //……  

        

        }  

        return result;  

    }

 

(注:IIS7 的入口似乎是PipeLineRuntime.InitializeApplication(IntPtr appContext),过程有所不同,但是不影响后面的流程)其中ecb是一个指向httprequest的信息的指针,由IIS提供。 CreateWorkerRequest根据ecb提供的信息,比如IIS的版本、模式等,创建一个ISAPIWorkerRequest对 象,ISAPIWorkerReuqeuest是一个http请求的.NET封装。创建好WorkerRequest之后,调用 HttpRuntime.ProcessRequestNoDemand(iSAPIWorkerRequest);开始执行请求,这个方法是会从 httpRuntime对象中的一个队列中获取一个workerrequest进行处理,最终调用的是HttpRuntime类中的ProcessRequestInternal(代码有删节):

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

private void ProcessRequestInternal(HttpWorkerRequest wr)  

        {  

            Interlocked.Increment(ref this._activeRequestCount);  

            if (this._disposingHttpRuntime)  

                 wr.SendStatus(503, "Server Too Busy");  

            HttpContext httpContext;  

            try

            {  

                httpContext = new HttpContext(wr, false);  

            }  

            catch

            {  

                try

                {  

                    wr.SendStatus(400, "Bad Request");  

                    //…….  

        

                }  

                finally

                {  

                    Interlocked.Decrement(ref this._activeRequestCount);  

                }  

            }  

            wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, httpContext);  

            HostingEnvironment.IncrementBusyCount();  

            try

            {  

                httpContext.Response.InitResponseWriter();  

                IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(httpContext);  

                if (applicationInstance == null)  

                {  

                    throw new HttpException(SR.GetString("Unable_create_app_object"));  

                }  

                if (applicationInstance is IHttpAsyncHandler)  

                {  

                    IHttpAsyncHandler httpAsyncHandler = (IHttpAsyncHandler)applicationInstance;  

                    httpContext.AsyncAppHandler = httpAsyncHandler;  

                    httpAsyncHandler.BeginProcessRequest(httpContext, this._handlerCompletionCallback, httpContext);  

                }  

                else

                {  

                    applicationInstance.ProcessRequest(httpContext);  

                    this.FinishRequest(httpContext.WorkerRequest, httpContext, null);  

                }  

            }  

            catch (Exception e)  

            {  

                httpContext.Response.InitResponseWriter();  

                this.FinishRequest(wr, httpContext, e);  

            }  

        }

 

在 这段代码中,HttpRuntime可以根据当前服务器的状况回送不同的Http状态码。如果一切正常,首先根据WorkerRequest创建了 HttpContext,HttpApplication根据HttpContext创建了一个IHttpHandler对象,这是一个比较复杂的过程。 先看代码:

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

internal static IHttpHandler GetApplicationInstance(HttpContext context)  

{  

    if (HttpApplicationFactory._customApplication != null)  

    {  

        return HttpApplicationFactory._customApplication;  

    }  

    if (context.Request.IsDebuggingRequest)  

    {  

        return new HttpDebugHandler();  

    }  

    HttpApplicationFactory._theApplicationFactory.EnsureInited();  

    HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);  

    return HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);  

}

 

customApplication 应该是使用 ASP.NET State Service的时候的情况,DebugHandler应该是调试状态下的情况,不作深究,除此以外,一共有三大步骤,首先要确保调用且仅调用了一次 ApplicationFactory的Init方法,在这个方法中,主要完成了以下工作(代码有删节):