您的位置:首页 > 其它

Autofac官方文档(二十三)【应用集成之Web API】

2017-12-16 23:33 218 查看
Web API 2集成需要
Autofac.WebApi2
NuGet包。

Web API集成需要
Autofac.WebApi
NuGet包。

Web API集成为控制器,模型绑定器和操作过滤器提供了依赖注入集成。 它也增加了每个请求生命周期的支持。

本页面介绍了ASP.NET经典的Web API集成。 如果您正在使用ASP.NET Core,请参阅ASP.NET Core集成页面。

Quick Start
Get the HttpConfiguration
Register Controllers
Set the Dependency Resolver
Provide Filters via Dependency Injection
Register the Filter Provider
Implement the Filter Interface
Register the Filter
Filter Overrides
Why We Use Non-Standard Filter Interfaces
Standard Web API Filter Attributes are Singletons
Instance Filters Don’t Get Injected
Provide Model Binders via Dependency Injection
Register the Binder Provider
Register Model Binders
Mark Parameters With ModelBinderAttribute
Per-Controller-Type Services
Add the Controller Configuration Attribute
Supported Services
Service Registration
Clearing Existing Services
Per-Controller-Type Service Limitations
Batching
OWIN Integration
Unit Testing
Example


快速开始

要将Autofac与Web API集成,您需要引用Web API集成NuGet包,注册您的控制器并设置依赖关系解析器。 您也可以选择启用其他功能。

protected void Application_Start()
{
var builder = new ContainerBuilder();

//得到你的HttpConfiguration.
var config = GlobalConfiguration.Configuration;

//注册您的Web API控制器.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

//可选:注册Autofac过滤器提供商.
builder.RegisterWebApiFilterProvider(config);

//可选:注册Autofac模型绑定器提供程序
builder.RegisterWebApiModelBinderProvider();

//将依赖关系解析器设置为Autofac。
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}


以下各节详细介绍了每个功能的用途以及如何使用它们。

获取HttpConfiguration

在Web API中,设置应用程序需要您更新
HttpConfiguration
对象的属性并设置值。 根据您的应用程序托管方式,您获得此配置的方式可能有所不同。 通过文档,我们将参考“你的
HttpConfiguration
”,你需要做出选择如何得到它。

对于标准的IIS托管,
HttpConfiguration
GlobalConfiguration.Configuration


var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);


对于自托管,
HttpConfiguration
是您的
HttpSelfHostConfiguration
实例

var builder = new ContainerBuilder();
var config = new HttpSelfHostConfiguration("http://localhost:8080");
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);


对于OWIN集成,
HttpConfiguration
是您在应用程序启动类中创建并传递给Web API中间件的一个。

var builder = new ContainerBuilder();
var config = new HttpConfiguration();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);


注册控制器

在应用程序启动时,在构建Autofac容器的同时,您应该注册您的Web API控制器及其依赖项。 这通常发生在OWIN启动类或
Global.asax
Application_Start
方法中。

默认情况下,实现
IHttpController
的类型和具有后缀
Controller
的名称将被注册。

var builder = new ContainerBuilder();

//.您可以使用程序集扫描一次注册控制器...
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

// ...或者您可以手动注册个人控制器
builder.RegisterType<ValuesController>().InstancePerRequest();


If your controllers do not follow the standard naming convention you may choose to provide a custom suffix using an overload of the RegisterApiControllers method.

如果您的控制器不遵循标准命名约定,则可以选择使用
RegisterApiControllers
方法的重载提供自定义后缀。

//您还可以使用程序集扫描以自定义后缀注册控制器
builder.RegisterApiControllers("MyCustomSuffix", Assembly.GetExecutingAssembly());


设置依赖关系解析器

在构建你的容器之后,将它传递给
AutofacWebApiDependencyResolver
类的新实例。 将新的解析器附加到您的
HttpConfiguration.DependencyResolver
,让Web API知道它应该使用
AutofacWebApiDependencyResolver
找到服务。 这是Autofac的
IDependencyResolver
接口的实现。

var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);


通过依赖注入来提供过滤器

因为属性是通过反射API创建的,所以你不能自己调用构造函数。 除了属性注入特性之外,没有别的选择。 与Web API的Autofac集成提供了一种机制,允许您创建实现过滤器接口(
IAutofacActionFilter
IAutofacAuthorizationFilter
IAutofacExceptionFilter
)的类,并使用容器构建器上的注册语法将它们连接到所需的控制器或操作方法。

注册过滤器提供程序

