依賴注入容器Autofac的詳解


Autofac和其他容器的不同之處是它和C#語言的結合非常緊密,在使用過程中對你的應用的侵入性幾乎為零,更容易與第三方的組件集成,並且開源,Autofac的主要特性如下:

1,靈活的組件實例化:Autofac支持自動裝配,給定的組件類型Autofac自動選擇使用構造函數注入或者屬性注入,Autofac還可以基於lambda表達式創建實例,這使得容器非常靈活,很容易和其他的組件集成。
2,資源管理的可視性:基於依賴注入容器構建的應用程序的動態性,意味着什么時候應該處理那些資源有點困難。Autofac通過容器來跟蹤組件的資源管理。對於不需要清理的對象,例如Console.Out,我們調用ExternallyOwned()方法告訴容器不用清理。細粒度的組件生命周期管理:應用程序中通常可以存在一個應用程序范圍的容器實例,在應用程序中還存在大量的一個請求的范圍的對象,例如一個HTTP請求,一個IIS工作者線程或者用戶的會話結束時結束。通過嵌套的容器實例和對象的作用域使得資源的可視化。
3,Autofac的設計上非常務實,這方面更多是為我們這些容器的使用者考慮:
●組件侵入性為零:組件不需要去引用Autofac。
●靈活的模塊化系統:通過模塊化組織你的程序,應用程序不用糾纏於復雜的XML配置系統或者是配置參數。
●自動裝配:可以是用lambda表達式注冊你的組件,autofac會根據需要選擇構造函數或者屬性注入
●XML配置文件的支持:XML配置文件過度使用時很丑陋,但是在發布的時候通常非常有用

Autofac的簡單使用,並加入了Repository模式.

定義兩個簡單實體類:

public class Persion
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Custom
{
    public string CustomName { get; set; }
    public int CustomID { get; set; }
}

 



定義泛型數據庫訪問接口:

public interface Idal<T> where T:class
{
    void Insert(T entity);
    void Update(T entity);
    void Delete(T entity);
}


泛型數據庫訪問接口的泛型實現:

public class Dal<T>:Idal<T> where T : class
{

    #region Idal<T> Members

    public void Insert(T entity)
    {
        HttpContext.Current.Response.Write("您添加了一個:"
           +entity.GetType().FullName);
    }

    public void Update(T entity)
    {

        HttpContext.Current.Response.Write("您更新一個:"
             +entity.GetType().FullName);
    }

    public void Delete(T entity)
    {
        HttpContext.Current.Response.Write("您刪除了一個:"
              +entity.GetType().FullName);
    }

    #endregion
}


使用Repository模式實現訪問。

Repository的泛型接口:

public interface IRepository<T> where T:class
{
    void Insert(T entity);
    void Update(T entity);
    void Delete(T entity);
}

 

Repository泛型接口的泛型實現:

public class Repository<T>:IRepository<T> where T:class
{
    private Idal<T> _dal;
    public Repository(Idal<T> dal)
    {
        _dal = dal;
    }

    #region IRepository<T> Members

    public void Insert(T entity)
    {
        _dal.Insert(entity);
    }

    public void Update(T entity)
    {
        _dal.Update(entity);
    }

    public void Delete(T entity)
    {
        _dal.Delete(entity);
    }

    #endregion
}


IDependency的依賴接口,不需要任何方法體,所有的業務對象都實現該接口

public interface IDependency
{
}


實現IDependency接口的CustomBll類,通過Repository模式存儲數據。

public class CustomBll:IDependency
{
    private readonly IRepository<Custom> _repository;
    public CustomBll(IRepository<Custom> repository)
    {
        _repository = repository;
    }

    public void Insert(Custom c)
    {
        _repository.Insert(c);
    }

    public void Update(Custom c)
    {
        _repository.Update(c);
    }

    public void Delete(Custom c)
    {
        _repository.Delete(c);
    }
}



實現IDependency接口的PersionBll類,通過Repository模式存儲數據。

public class PersionBll:IDependency
{
    private readonly IRepository<Persion> _repository;
    public PersionBll(IRepository<Persion> repository)
    {
        _repository = repository;
    }

    public void Insert(Persion p)
    {
        _repository.Insert(p);
    }

    public void Update(Persion p)
    {
        _repository.Update(p);
    }

    public void Delete(Persion p)
    {
        _repository.Delete(p);
    }
}



下面編寫組件實例化測試

var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(Dal<>)).As(typeof(Idal<>))
    .InstancePerDependency();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>))
    .InstancePerDependency();
builder.Register(c=>new PersionBll((IRepository<Persion>)
    c.Resolve(typeof(IRepository<Persion>))));
builder.Register(c => new CustomBll((IRepository<Custom>)
    c.Resolve(typeof(IRepository<Custom>))));

//var container = builder.Build()教程里都是使用這行代碼,
//我本地測試需要加入ContainerBuildOptions枚舉選項。
using (var container = builder.Build(ContainerBuildOptions.None))  
{

    // var repository= container.Resolve(typeof(IRepository<Persion>),new TypedParameter());
    // IRepository<Persion> _repository = repository as Repository<Persion>;
    // var m = new PersionBll(_repository);
    Persion p = new Persion();
    p.Name = "小人";
    p.Age = 27;
    var m = container.Resolve<PersionBll>();
    m.Insert(p);
    Custom c = new Custom();
    c.CustomName = "小小";
    c.CustomID = 10;
    var cc = container.Resolve<CustomBll>();
    cc.Update(c);
}



這里通過ContainerBuilder方法RegisterGeneric對泛型類進行注冊(當然也可以通過ContainerBuilder方法RegisterType對不是泛型的類進行注冊),當注冊的類型在相應得到的容器中可以Resolve你的類實例。
builder.RegisterGeneric(typeof(Dal<>)).As(typeof(Idal<>)).InstancePerDependency();通過AS可以讓類中通過構造函數依賴注入類型相應的接口。(當然也可以使用builder.RegisterType<類>().As<接口>();來注冊不是泛型的類 )
Build()方法生成一個對應的Container實例,這樣,就可以通過Resolve解析到注冊的類型實例。

注:如果要獲得某個泛型的實例,需要將泛型T代表的類傳進去。如上c.Resolve(typeof(IRepository<Persion>))返回的是Object,需要轉換為響應的接口。

當然可以使用autofac的新特性RegisterAssemblyTypes,從一個程序集的注冊類型設置根據用戶指定的規則,例子如下:

var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(Dal<>)).As(typeof(Idal<>)).InstancePerDependency();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerDependency();
//上面的那些類如果在單獨的工程里,如生成的程序集為AutofacUnitTest,就可以使用
//Assembly.Load("AutofacUnitTest")獲得響應的程序集。如果所有的文件在一個控制台程序里,
//可以通過Assembly.GetExecutingAssembly(); 直接獲得相應的程序集。
Assembly dataAccess = Assembly.Load("AutofacUnitTest");
builder.RegisterAssemblyTypes(dataAccess)
        .Where(t => typeof(IDependency).IsAssignableFrom(t) && t.Name.EndsWith("Bll"));
//RegisterAssemblyTypes方法將實現IDependency接口並已Bll結尾的類都注冊了,語法非常的簡單。

 


免責聲明!

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



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