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

来源:互联网 发布:linux设置主机别名 编辑:程序博客网 时间:2024/06/11 05:47

Autofac始终保持最新,以支持最新版本的ASP.NET MVC,所以文档也保持最新。 一般而言,各个版本的集成保持相当一致。

MVC集成需要Autofac.Mvc5 NuGet包。

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

本页解释了ASP.NET经典MVC集成。 如果您正在使用ASP.NET Core,请参阅ASP.NET Core集成页面。

    Quick Start    Register Controllers    Set the Dependency Resolver    Register Model Binders    Register Web Abstractions    Enable Property Injection for View Pages    Enable Property Injection for Action Filters    Enable Injection of Action Parameters    OWIN Integration    Using “Plugin” Assemblies    Using the Current Autofac DependencyResolver    Glimpse Integration    Unit Testing    Example

快速开始

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

protected void Application_Start(){  var builder = new ContainerBuilder();  //注册您的MVC控制器。 (MvcApplication是Global.asax中类的名称。)  builder.RegisterControllers(typeof(MvcApplication).Assembly);  //可选:注册需要DI的模型绑定器  builder.RegisterModelBinders(typeof(MvcApplication).Assembly);  builder.RegisterModelBinderProvider();  //可选:注册Web抽象如HttpContextBase。  builder.RegisterModule<AutofacWebTypesModule>();  //可选:在视图页面中启用属性注入。  builder.RegisterSource(new ViewRegistrationSource());  //可选:启用属性注入到ation过滤器。  builder.RegisterFilterProvider();  //可选:启用action 方法参数注入(RARE)  builder.InjectActionInvoker();  //将依赖关系解析器设置为Autofac  var container = builder.Build();  DependencyResolver.SetResolver(new AutofacDependencyResolver(container));}

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

注册控制器

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

var builder = new ContainerBuilder();//您可以使用程序集扫描一次注册控制器...builder.RegisterControllers(typeof(MvcApplication).Assembly);//...或者您可以手动注册个人控制器。builder.RegisterType<HomeController>().InstancePerRequest();

请注意,ASP.NET MVC通过其具体类型请求控制器,因此将其注册为As<IController>()是不正确的。 另外,如果您手动注册控制器并选择指定生命周期,则必须将它们注册为InstancePerDependency()InstancePerRequest() - 如果您尝试为多个请求重用控制器实例,ASP.NET MVC将引发异常。

设置依赖关系解析器

在构建你的容器之后,将它传递给AutofacDependencyResolver类的新实例。 使用静态的DependencyResolver.SetResolver方法让ASP.NET MVC知道它应该使用AutofacDependencyResolver来定位服务。 这是Autofac的IDependencyResolver接口的实现。

var container = builder.Build();DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

You can do this with the RegisterModelBinders() method. You must also remember to register the AutofacModelBinderProvider using the RegisterModelBinderProvider() extension method. This is Autofac’s implementation of the IModelBinderProvider interface.

注册模型绑定器

您可以采取的可选步骤是为模型绑定器启用依赖项注入。与控制器类似,模型绑定器(实现IModelBinder的类)可以在应用程序启动时在容器中注册。 你可以用RegisterModelBinders()方法做到这一点。 您还必须记住使用RegisterModelBinderProvider()扩展方法注册AutofacModelBinderProvider。 这是Autofac的IModelBinderProvider接口的实现。

builder.RegisterModelBinders(Assembly.GetExecutingAssembly());builder.RegisterModelBinderProvider();

由于RegisterModelBinders()扩展方法使用程序集扫描来添加模型绑定器,所以您需要指定要注册的模型绑定器(IModelBinder实现)的类型。

这是通过使用Autofac.Integration.Mvc.ModelBinderTypeAttribute完成的,如下所示:

[ModelBinderType(typeof(string))]public class StringBinder : IModelBinder{  public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)  {    //在这里实现  }}

ModelBinderTypeAttribute的多个实例可以被添加到一个类,如果它被注册为多个类型的话。

注册Web抽象

MVC集成包括一个Autofac模块,它将为Web抽象类添加HTTP请求生命周期的注册。这将允许您将Web抽象作为依赖项放入您的类中,并在运行时获取正确的注入值。

以下抽象类包含在内:

    HttpContextBase    HttpRequestBase    HttpResponseBase    HttpServerUtilityBase    HttpSessionStateBase    HttpApplicationStateBase    HttpBrowserCapabilitiesBase    HttpFileCollectionBase    RequestContext    HttpCachePolicyBase    VirtualPathProvider    UrlHelper

要使用这些抽象,请使用标准RegisterModule()方法将AutofacWebTypesModule添加到容器中。

builder.RegisterModule<AutofacWebTypesModule>();

为视图页启用属性注入

通过在构建应用程序容器之前将ViewRegistrationSource添加到ContainerBuilder,可以使属性注入可用于您的MVC视图。

builder.RegisterSource(new ViewRegistrationSource());

您的视图页面必须从MVC支持创建视图的基类之一继承。当使用Razor视图引擎时,这将是WebViewPage类。

public abstract class CustomViewPage : WebViewPage{  public IDependency Dependency { get; set; }}

使用web forms视图引擎时,ViewPageViewMasterPageViewUserControl类都受支持。

public abstract class CustomViewPage : ViewPage{  public IDependency Dependency { get; set; }}

确保您的实际视图页面从您的自定义基类继承。这可以使用Razor视图引擎的.cshtml文件中的@inherits指令来实现:

@inherits Example.Views.Shared.CustomViewPage

在使用 web forms视图引擎时,请在.aspx文件中的@Page指令中设置Inherits属性。

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="Example.Views.Shared.CustomViewPage"%>

由于ASP.NET MVC内部的问题,依赖注入不可用于Razor布局页面。Razor视图将工作,但布局页面不会。有关更多信息,请参阅问题#349。

为Action筛选器启用属性注入

在构建容器并将其提供给AutofacDependencyResolver之前,要为您的过滤器属性使用属性注入,请调用ContainerBuilder上的RegisterFilterProvider()方法。

builder.RegisterFilterProvider();

这允许您将属性添加到您的过滤器属性中,并且在容器中注册的任何匹配依赖项将被注入到属性中。

例如,下面的动作过滤器将从容器中注入ILogger实例(假设你注册了一个ILogger,注意该属性本身不需要在容器中注册。

public class CustomActionFilter : ActionFilterAttribute{  public ILogger Logger { get; set; }  public override void OnActionExecuting(ActionExecutingContext filterContext)  {    Logger.Log("OnActionExecuting");  }}

相同的简单方法适用于其他过滤器属性类型,例如授权属性。

public class CustomAuthorizeAttribute : AuthorizeAttribute{  public ILogger Logger { get; set; }  protected override bool AuthorizeCore(HttpContextBase httpContext)  {    Logger.Log("AuthorizeCore");    return true;  }}

像往常一样将属性应用到您的actions 之后,您的工作就完成了。

[CustomActionFilter][CustomAuthorizeAttribute]public ActionResult Index(){}

启用注入Action参数

虽然不常见,但有些人希望Autofac在调用时在操作方法中填充参数。 建议您在控制器上使用构造函数注入而不是action方法注入,但是如果需要,可以启用操作方法注入:

//Autofac ExtensibleActionInvoker尝试从请求生命周期范围解析参数如果模型绑定器无法绑定到参数。builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();builder.InjectActionInvoker();

请注意,您也可以使用InjectActionInvoker()机制与您自己的自定义调用程序。

builder.RegisterType<MyCustomActionInvoker>().As<IActionInvoker>();builder.InjectActionInvoker();

OWIN集成

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

  • 做标准的MVC集成的所有东西 - 注册控制器,设置依赖解析器等。
  • 使用基础Autofac OWIN集成设置您的应用程序。
  • 添加对Autofac.Mvc5.Owin NuGet包的引用。
  • 在您的应用程序启动类中,在注册基础Autofac中间件后注册Autofac MVC中间件。
public class Startup{  public void Configuration(IAppBuilder app)  {    var builder = new ContainerBuilder();     //标准MVC设置:      //注册您的MVC控制器。     builder.RegisterControllers(typeof(MvcApplication).Assembly);    //运行其他可选步骤,如注册模型绑定器,Web抽象等,然后将依赖关系解析器设置为Autofac。    var container = builder.Build();    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));   //OWIN MVC设置:   //先注册Autofac中间件,然后注册Autofac MVC中间件。    app.UseAutofacMiddleware(container);    app.UseAutofacMvc();  }}

小问题:MVC在OWIN管道中不能运行100%。它仍然需要HttpContext.Current和其他一些非OWIN的东西。在应用程序启动时,当MVC注册路由时,它实例化一个IControllerFactory,最终创建两个请求生存期范围。它只发生在应用程序在路由注册时启动,而不是一旦请求开始得到处理,但它是要注意的事情。这是两条管道被碾压在一起的产物。我们研究了一些方法来尝试解决这个问题,但却无法以一种干净的方式来实现。

使用“插件”程序集

如果你有一个“插件程序集”中没有被主应用程序引用的控制器,你将需要使用ASP.NET BuildManager注册你的控制器插件程序集。

你可以通过配置或者编程来完成。

如果选择配置,则需要将插件程序集添加到/configuration/system.web/compilation/assemblies列表中。如果您的插件程序集不在bin文件夹中,则还需要更新/configuration/runtime/assemblyBinding/probing路径。

<?xml version="1.0" encoding="utf-8"?><configuration>  <runtime>    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">      <!--          If you put your plugin in a folder that isn't bin, add it to the probing path      -->      <probing privatePath="bin;bin\plugins" />    </assemblyBinding>  </runtime>  <system.web>    <compilation>      <assemblies>        <add assembly="The.Name.Of.Your.Plugin.Assembly.Here" />      </assemblies>    </compilation>  </system.web></configuration>

如果选择编程注册,则需要在ASP.NET BuildManager启动之前的预应用程序启动期间执行。

创建一个初始化类来执行程序集扫描/加载和注册BuildManager:

using System.IO;using System.Reflection;using System.Web.Compilation;namespace MyNamespace{  public static class Initializer  {    public static void Initialize()    {      var pluginFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins"));      var pluginAssemblies = pluginFolder.GetFiles("*.dll", SearchOption.AllDirectories);      foreach (var pluginAssemblyFile in pluginAssemblyFiles)      {        var asm = Assembly.LoadFrom(pluginAssemblyFile.FullName);        BuildManager.AddReferencedAssembly(asm);      }    }  }}

然后确保使用程序集属性注册您的应用程序之前的开始代码:

[assembly: PreApplicationStartMethod(typeof(Initializer), "Initialize")]

使用当前的Autofac DependencyResolver

一旦将MVC DependencyResolver设置为AutofacDependencyResolver,就可以使用AutofacDependencyResolver.Current作为获取当前依赖项解析器并将其转换为AutofacDependencyResolver的快捷方式。

不幸的是,在使用AutofacDependencyResolver.Current时会遇到一些问题,这可能会导致不正确的工作。通常,这些问题通过使用像GlimpseCastle DynamicProxy这样的产品来“包装”或“装饰”依赖解析器来添加功能。如果当前的依赖关系解析器被装饰或以其他方式进行包装/代理,则不能将其转换为AutofacDependencyResolver,并且没有单独的方法来“解包”或转到实际的解析器。

在Autofac MVC集成版本3.3.3之前,我们通过动态地将它添加到请求生命周期范围来跟踪当前的依赖关系解析器。这让我们无法从代理中解开AutofacDependencyResolver,但是这意味着AutofacDependencyResolver.Current只能在请求生命期内工作 - 不能在后台任务或应用程序启动时使用它。

从版本3.3.3开始,定位AutofacDependencyResolver.Current的逻辑改为首先尝试转换当前的依赖关系解析器;然后专门查找使用Castle DynamicProxy包装的标志,并通过反射将其打开。没有这个…我们找不到当前的AutofacDependencyResolver,所以我们抛出一个InvalidOperationException异常,

依赖关系解析器的类型是“Some.Other.DependencyResolver”,但预计是“Autofac.Integration.Mvc.AutofacDependencyResolver”类型。它也不会被Castle Project中的DynamicProxy所包装。这个问题可能是DynamicProxy实现发生变化的结果,也可能是由于使用了不同的代理库来封装依赖关系解析器。

这是典型的地方,当通过ContainerBuilder.RegisterFilterProvider()使用动作过滤器提供程序时。筛选器提供程序需要访问Autofac依赖关系解析器并使用AutofacDependencyResolver.Current来执行此操作。

如果你看到这个,这意味着你正在用一种无法解开的方式装饰解析器,而依赖于AutofacDependencyResolver.Current的函数将会失败。目前的解决方案是不装饰依赖解析器。

Glimpse 集成

使用Autofac时,将MVC应用程序与Glimpse集成在一起与其他任何集成都非常相似。 但是,如果使用动作方法参数注入(例如,使用builder.InjectActionInvoker()),则Glimpse执行检查将失败。

您可以通过将以下内容添加到Glimpse配置来解决此问题:

  <glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd">    <inspectors>      <ignoredTypes>        <add type="Glimpse.Mvc.Inspector.ExecutionInspector, Glimpse.Mvc"/>      </ignoredTypes>    </inspectors>    <tabs>      <ignoredTypes>        <add type="Glimpse.Mvc.Tab.Execution, Glimpse.Mvc"/>      </ignoredTypes>    </tabs></glimpse>

同样,如果您使用action参数注入,则只需执行此操作。这是推荐使用控制器构造函数注入而不是action方法参数注入的许多原因之一。

单元测试

当单元测试一个使用Autofac的应用程序,并且你已经注册了InstancePerRequest组件时,当你尝试解析这些组件时,你会得到一个异常,因为在单元测试期间没有HTTP请求生命周期。

每个请求生存期范围主题概述了针对每个请求范围组件进行测试和故障排除的策略。

阅读全文
0 0
原创粉丝点击