依賴注入
與 MVC 類似, Web API 提供了System.Web.Http.Services.IDependencyResolver 接口來實現依賴注入, 我們可以很容易的用 Unity 來實現這個接口:
public class UnityDependencyResolver : IDependencyResolver { private readonly IUnityContainer _container; public UnityDependencyResolver(IUnityContainer container) { this._container = container; } public object GetService(Type serviceType) { return this._container.IsRegistered(serviceType) ? this._container.Resolve(serviceType) : null; } public IEnumerable<Object> GetServices(Type serviceType) { return this._container.Registrations .Where(reg => type.IsAssignableFrom(reg.RegisteredType)) .Select(reg => string.IsNullOrEmpty(reg.Name) ? this._container.Resolve(type) : this._container.Resolve(type, reg.Name)); } }
使用 UnityDependencyResolver 的方法也很簡單, 只要在 Global.asax.cs 里添加下面一行代碼即可:
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new UnityDependencyResolver(container));
將 UnityDependencyResolver 配置好之后, Web API 框架將會在運行時向其請求一系列的接口實現:
- 應用啟動時, Web API 框架會依次請求下列接口:
- System.Web.Http.Dispatcher.IHttpControllerFactory
- System.Web.Http.Common.ILogger
- System.Web.Http.Dispatcher.IHttpControllerActivator
- System.Web.Http.Controllers.IHttpActionSelector
- System.Web.Http.Controllers.IHttpActionInvoker
- 在第一次訪問某個 Controller 之前, 還會請求下面的接口 (如果重復訪問相同的 Controller , 則不會再次調用):
- System.Web.Http.Filters.IFilterProvider
- 每次處理 HTTP 請求時, Web API 請求下列接口:
- System.Web.Http.Controllers.IActionValueBinder
- System.Web.Http.ValueProviders.ValueProviderFactory (僅 Action 需要參數時才需要)
- System.Web.Http.ModelBinding.ModelBinderProvider (僅 Action 需要參數時才需要)
- System.Web.Http.Metadata.ModelMetadataProvider (僅 Action 需要參數時才需要)
- System.Web.Http.Validation.ModelValidatorProvider (僅 Action 需要參數時才需要)
- System.Net.Http.Formatting.IFormatterSelector
這些接口都是 Web API 公開的擴展點, 可以根據需要來對這些接口進行實現, 並通過 Unity 進行配置, 讓其注入到 Web API 運行時中。 接下來將逐個討論這些擴展點。
擴展
IHttpControllerFactory
IHttpControllerFactory 接口有兩個方法, 負責創建和銷毀 HttpController 實例:
- CreateController(HttpControllerContext, Type) : IHttpController
- ReleaseController(IHttpController) : void
這個接口的默認實現是 DefaultHttpControllerFactory , 根據當前請求的上下文通過創建 HttpControllerDescriptor , 然后通過 HttpControllerDescriptor 的 ControllerActivator 創建對應的 IHttpController 實例。
ILogger
只是一個日志接口, 有下面的幾個方法:
- Log(string, TraceLevel, Func
) : void - LogException(string, TraceLevel, Exception) : void
默認的實現是 DiagnosticLogger , 通過 ILSpy 觀察, 貌似什么都沒有做。
IHttpControllerActivator
負責創建具體的 Controller 實例, 只有一個方法:
- Create(HttpControllerContext, Type) : IHttpController
默認的實現是 DefaultHttpControllerActivator , 先向 DependencyResolver 請求對應 Controller 類型的實例, 如果返回為空, 則通過動態編譯包裝 Controller 類型構造函數的 lambda 表達式進行創建實例, 相關的代碼如下:
Func<IHttpController> func = TypeActivator.Create<IHttpController>(controllerType); Tuple<HttpControllerDescriptor, Func<IHttpController>> value = Tuple.Create<HttpControllerDescriptor, Func<IHttpController>>(controllerContext.ControllerDescriptor, func); Interlocked.CompareExchange<Tuple<HttpControllerDescriptor, Func<IHttpController>>>(ref this._fastCache, value, null); result = func();
IHttpActionSelector
負責選擇合適的動作, 默認的實現是 ApiControllerSelector , 選擇規則如下:
- 如果路由定義了 {action} , 則通過當前的 HttpControllerContext 中的 action 的值尋找合適的方法;
- 否則, 根據當前的 HTTP 請求方法 (POST, GET, PUT, DELETE) 尋找合適的方法。
IHttpActionInvoker
負責調用 HttpActionSelector 選擇到的方法, 該接口有一個方法:
- InvokeActionAsync(HttpActionContext, CancellationToken) : Task<HttpResponseMessage>
默認的實現是 ApiControllerActionInvoker , 通過反射找出動作方法的參數信息, 然后再通過動態創建 lambda 表達式對方法進行調用, 取得返回結果, 部分代碼如下:
ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "instance"); ParameterExpression parameterExpression2 = Expression.Parameter(typeof(object[]), "parameters"); List<Expression> list = new List<Expression>(); ParameterInfo[] parameters = methodInfo.GetParameters(); for (int i = 0; i < parameters.Length; i++) { ParameterInfo parameterInfo = parameters[i]; BinaryExpression expression = Expression.ArrayIndex(parameterExpression2, Expression.Constant(i)); UnaryExpression item = Expression.Convert(expression, parameterInfo.ParameterType); list.Add(item); } UnaryExpression instance2 = (!methodInfo.IsStatic) ? Expression.Convert(parameterExpression, methodInfo.ReflectedType) : null; MethodCallExpression methodCallExpression = Expression.Call(instance2, methodInfo, list); if (methodCallExpression.Type == typeof(void)) { Expression<Action<object, object[]>> expression2 = Expression.Lambda<Action<object, object[]>>(methodCallExpression, new ParameterExpression[] { parameterExpression, parameterExpression2 }); Action<object, object[]> voidExecutor = expression2.Compile(); return delegate(object instance, object[] methodParameters) { voidExecutor(instance, methodParameters); return null; } ; } UnaryExpression body = Expression.Convert(methodCallExpression, typeof(object)); Expression<Func<object, object[], object>> expression3 = Expression.Lambda<Func<object, object[], object>>(body, new ParameterExpression[] { parameterExpression, parameterExpression2 }); return expression3.Compile();
取得返回結果之后, 再調用 ApiResponseConverter 的 GetResponseConverter 方法找到合適的 Converter , 最后返回 Task<HttpResponseMessage>
IFilterProvider
負責提供過濾的標記, Web API 框架內置了下面的幾個 FilterProvider :
- EnumerableEvaluatorFilterProvider 負責提供對 IENumerable 的每個元素的轉換的標記, 簡單的說, 就是負責提供將 Action 方法返回的 IEnumerable 的結果進行自定義轉換的標記;
- QueryCompositionFilterProvider 負責對 Action 方法返回的 IQueryable 的結果進行符合 OData 約定的 URL 參數進行再次過濾的標記 QueryCompositionFilterAttribute , 目前只支持 $filter 、 $orderby 、 $skip 以及 $top ;
- ActionDescriptorFilterProvider
- ConfigurationFilterProvider
注意, 這里說的是 FilterProvider, 不是 Filter , 也不是 FilterAttribute 。
IActionValueBinder
負責綁定 Action 方法的參數, 默認的實現是 DefaultActionValuebinder , 通過調用 ValueProviderFactory 、 ModelBinderProvider 進行參數綁定, 支持多種形式的參數綁定, 綁定策略比較復雜, 總的來說是簡單的參數從 URL 中綁定, 復雜參數從 HTTP 請求內容中獲取。
ValueProviderFactory
定義了 Action 參數從哪里獲取, 有以下幾個實現, 分別支持從 URI 、 QueryString、 Post 內容中提取參數值:
- CompositeValueProviderFactory
- KeyValueModelProviderFactory
- RouteDataValueProviderFactory
- QueryStringValueProviderFactory
ModelBinderProvider
定義了如何將獲取到的 HTTP 請求的的參數之綁定到指定的參數。 System.Web.Http.ModelBinding.Binders 命名空間內提供了多種 BinderProvider , 應該可以處理大多數常見的類型。
ModelMetadataProvider
負責提供模型元數據描述信息。
ModelValidatorProvider
負責根據元素據信息對模型進行驗證。
IFormatterSelector
負責選擇合適的格式, 包括客戶端請求的格式以及服務端返回的格式, 默認實現是 FormatterSelector , 能夠提下面的 MediaFormater :
- BufferedmediaTypeFormatter 提供對二進制格式的讀取與寫入;
- FormUrlEncodedMediaTypeFormatter 提供對表單 URL 編碼格式的讀取與寫入;
- JsonMediaTypeFormatter 提供對 Json 格式的讀取與寫入;
- XmlMediaFormatter 提供對 XML 格式的讀取與寫入。