經過上篇蜻蜓點水的介紹后,本篇通過實例快速上手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文件夾中。
{
public void Save( string message)
{
//save as txt
}
}
HomeController需添加一個ILog類型變量,為了直觀看到類名,我把_log的類名賦給ViewBag.LogTypeName並顯示出來。代碼如下:
{
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();
}
//....
接着,在對應頁面加入以下代碼(抱歉這里用英文描述,因為我的代碼高亮插件不能顯示中文):
此時運行程序會報錯,因為HomeController找不到無參構造函數,而我們也沒有給_log指定任何類型的實例。
現在我們讓Autofac發揮作用,在Global文件的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類,如下:
{
public void Save( string message)
{
//save to Db.
}
}
然后在Application_Start的方法的末端處添加如下代碼:
運行程序,看到頁面如下:
可看出ILog的類型已變成了DbLog。但為何要強調末端處?實際上,DBLog已經通過builder.RegisterAssemblyTypes被注冊過一次,如果對同一個類型或接口注冊多次(比如這里的ILog),在Autofac中會以列表的形式保存,如果只取一個,則Autofac會從列表返回最新的那個。
為了證明,我們在HomeController中再加入一個變量,類型為IEnumerable<ILog>,然后將列表中所有類名顯示出來,用逗號隔開。
{
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會發現方法內部就是這種思路:
RegisterControllers(
this ContainerBuilder builder,
params Assembly [] controllerAssemblies)
{
return builder.RegisterAssemblyTypes(controllerAssemblies)
.Where(t => typeof ( IController ).IsAssignableFrom(t) &&
t.Name.EndsWith( "Controller" ));
}
由代碼可知,該方法篩選出所有實現IController接口且類型名以“Controller”結尾的類。你可以根據自己項目的實際情況來篩選,很多使用Autofac的開源站點也都是這么做的。
結語
未完,待續……^_^