您的位置:首页 > 编程语言 > ASP

asp.net mvc源码分析-Controllerl篇 如何创建Controller实例

2012-11-08 15:12 986 查看
在上一篇文章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);  只要大家理解了它就可以了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: