当前位置 > 首页 > Asp.net

Asp.net web Api源码分析-HttpActionDescriptor的创建

2012-12-4 21:46:00来源:Asp.net

紧接着上文Asp.net web Api源码分析-HttpControllerDispatcher (Controller的创建)这里已经创建好了IHttpController,现在让我们来看看它的ExecuteAsync方法,这个方法很是复杂啊。

public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
{
if (_request != null)
{
// if user has registered a controller factory which produces the same controller instance, we should throw here
throw Error.InvalidOperation(SRResources.CannotSupportSingletonInstance, typeof(ApiController).Name, typeof(IHttpControllerActivator).Name);
}

Initialize(controllerContext);

// We can't be reused, and we know we're disposable, so make sure we go away when
// the request has been completed.
if (_request != null)
{
_request.RegisterForDispose(this);
}

HttpControllerDescriptor controllerDescriptor = controllerContext.ControllerDescriptor;
ServicesContainer controllerServices = controllerDescriptor.Configuration.Services;
HttpActionDescriptor actionDescriptor = controllerServices.GetActionSelector().SelectAction(controllerContext);
HttpActionContext actionContext = new HttpActionContext(controllerContext, actionDescriptor);

IEnumerable<FilterInfo> filters = actionDescriptor.GetFilterPipeline();

FilterGrouping filterGrouping = new FilterGrouping(filters);

IEnumerable<IActionFilter> actionFilters = filterGrouping.ActionFilters;
IEnumerable<IAuthorizationFilter> authorizationFilters = filterGrouping.AuthorizationFilters;
IEnumerable<IExceptionFilter> exceptionFilters = filterGrouping.ExceptionFilters;

// Func<Task<HttpResponseMessage>>
Task<HttpResponseMessage> result = InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, () =>
{
HttpActionBinding actionBinding = actionDescriptor.ActionBinding;
Task bindTask = actionBinding.ExecuteBindingAsync(actionContext, cancellationToken);
return bindTask.Then<HttpResponseMessage>(() =>
{
_modelState = actionContext.ModelState;
Func<Task<HttpResponseMessage>> invokeFunc = InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>
{
return controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken);
});
return invokeFunc();
});
})();

result = InvokeActionWithExceptionFilters(result, actionContext, cancellationToken, exceptionFilters);

return result;
}

 

首先调用Initialize方法初始化ControllerContext、_request、_configuration,紧接着就创建一个HttpActionDescriptor

 HttpActionDescriptor actionDescriptor = controllerServices.GetActionSelector().SelectAction(controllerContext);

   在DefaultServices中有这么一句SetSingle<IHttpActionSelector>(new ApiControllerActionSelector());, 所以我们就知道controllerServices.GetActionSelector()返回的是一个 ApiControllerActionSelector实例。其中ApiControllerActionSelector的SelectAction 实现也比较简单:

    public virtual HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
        {
            ActionSelectorCacheItem internalSelector = GetInternalSelector(controllerContext.ControllerDescriptor);
            return internalSelector.SelectAction(controllerContext);

        }

我们首先来看看GetInternalSelector方法实现:、

   private ActionSelectorCacheItem GetInternalSelector(HttpControllerDescriptor controllerDescriptor)
        {
            // First check in the local fast cache and if not a match then look in the broader
            // HttpControllerDescriptor.Properties cache
            if (_fastCache == null)
            {
                ActionSelectorCacheItem selector = new ActionSelectorCacheItem(controllerDescriptor);
                Interlocked.CompareExchange(ref _fastCache, selector, null);
                return selector;
            }
            else if (_fastCache.HttpControllerDescriptor == controllerDescriptor)
            {
                // If the key matches and we already have the delegate for creating an instance then just execute it
                return _fastCache;
            }
            else
            {
                // If the key doesn't match then lookup/create delegate in the HttpControllerDescriptor.Properties for
                // that HttpControllerDescriptor instance
                ActionSelectorCacheItem selector