Asp.Net Web API 2第十一課——在Web API中使用Dependency Resolver

來源:互聯網
上載者:User

標籤:

前言

閱讀本文之前,您也可以到Asp.Net Web API 2 系列導航進行查看 http://www.cnblogs.com/aehyok/p/3446289.html

本文主要來介紹在Asp.Net Web API使用Web API的Decpendency Resolver在控制器中如何注入依賴。

本文使用VS2013。本文的範例程式碼下載連結為http://pan.baidu.com/s/1BvFTs

為什麼要使用Dependency Resolver

一個dependency 其實就是一個對象或者另外一個對象需要的一個介面。例如,在Asp.Net Web API 2第二課——CRUD操作 http://www.cnblogs.com/aehyok/p/3434578.html中,我們定義了一個ProductsController的類,這個類需要一個IProductRepository 的執行個體,這個實現看起來像這樣:

public class ProductsController : ApiController{    private static IProductRepository repository = new ProductRepository();    // Controller methods not shown.} 

這不是最好的設計,因為對於調用建立的ProductRepository 是通過在控制器中硬式編碼方式實現的。如果要使用IProductRepository的不同執行個體,我們將需要在ProductRepository中改變代碼。如果ProductsController不依賴於任何具體執行個體的IProductRepository那會是比較好的。

Dependency injection解決了這個問題。在Dependency injection中,對象是不會負責建立自己的依賴項的。相反,當你建立一個對象,注入這個依賴的時候是通過建構函式參數或者setter方法。

這裡是ProductsController中修改後的實現代碼:

public class ProductsController : ApiController{    private readonly IProductRepository repository;    public ProductsController(IProductRepository repository)    {        if (repository == null)        {            throw new ArgumentNullException("repository");        }        this.repository = repository;    }

這樣是比較好的。現在可以切換到另外一個IProductRepository 的執行個體,而不用觸及到ProductsController的實現。

但是,在Asp.Net Web API中,你不能直接的建立一個控制器。相反,這個架構給你建立一個控制器,而且它並不知道IProductRepository 的相關資訊。這個架構也只能通過調用無參數的建構函式來建立你的控制器。

就在這個時候dependency resolver來了。dependency resolver的工作就是建立這個架構所需要的對象,包含congtrollers對象。通過提供一個自訂的dependency resolver,你可以代表架構來建立控制器執行個體。

一個簡單的dependency resolver

 下面的代碼展示了一個簡單的dependency resolver。這個代碼主要只是展示了在Web API中依賴注入如何工作的。之後,我們將看到怎樣來合并一個Ioc的容器。

class SimpleContainer : IDependencyResolver{    static readonly IProductRepository respository = new ProductRepository();    public IDependencyScope BeginScope()    {        // This example does not support child scopes, so we simply return ‘this‘.        return this;     }    public object GetService(Type serviceType)    {        if (serviceType == typeof(ProductsController))        {            return new ProductsController(respository);        }        else        {            return null;        }    }    public IEnumerable<object> GetServices(Type serviceType)    {        return new List<object>();    }    public void Dispose()    {        // When BeginScope returns ‘this‘, the Dispose method must be a no-op.    }}

一個 dependency resolver實現了這個IDependencyResolver 介面。這個IDependencyResolver  介面繼承了另外的兩個介面IDependencyScope 、IDisposable。

namespace System.Web.Http.Dependencies{    public interface IDependencyResolver : IDependencyScope, IDisposable    {        IDependencyScope BeginScope();    }    public interface IDependencyScope : IDisposable    {        object GetService(Type serviceType);        IEnumerable<object> GetServices(Type serviceType);    }}

IDependencyScope 介面定義了兩個方法:

  • GetService: 建立一個指定類型的執行個體
  • GetServices: 建立一個指定類型的集合對象

對於控制器,這個架構調用 GetService來獲得控制器的單個執行個體。這就是我們簡單的容器建立控制器和注入repository

對於你的dependency resolver不處理的任何類型,GetService 會返回null,GetServices 也會返回一個空的集合對象,尤其是,別拋出一個未知類型的異常。

這個IDependencyResolver 介面繼承了IDependencyScope ,添加了一個方法:

