【问题标题】:Using Ninject WCF Extension with WCF Web Service将 Ninject WCF 扩展与 WCF Web 服务一起使用
【发布时间】:2011-03-28 20:52:06
【问题描述】:

我有一个 WCF Web 服务,我想在其中使用我希望依赖注入到我的 WCF Web 服务中的存储库和服务,但是 Ninject WCF 扩展示例几乎有一个 ctor,它正在实例化每个依赖项的实例,我不想要,我想要一个更纯粹的依赖注入。

是否有人在将 Ninject 与 WCF 结合使用方面取得了任何成功,Google 似乎对我正在寻找的主题返回的相关结果很少。

【问题讨论】:

    标签: wcf dependency-injection ninject


    【解决方案1】:

    TimeService 后面的代码有:

    <%@ ServiceHost Language="C#" Debug="true" Service="WcfTimeService.TimeService" CodeBehind="TimeService.svc.cs" **Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory"** %>
    

    bastard injection ctor 混淆了问题 - Ninject 将选择最具体的构造函数。该示例的一般问题是它涵盖了所有基础(IIS 托管、EXE 托管、服务托管),而 WCF 也不能完全使所有这些东西易于管理(@Ian Davis:我很容易出错,你能提供请提供更详细的信息,也许是以自述文件中示例说明的摘要的形式,也许更详细地说明您使用 BI 的各种案例的原因?)

    【讨论】:

      【解决方案2】:

      我目前在 WCF 中使用 Ninject (v3) 的方式是基于 Ninject WCF 扩展和Pieter De Rycke's great blog post

      简而言之,这就是我正在做的事情:

      1) 通过 NuGet,我在我的 WCF 项目中添加了对 Ninject.Extensions.Wcf 的引用。这将使用 NinjectWebCommon.cs 创建 App_Start 文件夹,该文件夹负责初始化 Ninject。

      2) 通常,您会在 NinjectWebCommon.cs 的 CreateKernel 方法中设置 Ninject 映射。但是,由于我在同一解决方案中有一个 MVC3 站点,并且希望该站点具有相同的 Ninject 映射,因此我的 CreateKernel 如下所示:

          private static IKernel CreateKernel()
          {
              var kernel = new StandardKernel();
              kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
              kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
      
              InfrastructureSetup.RegisterServices(kernel);
              return kernel;
          }
      

      3) 在 InfrastructureSetup.RegisterServices 中,我有我的 Ninject 映射:

      public static class InfrastructureSetup
      {
          public static void RegisterServices(IKernel kernel)
          {
              kernel.Bind<IRepositoryContext>().To<MyEntityFrameworkContext>().InRequestScope();
              kernel.Bind<IFooRepository>().To<FooRepository>().InRequestScope();
              kernel.Bind<IBarRepository>().To<BarRepository>().InRequestScope();
      
              // ... and so on. I want InRequestScope() for the EF context, since
              // otherwise my repositories (which take IRepositoryContext in their 
              // constructors) end up getting different EF contexts, messing things up
          }
      }
      

      4) 我还想向我的 WCF 构造函数注入一些东西(IFooService 等),所以我根据 Pieter De Rycke 的建议编辑了 WCF 项目的 Web.config:

          <behaviors>
              <serviceBehaviors>
                  <behavior name="">
                      <serviceMetadata httpGetEnabled="true" />
                      <serviceDebug includeExceptionDetailInFaults="false" />
                      <!-- Add the Ninject behavior to the WCF service. This is needed to support dependency injection to the WCF constructors -->
                      <ninject />
                  </behavior>
              </serviceBehaviors>
          </behaviors>
        <extensions>
          <behaviorExtensions>
            <!-- Add the Ninject behavior extension -->
            <add name="ninject"
              type="MyWCFProject.Infrastructure.NinjectBehaviorExtensionElement, MyWCFProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          </behaviorExtensions>
        </extensions>
      

      5) 在 MyWCFProject.Infrastructure 命名空间中,我有三个基本上是从 Pieter 复制粘贴的文件:

      NinjectBehaviorAttribute.cs:

      using System;
      using System.Collections.ObjectModel;
      using System.ServiceModel;
      using System.ServiceModel.Channels;
      using System.ServiceModel.Description;
      using System.ServiceModel.Dispatcher;
      using Ninject.Web.Common;
      
      namespace MyWCFProject.Infrastructure
      {
      public class NinjectBehaviorAttribute : Attribute, IServiceBehavior
      {
          public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
              Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
          {
          }
      
          public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
          {   
              Type serviceType = serviceDescription.ServiceType;
      
              // Set up Ninject to support injecting to WCF constructors
              var kernel = new Bootstrapper().Kernel;
              IInstanceProvider instanceProvider = new NinjectInstanceProvider(kernel, serviceType);
      
              foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
              {
                  foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
                  {
                      DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
                      dispatchRuntime.InstanceProvider = instanceProvider;
                  }
              }
          }
      
          public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
          {
          }
      }
      }
      

      NinjectBehaviorExtensionElement.cs:

      using System;
      using System.ServiceModel.Configuration;
      
      namespace MyWCFProject.Infrastructure
      {
          public class NinjectBehaviorExtensionElement : BehaviorExtensionElement
          {
              public override Type BehaviorType
              {
                  get { return typeof(NinjectBehaviorAttribute); }
              }
      
              protected override object CreateBehavior()
              {
                  return new NinjectBehaviorAttribute();
              }
          }
      }
      

      NinjectInstanceProvider.cs:

      using System;
      using System.ServiceModel;
      using System.ServiceModel.Channels;
      using System.ServiceModel.Dispatcher;
      using Ninject;
      
      namespace MyWCFProject.Infrastructure
      {
          public class NinjectInstanceProvider : IInstanceProvider
          {
              private Type serviceType;
              private IKernel kernel;
      
              public NinjectInstanceProvider(IKernel kernel, Type serviceType)
              {
                  this.kernel = kernel;
                  this.serviceType = serviceType;
              }
      
              public object GetInstance(InstanceContext instanceContext)
              {
                  return this.GetInstance(instanceContext, null);
              }
      
              public object GetInstance(InstanceContext instanceContext, Message message)
              {
                  return kernel.Get(this.serviceType);
              }
      
              public void ReleaseInstance(InstanceContext instanceContext, object instance)
              {
              }
          }
      }
      

      目前,这个解决方案似乎运作良好;依赖注入对 WCF 和 MVC3 站点都有效,我可以请求将依赖项注入到 WCF 构造函数中,并且 EF 上下文在请求期间保持不变。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-15
        • 1970-01-01
        • 2011-12-26
        • 2011-01-08
        • 2013-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多