什么是依賴注入?
public class Product { public int ID { get; set; } public string Name { get; set; } public decimal Price { get; set; } }
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); } }
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實現的時候只需要在
替換成