IoC在ASP.NET Web API中的應用

來源:互聯網
上載者:User

標籤:play   activator   cheng   ddd   contains   tab   官網   from   turn   

參考頁面:

http://www.yuanjiaocheng.net/webapi/create-crud-api-1-get.html

http://www.yuanjiaocheng.net/webapi/create-crud-api-1-post.html

http://www.yuanjiaocheng.net/webapi/create-crud-api-1-put.html

http://www.yuanjiaocheng.net/webapi/create-crud-api-1-delete.html

http://www.yuanjiaocheng.net/webapi/Consume-web-api.html

控制反轉(Inversion of Control,IoC),簡單地說,就是應用本身不負責依賴對象的建立和維護,而交給一個外部容器來負責。這樣控制權就由應用轉移到了外部IoC容器,控制權就實現了所謂的反轉。比如在類型A中需要使用類型B的執行個體,而B執行個體的建立並不由A來負責,而是通過外部容器來建立。通過IoC的方式實現針對目標HttpController的啟用具有重要的意義。[本文已經同步到《How ASP.NET Web API Works?》]

一、 基於IoC的HttpControllerActivator

將IoC應用於HttpController啟用系統的目的在於讓一個預定義的IoC容器來提供最終的HttpController對象。通過《ASP.NET Web API的Controller是如何被建立的?》的介紹我們知道HttpController的啟用最終由HttpControllerActivator對象來完成,所以將IoC與ASP.NET Web API的HttpController啟用系統進行整合最為直接的方式莫過於自訂一個HttpControllerActivator。

我們通過一個簡單一實例來示範如何通過自訂HttpControllerActivator的方式實現與IoC的整合,我們採用的IoC架構是Unity。我們在一個ASP.NET Web API應用中定義了這個UnityHttpControllerActivator類型。UnityHttpControllerActivator具有一個表示Unity容器的屬性UnityContainer,該屬性在建構函式中被初始化。在用於建立的HttpController的Create方法中,我們調用此UnityContainer對象的Resolve方法建立目標HttpController對象。

   1: public class UnityHttpControllerActivator : IHttpControllerActivator
   2: {
   3:     public IUnityContainer UnityContainer { get; private set; }
   4:  
   5:     public UnityHttpControllerActivator(IUnityContainer unityContainer)
   6:     {        
   7:         this.UnityContainer = unityContainer;
   8:     }
   9:  
  10:     public  IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
  11:     {
  12:         return (IHttpController)this.UnityContainer.Resolve(controllerType);
  13:     }
  14: }

接下來我們定義了如下一個繼承自ApiController的ContactsController來管理連絡人資訊。簡單起見,我們只定義了唯一的Action方法Get用於擷取連絡人資訊。該方法具有一個可預設的參數id表示希望擷取的連絡人的ID,如果沒有提供此參數則返回所有連絡人列表。

   1: public class ContactsController : ApiController
   2: {
   3:     public IContactRepository Repository { get; private set; }
   4:     public ContactsController(IContactRepository repository)
   5:     {
   6:         this.Repository = repository;
   7:     }
   8:     public IEnumerable<Contact> Get(string id = "")
   9:     {
  10:         return this.Repository.GetContacts(contact => 
  11:             string.IsNullOrEmpty(id) || id == contact.Id);
  12:     }
  13: }
  14:  
  15: public class Contact
  16: {
  17:     public string Id { get; set; }
  18:     public string Name { get; set; }
  19:     public string PhoneNo { get; set; }
  20:     public string EmailAddress { get; set; }
  21:     public string Address { get; set; }
  22: }

Action方法利用Repository屬性返回的對象來實施連絡人的查詢工作,這個IContactRepository介面類型的屬性在建構函式中初始化。我們利用IContactRepository介面來抽象對連絡人資料的儲存,如下面的代碼片斷所示,我們在此介面中僅定義了唯一的GetContacts方法根據指定的添加來篩選對應的連絡人清單。

   1: public interface IContactRepository
   2: {
   3:     IEnumerable<Contact> GetContacts(Predicate<Contact> predicate);
   4: }

我們定義了如下一個DefaultContactRepository類型作為IContactRepository介面的預設實現者,簡單起見,我們採用一個靜態字典來儲存連絡人清單。

   1: public class DefaultContactRepository : IContactRepository
   2: {
   3:     private static List<Contact> contacts = new List<Contact>
   4:     {
   5:         new Contact{ Id="001", Name = "張三",  PhoneNo="123", EmailAddress = "[email protected]"},
   6:         new Contact{ Id="002", Name = "李四",  PhoneNo="456",EmailAddress = "[email protected]"}
   7:     };
   8:  
   9:     public IEnumerable<Contact> GetContacts(Predicate<Contact> predicate)
  10:     {
  11:         return contacts.Where(contact=>predicate(contact));
  12:     }
  13: }

