asp.net mvc源碼分析-Controllerl篇 如何建立Controller執行個體

來源:互聯網
上載者:User

在上一篇文章asp.net mvc源碼分析-路由篇 如何找到 IHttpHandler中最後提到了MvcHandler,來上我們看看它的定義

 public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState

它有幾個比較重要的屬性:

internal ControllerBuilder ControllerBuilder  ,ControllerBuilder 類主要負責建立IControllerFactory

public RequestContext RequestContext,RequestContext是對這次請求的HttpContext(httpContext類)和RouteData的封裝

而它的BeginProcessRequest方法中有幾句比較重要的代碼:

IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
IAsyncController asyncController = controller as IAsyncController;
if (asyncController != null) {
}
else
{
  Action action = delegate {
                        try {
                            controller.Execute(RequestContext);
                        }
                        finally {
                            factory.ReleaseController(controller);
                        }
 return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
}

在這篇文章中我們主要關心ProcessRequestInit(httpContext, out controller, out factory);    如何建立controller

ProcessRequestInit方法大致如下:

  private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) {
            string controllerName = RequestContext.RouteData.GetRequiredString("controller");
            factory = ControllerBuilder.GetControllerFactory();
            controller = factory.CreateController(RequestContext, controllerName);
  }

         string controllerName = RequestContext.RouteData.GetRequiredString("controller");這句很簡單擷取Controller的名稱,RouteData是當前路由資料,裡面的key包括我們註冊是的url格式  "{controller}/{action}/{id}",  和預設的defaults=new { controller = "Home", action = "Index", id = UrlParameter.Optional } 

現在大家知道為什麼了我上一篇文章提到{controller}/{action}是必須得了吧。

現在讓我們來看看ControllerBuilder的主要代碼:

 public ControllerBuilder()            : this(null) {        }        internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) {            _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(                () => _factoryThunk(),                 new DefaultControllerFactory { ControllerBuilder = this },                "ControllerBuilder.GetControllerFactory"            );        }        public static ControllerBuilder Current {            get {                return _instance;            }        }  public IControllerFactory GetControllerFactory() {            return _serviceResolver.Current;        }        public void SetControllerFactory(IControllerFactory controllerFactory) {            if (controllerFactory == null) {                throw new ArgumentNullException("controllerFactory");            }            _factoryThunk = () => controllerFactory;        }        public void SetControllerFactory(Type controllerFactoryType) {            if (controllerFactoryType == null) {                throw new ArgumentNullException("controllerFactoryType");            }            if (!typeof(IControllerFactory).IsAssignableFrom(controllerFactoryType)) {                throw new ArgumentException(                    String.Format(                        CultureInfo.CurrentCulture,                        MvcResources.ControllerBuilder_MissingIControllerFactory,                        controllerFactoryType),                    "controllerFactoryType");            }            _factoryThunk = delegate() {                try {                    return (IControllerFactory)Activator.CreateInstance(controllerFactoryType);                }                catch (Exception ex) {                    throw new InvalidOperationException(                        String.Format(                            CultureInfo.CurrentCulture,                            MvcResources.ControllerBuilder_ErrorCreatingControllerFactory,                            controllerFactoryType),                        ex);                }            };        }

  由以上代碼我們可以知道如果沒有調用ControllerBuilder的SetControllerFactory方法那我們就用預設的DefaultControllerFactory,如果設定了我們就可以用我們自己ControllerFactory。如果項目有需要實現自己的ControllerFactory,那麼我們可以Global.asax.cs的 protected void Application_Start()方法調用 ControllerBuilder.Current.SetControllerFactory(xxx); 

讓我們來看看DefaultControllerFactory是怎麼建立的:

  internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver) {
            if (controllerActivator != null) {
                _controllerActivator = controllerActivator;
            }
            else {
                _activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
                    () => null,
                    new DefaultControllerActivator(dependencyResolver),
                    "DefaultControllerFactory contstructor"
                );
            }
        }

這裡我們涉及到一個IControllerActivator介面,預設情況下用的是DefaultControllerActivator類,

現在我們已經得到了ControllerFactory,再看看它是怎麼建立Controller的,說白了就是DefaultControllerFactory的CreateController方法

 public virtual IController CreateController(RequestContext requestContext, string controllerName) {
    。。
            Type controllerType = GetControllerType(requestContext, controllerName);
            IController controller = GetControllerInstance(requestContext, controllerType);
            return controller;
        }

