.NET手记-为ASP.NET MVC程序集成Autofac
MVC
Autofac总是会紧跟最新版本的ASP.NET MVC框架,所以文档也会一直保持更新。一般来讲,不同版本的框架集成Autofac的方法一般不变。
MVC集成需要引用 Autofac.Mvc5 NuGet包.
MVC 集成库提供对控制器(Controller)、模型绑定器(model binders)、行为筛选器(action filters)和视图(views)的依赖注入. 它也添了对 每次请求生命周期(per-request lifetime)的支持.
- 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 确保对行为筛选器的属性注入可用
- OWIN Integration OWIN集成
- Using “Plugin” Assemblies 使用插件Assemblies
- Using the Current Autofac DependencyResolver 使用当前Autofac依赖解析器
- Unit Testing 单元测试
- Example Implementation 示例实现
快速开始 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引擎时,支持的基类为ViewPage、ViewMasterPage以及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之前调用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;
}
}
在应用筛选器到你的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的更多相关文章
- 如何在 ASP.NET MVC 中集成 AngularJS(3)
今天来为大家介绍如何在 ASP.NET MVC 中集成 AngularJS 的最后一部分内容. 调试路由表 - HTML 缓存清除 就在我以为示例应用程序完成之后,我意识到,我必须提供两个版本的路由表 ...
- 如何在 ASP.NET MVC 中集成 AngularJS(2)
在如何在 ASP.NET MVC 中集成 AngularJS(1)中,我们介绍了 ASP.NET MVC 捆绑和压缩.应用程序版本自动刷新和工程构建等内容. 下面介绍如何在 ASP.NET MVC 中 ...
- 如何在 ASP.NET MVC 中集成 AngularJS(1)
介绍 当涉及到计算机软件的开发时,我想运用所有的最新技术.例如,前端使用最新的 JavaScript 技术,服务器端使用最新的基于 REST 的 Web API 服务.另外,还有最新的数据库技术.最新 ...
- 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 ...
- 跟我学ASP.NET MVC之三:完整的ASP.NET MVC程序-PartyInvites
摘要: 在这篇文章中,我将在一个例子中实际地展示MVC. 场景 假设一个朋友决定举办一个新年晚会,她邀请我创建一个用来邀请朋友参加晚会的WEB程序.她提出了四个注意的需求: 一个首页展示这个晚会 一个 ...
- 跟我学ASP.NET MVC之二:第一个ASP.NET MVC程序
摘要: 本篇文章带你一步一步创建一个简单的ASP.NET MVC程序. 创建新ASP.NET MVC工程 点击“OK”按钮后,打开下面的窗口: 这里选择“Empty”模板以及“MVC”选项.这次不创 ...
- 05 入门 - 浅谈 ASP.NET MVC程序的工作原理
目录索引:<ASP.NET MVC 5 高级编程>学习笔记 本篇内容 1. Global.asax文件 2. RouteConfig.cs文件 3. 视图命名和寻址的规则 前面创建了一个简 ...
- 用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器(转)
用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器 现在不用Git,都不好意思说自己是程序员. 当你想用Git,而源代码服务器是Windows系统时,你 ...
- IIS8发布Asp.net MVC程序后出现404错误,处理程序staticFile
新部署的虚拟机,运行Asp.net MVC程序,出现如下图错误: 解决方法: 添加功能和角色->添加角色->Web服务器IIS->应用程序开发->Asp.net3.5 /Asp ...
随机推荐
- Linux基础知识回顾及BASH学习
2019-2020-030189224 <网络攻防技术与实践>第一周学习总结 Linux基础知识错题回顾 1.Linux中使用(B)命令新建空白文件. A .mkdir B .touch ...
- Linux vfpd锁定用户目录
在linux ftp配置中,为了防止用户cd 到其他目录,需要锁定用户的根目录. Step1:修改配置文件 [root@ess ~]# vi /etc/vsftpd/vsftpd.conf #chro ...
- laravel简书(2)
用户注册 public function register() { //验证 $this->validate(\request(),[ ' ...
- 检查mysql表是否损坏的脚本
#!/bin/bash#此脚本的主要用途是检测mysql服务器上所有的db或者单独db中的坏表#变量说明 pass mysql账户口令 name mysql账号名称 data_path mysql目录 ...
- node.js中使用 http-proxy 创建代理服务器
代理,也称网络代理,是一种特殊网络服务,允许一个终端通过代理服务与另一个终端进行非直接的连接,这样利于安全和防止被攻击. 代理服务器,就是代理网络用户去获取网络信息,就是信息的中转,负责转发. 代理又 ...
- tiny4412 --uboot移植(2) 点灯
开发环境:win10 64位 + VMware12 + Ubuntu14.04 32位 工具链:linaro提供的gcc-linaro-6.1.1-2016.08-x86_64_arm-linux-g ...
- pip 国内源 配置
pip 国内源 配置 2017年12月09日 16:05:20 阅读数:183 最近使用 pip 安装包,动辄十几 k 甚至几 k 的下载速度,确实让人安装的时候心情十分不好.所以还是要给 pip 换 ...
- 浅谈卷积和C++实现
1 信号处理中的卷积 无论是信号处理.图像处理还是其他一些领域,我们经常会在一些相互关联的数据处理中使用卷积.卷积可以说是算法中一个非常重要的概念.这个概念最早起源于信号处理之中. 假设对于一个线性系 ...
- python 之字符编码
一 了解字符编码的储备知识 python解释器和文件本编辑的异同 相同点:python解释器是解释执行文件内容的,因而python解释器具备读py文件的功能,这一点与文本编辑器一样 不 ...
- day 5,格式化输出,for,while, break,continue,列表
本节内容: 1,格式化输出 2,数据类型 3,for 循环 4,while 循环 5,列表 pycharm的简单使用,设置pycharm自动生成日期和计算机用户名 ctrl+d复制一行 1,格式化输出 ...