依赖注入

与 MVC 类似, Web API 提供了System.Web.Http.Services.IDependencyResolver 接口来实现依赖注入, 我们可以很容易的用 Unity 来实现这个接口:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 里添加下面一行代码即可:

?
1
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 表达式进行创建实例, 相关的代码如下:

?
1
2
3
4
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 表达式对方法进行调用, 取得返回结果, 部分代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 格式的读取与写入。

转载自:http://www.cnblogs.com/beginor/archive/2012/03/22/2411496.html

转载于:https://www.cnblogs.com/kericai/archive/2013/01/12/2857811.html

MVC核心功能组件和简介相关推荐

  1. 002 第一季SpringBoot2核心技术-核心功能:配置文件、Web开发(原生组件)、数据访问、单元测试、指标监控、原理解析:@Value、命令行参数、手动获取bean、自定义starter

    三.核心技术之- ->核心功能 1. 配置文件 1.1 文件类型 1.1.1 properties 同以前的properties用法 优先级高于yml的方式. 1.1.2 yaml 1) 简介 ...

  2. Springboot总结,核心功能,优缺点

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:lizmit https://blog.csdn.net/q ...

  3. 一文带你看懂Springboot核心功能及优缺点

    点击上方[视学算法]→右上角[...]→[设为星标⭐] SpringBoot核心功能 1.独立运行Spring项目 Spring boot 可以以jar包形式独立运行,运行一个Spring Boot项 ...

  4. Shiro 核心功能案例讲解 基于SpringBoot 有源码

    Shiro 核心功能案例讲解 基于SpringBoot 有源码 从实战中学习Shiro的用法.本章使用SpringBoot快速搭建项目.整合SiteMesh框架布局页面.整合Shiro框架实现用身份认 ...

  5. 问题小结(二)——maven的核心功能、面向对象编程和面向接口编程的区别、抽象类和接口的区别等

    文章目录 1. Java创建对象有哪四种方式? 2. 什么是maven?maven的核心功能有哪些? 3. 什么是MVC?说说分层的好处. 4. Spring的两大核心技术是什么? 5. 什么是IOC ...

  6. ASP.NET Core MVC – Tag Helper 组件

    ASP.NET Core Tag Helpers系列目录,这是第五篇,共五篇: ASP.NET Core MVC – Tag Helpers 介绍 ASP.NET Core MVC – Caching ...

  7. 史上最强Dubbo面试28题答案详解:核心功能+服务治理+架构设计等

    1.Dubbo是什么? Dubbo 是一个分布式.高性能.透明化的 RPC 服务框架,提供服务自动注册.自动发现等高效服务治理方案, 可以和 Spring 框架无缝集成. RPC 指的是远程调用协议, ...

  8. Java核心类库篇1——简介

    Java核心类库篇1--简介 1.核心类库 包名 主要功能 java.applet 提供了创建applet需要的所有类 java.awt.* 提供了创建用户界面以及绘制和管理图形.图像的类 java. ...

  9. java mybatis的作用,【java框架】MyBatis-Plus(1)--MyBatis-Plus快速上手开发及核心功能体验-博客...

    1.MyBatis-Plus入门开发及配置 1.1.MyBatis-Plus简介 MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变, ...

最新文章

  1. R语言构建xgboost模型:模型的特性重要度计算及可视化、模型对应的结构树(文本文件)
  2. .vue文件中style标签的几个标识符
  3. 设计模式-工厂模式学习(初级)
  4. Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_2
  5. Spring4新特性——核心容器的其他改进
  6. CCF——图像旋转201503-1
  7. python中的下标索引
  8. abrels.inc.php_setlist.js
  9. 基于Matlab的跨孔层析成像的最短路径法弯曲射线追踪(二)
  10. RFM模型+SOM聚类︱离群值筛选问题
  11. linux fdisk运用
  12. BackTrack4安装中文语言包
  13. 华为android解锁,华为bootloader怎么解锁 华为手机bootloader解锁教程
  14. 高德poi类别23个大类 261个中类 4705个小类
  15. Linux 下文件和目录的特点
  16. 计算机高程知识点,测量学复习基本知识点(全).doc
  17. PostgreSQL 中的系统字段:tableoid、xmin、xmax、cmin、cmax、ctid
  18. 如何理解混淆矩阵,以及预测少数类的评估指标?
  19. java 消息摘要_java – 使用BouncyCastle签名消息摘要
  20. Ubuntu18.04下更改apt源为阿里云源

热门文章

  1. python3urllib中的quote与encode的区别_Python的urllib.quote()和urllib.unquote()的等效Javascript函数...
  2. python的类与模块_Python类与模块属性
  3. 2021.12.15
  4. hihoCoder #1384 : Genius ACM [枚举+倍增]
  5. java classloader_Java Classloader原理分析
  6. Centos7 网络配置
  7. Phyton自定义包导入。
  8. 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法...
  9. Httpster –世界各地最潮的网页设计案例聚合网站
  10. CSS Grid layout布局