Controller的创建
在ASP.NET MVC 中所有的Controller类都直接或间接继承IController接口,所有的网页的Controller数据请求与响应处理的入口就是IController接口中的Execute方法,Execute方法只接收RequestContext参数,RequestContext参数中的RouteData是有关所请求路由的信息,里面包含了Controller,Action的名字等信息。HttpContext包含了HTTP 请求的信息。
Controller的创建来源于IControllerFactory接口中的IController CreateController(RequestContext requestContext, string controllerName);
当请求进入到MvcHandler类的ProcessRequest(HttpContext httpContext)方法钟就进行IControllerFactory,IController的创建;
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { HttpContext currentContext = HttpContext.Current; if (currentContext != null) { bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(currentContext); if (isRequestValidationEnabled == true) { ValidationUtility.EnableDynamicValidation(currentContext);} } AddVersionHeader(httpContext);//响应头里面加入MVC的版本号 RemoveOptionalRoutingParameters(); string controllerName = RequestContext.RouteData.GetRequiredString("controller"); // Get the controller type
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
if (controller == null)
{ throw new InvalidOperationException( String.Format( CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, factory.GetType(), controllerName) ); }
}
public class ControllerBuilder { private static ControllerBuilder _instance = new ControllerBuilder(); private Func<IControllerFactory> _factoryThunk = () => null; private HashSet<string> _namespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private IResolver<IControllerFactory> _serviceResolver; 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);// 使用指定的类型来设置控制器工厂。 public void SetControllerFactory(Type controllerFactoryType); }
从ProcessRequestInit代码中可以看到 IControllerFactory 来源于 ControllerBuilder.GetControllerFactory方法,ControllerBuilder类动态的生成构造器;ControllerBuilder类的构造函数中默认设置了DefaultControllerFactory 类作为IControllerFactory接口的实现类,我们也可以自己来实现IControllerFactory接口来,通过SetControllerFactory方法附件到ControllerBuilder类中;这样设计提高了框架的扩展性和灵活性;
DefaultControllerFactory 类作为MVC框架中的 IControllerFactory接口的默认实现类,Controller也是通过这个类来进行创建;主要分两步,首先要获取 controller的类型,然后进行controller的构造;
public virtual IController CreateController(RequestContext requestContext, string controllerName) { if (requestContext == null) { throw new ArgumentNullException("requestContext");} if (String.IsNullOrEmpty(controllerName) && !requestContext.RouteData.HasDirectRouteMatch())
{ throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName"); } Type controllerType = GetControllerType(requestContext, controllerName);
IController controller = GetControllerInstance(requestContext, controllerType);
return controller; }
在获取controller类型的过程中,首先判断RouteData的RouteValueDictionary中有没有默认的IControllerFactory类型,如果存在直接返回controllerType;由于不同的Controller存在不同的Namespaces中,因此获取controllerType首先获取Namespaces;获取Namespaces的顺序首先是RouteData中的DataTokens中key为“Namespaces”的数据,当上述情况不存在时,获取ControllerBuilder.DefaultNamespaces中的Namespaces列表,当二者的Namespaces都为空时,就进行整个应用程序的所有Namespaces进行全局搜索对应的controllerType;
由于RouteData中的controllerName 是不区别大小写的,而C#的类名是区分大小写的,因此直接通过名字查找是行不通的,MVC 框架采用的是查找到所有的类型,然后根据这些类的名字去匹配controllerName;由于应用程序中含有大量DLL,含有大量的controller,因此MVC 框架采用了缓存机制;
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); } } }
}
在 ControllerTypeCache类中的EnsureInitialized 构造了 Dictionary<string, ILookup<string, Type>>结构的缓存_cache ,Dictionary的key是控制器的名称(去掉“Controller”后缀),Value是Key为Namespace,Value为ControllerType;当查找ControllerType时,首先通过Controller查找,然后在进行Namespace匹配,提高了查询的效率;
对于GetFilteredTypesFromAssemblies方法中的TypeCacheName参数是Cache的Name,在MVC中对于的值是"MVC-ControllerTypeCache.xml",IsControllerType是判断是否为ControllerType的委托方法(判断Type是否是抽象类,是否继承IController接口,是否是Controller结尾),buildManager是管理 ASP.NET 应用程序编译的方法的类,缓存文件的读取/写入,加载应用程序的dll都是通过这个类的方法实现;
对于_cache 缓存的地址是在HttpRuntime.CodegenDir+"//UserCache//MVC-ControllerTypeCache.xml"文件中;
<?xml version="1.0" encoding="utf-8"?>
<!--此文件自动生成。请不要修改此文件的内容。-->
<typeCache lastModified="2015-11-27 15:32:08" mvcVersionId="72d59038-e845-45b1-853a-70864614e003">
<assembly name="ApplicationWeb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<module versionId="a5615a50-9b2b-4ea3-8dbc-870592b04b35">
<type>ApplicationWeb.Controllers.AccountController</type>
<type>ApplicationWeb.Controllers.HomeController</type>
</module>
</assembly>
</typeCache>
当获取到控制器的Type后就可以进行ControllerType的创建,在DefaultControllerFactory类中对ControllerType的创建时通过IControllerActivator接口中的 IController Create(RequestContext requestContext, Type controllerType)来实现的;通过DefaultControllerFactory代码我们可以发现IControllerActivator接口的默认实现类时DefaultControllerActivator;DefaultControllerActivator类中的Create方法首先通DefaultDependencyResolver类中的GetService方法创建(内部也是调用的Activator.CreateInstance)方法;
private class DefaultControllerActivator : IControllerActivator { private 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); } } }

浙公网安备 33010602011771号