Ninject 3.0.0和NServiceBus 3.3.0注入问题

时间:2013-04-17 11:16:48

标签: 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.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()));
    }
}

以下是实现IWcfGatewayService的类型示例:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
public abstract class WcfGatewayService<TCommand> : IWcfGatewayService where TCommand : ICommand
{
    public IBus Bus { get; set; }

    public ResponseCode Process(TCommand command)
    {
        try
        {
            Bus.SendLocal(command);
            return ResponseCode.Sent;
        }
        catch (Exception)
        {
            return ResponseCode.Failed;
        }
    }
}

这是实际服务的实现:

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();
    }
}

我遇到的问题是,当调用Process方法(在WcfGatewayService中)时,它失败,因为Bus属性为null,即没有注入IBus实例。但是,NinjectBuilder(NServiceBus.ObjectBuilder.Ninject)的文档明确指出,对NinjectBuilder的调用将向IoC注册IBus实例,即Ninject。由于情况似乎并非如此,我怀疑我一定忽视了一些事情。

有没有人有这种设置的经验?有关为什么Bus属性没有注入IBus实例的任何建议?

2 个答案:

答案 0 :(得分:1)

问题是您没有使用Ninject.Extension.WCF来创建服务主机。您可以通过添加自己的自定义依赖项并将其声明为属性来验证这一点。即使使用InjectAttribute,它也将始终为null,因为您自己实例化服务主机并只注册服务类型。为了让ninject魔法工作,您需要使用Ninject.Extension.WCF提供的机制创建主机。例如,见:

https://github.com/ninject/ninject.extensions.wcf/blob/master/src/Examples/WindowsTimeService/WindowsTimeService.cs

  var yourServiceConfiguration = NinjectWcfConfiguration.Create<YourService, NinjectServiceSelfHostFactory>();

  var selfHost = new NinjectSelfHostBootstrapper(
            kernel, 
            yourServiceConfiguration );
  selfHost.Start();

然后您可以在巴士关闭时停止它。通常在使用ninject属性注入时,Ruben在他的回答中是对的,你必须在属性上声明InjecAttribute。但是nservicebus的ninject对象构建器有一个特殊的启发式方法,它允许在不必声明inject属性的情况下进行属性注入。这是为了方便,因为大多数NSB示例使用属性注入而没有任何自定义容器声明。我们认为Ninject和NSB一起也必须支持。

答案 1 :(得分:0)

虽然命令中有Bus属性,但它上面没有[Inject]属性。 OOTB Ninject在没有这样的标记的情况下不会注入属性(但是Windsor确实如此(从我在http://manning.com/seemann中读取章节的粗略记忆(这是必需的阅读)))


如果这不是问题所在,你会发现一些好的老式调试每次都会击败SO或邮件列表: -

要诊断Ninject是否实际用于创建服务,添加ctor并在其上粘贴断点并查看调用者是否为Ninject是一个好主意。实现同样事情的另一种方法是实现IActivation(或称为IStart)。或者在OnActivation添加Configure条款。