Mvc
|
Web Api(web host)
|
1、路由注册、处理、解析对应handler
UrlRoutingModule通过重载IHttpModule来接管mvc和webapi的处理
以下为简要逻辑代码(删减了部分)
protected virtual void Init(HttpApplication application) {
application.PostResolveRequestCache += OnApplicationPostResolveRequestCache;
}
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) {
HttpApplication app = (HttpApplication)sender;
HttpContextBase context = new HttpContextWrapper(app.Context);
PostResolveRequestCache(context);
}
public virtual void PostResolveRequestCache(HttpContextBase context) {
// Match the incoming URL against the route table
RouteData routeData = RouteCollection.GetRouteData(context);
// If a route was found, get an IHttpHandler from the route's RouteHandler
IRouteHandler routeHandler = routeData.RouteHandler;
RequestContext requestContext = new RequestContext(context, routeData);
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
SR.GetString(SR.UrlRoutingModule_NoHttpHandler),
routeHandler.GetType()));
}
// Remap IIS7 to our handler
context.RemapHandler(httpHandler);
}
逻辑为:从注册的RouteData中解析RouteHandler,然后再调用GetHttpHandler获取相应的IHttpHandler
mvc中的HttpHandler是MvcHandler
webapi中的是 HttpControllerHandler
所以路由注册的目标是:注册+指定handler
下面看下二者的不同
|
//WebApiApplication.cs RouteConfig.RegisterRoutes(RouteTable.Routes);
//RouteConfig.cs
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
RouteTable.Routes 作为注册入口,
在MapRoute中指定RouteHandler为MvcRouteHandler的处理器
然后再获取IHttpHandler
//MvcRouteHandler.cs protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
return (IHttpHandler) new MvcHandler(requestContext);
}
|
//WebApiApplication.cs GlobalConfiguration.Configure(WebApiConfig.Register);
//WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
GlobalConfiguration.HttpConfiguration 作为注册入口,
并在HostedHttpRoute中指定RouteHandler为HttpControllerRouteHandler
然后再获取IHttpHandler
//HttpControllerRouteHandler.cs protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return (IHttpHandler) new HttpControllerHandler(requestContext.RouteData);
}
|
2、创建Controller
|
为了方便理解逻辑,使用同步版本来描述,实际使用中,继承controller的都是使用一步版本
在上一步已经获取到 MvcHandler,接着显式调用 IHttpHandler.ProcessRequest 方法
void IHttpHandler.ProcessRequest(HttpContext httpContext)
{
this.ProcessRequest(httpContext);
}
protected virtual void ProcessRequest(HttpContext httpContext)
{
this.ProcessRequest((HttpContextBase) new HttpContextWrapper(httpContext));
}
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory; this.ProcessRequestInit(httpContext, out controller, out factory); try
{ controller.Execute(this.RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
}
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
string requiredString = this.RequestContext.RouteData.GetRequiredString(nameof (controller));
factory = this.ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(this.RequestContext, requiredString);
}
上述ProcessRequestInit方法内部,只展示了基本逻辑,
通过ControllerFactory创建 Contrller,
之后调用 Controller.Execute 执行Controller创建Action的逻辑
|
同样,找到 HttpControllerHandler开始处理,
web api在创建controller之前可对请求流做管道式处理,
可在请求消息到达路由选择前提前加入处理逻辑
//HttpTaskAsyncHandler.cs
public abstract Task ProcessRequestAsync(HttpContext context);
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
return TaskAsyncHelper.BeginTask(() => ProcessRequestAsync(context), cb, extraData);
}
void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {
TaskAsyncHelper.EndTask(result);
}
public override Task ProcessRequestAsync(HttpContext context)
{
return this.ProcessRequestAsyncCore((HttpContextBase) new HttpContextWrapper(context));
}
internal async Task ProcessRequestAsyncCore(HttpContextBase contextBase)
{
HttpRequestMessage request = contextBase.GetHttpRequestMessage() ?? HttpControllerHandler.ConvertRequest(contextBase);
request.SetRouteData(this._routeData);
CancellationToken cancellationToken = contextBase.Response.GetClientDisconnectedTokenWhenFixed();
HttpResponseMessage response = (HttpResponseMessage) null;
try
{ //创建HttpMessageHandler管道,只有最后一个为 HttpMessageHandler衍生类,其余皆为子类DelegatingHandler的衍生类
response = await this._server.SendAsync(request, cancellationToken);
await HttpControllerHandler.CopyResponseAsync(contextBase, request, response, HttpControllerHandler._exceptionLogger.Value, HttpControllerHandler._exceptionHandler.Value, cancellationToken);
}
catch (OperationCanceledException ex)
{
...
} ...
}
通过GlobalConfiguration.HttpConfiguration入口可配置自定义的HttpMessageHandler委托链,
其中HttpServer是第一个被执行的HttpMessageHandler,
HttpRoutingDispatcher是最后一个,具体封装实现是在HttpServer.Initialize()中,如下:
protected virtual void Initialize()
{
this._configuration.EnsureInitialized();
this.InnerHandler = HttpClientFactory.CreatePipeline(this._dispatcher, (IEnumerable<DelegatingHandler>) this._configuration.MessageHandlers);
}
作为最后一个handler的HttpRoutingDispatcher在构造函数中默认指定HttpControllerDispatcher为处理handler
HttpControllerDispatcher才是真正的controller创建入口
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
...
try
{
HttpControllerDescriptor controllerDescriptor = this.ControllerSelector.SelectController(request);
IHttpController controller = controllerDescriptor.CreateController(request);
controllerContext = HttpControllerDispatcher.CreateControllerContext(request, controllerDescriptor, controller);
return await controller.ExecuteAsync(controllerContext, cancellationToken);
}
catch (OperationCanceledException ex)
{
...
}
HttpResponseMessage response = await this.ExceptionHandler.HandleAsync(exceptionContext, cancellationToken);
return response;
}
|
3、创建action
|
//ControllerBase类中方法
void IController.Execute(RequestContext requestContext)
{
this.Execute(requestContext);
}
protected virtual void Execute(RequestContext requestContext)
{
...
this.ExecuteCore();
}
//Controller类中方法
protected override void ExecuteCore()
{
this.PossiblyLoadTempData();
try
{
string actionName = Controller.GetActionName(this.RouteData);
if (this.ActionInvoker.InvokeAction(this.ControllerContext, actionName))
return;
this.HandleUnknownAction(actionName);
}
finally
{
this.PossiblySaveTempData();
}
}
对应的同步版本ControllerActionInvoker逻辑为:
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext); ActionDescriptor action = this.FindAction(controllerContext, controllerDescriptor, actionName);
//5种过滤器
FilterInfo filters = this.GetFilters(controllerContext, action);
try
{ //身份过滤器
AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, action);
if (authenticationContext.Result != null)
{
AuthenticationChallengeContext challengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, action, authenticationContext.Result);
this.InvokeActionResult(controllerContext, challengeContext.Result ?? authenticationContext.Result);
}
else
{ //权限过滤器
AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, action);
if (authorizationContext.Result != null)
{
AuthenticationChallengeContext challengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, action, authorizationContext.Result);
this.InvokeActionResult(controllerContext, challengeContext.Result ?? authorizationContext.Result);
}
else
{ //action 过滤器
if (controllerContext.Controller.ValidateRequest)
ControllerActionInvoker.ValidateRequest(controllerContext);
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, action);
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, action, parameterValues);
AuthenticationChallengeContext challengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, action, actionExecutedContext.Result);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, challengeContext.Result ?? actionExecutedContext.Result);
}
}
}
catch (Exception ex)
{ //异常过滤器
ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled)
throw;
else
this.InvokeActionResult(controllerContext, exceptionContext.Result);
}
return true;
}
|
//ApiController.cs public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
{
this.Initialize(controllerContext);
ServicesContainer services = controllerContext.ControllerDescriptor.Configuration.Services; HttpActionDescriptor actionDescriptor = services.GetActionSelector().SelectAction(controllerContext);
this.ActionContext.ActionDescriptor = actionDescriptor;
//4种过滤器
FilterGrouping filterGrouping = actionDescriptor.GetFilterGrouping();
IActionFilter[] actionFilters = filterGrouping.ActionFilters;
IAuthenticationFilter[] authenticationFilters = filterGrouping.AuthenticationFilters;
IAuthorizationFilter[] authorizationFilters = filterGrouping.AuthorizationFilters;
IExceptionFilter[] exceptionFilters = filterGrouping.ExceptionFilters;
IHttpActionResult innerResult = (IHttpActionResult) new ActionFilterResult(actionDescriptor.ActionBinding, this.ActionContext, services, actionFilters);
if (authorizationFilters.Length > )
innerResult = (IHttpActionResult) new AuthorizationFilterResult(this.ActionContext, authorizationFilters, innerResult);
if (authenticationFilters.Length > )
innerResult = (IHttpActionResult) new AuthenticationFilterResult(this.ActionContext, this, authenticationFilters, innerResult);
if (exceptionFilters.Length > )
{
IExceptionLogger logger = ExceptionServices.GetLogger(services);
IExceptionHandler handler = ExceptionServices.GetHandler(services);
innerResult = (IHttpActionResult) new ExceptionFilterResult(this.ActionContext, exceptionFilters, logger, handler, innerResult);
}
return innerResult.ExecuteAsync(cancellationToken);
}
|
|
|
|
|