預設我們是沒有namespaces,而GetControllerType(requestContext, controllerName)主要是調用 GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, null /* namespaces */)

  private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces) {            // Once the master list of controllers has been created we can quickly index into it            ControllerTypeCache.EnsureInitialized(BuildManager);            ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);            switch (matchingTypes.Count) {                case 0:                    // no matching types                    return null;                case 1:                    // single matching type                    return matchingTypes.First();                default:                    // multiple matching types                    throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);            }        }

這裡面主要涉及到一個ControllerTypeCache,它負責緩衝當前程式中所有的Controller。

讓我們看看ControllerTypeCache的主要方法吧

public void EnsureInitialized(IBuildManager buildManager) {            if (_cache == null) {                lock (_lockObj) {                    if (_cache == null) {                        List<Type> controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(_typeCacheName, IsControllerType, buildManager);                        var groupedByName = controllerTypes.GroupBy(                            t => t.Name.Substring(0, t.Name.Length - "Controller".Length),                            StringComparer.OrdinalIgnoreCase);                        _cache = groupedByName.ToDictionary(                            g => g.Key,                            g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),                            StringComparer.OrdinalIgnoreCase);                    }                }            }        }  internal static bool IsControllerType(Type t) {            return                t != null &&                t.IsPublic &&                t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&                !t.IsAbstract &&                typeof(IController).IsAssignableFrom(t);        } public ICollection<Type> GetControllerTypes(string controllerName, HashSet<string> namespaces) {            HashSet<Type> matchingTypes = new HashSet<Type>();            ILookup<string, Type> nsLookup;            if (_cache.TryGetValue(controllerName, out nsLookup)) {                // this friendly name was located in the cache, now cycle through namespaces                if (namespaces != null) {                    foreach (string requestedNamespace in namespaces) {                        foreach (var targetNamespaceGrouping in nsLookup) {                            if (IsNamespaceMatch(requestedNamespace, targetNamespaceGrouping.Key)) {                                matchingTypes.UnionWith(targetNamespaceGrouping);                            }                        }                    }                }                else {                    // if the namespaces parameter is null, search *every* namespace                    foreach (var nsGroup in nsLookup) {                        matchingTypes.UnionWith(nsGroup);                    }                }            }            return matchingTypes;        }

 List<Type> controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(_typeCacheName, IsControllerType, buildManager);這句代碼就是用來查詢當前程式的類,這個類必須通過IsControllerType方法的驗證(類是共有非抽象繼承於IController且類名Controller結尾),而這個_cache是個Dictionary<string, ILookup<string, Type>>類型的資料。
現在我們已經得到了ControllerType,來看看 IController controller = GetControllerInstance(requestContext, controllerType);吧裡面主要就一句
 ControllerActivator.Create(requestContext, controllerType);而ControllerActivator就是先前的DefaultControllerActivator,DefaultControllerActivator的代碼如下:

private class DefaultControllerActivator : IControllerActivator {            Func<IDependencyResolver> _resolverThunk;            public DefaultControllerActivator()                : this(null) {            }            public DefaultControllerActivator(IDependencyResolver resolver) {                if (resolver == null) {                    _resolverThunk = () => DependencyResolver.Current;                }                else {                    _resolverThunk = () => resolver;                }            }            public IController Create(RequestContext requestContext, Type controllerType) {                try {                    return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));                }                catch (Exception ex) {                    throw new InvalidOperationException(                        String.Format(                            CultureInfo.CurrentCulture,                            MvcResources.DefaultControllerFactory_ErrorCreatingController,                            controllerType),                        ex);                }            }        }

 這裡的_resolverThunk()來源於DependencyResolver.Current,
private static DependencyResolver _instance = new DependencyResolver();
        public static IDependencyResolver Current {
            get {
                return _instance.InnerCurrent;
            }
        }
 private IDependencyResolver _current = new DefaultDependencyResolver();
        public IDependencyResolver InnerCurrent {
            get {
                return _current;
            }
        }
所以真正建立controller是在DefaultDependencyResolver的GetService方法,核心代碼   return Activator.CreateInstance(serviceType);
這篇檔案扯得比較遠,可見建立Controller是多麼的麻煩啊。閱讀原始碼主要是讓我們理解其邏輯,同時也讓我們學習其開發的思想。
本文講的這麼多,在項目中最常用的就是ControllerBuilder.Current.SetControllerFactory(xxx);  只要大家理解了它就可以了。 

  

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.