Wcf Ninject 3.0.0和NServiceBus 3.3.0注入问题
我开发了一个小型测试系统来了解NServiceBus。testproject中的类来自使用Castle.Windsor进行依赖注入的生产系统 除了Ninject和NServiceBus组件外,testproject还引用了:Wcf Ninject 3.0.0和NServiceBus 3.3.0注入问题,wcf,ninject,nservicebus,Wcf,Ninject,Nservicebus,我开发了一个小型测试系统来了解NServiceBus。testproject中的类来自使用Castle.Windsor进行依赖注入的生产系统 除了Ninject和NServiceBus组件外,testproject还引用了: Ninject.Extensions.ContextPreservation 3.0.0.0 Ninject.Extensions.Conventions 3.0.0.0 Ninject.Extensions.NamedScope 3.0.0.0 Ninject.Exten
Ninject.Extensions.ContextPreservation 3.0.0.0
Ninject.Extensions.Conventions 3.0.0.0
Ninject.Extensions.NamedScope 3.0.0.0
Ninject.Extensions.Wcf 3.0.0.0
Ninject.Web.Common 3.0.0.0
NServiceBus.ObjectBuilder.Ninject 3.3.0.0
这是NServiceBus端点配置:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
private IKernel _kernel;
public void Init()
{
_kernel = new StandardKernel(new EndpointModule());
Configure.With()
.NinjectBuilder(_kernel)
.Log4Net()
.XmlSerializer();
}
}
EndpointModule定义为:
public class EndpointModule : NinjectModule
{
public override void Load()
{
Kernel.Bind(x => x.FromThisAssembly().SelectAllTypes().InheritedFrom<IWcfGatewayService>().BindToSelf().Configure(c => c.InTransientScope()));
}
}
下面是引导程序:
public class WcfServiceBootstrapper : IWantToRunAtStartup
{
private readonly List<ServiceHostBase> _hosts = new List<ServiceHostBase>();
public void Run()
{
var serviceTypes = GetType().Assembly.GetTypes().Where(t => typeof(IWcfGatewayService).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface).ToList();
foreach (var host in from serviceType in serviceTypes let baseAddress = new[] { new Uri(string.Format("http://localhost:8778/omjykonservices/{0}", serviceType.Name)) } select new ServiceHost(serviceType, baseAddress))
{
_hosts.Add(host);
var serviceMetadataBehaviour = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
MetadataExporter = {PolicyVersion = PolicyVersion.Policy15}
};
host.Description.Behaviors.Add(serviceMetadataBehaviour);
host.Open();
}
}
public void Stop()
{
foreach (var host in _hosts.Where(host => host != null))
{
host.Close();
}
_hosts.Clear();
}
}
公共类WcfServiceBootstrapper:iwanttorunatstart
{
私有只读列表_hosts=new List();
公开募捐
{
var serviceTypes=GetType().Assembly.GetTypes().Where(t=>typeof(IWcfGatewayService).IsAssignableFrom(t)&&&!t.IsAbstract&&!t.IsInterface).ToList();
foreach(从serviceTypes中的serviceType中的var host)让baseAddress=new[]{newURI(string.Format(“http://localhost:8778/omjykonservices/{0},serviceType.Name))}选择新的ServiceHost(serviceType,baseAddress))
{
_hosts.Add(主机);
var serviceMataDatabehaviour=新serviceMataDatabehavior
{
HttpGetEnabled=true,
MetadataExporter={PolicyVersion=PolicyVersion.Policy15}
};
host.Description.Behaviors.Add(serviceMetadataBehaviour);
host.Open();
}
}
公共停车场()
{
foreach(var host in_hosts.Where(host=>host!=null))
{
host.Close();
}
_hosts.Clear();
}
}
我遇到的问题是,当调用Process方法(在WcfGatewayService中)时,它会失败,因为总线属性为null,即没有注入IBus实例。但是,NinjectBuilder的文档(NServiceBus.ObjectBuilder.Ninject)明确指出,对NinjectBuilder的调用将向IoC注册一个IBus实例,即Ninject。既然情况似乎并非如此,我怀疑我一定忽略了什么
有没有人有过这种设置的经验?关于为什么总线属性没有获得IBus注入实例的任何建议?当命令上有
Bus
属性时,它没有[Inject]属性。OOTB Ninject不会在没有这样标记的情况下注入到属性中(但Windsor会这样做(根据我粗略的记忆,在中阅读了关于它的章节(这是必读)))
如果这不是问题所在,您会发现一些好的老式调试每次都会击败SO或邮件列表:-
要诊断Ninject是否实际用于创建服务,最好添加一个ctor并在其上粘贴一个断点,然后查看调用方是否是Ninject。实现同样目标的另一种方法是实现
IActivation
(或者称为IStart)。或者在您的配置中添加OnActivation
子句。问题是您没有使用Ninject.Extension.WCF创建服务主机。您可以通过添加自己的自定义依赖项并声明为属性来验证这一点。即使使用InjectAttribute,它也将始终为null,因为您自己正在实例化服务主机,只需注册服务类型。为了让ninject magic工作,您需要使用ninject.Extension.WCF提供的机制创建主机。例如,请参见:
var yourServiceConfiguration=NinjectWcfConfiguration.Create();
var selfHost=new NinjectSelfHostBootstrapper(
内核
您的服务配置);
selfHost.Start();
然后你可以在公共汽车停下来的时候停车。Ruben的回答是正确的,通常在使用ninject的属性注入时,您必须声明属性上的InjeAttribute。但是用于nservicebus的ninject对象生成器有一种特殊的启发式方法,它允许进行属性注入,而无需声明注入属性。这是为了方便而添加的,因为大多数NSB示例使用属性注入,而没有任何自定义容器声明。我们认为Ninject和NSB也必须支持这一点。我很好奇为什么您不使用Windsor作为NServiceBus的容器,因为(正如您所说)其他所有东西都已经在使用它了。原因是我已经在很多其他项目中使用Ninject,坦率地说,我非常喜欢它,因此,我决定将其与实验NServiceBus结合使用,我碰巧也喜欢:-)我们可以(面对面)讨论这个问题,例如,如果你愿意,明天;-)你能快点试试构造函数注入吗?它能工作吗?还是有激活异常?丹尼尔,鲁本,谢谢你的回答。我编辑了最初的帖子,因为我遗漏了一个重要的部分,我认为这会阻止构造函数注入。类WcfServiceBootstrapperI我已经尝试在总线属性上使用[Inject]了,但没有成功。鲁本,丹尼尔。可能是在WcfServiceBootstrapper中创建ServiceHosts的方式与此问题有关吗?@norgie我知道如果Ninject正在创建,并且该属性有一个[Inject]
,它应该可以工作。如果每个服务都有一个.svc文件,则需要将其指向Ninject工厂类以实现这一点。如果没有,你需要找出谁在做新的,并与之讨论确保它要求DI容器来做。Hy ruben,这一次你是不对的。ninject生成器注册了一个特殊的启发式,它不需要注入attribute@DanielMarbach酷-我已经习惯了:)现在我们只需要知道为什么/如果Ninject(在.svc文件点中引用我的工厂)谢谢Daniel。我短路Ninject的原因是,我拥有的Wcf扩展版本只支持http,在运行时由NServiceBus托管时会引发异常,如本示例应用程序中所示。所以我忽略了Ninject中Wcf有一个自托管选项的事实。
public class PlaceOrderCommandService : WcfGatewayService<PlaceOrderCommand>, IPlaceOrderCommandService
{}
[ServiceContract]
public interface IPlaceOrderCommandService
{
[OperationContract(Action = "http://tempuri.org/IPlaceOrderCommandService/Process", ReplyAction = "http://tempuri.org/IPlaceOrderCommandService/ProcessResponse")]
ResponseCode Process(PlaceOrderCommand command);
}
public class WcfServiceBootstrapper : IWantToRunAtStartup
{
private readonly List<ServiceHostBase> _hosts = new List<ServiceHostBase>();
public void Run()
{
var serviceTypes = GetType().Assembly.GetTypes().Where(t => typeof(IWcfGatewayService).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface).ToList();
foreach (var host in from serviceType in serviceTypes let baseAddress = new[] { new Uri(string.Format("http://localhost:8778/omjykonservices/{0}", serviceType.Name)) } select new ServiceHost(serviceType, baseAddress))
{
_hosts.Add(host);
var serviceMetadataBehaviour = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
MetadataExporter = {PolicyVersion = PolicyVersion.Policy15}
};
host.Description.Behaviors.Add(serviceMetadataBehaviour);
host.Open();
}
}
public void Stop()
{
foreach (var host in _hosts.Where(host => host != null))
{
host.Close();
}
_hosts.Clear();
}
}
var yourServiceConfiguration = NinjectWcfConfiguration.Create<YourService, NinjectServiceSelfHostFactory>();
var selfHost = new NinjectSelfHostBootstrapper(
kernel,
yourServiceConfiguration );
selfHost.Start();