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 }
);
}
}
}

至此完工,測試Api返回數據

QQ截圖20140509112520 QQ截圖20140509112507

 

原文地址:http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver


免責聲明!

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



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