也說Autofac在MVC的簡單實踐:破解在Controller構造函數中的實例化


相信大家對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相關庫的下載,請點擊此處

 


免責聲明!

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



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