MVC

Autofac总是会紧跟最新版本的ASP.NET MVC框架,所以文档也会一直保持更新。一般来讲,不同版本的框架集成Autofac的方法一般不变。

MVC集成需要引用 Autofac.Mvc5 NuGet包.

MVC 集成库提供对控制器(Controller)、模型绑定器(model binders)、行为筛选器(action filters)和视图(views)的依赖注入. 它也添了对 每次请求生命周期(per-request lifetime)的支持.

快速开始 Quick Start

为了将Autofac集成进MVC项目,你需要引用Autofac.MVC集成库,注册你的控制器以及设定依赖解析器。你也可以启用其他可选的特性。

protected void Application_Start()
{
var builder = new ContainerBuilder(); // Register your MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly); // OPTIONAL: Register model binders that require DI.
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider(); // OPTIONAL: Register web abstractions like HttpContextBase.
builder.RegisterModule<AutofacWebTypesModule>(); // OPTIONAL: Enable property injection in view pages.
builder.RegisterSource(new ViewRegistrationSource()); // OPTIONAL: Enable property injection into action filters.
builder.RegisterFilterProvider(); // Set the dependency resolver to be Autofac.
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}

接下来的部分将说明关于这些特性进一步的细节以及如何使用它们。

注册控制器 Register Controllers

在应用程序启动时,你在构建自己的容器(ContainerBuilder)时, 也应该注册所有的控制器以及它们的依赖项. 这通常会发生在典型的OWIN启动类或者  Global.asax 的 Application_Start 方法中.

var builder = new ContainerBuilder();

// You can register controllers all at once using assembly scanning...
builder.RegisterControllers(typeof(MvcApplication).Assembly); // ...or you can register individual controlllers manually.
builder.RegisterType<HomeController>().InstancePerRequest();

注意,ASP.NET MVC通过实体类型来请求控制器实例,所以不能将他们注册为 As<IController>(). 同时,如果你手动注册控制器且选择定制生命周期,你必须将他们注册为InstancePerDependency() 或者 InstancePerRequest()- 在这种情况下,如果你尝试为多个请求重用一个控制器实例,ASP.NET MVC程序将会抛出异常

设定依赖解析器 Set the Dependency Resolver

在构建好容器后, 将他传入一个AutofacDependencyResolver 类的实例中. 使用静态方法 DependencyResolver.SetResolver 来使 ASP.NET MVC知道它应该使用 AutofacDependencyResolver 来定位服务(Service). 这是一个 IDependencyResolver 接口的Autofac实现.

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

注册模型绑定器 Register Model Binders

你可以使用的一个可选步骤是确保对模型绑定器的依赖注入。和注册控制器类似,模型绑定器(IModelBinder接口的实现类)能够在应用程序启动时注册进容器中。你可以使用 RegisterModelBinders() 方法来这样做。你同时也必须记住要使用 RegisterModelBinderProvider() 拓展方法注册 AutofacModelBinderProvider。这是一个 IModelBinderProvider 接口的Autofac实现。

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

由于 RegisterModelBinders() 方法采用集合(Assembly)扫描来添加模型绑定器,所以你需要指定模型绑定器为哪种类型注册。

可以通过 Autofac.Integration.Mvc.ModelBinderTypeAttribute 属性标签来指定,如下:

[ModelBinderType(typeof(string))]
public class StringBinder : IModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Implementation here
}
}

如果要注册为多个类型的模型绑定器,可以直接为类添加多个 ModelBinderTypeAttribute 标签。

注册网络抽象 Register Web Abstractions

MVC集成库包括了一个Autofac模块,这个模块能够为网络抽象类添加HTTP请求生命周期域的注册 . 这允许你将网络抽象作为你的类的依赖,同时能够在运行时获取注入的正确值(Value).

这包括了下面的抽象类:

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

为了使用这些抽象类,通过使用标准的 RegisterModule() 方法来将 AutofacWebTypesModule 添加到容器中。

builder.RegisterModule<AutofacWebTypesModule>();

确保视图页面的属性注入 Enable Property Injection for View Pages

在构建应用容器之前,你可以通过将ViewRegistrationSource添加到你的ContainerBuilder使得可以在视图页中使用属性注入。

builder.RegisterSource(new ViewRegistrationSource());

你的视图页必须继承一个MVC用于创建视图的基类。在使用Razor视图引擎时,这时的基类是指WebViewPage类。

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

使用Web form引擎时,支持的基类为ViewPageViewMasterPage以及ViewUserControl

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

确保你实际的视图页继承于你的自定义基类。对于Razor视图引擎,你可以直接在.cshtml文件中使用@Inherits来实现.

@inherits Example.Views.Shared.CustomViewPage

