Controller的激活

上篇说到Route的使用,GetRoute的方法里面获得RouteData。然后通过一些判断,将最后的RouteData中的RouteHandler添加到context.RemapHandler。这个方法的意思就是将请求重新映射到这个handler中出来。在上一篇也说到了这个Handler其实是MvcRouteHandler。

 RouteData routeData = this.RouteCollection.GetRouteData(context);
if (routeData != null)
{
IRouteHandler routeHandler = routeData.RouteHandler;
if (routeHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
}
if (!(routeHandler is StopRoutingHandler))
{
RequestContext requestContext = new RequestContext(context, routeData);
context.Request.RequestContext = requestContext; //注意着句 这就是在得到的MvcRouteHandler 调用GetHttpHandler获得HttpHandler
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); if (httpHandler == null)
{
object[] args = new object[] { routeHandler.GetType() };
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), args));
}
if (httpHandler is UrlAuthFailureHandler)
{
if (!FormsAuthenticationModule.FormsAuthRequired)
{
throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3"));
}
UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
}
else
{
context.RemapHandler(httpHandler);
}
}

那看看routeHandler.GetHttpHandler,也就是MvcRouteHandler.GetHttpHandler是如何处理请求的。

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
} protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
{
string controllerName = (string)requestContext.RouteData.Values["controller"];
if (String.IsNullOrWhiteSpace(controllerName))
{
throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController);
} IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
}

这个是MVCRouteHandler里面的。GetHttpHandler的实现调用了一个HttpContext的SetSessionStateBehavior(设置session状态的行为)。然后返回了一个MVCHandler。所以GethttpHandler

其实就做了两个事:

  1. 设置SetSessionStateBehavior的行文
  2. 返回了一个MVCHandler

返回的MVCHandler就会被下面这行语句调用,然后开始处理请求。但我们还是想看一下GetSessionStateBehavior这个方法。这个流程中会有寻找ControllerFactory的过程,这个类之后也会用到。

context.RemapHandler(httpHandler);

寻找ControllerFactory

 requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));

其实里面的参数是调用了GetSessionStateBehavior的方法之后返回的SessionStateBehavior这属性。主要看SessionStateBehavior这个方法。首先获取了RouteData中的controller的value,如果为空则报错。然后通过下面代码获得ControllerFactory,然后调用ControllerFactory的GetControllerSesionBehavior。

IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();

controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);

先看第一句,先看_controllerFactory和ControllerBuilder。

//MvcRouteHandler
private IControllerFactory _controllerFactory; public MvcRouteHandler(IControllerFactory controllerFactory)
{
_controllerFactory = controllerFactory;
}

在MvcRouteHandler中可以看到_controllerFactory是一个属性,而且是在构造MvcRouteHandler的时候进行赋值的。在Route的MapRoute核心实现中

//这是在RouteCollectionExtensions类里面的 MapRoute方法。
Route route = new Route(url, new MvcRouteHandler())
{
Defaults = CreateRouteValueDictionaryUncached(defaults),
Constraints = CreateRouteValueDictionaryUncached(constraints),
DataTokens = new RouteValueDictionary()
};

构造函数里面是没有传任何参数的。所以这个是为null的。那么ControllerBuilder是什么呢?如果看源码的话可以看到这个是

public class ControllerBuilder
{
private static ControllerBuilder _instance = new ControllerBuilder(); private Func<IControllerFactory> _factoryThunk = () => null; private IResolver<IControllerFactory> _serviceResolver; 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;
}
}

通过 ControllerBuilder.Current.GetControllerFactory() 这个代码的话,可以看到首先调用了静态属性Current,属性Current返回了_instance的字段,是创建了一个ControllerBuilder,没有传值,也就是调用下面的构造函数的时候 serviceResolver是为空的,所以_serviceResolver是new了一个SingleServiceResolver类。返回的Currnet调用了GetControllerfactory(),刚好是前面的_serviceResolver字段的Current。当然 可以通过SetControllerFactory方法来进行 _factoryThunk的设置。

