相信大家對Autofac並不陌生,很多人都在使用。本文只是介紹一下本人在使用時的一點想法總結。
你是不是很頭疼的要在Global中寫一堆代碼來維護Autofac?
你是不是很頭疼為Controller增加構造函數為變量賦值?
你是不是很頭疼每次增加接口和實現的時候都要重新編譯?
那么本文介紹一些Autofac的其它實踐,也許能夠對你有所幫助。
在使用一個框架時,肯定要去它的官網查閱一下。autofac的官網給出了一些經典的使用案例。如注冊容器:
var builder = new ContainerBuilder(); // Register individual components builder.RegisterInstance(new TaskRepository) .As<ITaskRepository>(); builder.RegisterType<TaskController>(); builder.Register(c => new LogManager(DateTime.Now)) .As<ILogger>(); // Scan an assembly for components builder.RegisterAssemblyTypes(myAssembly) .Where(t => t.Name.EndsWith("Repository")) .AsImplementedInterfaces(); var container = builder.Build();
在mvc中使用:
public class TaskController { private ITaskRepository _repository; private ILogger _logger; // Autofac will automatically find the registered // values and pass them in for you. public TaskController( ITaskRepository repository, ILogger logger) { this._repository = repository; this._logger = logger; } }
在這里先重點說一下在mvc中的使用,如上代碼可見,在一個請求到達時,需要對controller進行實例化,而正如autofac官網所說“If there is more than one constructor on a component type, Autofac will use the constructor with the most resolvable parameters.”,如果有多個帶參構造函數,autofac默認使用參數最多的構造函數。在上面代碼中,即便在一個action中,你只用了_logger,那么_repository也依舊需要被autofac解析。
而在mvc的具體應用中,我們可能會使用多重繼承,如下圖的結構
在這種情況下,每個controller可能會有很多構造函數,在每個請求到達時,都需要實例化相當一部分的變量。本人沒有研究過這種實例化是否會影響效率,只是覺得這樣對於開發來講過於繁瑣,且不利於維護,代碼也並不流暢。我的想法是在action中,在需要的點去實例化。
經過一些查閱,autofac官方提供了很多庫,發現其中Autofac.Mef是可以用另一種方式實現達到同樣的效果。文檔的介紹只有一句話“The MEF integration allows you to expose extensibility points in your Autofac applications using the Managed Extensibility Framework.” mef可能主要用來在對已經開發完畢的版本做補充的時候使用。如某個系統已經開發結束並部署運行了,這時候會有些功能的增加和擴展,在不修改原版本的前提下,使用mef可以將后補充的功能ioc到原系統。mef需要引用System.ComponentModel.Composition.dll庫。
先不說別的了,代碼說明一切。在接口實現上需要加入ExportAttribute,如:
[Export(typeof(ICustomerBusiService))] public class CustomerBusiService : ICustomerBusiService
注意,ICustomerBusiService不用做任何的描述,只描述其實現CustomerBusiService即可。為了達到我的目的,我在頂層的controller中增加了一個獲取實例的方法,以便action中根據自己的需要獲取實例化:
public abstract class AbstractController : Controller { private static IAutofacResolver _resolver = new AutofacResolver(); protected T GetService<T>() { return _resolver.GetService<T>(); } }
下面展示一下IAutofacResolver及其實現AutofacResolver
public interface IAutofacResolver { T GetService<T>(); } public class AutofacResolver : IAutofacResolver { private Autofac.IContainer _container; public T GetService<T>() { if (_container == null || !_container.IsRegistered<T>()) { RegisterPartsFromReferencedAssemblies(); } return _container.Resolve<T>(); } private void RegisterPartsFromReferencedAssemblies() { var asses = BuildManager.GetReferencedAssemblies().Cast<Assembly>(); var assemblyCatalogs = asses.Select(x => new AssemblyCatalog(x)); var catalog = new AggregateCatalog(assemblyCatalogs); var builder = new ContainerBuilder(); builder.RegisterComposablePartCatalog(catalog); _container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(_container)); } }
我們知道Asp.Net的項目,只要bin目錄有變化,該站點會相應的重新啟動,所以在你制作的新的接口庫和實現庫完成之后,只要push到bin目錄,RegisterPartsFromReferencedAssemblies()中的BuildManager.GetReferencedAssemblies()會捕捉到所有的當前站點的所有dll引用,並根據ExportAttribute加載到Autofac。該方式在第一次使用GetService<T>()的時候會執行RegisterPartsFromReferencedAssemblies(),之后就不會在執行該方法了。該方式不需要在Global中用一堆代碼維護Autofac,有點一勞永逸的感覺。
有了這樣一個結構,那么在具體的controller中我不需要有構造函數,在acton中只要調用GetService<T>()就可以獲取我需要的實例。
public class AccountController : AbstractMvcController { [HttpPost] public ActionResult Register(Customer customer) { var ibsCusomter = GetService<ICustomerBusiService>(); ibsCusomter.Register(customer); return View(); } }
以上就是全部內容。本文並沒有針對復雜的autofac應用進行說明,比如注冊復雜的模型,激活事件等。只是對比較簡單普遍的autofac的使用進行一些分析,個人認為mvc的站點開發中,不太會用到比較復雜的東西,因為每個用戶請求都是獨立的,又有並發的問題,所以autofac的單實例也基本不會考慮。
autofac相關庫的下載,請點擊此處