您需要注册Autofac筛选器提供程序实现,因为它可以根据注册完成筛选器的配置工作。 这是通过调用容器生成器上的
RegisterWebApiFilterProvider
方法并提供一个
HttpConfiguration
实例来完成的。

var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(config);


实现过滤器接口

而不是从现有的Web API过滤器属性派生出来,而是实现在集成中定义的适当的过滤器接口。 下面的过滤器是一个动作过滤器,并实现
IAutofacActionFilter
而不是
System.Web.Http.Filters.IActionFilter


public class LoggingActionFilter : IAutofacActionFilter
{
readonly ILogger _logger;

public LoggingActionFilter(ILogger logger)
{
_logger = logger;
}

public Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
_logger.Write(actionContext.ActionDescriptor.ActionName);
return Task.FromResult(0);
}

public Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{
_logger.Write(actionExecutedContext.ActionContext.ActionDescriptor.ActionName);
return Task.FromResult(0);
}
}


请注意,示例中没有运行实际的异步代码,因此它将返回
Task.FromResult(0)
,这是返回“空任务”的常用方法。如果您的过滤器确实需要异步代码,则可以返回一个真实的
Task
对象或 像任何其他异步方法一样使用
async/await
代码。

注册过滤器

为了执行过滤器,您需要将其注册到容器中,并通知哪个控制器以及可选的操作应该成为目标。 这是使用以下
ContainerBuilder
扩展方法完成的:

AsWebApiActionFilterFor<TController>()
AsWebApiActionFilterOverrideFor<TController>()
AsWebApiAuthorizationFilterFor<TController>()
AsWebApiAuthorizationOverrideFilterFor<TController>()
AsWebApiAuthenticationFilterFor<TController>()
AsWebApiAuthenticationOverrideFilterFor<TController>()
AsWebApiExceptionFilterFor<TController>()
AsWebApiExceptionOverrideFilterFor<TController>()


这些方法需要控制器类型的泛型类型参数,以及一个可选的lambda表达式,用于指示过滤器应用于控制器上的特定方法。 如果不提供lambda表达式,则过滤器将应用于控制器上的所有操作方法,方法与在控制器级别放置基于属性的过滤器相同。

您可以根据需要应用尽可能多的过滤器。 注册一种类型的过滤器不会删除或替换以前注册的过滤器。

在下面的示例中,过滤器正在应用于
ValuesController
上的Get操作方法。

var builder = new ContainerBuilder();

builder.Register(c => new LoggingActionFilter(c.Resolve<ILogger>()))
.AsWebApiActionFilterFor<ValuesController>(c => c.Get(default(int)))
.InstancePerRequest();


将过滤器应用于需要参数的操作方法时,请在您的lambda表达式中使用参数的数据类型为
default
的关键字作为占位符。例如,上面例子中的
Get
操作方法需要一个
int
参数,并使用
default(int)
作为lambda表达式中的强类型占位符。

也可以在通用类型参数中提供基本控制器类型,以将过滤器应用于所有派生控制器。此外,还可以使您的操作方法的
lambda
表达式针对基本控制器类型上的方法,并将其应用于所有派生控制器上的该方法。

过滤器覆盖

在注册过滤器时,有像
AsWebApiActionFilterFor<TController>()
这样的基本注册方法,并覆盖像
AsWebApiActionFilterOverrideFor<TController>()
这样的注册方法。重写方法的要点是提供一种方法来确保首先执行某些过滤器。您可以根据需要进行多次覆盖 - 这些不是替换筛选器,只是首先运行的筛选器。

过滤器将按以下顺序运行:

Controller-scoped overrides
Action-scoped overrides
Controller scoped filters
Action scoped filters


为什么我们使用非标准的过滤器接口

如果您想知道为什么要引入特殊的接口,那么在Web API中查看
IActionFilter
接口的签名时,这应该会变得更加明显。

public interface IActionFilter : IFilter
{
Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation);
}


现在将其与您需要实现的Autofac接口进行比较

public interface IAutofacActionFilter
{
Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken);

Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken);
}


问题是
OnActionExecutingAsync
OnActionExecutedAsync
方法实际上是在
ActionFilterAttribute
而不是在
IActionFilter
接口上定义的。 在Web API中广泛使用
System.Threading.Tasks
命名空间意味着链接返回任务以及属性中的相应错误处理实际上需要大量代码(
ActionFilterAttribute
包含近100行代码)。 这绝对不是你想要处理自己的事情。

Autofac引入了新的接口,使您能够专注于实现过滤器的代码,而不是所有的管道。 在内部,它创建实际的Web API属性的自定义实例,从容器中解析过滤器实现,并在适当的时候执行它们。