使用Web Form引擎时,你可以在.aspx文件中的@Page里直接设置Inherits属性来实现。

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

由于ASP.NET MVC内部的问题,在Razor Layout页面中是不能使用依赖注入的。Razor视图中则可以使用,但是布局页面是不可以的。

确保对行文筛选器的属性注入 Enable Property Injection for Action Filters

为了能够为你的筛选器属性使用属性注入,需要在构建容器并将容器提供为AutofacDependencyResolver之前调用ContainerBuilderRegisterFilterProvider()方法。

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;
}
}

在应用筛选器到你的action中,它会像正常一样工作。

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

OWIN集成 OWIN Integration

如果你正在使用MVC作为OWIN程序的一部分,那么你需要做下面的事情:

  • 做完所有标准的MVC集成步骤-注册控制器,设置依赖解析器等等
  • 使用Autofac 基本OWIN集成步骤设置你的应用。
  • 添加对 Autofac.Mvc5.Owin 包的引用.
  • 在你的应用启动类中, 在注册完基本Autofac中间件后再注册Autofac MVC中间件.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder(); // STANDARD MVC SETUP: // Register your MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly); // Run other optional steps, like registering model binders,
// web abstractions, etc., then set the dependency resolver
// to be Autofac.
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); // OWIN MVC SETUP: // Register the Autofac middleware FIRST, then the Autofac MVC middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
}

使用“插件”集合 Using “Plugin” Assemblies

如果你在一个插件集合中有没有被主程序引用的控制器,那么你需要使用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>

如果你选择编程来注册,你需要在应用预启动中处理.

创建一个初始化类来实现集合扫描/载入同时使用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依赖解析器 Using the Current Autofac DependencyResolver

一旦你将 MVC DependencyResolver 设置为 AutofacDependencyResolver, 你就可以使用 AutofacDependencyResolver.Current 作为获取当前依赖解析器的快捷方式 同时将它作为 AutofacDependencyResolver 使用.

不幸的是,使用AutofacDependencyResolver.Current 存在很多陷阱,它们可能导致一些东西不会正常工作. 通常这些问题是由类似 Glimpse 或者Castle DynamicProxy 的产品导致的。为了添加功能,它们可能会折叠(封装?)或修改依赖解析器.如果当前的依赖解析器被修改或者代理, 你不能将它当作AutofacDependencyResolver使用同时也没有方法获得真实的解析器.

在Autofac MVC集成库版本3.3.3之前, 我们通过动态地添加依赖解析器到请求生命周期域来追踪它. 这导致我们可以绕开不能从代理中解绑 AutofacDependencyResolver的问题 ... 但是这样意味着AutofacDependencyResolver.Current 仅仅在请求生命周期域中起作用 - 你不能在后台任务或者应用启动时使用它.

版本 3.3.3开始的时候, 定位 AutofacDependencyResolver.Current 的逻辑改为首先计算当前的依赖解析器; 然后特地寻找使用 Castle DynamicProxy 被折叠的签名同时通过反射来解除折叠. 但是未能... 我们无法找到AutofacDependencyResolver 所以我们抛出了一个如下异常:

The dependency resolver is of type ‘Some.Other.DependencyResolver’ but was expected to be of type ‘Autofac.Integration.Mvc.AutofacDependencyResolver’. It also does not appear to be wrapped using DynamicProxy from the Castle Project. This issue could be the result of a change in the DynamicProxy implementation or the use of a different proxy library to wrap the dependency resolver.

最典型的地方是当我们通过 ContainerBuilder.RegisterFilterProvider() 使用行为筛选提供器(action filter provider). 筛选器提供者需要访问依赖解析器 同时能够使用 AutofacDependencyResolver.Current 来实现.

如果你看到这些,这意味着你正在用某种不能被折叠的方式修改(或者直译为装饰?)解析器,依赖于 AutofacDependencyResolver.Current 的功能将会失败. 当前的解决方案不会修改/装饰?解析器.

单元测试 Unit Testing

当对一个使用了 InstancePerRequest 组件的ASP.NET MVC 应用进行单元测试时, 你在尝试解析它的实例时将会抛出一个异常.这是因为在单元测试时没有HTTP请求。

每次请求生命周期域(per-request lifetime scope )这篇主题文章概述了对 per-request-scope 组件测试的策略.

示例实现 Example Implementation

Autofac源码中包含了一个示例web应用程序,叫做Remember.Web。它演示了各种使用Autofac对MVC的注入方式。

项目地址:https://github.com/autofac/Autofac