internal class SingleServiceResolver<TService> : IResolver<TService>
where TService : class
{
private Lazy<TService> _currentValueFromResolver;
private Func<TService> _currentValueThunk;
private TService _defaultValue;
private Func<IDependencyResolver> _resolverThunk;
private string _callerMethodName; //currentvalueThunk= () => _factoryThunk(), _factoryThunk = () => null;
//DefaultValue= new DefaultControllerFactory { ControllerBuilder = this },
//callerMethodName = "ControllerBuilder.GetControllerFactory" public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName)
{
if (currentValueThunk == null)
{
throw new ArgumentNullException("currentValueThunk");
}
if (defaultValue == null)
{
throw new ArgumentNullException("defaultValue");
} _resolverThunk = () => DependencyResolver.Current; _currentValueFromResolver = new Lazy<TService>(GetValueFromResolver);
_currentValueThunk = currentValueThunk;
_defaultValue = defaultValue;
_callerMethodName = callerMethodName;
} public TService Current
{
get { return _currentValueFromResolver.Value ?? _currentValueThunk() ?? _defaultValue; }
} private TService GetValueFromResolver()
{
TService result = _resolverThunk().GetService<TService>(); if (result != null && _currentValueThunk() != null)
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, MvcResources.SingleServiceResolver_CannotRegisterTwoInstances, typeof(TService).Name.ToString(), _callerMethodName));
} return result;
}
} internal interface IResolver<T>
{
T Current { get; }
}

可以看出IResolver只有一个T的Current的属性。重点还是在SingleServiceResolver,上面代码调用的是这个构造函数。我将参数放到上面便与理解。我们也看到了Current的逻辑链,我们先看后面两个,因为这两是我们参数赋值的。_currentValueThunk()的为 () => _factoryThunk()也就是 _factoryThunk = () => null(默认的情况是这样,如果通过SetControllerFactory设置了 _factoryThunk()的话就会返回设置的ControllerFactory),所以会直接轮到 _defaultValue也就是默认的ControllerFactory的类型。那前面这个 _currentValueFromResolver是什么呢?是一个Lazy(GetValueFromResolver)的方法。这个方法里面会先去调用 _resolverThunk的GetSevice的方法。

_resolverThunk = () => DependencyResolver.Current;

终于看到DependencyResolver这个类了,DependencyResolver这个其实实现第三方DI的类类型。我们可以使用下面这种方法进行注册

//这个是注册DependencyResolver的方法 不是在源码中的  AutofacDependencyResolver实现了 IDependencyResolver
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

当然默认的情况下是没有类注册的上面的result也是为null的,那么如果什么都没做的话便会使用默认的ControllerFactory。这样优先级也出来了。

  • 通过DependencyResolver.SetResolver的优先级最高
  • 通过SetControllerFactory的第二
  • 如果都没有就会使用默认的ControllerFactory。

说了这么多,理一下整个获取ControllerFactory流程和逻辑:

  • 首先看MVCRouteHandler的构造时_controllerFactory属性有没有赋值
  • 没有话调用ControllerBuilder.Current.GetControllerFactory()
    • 里面返回了_serviceResolver的SingleServiceResolver的Current属性
    • SingleServiceResolver 判断DependencyResolver和_factoryThunk是否为空,为空返回默认的DefaultControllerFactory。

来看一下DefaultControllerFactory的GetControllerSessionBehavior的方法。

protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return SessionStateBehavior.Default;
} return _sessionStateCache.GetOrAdd(
controllerType,
type =>
{
var attr = type.GetCustomAttributes(typeof(SessionStateAttribute), inherit: true)
.OfType<SessionStateAttribute>()
.FirstOrDefault(); return (attr != null) ? attr.Behavior : SessionStateBehavior.Default;
});
}

使用了一个_sessionStaeCache的GetorAdd方法,具体的就不看了,主要是了解上面找ControllerFactory的过程。

MVCHandler

