1. 程式人生 > 其它 >ASP.NET Web API中的依賴注入什麼是依賴注入ASP.NET Web API依賴解析器使用Unity解析依賴配置依賴解析

ASP.NET Web API中的依賴注入什麼是依賴注入ASP.NET Web API依賴解析器使用Unity解析依賴配置依賴解析

什麼是依賴注入

    依賴,就是一個物件需要的另一個物件,比如說,這是我們通常定義的一個用來處理資料訪問的儲存,讓我們用一個例子來解釋,首先,定義一個領域模型如下:

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返回資料

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