Ioc容器Autofac系列(2)-- asp.net mvc中整合autofac
经过上篇蜻蜓点水的介绍后,本篇通过实例快速上手autofac,展示当asp.net mvc引入了autofac之后会带来什么。
创建Asp.net MVC并引入Autofac
首先,创建一个MVC站点,为方便起见,选初始带HomeController和AccountController的那种。然后通过NuGet或到Autofac官网下载来引入类库。个人推荐前者,因为从VS2010开始,已内集可视化的NuGet功能,使用起来非常方便。如下图所示:
这是vs2012的界面,点击“Manage NuGet Packages…”,弹出窗体如下,在右上角搜索框中输入“Autofac”,找到对应的库点击安装即可。这里需要应用的库有两个“Autofac”和“Autofac ASP.Net MVC3 Integration”。
autofac实现对Controller的自动注入
现在HomeController需要用到日志记录功能。沿用上篇ILog接口,假设目前已有一种ILog的实现类--TxtLog,放在根目录下Services文件夹中。
1
2
3
4
5
6
7 |
public class TxtLog:ILog { public
void Save( string message) { //save as txt } } |
HomeController需添加一个ILog类型变量,为了直观看到类名,我把_log的类名赋给ViewBag.LogTypeName并显示出来。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
public class HomeController : Controller { private
ILog _log; public
HomeController(ILog log) { _log = log; } public
ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!" ; ViewBag.LogTypeName = _log.GetType().Name; return
View(); } //.... |
接着,在对应页面加入以下代码(抱歉这里用英文描述,因为我的代码高亮插件不能显示中文):
<h2>ILog‘s type name is @ViewBag.LogTypeName</h2>
此时运行程序会报错,因为HomeController找不到无参构造函数,而我们也没有给_log指定任何类型的实例。
现在我们让Autofac发挥作用,在Global文件的Application_Start方法中添加配置代码,如下:
1
2
3
4
5
6
7
8
9
10
11
12 |
protected
void Application_Start() { ...... ContainerBuilder builder = new
ContainerBuilder(); builder.RegisterControllers(Assembly.GetExecutingAssembly()); builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()) .AsImplementedInterfaces(); var container = builder.Build(); DependencyResolver.SetResolver( new
AutofacDependencyResolver(container)); } |
先不管含义,加了这些代码以后,再运行程序,会发现HomeController的ILog变量被赋予了TxtLog类型的实例,而我们并没有做任何new操作,结果如下图:
autofac应对需求变更
回头再看Application_Start中配置文件的代码:
-
builder.RegisterControllers注册了当前程序集内所有的Controller类。
-
builder.RegisterAssemblyTypes注册了当前程序集内的所有类。
如果此刻需求改变,我们需要将所有的TxtLog换成DbLog,该怎么办?首先添加DBLog类,如下:
1
2
3
4
5
6
7 |
public class DbLog:ILog { public
void Save( string message) { //save to Db. } } |
然后在Application_Start的方法的末端处添加如下代码:
1 |
builder.RegisterType<DbLog>().As<ILog>(); |
运行程序,看到页面如下:
可看出ILog的类型已变成了DbLog。但为何要强调末端处?实际上,DBLog已经通过builder.RegisterAssemblyTypes被注册过一次,如果对同一个类型或接口注册多次(比如这里的ILog),在Autofac中会以列表的形式保存,如果只取一个,则Autofac会从列表返回最新的那个。
为了证明,我们在HomeController中再加入一个变量,类型为IEnumerable<ILog>,然后将列表中所有类名显示出来,用逗号隔开。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
public class HomeController : Controller { private
ILog _log; private
IEnumerable<ILog> _logList; public
HomeController(ILog log,IEnumerable<ILog> logList ) { _log = log; _logList = logList; } public
ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!" ; ViewBag.LogTypeName = _log.GetType().Name; ViewBag.LogTypeNames = _logList.Select(x => x.GetType().Name).Aggregate((x, y) => x+ "," +y ); return
View(); } |
运行程序,页面显示如下:
可以看到,针对ILog接口注册了三个类型。前两个通过builder.RegisterAssemblyTypes注册,最后一个是我们手动添加。
但重复的注册类型总让人觉得不够优雅,因此实际开发中并不推荐一次性注册所有类,可条件筛选。翻开Autofac的源码,查看我们上文用到的builder.RegisterControllers会发现方法内部就是这种思路:
1
2
3
4
5
6
7
8
9 |
public static IRegistrationBuilder< object , ScanningActivatorData, DynamicRegistrationStyle> RegisterControllers( this
ContainerBuilder builder, params
Assembly[] controllerAssemblies) { return
builder.RegisterAssemblyTypes(controllerAssemblies) .Where(t => typeof (IController).IsAssignableFrom(t) && t.Name.EndsWith( "Controller" )); } |
由代码可知,该方法筛选出所有实现IController接口且类型名以“Controller”结尾的类。你可以根据自己项目的实际情况来筛选,很多使用Autofac的开源站点也都是这么做的。
结语
未完,待续……^_^
Ioc容器Autofac系列(2)-- asp.net mvc中整合autofac(转),古老的榕树,5-wow.com
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。