【问题标题】:ReBus equivalent to NServiceBus Saga ReplyToOriginatorReBus 相当于 NServiceBus Saga ReplyToOriginator
【发布时间】:2014-09-05 20:29:31
【问题描述】:

我在 ReBus 与 Sagas 合作,根据我使用 NServiceBus 的经验,您可以回复 Saga 的原始创建者以提供更新,如下所示:

 Saga<>.ReplyToOriginator

我没有看到使用 ReBus 的等效方法。有没有办法做到这一点,如果没有什么是好的模式(除了发起者轮询)我可以使用它来实现同样的目标?一个例子是尝试创建一个客户,而客户想知道它是什么时候创建的,然后再尝试更改它的地址。

这是我快速整理的客户场景的一个简单示例:

public class CreateCustomerSaga : Saga<CreateCustomerData>,
    IAmInitiatedBy<CreateCustomerCommand>,
    IHandleMessages<CustomerUniqunessCheckResult>
{
    private readonly IBus _bus;
    private readonly ICustomerResourceAccess _customerResourceAccess;

    public CreateCustomerSaga(IBus bus, ICustomerResourceAccess customerResourceAccess)
    {
        _bus = bus;
        _customerResourceAccess = customerResourceAccess;
    }

    public override void ConfigureHowToFindSaga()
    {
        Incoming<CustomerUniqunessCheckResult>(x => x.IsCustomerUnique).CorrelatesWith(y => y.CustomerId);
    }

    public void Handle(CreateCustomerCommand message)
    {
        Data.CustomerId = message.CustomerId;
        Data.CustomerName = message.CustomerName;

        _bus.Send(new CheckCustomerUniquenessCommand(message.CustomerId));
    }

    public void Handle(CustomerUniqunessCheckResult message)
    {
        if (message.IsCustomerUnique)
        {
            _customerResourceAccess.CreateCustomer(Data.CustomerId, Data.CustomerName);

            // This is what seems to be missing from ReBus to reply to the original sender
            _bus.?(new CustomerCreatedEvent(Data.CustomerId));
        }
        else
        {
            // This is what seems to be missing from ReBus to reply to the original sender
            _bus.?(new CustomerAlreadExistsEvent(Data.CustomerId));
        }
    }
}

public class CustomerCreatedEvent
{
    public Guid CustomerId { get; set; }

    public CustomerCreatedEvent(Guid customerId)
    {
        CustomerId = customerId;
    }
}

public class CustomerAlreadExistsEvent
{
    public Guid CustomerId { get; set; }

    public CustomerAlreadExistsEvent(Guid customerId)
    {
        CustomerId = customerId;
    }
}

public class CustomerUniqunessCheckResult
{
    public bool IsCustomerUnique { get; set; }
}

public class CheckCustomerUniquenessCommand
{
    public CheckCustomerUniquenessCommand(Guid customerId)
    { }
}

public interface ICustomerResourceAccess
{
    void CreateCustomer(Guid customerId, string customerName);
}

public class CreateCustomerCommand
{
    public Guid CustomerId { get; set; }

    public string CustomerName { get; set; }
}

public class CreateCustomerData : ISagaData
{
    public CreateCustomerData()
    {
        Id = Guid.NewGuid();
    }

    public Guid CustomerId { get; set; }

    public string CustomerName { get; set; }

    public Guid Id { get; set; }

    public int Revision { get; set; }
}

【问题讨论】:

  • 您还有其他代码吗?您能否简要概述一下您所描述的技术?过去18年参与编程,我不知道你在说什么。如果它是新的东西,如果你能把它与现有的技术联系起来,那就太好了。
  • 我添加了一个例子,技术见标签(ReBus,C#)

标签: c# publish-subscribe saga rebus


【解决方案1】:

不,不幸的是,目前 Rebus 的 sagas 中没有 回复发起人 功能。不过,您可以轻松地做到这一点,方法是在您的 saga 像这样创建时存储发起者的端点(在所有可以启动 saga 的消息的 Handle 方法中):

if (IsNew) {
    Data.Originator = MessageContext.GetCurrent().ReturnAddress;
}

然后当你想回复发件人时:

bus.Advanced.Routing.Send(Data.Originator, new HelloThereMyFriend());

我经常考虑将它添加到 Rebus,或者作为 ISagaData 上的额外字段,或者作为额外接口 ISagaDataWithOriginator,您可以选择将其应用于您的传奇数据,但我从来没有需要(足够)我自己。

【讨论】:

    【解决方案2】:

    如果每个发送者都是单独的(虚拟)机器,就像在我的实现中一样,您可以通过在回复队列名称中使用他们的机器唯一 ID 或 MAC 地址来保证对发起者的回复,如下所示:

    Bus = Configure.With(adapter)
                   .Transport(t => t.UseSqlServer(DbConfiguration.DatabaseConnectionString,
                                                  sInstanceId, sInstanceId + ".Error")
                   .EnsureTableIsCreated())
                   ...
    

    如果每个发起者都有唯一的队列 ID,消费者可以简单地使用 Bus.Reply 回复发起者。

    可以使用 System.Management 确定唯一的机器 ID:

    string uuid = string.Empty;
    
    ManagementClass mc = new System.Management.ManagementClass("Win32_ComputerSystemProduct");
    if (mc != null)
    {
      ManagementObjectCollection moc = mc.GetInstances();
      if (moc != null)
      {
        foreach (ManagementObject mo in moc)
        {
          PropertyData pd = mo.Properties["UUID"];
          if (pd != null)
          {
            uuid = (string)pd.Value;
            break;
          }
        }
      }
    }
    

    或者使用机器的 MAC 地址(我们的备用代码):

    if (string.IsNullOrEmpty(uuid))
    {
      uuid = NetworkInterface.GetAllNetworkInterfaces()
      .Where(ni => ni.OperationalStatus == OperationalStatus.Up)
      .FirstOrDefault()
      .GetPhysicalAddress().ToString();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多