我們在Global.asax中對自訂的UnityHttpControllerActivator進行了註冊。如下面的代碼片斷所示,我們在Application_Start方法中建立了一個UnityContainer對象,並通過調用泛型方法RegisterType<TFrom,TTo>註冊了IContactRepository介面和DefaultContactRepository類型之間的匹配關係。我們最後根據這個UnityContainer建立一個UnityHttpControllerActivator對象,並將其註冊到當前ServicesContainer上。

   1: public class WebApiApplication: System.Web.HttpApplication
   2: {
   3:     protected void Application_Start()
   4:     {
   5:         //其他動作
   6:         IUnityContainer unityContainer = new UnityContainer();
   7:         unityContainer.RegisterType<IContactRepository,   DefaultContactRepository>(); 
   8:         GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new UnityHttpControllerActivator(unityContainer));
   9:     }
  10: }

當此ASP.NET Web API應用運行之後,我們可以直接在瀏覽器中輸入相應的地址擷取所有連絡人列表(“/api/contacts”)和針對某個ID為“001”(“/api/contacts/001”)的連絡人資訊,相應的連絡人資訊會以如所示的形式出現在瀏覽器上。

二、基於IoC的DependencyResolver

由於預設的DefaultHttpControllerActivator會先利用當前註冊的DependencyResolver對象去啟用目標HttpController,所以除了利用自訂的HttpControllerActivator將IoC引入HttpController啟用系統之外,另一個有效方案就是註冊自訂的DependencyResolver。

接下來將要自訂的DependencyResolver基於另一個叫作“Ninject”的IoC架構。較之Unity,Ninject是一個更加輕量級的IoC架構。篇幅所限,我們不便對這個IoC架構作過多的介紹,有興趣的讀者可以訪問其官網(“http://www.ninject.org/”)瞭解Ninject。

   1: public class NinjectDependencyResolver : IDependencyResolver
   2: {
   3:     private List<IDisposable> disposableServices = new List<IDisposable>();
   4:     public IKernel Kernel { get; private set; }
   5:  
   6:     public NinjectDependencyResolver(NinjectDependencyResolver parent)
   7:     {
   8:         this.Kernel = parent.Kernel;
   9: }
  10:  
  11:     public NinjectDependencyResolver()
  12:     {
  13:         this.Kernel = new StandardKernel();
  14:     }
  15:  
  16:     public void Register<TFrom, TTo>() where TTo : TFrom
  17:     {
  18:         this.Kernel.Bind<TFrom>().To<TTo>();
  19: }
  20:  
  21:     public IDependencyScope BeginScope()
  22:     {
  23:         return new NinjectDependencyResolver(this);
  24:     }
  25:  
  26:     public object GetService(Type serviceType)
  27:     {
  28:         return this.Kernel.TryGet(serviceType);
  29:     }
  30:  
  31:     public IEnumerable<object> GetServices(Type serviceType)
  32:     {
  33:         foreach (var service in this.Kernel.GetAll(serviceType))
  34:         {
  35:             this.AddDisposableService(service);
  36:             yield return service;
  37:         }
  38: }    
  39:  
  40:     public void Dispose()
  41:     {
  42:         foreach (IDisposable disposable in disposableServices)
  43:         {
  44:             disposable.Dispose();
  45:         }
  46: }
  47:  
  48:     private void AddDisposableService(object servie)
  49:     {
  50:         IDisposable disposable = servie as IDisposable;
  51:         if (null != disposable && !disposableServices.Contains(disposable))
  52:         {
  53:             disposableServices.Add(disposable);
  54:         }
  55:     }
  56: }

我們建立了如上一個類型為NinjectDependencyResolver的自訂DependencyResolver。NinjectDependencyResolver的核心是類型為IKernel的唯讀屬性Kernel,用於擷取服務執行個體的GetService和GetServices方法分別通過調用此Kernel屬性的TryGet和GetAll方法來實現。BeginScope方法返回一個新的NinjectDependencyResolver對象,它與自身擁有同一個Kernel對象。我們定義了額外的方法Register<TFrom,TTo>來註冊介面與實作類別型之間的映射關係。為了確保擷取的服務執行個體能夠被正常地釋放,我們定義了一個元素類型為IDisposable的列表。如果擷取的對象實現了IDisposable介面,它會被放入這個列表中,我們在實現的Dispose方法中釋放該列表中的所有對象。

現在我們將這個自訂的NinjectDependencyResolver應用到上一個示範執行個體中。我們只需要將Global.asax中針對自訂HttpControllerActivator的註冊替換成針對NinjectDependencyResolver的註冊即可。運行此ASP.NET Web API應用後通過瀏覽器試圖擷取連絡人資訊,我們依然會得到如所示的結果。

   1: public class MvcApplication : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start()
   4:     {
   5:         //其他動作
   6:         NinjectDependencyResolver dependencyResolver = new NinjectDependencyResolver();
   7:         dependencyResolver.Register<IContactRepository, DefaultContactRepository>();
   8:         GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver; 
   9:     }
  10: }

IoC在ASP.NET Web API中的應用

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.