思路在回到上面,MvcHandler被放到了下面这句代码,意思就是将请求映射到httphandler,里面细节看不太懂就不深究了,有时间在看。直接看MvcHandler的ProcessRequest方法。

context.RemapHandler(httpHandler);
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{ protected virtual void ProcessRequest(HttpContext httpContext)
{
HttpContextBase httpContextBase = new HttpContextWrapper(httpContext);
ProcessRequest(httpContextBase);
} protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory); try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
} private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{ //如果请求验证已经启用,请使其懒惰。 这允许像[HttpPost](它查找Request.Form)的属性正常工作,而不会触发完全验证。 容忍null HttpContext进行测试。
HttpContext currentContext = HttpContext.Current;
if (currentContext != null)
{
bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(currentContext);
if (isRequestValidationEnabled == true)
{
ValidationUtility.EnableDynamicValidation(currentContext);
}
} AddVersionHeader(httpContext);
RemoveOptionalRoutingParameters(); string controllerName = RequestContext.RouteData.GetRequiredString("controller"); //又是ControllerBuilder
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName); if (controller == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.ControllerBuilder_FactoryReturnedNull,
factory.GetType(),
controllerName));
}
} }

核心方法ProcessRequest,首先将请求放到上下文包装类中,将httpContextBase传入ProcessRequest方法内,调用了ProcessRequestInit的方法,实例化了controller和factory。所以controller方法是最和核心的。

方法内首先获得类型为HttpContext的currentContext,对其进行验证。然后在请求头中添加MVC的信息(AddVersionHeader)。然后去掉RouteData中的为UrlParameter.Optional的参数。然后获得了Controller的名字,然后通过ControllerBuilder获取controllerFactory.不过这个ControllerBuilder,不过里面的实现如果没有去进行赋值的话也是会走上面的流程的。

internal ControllerBuilder ControllerBuilder
{
get
{
if (_controllerBuilder == null)
{
_controllerBuilder = ControllerBuilder.Current;
}
return _controllerBuilder;
}
set { _controllerBuilder = value; }
}

如果什么都没设置走默认流程。

controller = factory.CreateController(RequestContext, controllerName);

看一下DefaultControllerFactory里面的CreateController。

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;
}

一开始入口检查,然后通过GetControllerType的方法获得ControllerType的类型,controller的实例。返回。这两个方法会在下一篇说到。

最新文章

  1. 在UTF-8中,一个汉字为什么需要三个字节?
  2. Django补充及初识Ajax
  3. DP专题训练之HDU 1506 Largest Rectangle in a Histogram
  4. Mysql(一)
  5. SU demos
  6. 在多浏览器使用JS复制内容到剪切板,无需插件
  7. 2016年11月24日 星期四 --出埃及记 Exodus 20:15
  8. ubuntu14.04 中文输入法无法使用
  9. Fisher's exact test( 费希尔精确检验)
  10. 使用ssh对服务器进行登录
  11. [转]影响Cache的几个HTTP头信息
  12. iOS开发-UI (一)常用控件
  13. Linux下memcache的安装和启动测试
  14. 解决ubuntu不能安装g++的问题
  15. JavaScript中的函数和C#中的匿名函数(委托、lambda表达式)
  16. 老男孩python学习自修第十一天【内置函数】
  17. A1017. Queueing at Bank
  18. 洛谷 P1490 买蛋糕 解题报告
  19. C++11--时钟和计时器&lt;chrono&gt;
  20. Windows的cmd窗口显示utf8字符

热门文章

  1. CentOS上安装Git及配置远程仓库
  2. Flask 框架app = Flask(__name__) 解析
  3. 2014百度之星初赛第二场hdu 4831 Scenic Popularity
  4. Linux加载一个可执行程序并启动的过程
  5. IDEA设置类和方法的注释
  6. Centos7.5源码安装nginx-1.16.0
  7. 组件通信 $ref
  8. 开发框架DevExtreme全新发布v19.1.3|附下载
  9. linux运维、架构之路-MySQL日志(三)
  10. linux运维、架构之路-linux目录结构