AutoFac實現WebAPI依賴注入(EF以及Mysql)


什么是依賴注入?

我們以實際的例子來加以介紹
實體如下
  public class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
EF的實現如下
 public class ProductContext: DbContext
    {
        public ProductContext(): base( "ProductContext")
        {

        }
        public DbSet< Product> Products { get; set; }
    }
  public class ProductRepo_EF 
    {
        private ProductContext _ctx = new ProductContext (); 
        public IEnumerable<Models.Product > GetAll()
        {
            return _ctx.Products.ToList();
        }

        public Models. Product GetProduct( int id)
        {
            return _ctx.Products.FirstOrDefault(x=>x.ID==id);
        }
    }
在controller中
public class ProductsController : ApiController{
    //這一行是問題根源所在
    ProductRepository _repository = new ProductRepository();

    public IEnumerable<Product> Get()
    {
        return _repository.GetAll();
    }

    public IHttpActionResult Get(int id)
    {
        var product = _repository.GetByID(id);
        if (product == null)
        {
            return NotFound();
        }
        return Ok(product);
    }}
我們的productController是依賴於productRespository來提供數據的,也就是我們形象的說法,這個controller依賴於_respository的實現。那如果我們的repo發生變化,甚至我們將不准備采用EF針對sqlserver提供的方式,我們想更換針對mysql的實現,如果有很多controller都依賴於repo的實現,那代碼的改動量將會很巨大,而且很容易犯錯。這在真正的工業代碼中將是無法想象的。 所以我們必須采用以來注入的松耦合實現方式。
public interface IProductRepository{
    IEnumerable<Product> GetAll();
    Product GetById(int id);
    }

public class ProductRepository : IProductRepository{
    
//
}

public class ProductsController : ApiController{
    private IProductRepository _repository;

    public ProductsController(IProductRepository repository)  
    {
        _repository = repository;
    }

  } 

利用構造函數向外界暴露依賴,這樣在再創建不同的實例的時候,只需要提供不同的實現就可以了,在代碼內部則不會發生改動。關於更多依賴注入的基礎知識,可以自行搜索,實在太多。我們這里針對webapi的依賴注入。 在mvc以及webapi中,與業務邏輯打交道,那就肯定少不了controller對於業務類(比方說Repo)的依賴。那這里想要實現解耦,就要控制controller實例的創建,但是在mvc框架中controller的創建是由框架自行完成的..頓時覺得無從下手了。在mvc2.0中,如果使用DefaultControllerFactory的實現,創建controller實例是通過反射調用無參構造函數來實現的。那我們想要使用默認工廠來通過構造函數注入,顯然是不現實的。只能整體更換整個工廠。而隨着mvc框架的發展,到mvc4的時候,框架已經對於外部的以來注入實現已經相當友好了。默認工廠不再通過單一的無參構造函數反射創建實例,而是統一的通過IDependencyresolver接口提供的 IDependencyResolver.GetService(Type serviceType)
方法來暴露實現。在創建controller實例的時候,首先通過該方法去取得controller實例,如果為null在調用無參構造創建實例。 所以我們只需要使用外部IOC容器擴展針對IDependencyResolver的實現即可。 外部IOC容器常用的有 Unity Autofac Ninject 等等。我們這里采用AutoFac做為我們的實現。因為文檔齊全,效率高,功能強大,也是主流IOC容器。 使用autofac可以自行創建,也可以采用autofac官方針對webapi的擴展。 通過Nuget安裝 autofac 以及autofac.extentions.webapi。將自動有AutofacWebApiDependencyResolver實現。

在global.asax中

var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());           
//僅僅這一個地方的改動,就達到了對數據庫的無縫鏈接。
builder.RegisterType<ProductRepo_EF>().As<IProductRepo>();           
var container = builder.Build();           
var resolver = new AutofacWebApiDependencyResolver(container);            
GlobalConfiguration.Configuration.DependencyResolver = resolver;
在這里我們使用了EF和EF to Mysql兩種repo實現,也就是通過兩種數據庫提供數據。
備注一下,使用EF To Mysql需要安裝mysql數據庫,以及在nuget包中


 
              
並且在web.config中提供mysql以及sqlserver兩種連接字符串即可。
這樣 ,當我們需要更換不同的repo實現的時候只需要在
builder.RegisterType< ProductRepo_EF >().As< IProductRepo >();   
替換成
builder.RegisterType< ProductRepo_Mysql >().As< IProductRepo >(); 即可。
我們的代碼改動僅僅只發生在注入的這一個地方。


免責聲明!

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



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