Использование расширения Ninject WCF с веб-службой WCF - PullRequest
11 голосов
/ 12 августа 2010

У меня есть веб-сервис WCF, в котором я хочу использовать свои репозитории и сервисы, которые я хочу внедрить в мой веб-сервис зависимостей, однако пример Ninject WCF Extension в значительной степени имеет ctor, который создает экземпляр каждой зависимости, чего я не хочу, я хотел бы получить более чистую инъекцию зависимостей.

Если у кого-нибудь был какой-либо успех с использованием Ninject с WCF, Google, похоже, возвращает мало релевантных результатов для тем, которые я ищу.

Ответы [ 2 ]

8 голосов
/ 13 августа 2010

Код для TimeService имеет:

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

Коды ублюдка вводят в заблуждение дело - Ninject выберет самый конкретный конструктор.Общая проблема с этим примером состоит в том, что он охватывает все базы (IIS Hosted, EXE hosted, Service Hosted), и WCF точно не делает все эти вещи простыми в управлении (@Ian Davis: я могу ошибаться, можете ли вы предоставитьпожалуйста, более подробно, возможно, в форме краткого изложения того, что примеры иллюстрируют в README, и, возможно, более подробно, почему в различных случаях, когда вы использовали BI?)

2 голосов
/ 31 июля 2012

То, как я сейчас использую Ninject (v3) с моим WCF, основано на расширении Ninject WCF и Великолепном сообщении в блоге Питера Де Райке .

В двух словах, вот что яделаю:

1) Через NuGet я добавил ссылку на Ninject.Extensions.Wcf в мой проект WCF.Это создает папку App_Start с NinjectWebCommon.cs, которая заботится об инициализации Ninject.

2) Как правило, вы устанавливаете свои сопоставления Ninject в методе CreateKernel в NinjectWebCommon.cs.Тем не менее, поскольку у меня есть сайт 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) Я также хочу добавить материал (IFooService и т. Д.) В мои конструкторы WCF, поэтому я отредактировал файл Web.config для проекта WCF по совету Питера де Райке:

    <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 остается неизменным на время запроса.

...