在WCF中使用Ninject輕量級IOC框架 之 SOAP風格服務


最近學習MVC 看到很多文章都用了Ninject框架進行解耦,就考慮是否能用在平時寫的WCF服務中,因為畢竟目前還是總要寫服務的……蛋疼ing……

傳送門:

Ninject框架官網:

http://www.ninject.org/download.html

目前最新版本是3.0,另外需要下載WCF相關的擴展

 

Ninject 入門:

http://www.touchsunlight.com/coding/59.html

 

WCF 入門:

園子里找A大吧……

 

以下為正文,請大家耐心圍觀,不要高呼No Picture&Code You Say a JB…… 最后會提供DEMO下載

 

現在我們來看一個場景

我想服務有一個行為,可以返回一段字符串,我們可以直接定義這個服務行為如下

 

[ServiceContract]
public class MessageService
{ 
      [OperationContract] 
       public string GetMessage() 
      {
           return "Hello World";
      }
}

 

但是這樣不好,我不一定返回的就是Hello World這條消息,於是我們定義了一個接口,所有實現這個接口的類型都擁有返回消息的能力

public interface IMessageProvider
{
       string GetMessage();
}
public class DefaultMessageProvider:IMessageProvider
{
     public string GetMessage(){return "Hello World";}
}

在服務里這么用

[ServiceContract]
public class MessageService
{
      private IMessageProvider provider=null;

      public MessageService(IMessageProvider provider)
      {
             this.provider=provider
      }
 
      [OperationContract] 
       public string GetMessage() 
      {
           return provider.GetMessage()
      }
}

我們的想法是美好的,但現實是殘酷的,在對服務請求時,服務的實例,是由WCF管道創建的,我們無法手動new一個新的MessageService實例,也就代表我們無法通過構造函數向MessageService中注入IMessageProvider真正的實現類。

 

這時候,我們就要利用Ninject通過查找關系映射列表,自動創建合理的依賴項實例這個特性了。

 

這里簡單介紹下Ninject框架的幾個基本知識

 

Ninject 內核Kernel 是整個Ninject框架的主入口點,也是關系列表的容器。

我們可以通過IKernel kernel=new StandardKernel()來創建一個容器對象;

Kernel通過Bind<T>.To<T>語法建立接口與實例間的關系,例如:kernel.Bind<IMessageProvider>().To<DefaultMessageProvider>();

在建立接口與實現類之間的關系后,我們可以通過kenrel的Get<T>()方法來獲取正確的對象實例,例如:IMessageProvider provider= kernel.Get<IMessageProvider>();

這里我們獲取到的對象實例為DefaultMessageProvider的實例。

 

kernel對象在使用Get<T>()獲取類型的實例時,會檢查類型所有依賴項,並提供合理的值,我們看這個例子

public Interface IA
{
      void Todo();
}

public Interface IB
{
      void Todo();
}

Public Class A:IA
{
     public void Todo(){ // Todo}
}

public Class B:IB
{
      private IA a;
      
      public B(IA a)
      {
            this a = a;
      }

     public void Todo()
  {
          a.Todo();
  }
}


public static Class Program
{
         public static void Main()
          {
                  IKernel kernel=new StandardKernel();
                  kernel.Bind<IA>().To<A>();
                  kernel.Bind<IB>().To<B>();
                  
                  IB b=kernel.Get<IB>();
                  
                  b.Todo();
           }
}

在這個例子中IB的實現類,依賴於IA的實現,並且使用構造函數的方式進行了依賴注入。

我們通過kernel.Get<IB>()時,會查找並創建B類型的實例,同時檢查發現B類依賴於IA接口,NInject會繼續檢查關系列表中是否存在IA的映射,並創建合理的實例。

最終返回B類型的實例,並且通過構造函數注入實現IA接口的類型的實例。

 

現在,我們來看Ninject的一個擴展Ninject.Extensions.Wcf

 

Ninject.Extensions.Wcf命名空間下提供了多種NinjectServiceHost以及他們的NinjectServiceHost<T>泛型版本。

我們在創建宿主的時候,不需要手動的去new一個ServiceHost實例。

可以直接通過kernel.Get<NinjectServiceHost<服務類型>>();的方式直接獲取宿主。

並且在服務宿主創建的時候,會自動檢查所有依賴關系。

示例代碼:

public static class Program
{
          public static void Main()
         {
                  IKernel kernel=new StandardKernel();
                   
                  kernel.Bind<IMessageProvider>().To<DefaultMessageProvider>();

                  ServiceHost host=kernel.Get<NinjectServiceHost<MessageService>>();
                  
                  
          }
}

這樣我們在創建服務宿主的時候,就會關聯所有依賴了,也完美解決了之前遇到的問題。

這里再次提醒,NinjectServiceHost<T>中的T為服務類型,而非契約類型,即使在關系映射列表中添加了kenrel.Bind<契約>().To<服務>();也不行。

 

上邊這個例子應用於自托管服務。

 

還有一種服務的托管形式是IIS。

寄宿於IIS中的服務,就更簡單了。

只需要改變下Global父類為NinjectHttpApplication 位於Ninject.Web.Common命名空間下,提供一個全局的Kernel即可。

/// <summary>
    /// 這里要注意,實現NinjectHttpApplication
    /// </summary>
    public class Global : NinjectHttpApplication
    {
        protected override Ninject.IKernel CreateKernel()
        {
            //創建一個IOC容器,並且將服務管理模塊與內部接口映射模塊添加進去 
           
            return new StandardKernel(new ServiceModule(), new InternalModule());

            
        }
    }

在服務的.svc頁,需要聲明Factory為NinjectServiceHostFactory,代碼如下

DemoService.svc

<%@ ServiceHost Language="C#" Service="NinjectSOAP.Service.Services.DemoService"
    Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>

 

擴展閱讀:

Ninject.Extensions.Wcf命名空間提供的擴展方法InRequestScope() 表示了產生的對象實例,生命周期為每次Request時創建,響應/運行完畢回收

 

Ninject.Modules.NinjectModule 提供了依賴關系列表的模塊化管理 

 

 結語:

  這篇文章不可否認很爛,其實也沒什么好寫的,很多東西擴展插件已經封裝好了。

      但是在看老外的示例代碼時出了很多莫名其妙的問題,因此自己重新寫了一個DEMO,進行了整理和歸納。

      同時也希望為有興趣在WCF中使用Ninject框架的朋友提供一份資料      

      心理明白……說不出來……一切盡在代碼中吧

      附Demo下載:NinjectSOAP.rar

 


免責聲明!

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



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