Web API 依賴注入與擴展


依賴注入

與 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 框架將會在運行時向其請求一系列的接口實現:

  1. 應用啟動時, Web API 框架會依次請求下列接口:
    1. System.Web.Http.Dispatcher.IHttpControllerFactory
    2. System.Web.Http.Common.ILogger
    3. System.Web.Http.Dispatcher.IHttpControllerActivator
    4. System.Web.Http.Controllers.IHttpActionSelector
    5. System.Web.Http.Controllers.IHttpActionInvoker
  2. 在第一次訪問某個 Controller 之前, 還會請求下面的接口 (如果重復訪問相同的 Controller , 則不會再次調用):
    1. System.Web.Http.Filters.IFilterProvider
  3. 每次處理 HTTP 請求時, Web API 請求下列接口:
    1. System.Web.Http.Controllers.IActionValueBinder
    2. System.Web.Http.ValueProviders.ValueProviderFactory (僅 Action 需要參數時才需要)
    3. System.Web.Http.ModelBinding.ModelBinderProvider (僅 Action 需要參數時才需要)
    4. System.Web.Http.Metadata.ModelMetadataProvider (僅 Action 需要參數時才需要)
    5. System.Web.Http.Validation.ModelValidatorProvider (僅 Action 需要參數時才需要)
    6. 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 , 選擇規則如下:

  1. 如果路由定義了 {action} , 則通過當前的 HttpControllerContext 中的 action 的值尋找合適的方法;
  2. 否則, 根據當前的 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 格式的讀取與寫入。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM