2

我开发了一个小型测试系统来了解 NServiceBus。测试项目中的类取自使用 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 属性为空,即没有注入 IBus 实例。但是,NinjectBuilder (NServiceBus.ObjectBuilder.Ninject) 的文档明确指出,对 NinjectBuilder 的调用将向 IoC 注册一个 IBus 实例,即 Ninject。由于情况似乎并非如此,我怀疑我一定忽略了一些东西。

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

4

2 回答 2

1

问题是您没有使用 Ninject.Extension.WCF 来创建服务主机。您可以通过添加自己的自定义依赖项并声明为属性来验证这一点。即使使用 InjectAttribute 它也将始终为空,因为您正在自己实例化服务主机并且只需注册服务类型。为了让 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 对象构建器具有特殊的启发式方法,它允许进行属性注入而无需声明注入属性。这是为了方便而添加的,因为大多数 NSB 示例使用属性注入而没有任何自定义容器声明。我们认为 Ninject 也必须与 NSB 一起支持。

于 2013-04-17T21:47:00.547 回答
0

虽然您Bus在命令上有一个属性,但它没有 [Inject] 属性。OOTB Ninject 不会注入没有此类标记的属性(但 Windsor 会注入(根据我对http://manning.com/seemann中有关它的章节的粗略记忆(这是必读的)))


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

要诊断 Ninject 是否真的被用于创建服务,最好添加一个 ctor 并在其上放置断点并查看调用者是否是 Ninject。实现相同目的的另一种方法是实现IActivation(或者称为 IStart)。或者OnActivation在您的Configure.

于 2013-04-17T21:07:33.187 回答