前面兩篇講解了控制器的創建過程,只是從框架源碼的角度去簡單的了解,在控制器創建過后所執行的過程也是尤為重要的,本篇就來簡單的說明一下控制器在創建過后將會做哪些工作。
我們知道控制器的生成過程都是在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
|
新聞熱點
疑難解答