我有一个WCF Web服务,我想在其中使用我希望依赖注入我的WCF Web服务的存储库和服务,但Ninject WCF扩展示例几乎有一个ctor,它实例化每个依赖项的实例,我不想要,我想要一个更纯粹的依赖注入。
有没有人在使用Ninject和WCF取得任何成功,谷歌似乎对我正在寻找的主题没有多少相关结果。
答案 0 :(得分:8)
TimeService背后的代码有:
<%@ ServiceHost Language="C#" Debug="true" Service="WcfTimeService.TimeService" CodeBehind="TimeService.svc.cs" **Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory"** %>
bastard injection ctors混淆了这个问题--Ninject将选择最具体的构造函数。该示例的一般问题是它涵盖了所有基础(IIS托管,EXE托管,服务托管),WCF并不能完全使所有这些东西易于管理(@Ian Davis:我很容易出错,你能提供吗?请详细说明一下,或许可以以自述文件中示例的内容摘要的形式,以及为什么使用BI的各种情况的更详细信息?)
答案 1 :(得分: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上下文在请求期间保持不变。