Ioc容器Autofac系列(2)-- asp.net mvc中整合autofac


經過上篇蜻蜓點水的介紹后,本篇通過實例快速上手autofac,展示當asp.net mvc引入了autofac之后會帶來什么。

創建Asp.net MVC並引入Autofac

首先,創建一個MVC站點,為方便起見,選初始帶HomeControllerAccountController的那種。然后通過NuGet或到Autofac官網下載來引入類庫。個人推薦前者,因為從VS2010開始,已內集可視化的NuGet功能,使用起來非常方便。如下圖所示:

image

這是vs2012的界面,點擊“Manage NuGet Packages…”,彈出窗體如下,在右上角搜索框中輸入“Autofac”,找到對應的庫點擊安裝即可。這里需要應用的庫有兩個“Autofac”和“Autofac ASP.Net MVC3 Integration”。

image

autofac實現對Controller的自動注入

現在HomeController需要用到日志記錄功能。沿用上篇ILog接口,假設目前已有一種ILog的實現類--TxtLog,放在根目錄下Services文件夾中。

public class TxtLog : ILog
{
     public void Save( string message)
     {
         //save as txt
     }
}

HomeController需添加一個ILog類型變量,為了直觀看到類名,我把_log的類名賦給ViewBag.LogTypeName並顯示出來。代碼如下:

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方法中添加配置代碼,如下:

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

先不管含義,加了這些代碼以后,再運行程序,會發現HomeControllerILog變量被賦予了TxtLog類型的實例,而我們並沒有做任何new操作,結果如下圖:

image

 

autofac應對需求變更

回頭再看Application_Start中配置文件的代碼:

  1. builder.RegisterControllers注冊了當前程序集內所有的Controller類。
  2. builder.RegisterAssemblyTypes注冊了當前程序集內的所有類。

如果此刻需求改變,我們需要將所有的TxtLog換成DbLog,該怎么辦?首先添加DBLog類,如下:

public class DbLog : ILog
{
     public void Save( string message)
     {
         //save to Db.
     }
}

然后在Application_Start的方法的末端處添加如下代碼:

builder.RegisterType< DbLog >().As< ILog >();

運行程序,看到頁面如下:

image

可看出ILog的類型已變成了DbLog。但為何要強調末端處?實際上,DBLog已經通過builder.RegisterAssemblyTypes被注冊過一次,如果對同一個類型或接口注冊多次(比如這里的ILog),在Autofac中會以列表的形式保存,如果只取一個,則Autofac會從列表返回最新的那個

為了證明,我們在HomeController中再加入一個變量,類型為IEnumerable<ILog>,然后將列表中所有類名顯示出來,用逗號隔開。

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

運行程序,頁面顯示如下:

image

可以看到,針對ILog接口注冊了三個類型。前兩個通過builder.RegisterAssemblyTypes注冊,最后一個是我們手動添加。

但重復的注冊類型總讓人覺得不夠優雅,因此實際開發中並不推薦一次性注冊所有類,可條件篩選。翻開Autofac的源碼,查看我們上文用到的builder.RegisterControllers會發現方法內部就是這種思路:

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的開源站點也都是這么做的。

結語

未完,待續……^_^


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM