1. 程式人生 > >.Net MVC 裡面的核心檔案Global.asax執行原理分析

.Net MVC 裡面的核心檔案Global.asax執行原理分析

這個 Global.asax檔案是MVC裡面的起始檔案,它不同於其它檔案比如,M層,V層和C層。他是一個獨立的可配置的檔案。

因為.Net MVC把前後端完全分離,極度抽象的一個框架。或許導致了很多從WebForm轉過來的不適應。Global檔案就是此類。

它與MVC裡面的篩選器,控制器類工程(controllerFactory)的互動式怎麼做大的呢?

實際上在System.Web名稱空間裡面,PipelineRunTime類的InitializeApplication方法會通過HttpApplicationFactory呼叫GetPipelineApplicationInstance方法建立Global.asax檔案類。

 app(Global.asax) = HttpApplicationFactory.GetPipelineApplicationInstance(appContext, context);

 GetPipelineApplicationInstance呼叫如下:
 
 internal static HttpApplication GetPipelineApplicationInstance(IntPtr appContext, HttpContext context)
    {
        _theApplicationFactory.EnsureInited();
        return _theApplicationFactory.GetSpecialApplicationInstance(appContext, context);
    }

_theApplicationFactory 是一個全域性靜態類例項 private static HttpApplicationFactory _theApplicationFactory = new HttpApplicationFactory();實際上就是httpApplicationFactory類工場例項。

EnsureInited程式碼如下

 private void EnsureInited()
    {
        if (!this._inited)
        {
            HttpApplicationFactory factory = this;
            lock (factory)
            {
                if (!this._inited)
                {
                    this.Init();
                    this._inited = true;
                }
            }
        }
    }

Init程式碼如下:

  private void Init()
    {
        if (_customApplication == null)
        {
            try
            {
                try
                {
                    this._appFilename = GetApplicationFile();
                    this.CompileApplication();
                }
                finally
                {
                    this.SetupChangesMonitor();
                }
            }
            catch
            {
                throw;
            }
        }
    }    

CompileApplication程式碼如下:

    private void CompileApplication()
    {
        this._theApplicationType = BuildManager.GetGlobalAsaxType();
        BuildResultCompiledGlobalAsaxType globalAsaxBuildResult = BuildManager.GetGlobalAsaxBuildResult();
        if (globalAsaxBuildResult != null)
        {
            if (globalAsaxBuildResult.HasAppOrSessionObjects)
            {
                this.GetAppStateByParsingGlobalAsax();
            }
            this._fileDependencies = globalAsaxBuildResult.VirtualPathDependencies;
        }
        if (this._state == null)
        {
            this._state = new HttpApplicationState();
        }
        this.ReflectOnApplicationType();
    }

ReflectOnApplicationType程式碼如下:

    private void ReflectOnApplicationType()
    {
        ArrayList list = new ArrayList();
        foreach (MethodInfo info in this._theApplicationType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance))
        {
            if (this.ReflectOnMethodInfoIfItLooksLikeEventHandler(info))
            {
                list.Add(info);
            }
        }
        Type baseType = this._theApplicationType.BaseType;
        if ((baseType != null) && (baseType != typeof(HttpApplication)))
        {
            foreach (MethodInfo info2 in baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
            {
                if (info2.IsPrivate && this.ReflectOnMethodInfoIfItLooksLikeEventHandler(info2))
                {
                    list.Add(info2);
                }
            }
        }
        this._eventHandlerMethods = new MethodInfo[list.Count];
        for (int i = 0; i < this._eventHandlerMethods.Length; i++)
        {
            this._eventHandlerMethods[i] = (MethodInfo) list[i];
        }
    }

ReflectOnMethodInfoIfItLooksLikeEventHandler程式碼如下:

   private bool ReflectOnMethodInfoIfItLooksLikeEventHandler(MethodInfo m)
    {
        if (m.ReturnType != typeof(void))
        {
            return false;
        }
        ParameterInfo[] parameters = m.GetParameters();
        int length = parameters.Length;
        if (length != 0)
        {
            if (length != 2)
            {
                return false;
            }
            if (parameters[0].ParameterType != typeof(object))
            {
                return false;
            }
            if ((parameters[1].ParameterType != typeof(EventArgs)) && !parameters[1].ParameterType.IsSubclassOf(typeof(EventArgs)))
            {
                return false;
            }
        }
        string name = m.Name;
        int index = name.IndexOf('_');
        if ((index <= 0) || (index > (name.Length - 1)))
        {
            return false;
        }
        if (StringUtil.EqualsIgnoreCase(name, "Application_OnStart") || StringUtil.EqualsIgnoreCase(name, "Application_Start"))
        {
            this._onStartMethod = m;
            this._onStartParamCount = parameters.Length;
        }
        else if (StringUtil.EqualsIgnoreCase(name, "Application_OnEnd") || StringUtil.EqualsIgnoreCase(name, "Application_End"))
        {
            this._onEndMethod = m;
            this._onEndParamCount = parameters.Length;
        }
        else if (StringUtil.EqualsIgnoreCase(name, "Session_OnEnd") || StringUtil.EqualsIgnoreCase(name, "Session_End"))
        {
            this._sessionOnEndMethod = m;
            this._sessionOnEndParamCount = parameters.Length;
        }
        return true;
    }

ReflectOnMethodInfoIfItLooksLikeEventHandler裡面獲取到了當前Global.asax方法Application_OnStart

再來看GetPipelineApplicationInstance方法裡面呼叫的第二個方法GetSpecialApplicationInstance。它裡面會呼叫 application = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);建立HtppApplication ,實際上就是Global.asax裡面的類MvcApplication。它會呼叫ProcessSpecialRequest方法反射上面得到的HttpApplication裡面的方法Application_start,最後用Invoke呼叫。

  this.InvokeMethodWithAssert(method, paramCount, eventSource, eventArgs);
            
  [ReflectionPermission(SecurityAction.Assert, Flags=ReflectionPermissionFlag.RestrictedMemberAccess)]
    private void InvokeMethodWithAssert(MethodInfo method, int paramCount, object eventSource, EventArgs eventArgs)
    {
        if (paramCount == 0)
        {
            method.Invoke(this, new object[0]);
        }
        else
        {
            object[] parameters = new object[] { eventSource, eventArgs };
            method.Invoke(this, parameters);
        }
    }

最後進入到Application_start()裡面呼叫MVC的一些前奏,比如配置全域性篩選器,建立路由表,註冊Area等等。

值得注意的是,這一系列事件都在 進入HTTPModule和HttpHandler之前發生,所以後面等到啟用Controller呼叫ControllerFactory和篩選器遞迴鏈的時候,Application_start裡面的配置都會起作用。

還有一點需要注意的是,這個Application_start只會在第一次請求載入,後續陸續請求不會再次載入。如果需要重新載入,關掉程式,重新來過,則又會執行到Application_start方法裡面。(Java/.NET討論群:676817308)