.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).
这包括了下面的抽象类:
HttpContextBaseHttpRequestBaseHttpResponseBaseHttpServerUtilityBaseHttpSessionStateBaseHttpApplicationStateBaseHttpBrowserCapabilitiesBaseHttpFileCollectionBaseRequestContextHttpCachePolicyBaseVirtualPathProviderUrlHelper
为了使用这些抽象类,通过使用标准的 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 ...
随机推荐
- Python设计模式 - UML - 部署图(Deployment Diagram)
简介 部署图也称配置图,用来显示系统中硬件和软件的物理架构.从中可以了解到软件和硬件组件之间的物理拓扑.连接关系以及处理节点的分布情况. 部署图建模步骤 - 找出需要进行部署的各类节点,如网络硬件设备 ...
- Flask最强攻略 - 跟DragonFire学Flask - 第二篇 Flask 中的 Render Redirect HttpResponse
1.Flask中的HTTPResponse 在Flask 中的HttpResponse 在我们看来其实就是直接返回字符串 2.Flask中的Redirect 每当访问"/redi" ...
- Linux redhat 7 进入单用户模式
redhat 7 进入单用户模式修复系统故障 1.启动机器,grub界面选择第一个,按e 2.往下翻,找到Linux16 开头的那一行 3.将ro改为"rw init=/sysroot/b ...
- django 模板使用
1 配置 在工程中创建模板目录templates. 在settings.py配置文件中修改TEMPLATES配置项的DIRS值: TEMPLATES = [ { 'BACKEND': 'django. ...
- 使用es6的then()方法封装jquery的ajax请求
使用场景: jsp页面中使用jquery的ajax请求比较频繁,以前vue框架的项目用过axios,所以就想着用then()封装一个公共请求的方法,这样每次请求就不用那么麻烦的写一大堆请求参数了. 示 ...
- 【你的职业规划】web前端的职业发展方向及学习攻略【转载】
web前端的职业发展方向有哪些?本文献给正在迷茫中,准备入坑web前端的初学者以及知海匠库web前端培训班的准前端工程师们: 一.职业方向定位 首先,只有确定好自己的职业方向,才能做好职业规划.在 ...
- FortiGate 路由
1.静态路由 防火墙外网口wan1 ip地址为202.1.1.2,对端ISP路由器G1/0口地址为202.1.1.1. 菜单: 路由--静态--静态路由,点击 "创建新的",按如下 ...
- mysql-8.0.15-winx64 解压版安装 图文详解
1.官网下载 https://dev.mysql.com/downloads/mysql/ 2.解压到合适的目录 3.配置环境变量 ①. path ②.MYSQL_HOME 4.新建一个my.ini ...
- Thinkphp5 表单提交额外参数和页面跳转参数传递url
1. 表单提交 <input type="hidden" name="project_name" value="$project_name&qu ...
- application/json和application/x-www-form-urlencoded使用选择
一.参考资料 选application/x-www-form-urlencoded还是application/json? @RequestBody应用 二.理解 1.@RequestBody的作用 注 ...