创建内部属性包装的另一个原因是支持过滤器的
InstancePerRequest
生存期范围。 请参阅下面的更多。

标准Web API筛选器属性是单例

您可能会注意到,如果您使用标准Web API筛选器,则无法使用
InstancePerRequest
依赖项。

与MVC中的过滤器提供程序不同,Web API中的过滤器提供程序不允许指定不应该的缓存过滤器实例。这意味着Web API中的所有过滤器属性都是单一实例,它们在应用程序的整个生命周期中都存在

如果您试图在过滤器中获取每个请求的依赖关系,那么只有在使用Autofac过滤器接口的情况下才能使用。使用标准的Web API过滤器,依赖关系将被注入一次 - 第一次解析过滤器 - 而不再解析一次。

如果您无法使用Autofac接口,并且您的过滤器中需要每个请求或每个依赖于实例的服务,则必须使用服务位置。幸运的是,Web API使获取当前的请求范围变得非常简单 - 它和
HttpRequestMessage
一起。

以下是使用Web API
IDependencyScope
的服务位置来获取每个请求相关性的过滤器示例:

public interface ServiceCallActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
//获取请求生存期范围,以便解析服务
var requestScope = actionContext.Request.GetDependencyScope();

//解析您想要使用的服务
var service = requestScope.GetService(typeof(IMyService)) as IMyService;

//在过滤器中完成剩下的工作
service.DoWork();
}
}


实例过滤器不会被注入

设置过滤器时,可能需要手动将过滤器添加到集合中,如下所示:

config.Filters.Add(new MyActionFilter());


Autofac不会注入以这种方式注册的过滤器的属性。 这与使用
RegisterInstance
将对象的预构造实例放入Autofac时有些类似 - Autofac不会注入或修改预构造的实例。 对于预先构建并添加到过滤器集合中的过滤器实例也是如此。 与属性过滤器一样(如上所述),您可以通过使用服务位置而不是属性注入来解决此问题。

通过依赖注入提供模型绑定器

与Web API的Autofac集成提供了使用依赖注入来解析模型绑定器的能力,并将绑定器与使用fluent 接口的类型相关联。

注册绑定器提供程序

您需要注册Autofac模型绑定器提供程序,以便在需要时可以解析任何已注册的
IModelBinder
实现。 这是通过调用容器生成器上的

RegisterWebApiModelBinderProvider
方法来完成的。

var builder = new ContainerBuilder();
builder.RegisterWebApiModelBinderProvider();


注册模型绑定器

一旦你已经实现了
System.Web.Http.ModelBinding.IModelBinder
来处理绑定的问题,使用Autofac注册它,让Autofac知道哪些类型应该绑定使用该绑定器。

builder
.RegisterType<AutomobileBinder>()
.AsModelBinderForTypes(typeof(CarModel), typeof(TruckModel));


使用
ModelBinderAttribute
标记参数

即使已经注册了模型绑定器,仍然需要使用
[ModelBinder]
属性标记参数,以便Web API知道使用模型绑定器而不是媒体类型格式化程序来绑定模型。 您不必再指定模型绑定器类型,但您必须使用该属性标记该参数。 Web API文档中也提到了这一点。

public HttpResponseMessage Post([ModelBinder] CarModel car) { ... }


每个控制器类型的服务

Web API有一个有趣的功能,允许您通过将实现
IControllerConfiguration
接口的属性添加到您的控制器来配置应该按每个控制器类型使用的一组Web API服务(如
IActionValueBinder
)。

Add the Controller Configuration Attribute

通过将
HttpControllerSettings
参数的
Services
属性传递给
IControllerConfiguration.Initialize
方法,可以覆盖全局服务集合。这种基于属性的方法似乎鼓励您直接实例化服务实例,然后覆盖全局注册的实例。 Autofac允许通过容器来配置这些每个控制器类型的服务,而不是被隐藏在没有依赖注入支持的属性中。

添加控制器配置属性

没有转义添加属性到配置应该被应用的控制器,因为那是Web API定义的扩展点。Autofac集成包含一个
AutofacControllerConfigurationAttribute
,您可以将其应用于Web API控制器,以指示它们需要按控制器类型配置。

这里要记住的一点是,当你构建你的容器时,应该应用什么服务的实际配置,并且不需要在实际属性中实现这些配置。在这种情况下,该属性可以被认为是纯粹的标记,指示容器将定义配置信息并提供服务实例。

[AutofacControllerConfiguration]
public class ValuesController : ApiController
{
// 实现...
}