.NET手记-为ASP.NET MVC程序集成Autofac的更多相关文章

  1. 如何在 ASP.NET MVC 中集成 AngularJS(3)

    今天来为大家介绍如何在 ASP.NET MVC 中集成 AngularJS 的最后一部分内容. 调试路由表 - HTML 缓存清除 就在我以为示例应用程序完成之后,我意识到,我必须提供两个版本的路由表 ...

  2. 如何在 ASP.NET MVC 中集成 AngularJS(2)

    在如何在 ASP.NET MVC 中集成 AngularJS(1)中,我们介绍了 ASP.NET MVC 捆绑和压缩.应用程序版本自动刷新和工程构建等内容. 下面介绍如何在 ASP.NET MVC 中 ...

  3. 如何在 ASP.NET MVC 中集成 AngularJS(1)

    介绍 当涉及到计算机软件的开发时,我想运用所有的最新技术.例如,前端使用最新的 JavaScript 技术,服务器端使用最新的基于 REST 的 Web API 服务.另外,还有最新的数据库技术.最新 ...

  4. MVC中使用EF(1):为ASP.NET MVC程序创建Entity Framework数据模型

    为ASP.NET MVC程序创建Entity Framework数据模型 (1 of 10) By  Tom Dykstra |July 30, 2013 Translated by litdwg   ...

  5. 跟我学ASP.NET MVC之三:完整的ASP.NET MVC程序-PartyInvites

    摘要: 在这篇文章中,我将在一个例子中实际地展示MVC. 场景 假设一个朋友决定举办一个新年晚会,她邀请我创建一个用来邀请朋友参加晚会的WEB程序.她提出了四个注意的需求: 一个首页展示这个晚会 一个 ...

  6. 跟我学ASP.NET MVC之二:第一个ASP.NET MVC程序

    摘要: 本篇文章带你一步一步创建一个简单的ASP.NET MVC程序.  创建新ASP.NET MVC工程 点击“OK”按钮后,打开下面的窗口: 这里选择“Empty”模板以及“MVC”选项.这次不创 ...

  7. 05 入门 - 浅谈 ASP.NET MVC程序的工作原理

    目录索引:<ASP.NET MVC 5 高级编程>学习笔记 本篇内容 1. Global.asax文件 2. RouteConfig.cs文件 3. 视图命名和寻址的规则 前面创建了一个简 ...

  8. 用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器(转)

    用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器   现在不用Git,都不好意思说自己是程序员. 当你想用Git,而源代码服务器是Windows系统时,你 ...

  9. IIS8发布Asp.net MVC程序后出现404错误,处理程序staticFile

    新部署的虚拟机,运行Asp.net MVC程序,出现如下图错误: 解决方法: 添加功能和角色->添加角色->Web服务器IIS->应用程序开发->Asp.net3.5 /Asp ...

随机推荐

  1. Java虚拟机 垃圾收集器与内存分配策略

    说起GC,我们要思考的主要有三件事 哪些内存需要回收 那些已经“死去”的对象,那么哪些对象“死”,哪些对象“活”呢,有个简单的办法 引用计数法,但是没法解决循环依赖问题 所以Java虚拟机采用的是可达 ...

  2. vue的条件渲染和列表渲染介绍

    一.条件渲染 1.v-if语句 <div v-if="seen">hahahah</div> <!-- v-if插入或者删除元素的指令 --> ...

  3. Linux下搭建ftp服务

    Linux下ftp服务可以通过搭建vsftpd服务来实现,以CentOS为例,首先查看系统中是否安装了vsftpd,可以通过执行命令 rpm -qa | grep vsftpd 来查看是否安装相应的包 ...

  4. typescript里面调用javasript

    index.html 里面加入函数: function tellYou() { egret.log("tell you."); javascript:android.funA(); ...

  5. redis主从复制详述

    一.主从复制详述 原理其实很简单,master启动会生成一个run id,首次同步时会发送给slave,slave同步命令会带上run id以及offset,显然,slave启动(初次,重启)内存中没 ...

  6. tomcat的缺少tcnative-1.dll的解决

    tomcat启动出现如下问题: The APR based Apache Tomcat Native library which allows optimal performance in produ ...

  7. python任意进制转换

    python任意进制转换 import string def module_n_converter(q, s, base=None): """ 将自然数按照给定的字符串转 ...

  8. PHP-预定义函数访问数据库

    (1)复习:自定义函数 (2)调用PHP预定义的函数——访问MySQL数据库 1.函数的基础概念   定义一个简单的函数: function  函数名( ){ #函数主体 }  调用/运行一次函数: ...

  9. 团队-爬取豆瓣电影TOP250-代码设计规范

    队长博客:http://www.cnblogs.com/gengwenhao/

  10. spring-boot json数据交互

    SpringBoot学习之Json数据交互 最近在弄监控主机项目,对javaweb又再努力学习.实际的项目场景中,前后分离几乎是所以项目的标配,全栈的时代的逐渐远去,后端负责业务逻辑处理,前端负责数据 ...