Использование расширения Ninject WCF с веб-службой WCF
У меня есть веб-служба WCF, в которой я хочу использовать свои репозитории и службы, которые я хочу использовать для ввода в мой веб-сервис WCF, однако пример расширения Ninject WCF в значительной степени имеет ctor, который создает экземпляр каждой зависимости, чего я не хочу, мне нужна более простая инъекция зависимостей.
Кто-нибудь имел какие-либо успехи в использовании Ninject с WCF, Google, похоже, не дает мало релевантных результатов для тем, которые я ищу.
Ответы
Ответ 1
Код для TimeService имеет:
<%@ ServiceHost Language="C#" Debug="true" Service="WcfTimeService.TimeService" CodeBehind="TimeService.svc.cs" **Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory"** %>
bastard injection ctors путают вопрос - Ninject выберет наиболее специфический конструктор. Общая проблема с образцом заключается в том, что он охватывает все базы (IIS Hosted, EXE Hosted, Service Hosted), а WCF точно не делает все это простое управление (@Ian Davis: я мог бы легко ошибаться, можете ли вы предоставить более подробно, пожалуйста, возможно, в виде резюме того, что примеры иллюстрируют в README, и, возможно, более подробно о том, почему в различных случаях, когда вы использовали BI?)
Ответ 2
Способ, которым я в настоящее время использую Ninject (v3) с моим WCF, основан на расширении Ninject WCF и Pieter De Rycke отличный пост в блоге.
Вкратце, вот что я делаю:
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 с помощью Pieter De Rycke:
<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 остается в течение всего времени запроса.