支持的服务

支持的服务可以分为单风格或多风格的服务。例如,你只能有一个
IHttpActionInvoker
,但是你可以有多个
ModelBinderProvider
服务。

您可以对以下单一样式的服务使用依赖注入:

IHttpActionInvoker
HttpActionSelector
ActionValueBinder
IBodyModelValidator
IContentNegotiator
IHttpControllerActivator
ModelMetadataProvider


支持以下多种风格的服务:

ModelBinderProvider
ModelValidatorProvider
ValueProviderFactory
MediaTypeFormatter


MediaTypeFormatter
之上的多样式服务列表中实际上是奇怪的。从技术上讲,它实际上不是一个服务,而是添加到
HttpControllerSettings
实例上的
MediaTypeFormatterCollection
,而不是
ControllerServices
容器。我们认为没有理由从依赖注入支持排除
MediaTypeFormatter
实例,并确保它们也可以从每个控制器类型的容器中解析出来。

服务注册

下面是一个为
ValuesController
注册一个自定义
IHttpActionSelector
实现为
InstancePerApiControllerType()
的例子。应用于控制器类型时,所有派生控制器也将收到相同的配置;
AutofacControllerConfigurationAttribute
由派生控制器类型继承,并且相同的行为适用于容器中的注册。注册单一样式的服务时,它将始终替换在全局级别配置的默认服务。

builder.Register(c => new CustomActionSelector())
.As<IHttpActionSelector>()
.InstancePerApiControllerType(typeof(ValuesController));


清除现有服务

默认情况下,多样式服务将附加到在全局级别配置的现有服务集。 在向容器注册多样式服务时,可以选择清除现有的一组服务,以便仅使用已注册为
InstancePerApiControllerType()
的服务。 这是通过在
InstancePerApiControllerType()
方法上将
clearExistingServices
参数设置为
true
来完成的。 如果多样式服务的任何注册表明他们希望发生这种类型的现有服务将被删除。

builder.Register(c => new CustomModelBinderProvider())
.As<ModelBinderProvider>()
.InstancePerApiControllerType(
typeof(ValuesController),
clearExistingServices: true);


每个控制器类型的服务限制

如果您使用的是每个控制器类型的服务,则不可能依赖于注册为
InstancePerRequest()
的其他服务。问题是Web API正在缓存这些服务,并且不会在每次创建该类型的控制器时从容器请求这些服务。如果没有在DI集成中引入键(用于控制器类型)的概念,Web API很可能无法轻松添加该支持,这意味着所有容器都需要支持键控服务。

批处理

如果您选择使用Web API批处理功能,请注意,对批处理端点的初始多部分请求是Web API创建请求生存期范围的地方。作为批处理一部分的子请求全部在内存中进行,并将共享相同的请求生命周期范围 - 批处理中的每个子请求都不会得到不同的范围。

这是由于在Web API中设计批处理的方式,并将父请求的属性复制到子请求。 ASP.NET Web API框架有意从父项到子项复制的一个属性是请求生存期范围。没有解决方法,并且不在Autofac的控制范围之内。

OWIN集成

如果您使用Web API作为OWIN应用程序的一部分,则需要:

做所有的标准Web API集成的东西 - 注册控制器,设置依赖解析器等。

使用基础Autofac OWIN集成设置您的应用程序。

添加对
Autofac.WebApi2.Owin
NuGet包的引用。

在您的应用程序启动类中,注册基础Autofac中间件后注册Autofac Web API中间件。

public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();

// STANDARD WEB API设置:

//得到你的HttpConfiguration。 在OWIN中,您将创建一个而不是使用GlobalConfiguration。

var config = new HttpConfiguration();

//注册您的Web API控制器
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

//运行其他可选步骤,如注册过滤器,按控制器类型的服务等,然后将依赖关系解析器设置为Autofac
var container = builder.Build(); config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

//OWIN WEB API设置:

//首先注册Autofac中间件,然后注册Autofac Web API中间件,最后注册标准Web API中间件。
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}


OWIN集成中的常见错误是使用
GlobalConfiguration.Configuration
。 在OWIN中,您从头开始创建配置。 使用OWIN集成时,不应在任何地方引用
GlobalConfiguration.Configuration


单元测试

在单元测试使用Autofac的情况下,如果您已经注册了
InstancePerRequest
组件,则当您尝试解析这些组件时,将会收到一个异常,因为在单元测试期间没有HTTP请求生存期。

每个请求生存期范围主题概述了针对每个请求范围组件进行测试和故障排除的策略。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: