ASP.NET Web API中的依賴注入

  什麼是依賴注入
   依賴,就是一個對象須要的另外一個對象,好比說,這是咱們一般定義的一個用來處理數據訪問的存儲,讓咱們用一個例子來解釋,首先,定義一個領域模型以下:
   namespace Pattern.DI.MVC.Models
   {
   public class Product
   {
   public int Id { get; set; }
   public string Name { get; set; }
   public decimal Price { get; set; }
   }
   }
   而後是一個用於實例的簡單存儲類:
   namespace Pattern.DI.MVC.Models
   {
   public class ProductContext
   {
   public List<Product> Products { get; internal set; }
   public ProductContext()
   {
   Products.Add(new Product() {Id = 1, Name = "蒼阿姨", Price = 100});
   Products.Add(new Product() {Id = 2, Name = "武藤奶奶", Price = 200});
   Products.Add(new Product() {Id = 3, Name = "小澤姐姐", Price = 300});
   }
   }
   public class ProductRepository
   {
   private ProductContext context=new ProductContext();
   public IEnumerable<Product> GetAll()
   {
   return context.Products;
   }
   public Product GetById(int id)
   {
   return context.Products.FirstOrDefault(p => p.Id == id);
   }
   }
   }
   如今,咱們定義一個ASP.NET Web API控制器來支持對Product實體集的GET請求:
   namespace Pattern.DI.MVC.Controllers
   {
   public class ProductController : ApiController
   {
   private readonly ProductRepository productRepository=new ProductRepository();
   public IEnumerable<Product> Get()
   {
   return productRepository.GetAll();
   }
   public Product Get(int id)
   {
   return productRepository.GetById(id);
   }
   }
   }
   如今注意到,這個控制器依賴了"ProductRepository"這個類,咱們在類中實例化了ProductRepository,這就是設計的"壞味道"了,由於以下幾個緣由:
   假如你想要使用另一個實現替換ProductRepository,你還要去修改ProductController類;
   假如ProductRepository存在依賴,你必須在ProductController中配置他們,對於一個擁有不少控制器的大項目來講,你就配置工做將深刻到任何可能的地方;
   這是很難去作單元測試的由於控制器中硬編碼了對數據庫的查詢,對於一個單元測試,你能夠在沒有確切設計以前,使用一個仿製的樁存儲體。
   咱們可使用注入一個ProductRepsoitory來解決這個問題,首先重構ProductRepository的方法到一個接口中:
   namespace Pattern.DI.MVC.Models
   {
   public interface IProductRepository
   {
   IEnumerable<Product> GetAll();
   Product GetById(int id);
   }
   public class ProductRepository:IProductRepository
   {
   private ProductContext context = new ProductContext();
   public IEnumerable<Product> GetAll()
   {
   return context.Products;
   }
   public Product GetById(int id)
   {
   return context.Products.FirstOrDefault(p => p.Id == id);
   }
   }
   }
   而後在ProductC0ntroller中使用參數傳入IProductRepository:
   namespace Pattern.DI.MVC.Controllers
   {
   public class ProductController : ApiController
   {
   private readonly IProductRepository productRepository;
   public ProductController(IProductRepository productRepository)
   {
   this.productRepository = productRepository;
   }
   public IEnumerable<Product> Get()
   {
   return productRepository.GetAll();
   }
   public Product Get(int id)
   {
   return productRepository.GetById(id);
   }
   }
   }
   這個示例使用了構造器注入,你一樣可使用設置器注入的方式,ASP.NET Web API在爲請求映射了路由以後建立控制器,並且如今他不知道任何關於IProductRepository的細節,這是經過API依賴器解析到的。
   ASP.NET Web API依賴解析器
   ASP.NET Web API定義了一個IDependencyResolever用來解析依賴項目,如下是這個接口的定義:
   public interface IDependencyResolver : IDependencyScope, IDisposable
   {
   IDependencyScope BeginScope();
   }
   public interface IDependencyScope : IDisposable
   {
   object GetService(Type serviceType);
   IEnumerable<object> GetServices(Type serviceType);
   }
   這個接口有兩個方法
   GetService爲一個類型建立一個實例;
   GetServices爲一個特定的類型建立一個實例集合
   這個接口繼承自IDependencyScope而且添加了BeginScope方法,在這篇文章接下來將討論這個方法。
   當ASP.NET Web API建立一個controller實例的時候,它首先調用IDependencyResolver的GetService方法,傳回一個Controller實例,你可使用一個擴展的鉤子去建立控制器而且解析依賴。假如GetService方法返回NULL,ASP.NET Web API將查找一個無參的構造函數。
   使用Unity解析依賴
   雖然你能夠重頭開始寫一個IDenpendencyResolver的實現,可是這個接口已經設計了能夠做爲ASP.NET Web API和IoC工具的橋樑。
   IoC容器是一個用來管理依賴項目的組建,你能夠在其中註冊類型,在使用的時候建立對象,IoC容易自動解析出依賴的關係,許多IoC容器容許你在對象的生命週期中進行控制。
   首先在項目中使用NuGet Package Manage Console安裝Unity,關於Unity的介紹能夠點擊這裏查看詳細。
   Install-Package Unity
   如下是一個使用Unity容器對IDependencyResolver的實現:
   using System;
   using System.Collections.Generic;
   using System.Linq;
   using System.Web;
   using Microsoft.Practices.Unity;
   using System.Web.Http.Dependencies;
   namespace Pattern.DI.MVC.Models
   {
   public class UnityResolver : IDependencyResolver
   {
   protected IUnityContainer container;
   public UnityResolver(IUnityContainer container)
   {
   if (container == null)
   {
   throw new ArgumentNullException("container");
   }
   this.container = container;
   }
   public object GetService(Type serviceType)
   {
   try
   {
   return container.Resolve(serviceType);
   }
   catch (ResolutionFailedException)
   {
   return null;
   }
   }
   public IEnumerable<object> GetServices(Type serviceType)
   {
   try
   {
   return container.ResolveAll(serviceType);
   }
   catch (ResolutionFailedException)
   {
   return new List<object>();
   }
   }
   public IDependencyScope BeginScope()
   {
   var child = container.CreateChildContainer();
   return new UnityResolver(child);
   }
   public void Dispose()
   {
   container.Dispose();
   }
   }
   }
   配置依賴解析
   在全局的HttpConfiguration對象中DependencyResolver屬性上設置依賴解析器,如下的代碼使用Unity註冊IProductRepository接口而且建立一個UnityResolver,修改App_Start/WebApiConfig.cs中的Register方法託福答案
   namespace Pattern.DI.MVC
   {
   public static class WebApiConfig
   {
   public static void Register(HttpConfiguration config)
   {
   var container = new UnityContainer();
   container.RegisterType<IProductRepository, ProductRepository>();
   config.DependencyResolver = new UnityResolver(container);
   config.Routes.MapHttpRoute(
   name: "DefaultApi",
   routeTemplate: "api/{controller}/{id}",
   defaults: new { id = RouteParameter.Optional }
   );
   }
   }
   }數據庫

相關文章
相關標籤/搜索