·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> ASP.NET Web API 控制器执行过程(一)

ASP.NET Web API 控制器执行过程(一)

作者:佚名      ASP.NET网站开发编辑:admin      更新时间:2022-07-23

asp.net Web API 控制器执行过程(一)

ASP.NET Web API 控制器执行过程()

前言

前面两篇讲解了控制器的创建过程,只是从框架源码的角度去简单的了解,在控制器创建过后所执行的过程也是尤为重要的,本篇就来简单的说明一下控制器在创建过后将会做哪些工作。

ASP.NET Web API 控制器执行过程

  • ASP.NET Web API 控制器执行过程(一)
  • ASP.NET Web API 控制器执行过程(二)

控制器执行过程

我们知道控制器的生成过程都是在HttpControllerDispatcher类型中来操作的,那我们要想知道控制器在创建过后执行操作的入口点也必须在HttpControllerDispatcher类型中才能发现。来看如下示例代码:

代码1-1

    PRivate Task<HttpResponseMessage> SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken)    {        IHttpRouteData routeData = request.GetRouteData();        HttpControllerDescriptor descriptor = this.ControllerSelector.SelectController(request);             IHttpController controller = descriptor.CreateController(request);            HttpConfiguration configuration = request.GetConfiguration();        HttpControllerContext controllerContext = new HttpControllerContext(descriptor.Configuration, routeData, request) {            Controller = controller,            ControllerDescriptor = descriptor        };        return controller.ExecuteAsync(controllerContext, cancellationToken);}

看过前面两篇的朋友看到这里的代码一定会很熟悉了,控制器的生成过程就包含在了其中,在代码1-1中我们会看到HttpControllerContext类型,从它的名称来看想必大家也都知道了它的作用,代表着进入控制器处理阶段的逻辑上的上下文对象,并且封装着一些很重要的信息。

HttpControllerContext控制器上下文

示例代码1-2

    public class HttpControllerContext    {        public HttpControllerContext();        public HttpControllerContext(HttpConfiguration configuration, IHttpRouteData routeData, HttpRequestMessage request);        public HttpConfiguration Configuration { get; set; }        public IHttpController Controller { get; set; }        public HttpControllerDescriptor ControllerDescriptor { get; set; }        public HttpRequestMessage Request { get; set; }        public IHttpRouteData RouteData { get; set; }    }

结合代码1-2和代码1-1可以看到在HttpControllerContext类型中对HttpConfiguration类型的对象,它的重要性不用多说了,里面包含着很多配置信息以及存放基础设施的容器对象,然后就是路由数据对象IHttpRouteData类型,以及最后的Http请求对象HttpRequestMessage类型的对象,并且在代码1-1中对HttpControllerContext类型中的Controller和ControllerDescriptor属性进行了赋值,Controller属性对应的就是当前被创建好的控制器,而ControllerDescriptor属性则是表示Controller属性对应控制器的描述类型,现在回头再看一下HttpControllerContext类型的对象就知道它里面包含的内容是有多重要了。

现在我们再回到代码1-1中,最后我们看到是由IHttpController类型的变量controller调用方法ExecuteAsync()方法由此进入控制器中,一般控制器都是继承自ApiController,我们就从ApiController类型来入手。

ApiController类型

示例代码1-3

    public abstract class ApiController : IHttpController, IDisposable    {        public virtual Task<System.Net.Http.HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken);    }

在代码1-3中我们可以看到再ApiController类型中定义了ExecuteAsync()方法,ApiController为抽象类型,控制器的主要执行过程也就是都在ExecuteAsync()方法中,下面我看一下具体的实现,如下示例代码。

代码1-4

    public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)    {        HttpControllerDescriptor controllerDescriptor = controllerContext.ControllerDescriptor;        ServicesContainer controllerServices = controllerDescriptor.Configuration.Services;        HttpActionDescriptor actionDescriptor = controllerServices.GetActionSelector().SelectAction(controllerContext);        HttpActionContext actionContext = new HttpActionContext(controllerContext, actionDescriptor);        FilterGrouping grouping = new FilterGrouping(actionDescriptor.GetFilterPipeline());        IEnumerable<IActionFilter> actionFilters = grouping.ActionFilters;        IEnumerable<IAuthorizationFilter> authorizationFilters = grouping.AuthorizationFilters;        IEnumerable<IExceptionFilter> exceptionFilters = grouping.ExceptionFilters;        return InvokeActionWithExceptionFilters(InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, () => actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate {            this._modelState = actionContext.ModelState;            return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();        }, new CancellationToken(), false))(), actionContext, cancellationToken, exceptionFilters);   }

