通过NServiceBus 6和IBU的删除,是否有某种方法使域事件上下文不受影响?

通过NServiceBus 6和IBU的删除,是否有某种方法使域事件上下文不受影响?,nservicebus,domain-events,nservicebus6,Nservicebus,Domain Events,Nservicebus6,目前,我们在域事件处理程序中使用IBus接口(NServiceBus v5)将命令发送到后端服务进行处理,我正在努力解决这个问题。对于IBus,无论是在接收Web API请求时还是作为NServiceBus处理程序(公共域模型)的一部分,都可以发送这些命令,而不管是什么触发了事件。但是,在NServiceBusV6中,随着向特定于上下文的接口IEndpointInstance或IMessageHandlerContext的转变,我的域事件处理程序现在似乎需要具备上下文意识。而且,看起来IMess

目前,我们在域事件处理程序中使用IBus接口(NServiceBus v5)将命令发送到后端服务进行处理,我正在努力解决这个问题。对于IBus,无论是在接收Web API请求时还是作为NServiceBus处理程序(公共域模型)的一部分,都可以发送这些命令,而不管是什么触发了事件。但是,在NServiceBusV6中,随着向特定于上下文的接口IEndpointInstance或IMessageHandlerContext的转变,我的域事件处理程序现在似乎需要具备上下文意识。而且,看起来IMessageHandlerContext只能通过方法注入来使用,所以我可能必须在整个调用堆栈中使用这个参数

是否有一些我没有看到的方法可以让我的域事件处理程序上下文不被察觉?还是我遵循了一些通过代码气味暴露自己的坏习惯

编辑

下面是一个将场景浓缩到最相关部分的尝试。域模型中有一个状态可能会更改的订单。当订单的状态发生变化时,我们已经通过发布服务器触发了StatusChanged域事件。此特定域事件的订户会写出状态更改的记录,并发送一个NServiceBus命令来传达此状态-此特定命令的处理程序将遵循是否发送电子邮件、SMS消息等的进一步逻辑,我认为这些细节不相关

订单域对象

公共类秩序
{
私有订单状态码_状态码;
公共订单状态代码状态代码
{
获取{return\u statusCode;}
私有集{u statusCode=value;}
}
公共作废更改状态(订单状态代码状态)
{
状态=状态;
发布(新状态已更改(CreateOrderSnapshot(),状态));
}
受保护的无效发布(T@event),其中T:IDomainEvent
{
DomainEventPublisher.Instance.Publish(@event);
}
}
域事件发布者

公共类DomainEventPublisher:IDomainEventPublisher
{
私有静态IDomainEventPublisher\u实例;
公共静态IDomainEventPublisher实例
{
获取{return _instance??(_instance=new DomainEventPublisher());}
}
public ISubscriptionService SubscriptionService{get;set;}
公共无效发布(T@event),其中T:IDomainEvent
{
if(SubscriptionService==null)返回;
var subscriptions=SubscriptionService.GetSubscriptions();
subscriptions.ToList().ForEach(x=>PublishToConsumer(x,@event.GetAwaiter().GetResult());
}
私有静态异步任务PublishToConsumer(IEventSubscriber x,T eventMessage),其中T:IDomainEvent
{
等待x.HandleEvent(事件消息);
}
}
状态已更改的域事件处理程序

公共类状态更改处理程序:IEventSubscriber
{
专用只读IBus_总线;
私人只读IOrdersRepository\u ordersepository;
公共状态更改处理程序(IBus总线、IORDERS存储命令存储)
{
_总线=总线;
_ordersRepository=ordersRepository;
}
公共异步任务HandleEvent(StatusChanged@event)
{
var statusTrailEntry=new OrderStatusTrailEntry(@event.ordersnashot,@event.Status);
var txOptions=newtransactionoptions{IsolationLevel=IsolationLevel.ReadCommitted};
使用(
var范围=新TransactionScope(TransactionScopeOption.Required,txOptions))
{
wait _ordersepository.SaveStatusTrail(statusTrailEntry);
if(通讯状态)
{
_发送(新的发送通信命令(@event.OrderSnapshot,@event.Status));
}
scope.Complete();
}
}
}
问题是,到目前为止,上面的示例代码都不需要知道状态是由于通过Web API请求传入的请求而更改的,还是由于在NServiceBus消息处理程序(在windows服务中)的上下文中更改的状态而更改的-IBus接口不是特定于上下文的。但是由于NserviceBusV6中IEndpointInstance和IMessageHandlerContext之间的区别,我觉得我没有同样的灵活性


如果我理解正确,我可以用容器注册IEndpointInstance并注入EventSubscriber,因此我将在Web API调用的情况下进行介绍,但我还需要添加一个IMessageHandlerContext作为参数,如果消息处理程序的上下文中的状态发生了更改,则可以选择通过调用堆栈从ChangeStatus传递到发布服务器,最后传递到域事件订阅服务器。在整个调用堆栈中添加此参数确实不太合适。

您能否分享一些代码/代码示例,以提供您正在做的事情的更多上下文?请@SeanFarmar-根据要求提供一些示例代码。希望能让它更清楚,而不是更复杂。你能给我发电子邮件给特定网络的sean.farmar吗?我也在努力解决这个问题。至少,文档应该解决这样的常见场景,其中大量使用依赖项注入。我们不愿意因为基础设施问题而污染我们的核心业务代码。在我的情况下,以及与IBus消息传递基础设施相当的情况下,我需要注入一个对NSB的NHibernate ISession的引用,所有这些都是通过容器解决的。
public class Order
{
    private OrderStatusCode _statusCode;

    public OrderStatusCode StatusCode
    {
        get { return _statusCode; }
        private set { _statusCode = value; }
    }

    public void ChangeStatus(OrderStatusCode status)
    {
        Status = status;

        Publish(new StatusChanged(CreateOrderSnapshot(), status));
    }

    protected void Publish<T>(T @event) where T : IDomainEvent
    {
        DomainEventPublisher.Instance.Publish(@event);
    }
}
public class DomainEventPublisher : IDomainEventPublisher
{
    private static IDomainEventPublisher _instance;
    public static IDomainEventPublisher Instance
    {
        get { return _instance ?? (_instance = new DomainEventPublisher()); }
    }

    public ISubscriptionService SubscriptionService { get; set; }

    public void Publish<T>(T @event) where T : IDomainEvent
    {
        if (SubscriptionService == null) return;

        var subscriptions = SubscriptionService.GetSubscriptions<T>();
        subscriptions.ToList().ForEach(x => PublishToConsumer(x, @event).GetAwaiter().GetResult());
    }

    private static async Task PublishToConsumer<T>(IEventSubscriber<T> x, T eventMessage) where T : IDomainEvent
    {
        await x.HandleEvent(eventMessage);
    }
}
public class StatusChangedHandler : IEventSubscriber<StatusChanged>
{
    private readonly IBus _bus;
    private readonly IOrdersRepository _ordersRepository;

    public StatusChangedHandler(IBus bus, IOrdersRepository ordersRepository)
    {
        _bus = bus;
        _ordersRepository = ordersRepository;
    }

    public async Task HandleEvent(StatusChanged @event)
    {
        var statusTrailEntry = new OrderStatusTrailEntry(@event.OrderSnapshot, @event.Status);

        var txOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
        using (
            var scope = new TransactionScope(TransactionScopeOption.Required, txOptions))
        {
            await _ordersRepository.SaveStatusTrail(statusTrailEntry);

            if (communicateStatus)
            {
                _bus.Send(new SendCommunicationCommand(@event.OrderSnapshot, @event.Status));
            }
            scope.Complete();
        }
    }
}