在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

原文地址:https://www.cnblogs.com/ShadowLoki/p/2833661.html