代码1-4中定义了控制器的执行过程,我们就从源码的角度去了解一下控制器的执行过程。

在代码1-4中先是从控制器上下文对象中获取当前控制器类型的描述对象HttpControllerDescriptor类型的实例,而后从HttpControllerDescriptor类型实例从获取在HttpConfiguration中的服务容器ServicesContainer类型的实例,对于这些类型前面的篇幅或多或少的讲过了。

在这之后从服务容器中获取IHttpActionSelector类型的行为选择器并且经过筛选获取到最佳匹配的HttpActionDescriptor类型,在之前也有讲到过HttpControllerDescriptor,这里的HttpActionDescriptor跟其相似,就是表示控制其行为(方法)的元数据信息。

下面我就来讲解一下控制器行为选择器的执行过程,也就是它筛选方法的几个步骤。

首先我们要知道控制器行为选择器的类型,从代码1-4中可以看到是通过服务容器对象的扩展方法来获取的,在前面的篇幅也都讲过了,这里可以得知我们要查看的控制器行为选择器的类型就是ApiControllerActionSelector类型。

ApiControllerActionSelector控制器行为选择器

示例代码1-5

    public class ApiControllerActionSelector : IHttpActionSelector    {        // Fields        private readonly object _cacheKey;        private ActionSelectorCacheItem _fastCache;        private const string ActionRouteKey = "action";        private const string ControllerRouteKey = "controller";        // Methods        public ApiControllerActionSelector();        public virtual ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor);        private ActionSelectorCacheItem GetInternalSelector(HttpControllerDescriptor controllerDescriptor);        public virtual HttpActionDescriptor SelectAction(HttpControllerContext controllerContext);        // Nested Types        private class ActionSelectorCacheItem        {        }        private class LookupAdapter : ILookup<string, HttpActionDescriptor>, IEnumerable<IGrouping<string, HttpActionDescriptor>>, IEnumerable        {        }   }

从代码1-5中我们可以看到ApiControllerActionSelector类型中包含着两个私有类,这两个私有类后面会有讲到起到的作用也很重要。

下面我们还是回到代码1-4中的逻辑,从调用控制器行为选择器中调用SelectAction()方法开始。

在ApiControllerActionSelector类型中调用SelectAction()时,实际是由SelectAction()方法调用GetInternalSelector()方法生成一个控制器方法的缓存对象,也就是ApiControllerActionSelector类型的私有类ActionSelectorCacheItem,而真正的筛选工作都是由它来执行的,所以下面才是介绍的重点。

控制器方法选择器-筛选方法的步骤

1初始化筛选

在ActionSelectorCacheItem类型的初始化的时候, ActionSelectorCacheItem实例中会首先根据HttpControllerDescriptor对象获取到控制器本身的类型,然后利用反射的技术根据条件获取到当前控制器类型中的所有方法,最后保存为MethodInfo[]。而所谓的条件就是(BindingFlags.Public 、BindingFlags.Instance、方法所属类型必须是ApiController类型的)。

我们看下ActionSelectorCacheItem类型中的字段信息,这些字段里存放的都是很重要的数据,后面会一一说明。

示例代码1-6

        private readonly ReflectedHttpActionDescriptor[] _actionDescriptors;        private readonly ILookup<string, ReflectedHttpActionDescriptor> _actionNameMapping;        private readonly IDictionary<ReflectedHttpActionDescriptor, string[]> _actionParameterNames = new Dictionary<ReflectedHttpActionDescriptor, string[]>();        private readonly HttpMethod[] _cacheListVerbKinds = new HttpMethod[] { HttpMethod.Get, HttpMethod.Put, HttpMethod.Post };        private readonly ReflectedHttpActionDescriptor[][] _cacheListVerbs;        private readonly HttpControllerDescriptor _controllerDescriptor;

1.1基础信息初始化- ReflectedHttpActionDescriptor[] _actionDescriptors

这个时候初始化工作并没有做完,这时候会把MethodInfo[]数组中的每个MethodInfo实例封装成ReflectedHttpActionDescriptor类型的对象,对于类型稍后再说。在封装成ReflectedHttpActionDescriptor类型的对象后,也会将每个实例存至一个ReflectedHttpActionDescriptor类型的数组中。

1.2 基础信息初始化- IDictionary<ReflectedHtt