惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News | PayPal Newsroom
P
Proofpoint News Feed
Cyberwarzone
Cyberwarzone
C
Cisco Blogs
SecWiki News
SecWiki News
Know Your Adversary
Know Your Adversary
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
NISL@THU
NISL@THU
WordPress大学
WordPress大学
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Threat Research - Cisco Blogs
AI
AI
Simon Willison's Weblog
Simon Willison's Weblog
Security Archives - TechRepublic
Security Archives - TechRepublic
有赞技术团队
有赞技术团队
L
LINUX DO - 热门话题
Hacker News: Ask HN
Hacker News: Ask HN
V
V2EX
G
GRAHAM CLULEY
TaoSecurity Blog
TaoSecurity Blog
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
F
Fortinet All Blogs
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
云风的 BLOG
云风的 BLOG
Recorded Future
Recorded Future
Latest news
Latest news
The Hacker News
The Hacker News
aimingoo的专栏
aimingoo的专栏
T
Troy Hunt's Blog
S
Schneier on Security
I
Intezer
Google DeepMind News
Google DeepMind News
A
Arctic Wolf
Apple Machine Learning Research
Apple Machine Learning Research
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
爱范儿
爱范儿
The Register - Security
The Register - Security
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
博客园 - 聂微东
宝玉的分享
宝玉的分享
Recent Commits to openclaw:main
Recent Commits to openclaw:main
美团技术团队
B
Blog RSS Feed

博客园 - 张志敏

System.Net.Http for Silverlight 通过网页进行 iOS 应用内部分发 使用 Intel HAXM 为 Android 模拟器加速,媲美真机 Mono for Android 实现高效的导航 Activity 生命周期及其栈管理方式 我的第一个 Mono for Android 应用 谈谈 INotifyPropertyChanged 的实现 在 Silverlight 5 项目中使用 async/await Task 编程中的异常处理 NHibernate 关系映射中的 Formula 开源一个 Sliverlight 导航框架 SQLite 常用 SQL 让 VS 编译 MonoTouch 项目源文件不再出错 MonoTouch绑定CocoaTouch类库 升级 Xcode 4.3 后找不到 xcodebuild 的解决方法 iOS 静态类库项目的建立与使用 从源代码编译里程碑的 ICS ROM IIS 7.5 下应用程序池的预定义账户 ASP.NET Web API 简介
Web API 依赖注入与扩展
张志敏 · 2012-03-22 · via 博客园 - 张志敏

依赖注入

与 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 格式的读取与写入。