  • BeginScope: 建立一個嵌套的範圍

之後,我們將來討論嵌套的範圍內如何來管理我們對象的生命週期。現在,BeginScope 方法的實現我們簡單的返回一個this。

Setting the Dependency Resolver

現在在Web API全域設定物件中來設定Dependency Resolver。

主要是在Global.asax這個檔案當中。然後在Application_Start 方法中,將GlobalConfiguration.Configuration.DependencyResolver設定為你的Dependency Reslover。

public class WebApiApplication : System.Web.HttpApplication{    void ConfigureApi(HttpConfiguration config)    {        config.DependencyResolver = new SimpleContainer();    }    protected void Application_Start()    {        ConfigureApi(GlobalConfiguration.Configuration);        // ...    }}

 那麼現在你可以正常運行程式了。

範圍和對象聲明周期

控制器被建立的每個請求。為了協助管理對象的聲明周期,IDependencyResolver 使用了IDisposable介面。被添加到HttpConfiguration 上的dependency resolver對象擁有全域的範圍。當架構建立一個新的控制器執行個體的時候,它調用IDependencyResolver.BeginScope。這個方法返回一個IDependencyScope 。這個架構在IDependencyScope 上調用GetService 去獲得這個控制器。當架構處理完這個請求的時候,它在子範圍中調用Dispose 。你能通過Dispose 方法來釋放控制器的依賴。

Dependency Injection with IoC Containers

一個Ioc容器就是一個軟體組件,它負責建立依賴。Ioc容器為依賴注入提供公用的架構。如果你使用一個Ioc容器,你不需要在代碼中直接連同對象,幾個開源的.Net Ioc容器是可以利用的,例如Autofac, Castle Windsor, Ninject, Spring.NET, StructureMap 等等。

下面的例子我們來使用Unity,這個Ioc容器是由Microsoft patterns & practices開發的。

namespace ProductStore{    using System;    using System.Collections.Generic;    using System.Web.Http;    using System.Web.Http.Dependencies;    using Microsoft.Practices.Unity;    class ScopeContainer : IDependencyScope    {        protected IUnityContainer container;        public ScopeContainer(IUnityContainer container)        {            if (container == null)            {                throw new ArgumentNullException("container");            }            this.container = container;        }        public object GetService(Type serviceType)        {            if (container.IsRegistered(serviceType))            {                return container.Resolve(serviceType);            }            else            {                return null;            }        }        public IEnumerable<object> GetServices(Type serviceType)        {            if (container.IsRegistered(serviceType))            {                return container.ResolveAll(serviceType);            }            else            {                return new List<object>();            }        }        public void Dispose()        {            container.Dispose();        }    }    class IoCContainer : ScopeContainer, IDependencyResolver    {        public IoCContainer(IUnityContainer container)            : base(container)        {        }        public IDependencyScope BeginScope()        {            var child = container.CreateChildContainer();            return new ScopeContainer(child);        }    }}

這個ScopeContainer 類實現了IDependencyScope 代表了一個子範圍。這個IoCContainer 類實現了全域範圍內的依賴解析。並在BeginScope 方法中建立一個新的ScopeContainer對象。這個Unity 容器也有一個子容器的概念。因為我們可以用Unity 的子容器來初始化ScopeContainer 。這個ScopeContainer.Dispose方法釋放了Unity的子容器。

下面的代碼用Unity註冊了controller和repository,然後設定Dependency resolver.

void ConfigureApi(HttpConfiguration config){    var unity = new UnityContainer();    unity.RegisterType<ProductsController>();    unity.RegisterType<IProductRepository, ProductRepository>(        new HierarchicalLifetimeManager());    config.DependencyResolver = new IoCContainer(unity);}

每次HTTP請求的時候Web API 控制器被建立,然後請求被處理之後控制器被釋放。

現在同樣可以運行了。

總結

 對依賴注入的研究,還沒有那麼深入,只知道簡單的怎麼用。

對於文中

    public IDependencyScope BeginScope()    {        // This example does not support child scopes, so we simply return ‘this‘.        return this;     }

如果不適用this,那麼其他還可以使用什麼,還有待進一步的深入。之後自己還要對依賴Unity的依賴注入進行研究。不過感覺好像沒MEF那麼好用。

本文的參考連結為http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

本文以同步到Web API系列導航中 http://www.cnblogs.com/aehyok/p/3446289.html

本文的範例程式碼下載連結為http://pan.baidu.com/s/1BvFTs

Asp.Net Web API 2第十一課——在Web API中使用Dependency Resolver

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.