


























与 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 公开的扩展点, 可以根据需要来对这些接口进行实现, 并通过 Unity 进行配置, 让其注入到 Web API 运行时中。 接下来将逐个讨论这些扩展点。
IHttpControllerFactory 接口有两个方法, 负责创建和销毁 HttpController 实例:
这个接口的默认实现是 DefaultHttpControllerFactory , 根据当前请求的上下文通过创建 HttpControllerDescriptor , 然后通过 HttpControllerDescriptor 的 ControllerActivator 创建对应的 IHttpController 实例。
只是一个日志接口, 有下面的几个方法:
默认的实现是 DiagnosticLogger , 通过 ILSpy 观察, 貌似什么都没有做。
负责创建具体的 Controller 实例, 只有一个方法:
默认的实现是 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();
负责选择合适的动作, 默认的实现是 ApiControllerSelector , 选择规则如下:
负责调用 HttpActionSelector 选择到的方法, 该接口有一个方法:
默认的实现是 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>
负责提供过滤的标记, Web API 框架内置了下面的几个 FilterProvider :
注意, 这里说的是 FilterProvider, 不是 Filter , 也不是 FilterAttribute 。
负责绑定 Action 方法的参数, 默认的实现是 DefaultActionValuebinder , 通过调用 ValueProviderFactory 、 ModelBinderProvider 进行参数绑定, 支持多种形式的参数绑定, 绑定策略比较复杂, 总的来说是简单的参数从 URL 中绑定, 复杂参数从 HTTP 请求内容中获取。
定义了 Action 参数从哪里获取, 有以下几个实现, 分别支持从 URI 、 QueryString、 Post 内容中提取参数值:
定义了如何将获取到的 HTTP 请求的的参数之绑定到指定的参数。 System.Web.Http.ModelBinding.Binders 命名空间内提供了多种 BinderProvider , 应该可以处理大多数常见的类型。
负责提供模型元数据描述信息。
负责根据元素据信息对模型进行验证。
负责选择合适的格式, 包括客户端请求的格式以及服务端返回的格式, 默认实现是 FormatterSelector , 能够提下面的 MediaFormater :
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。