1

我正在与 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; }
}
4

2 回答 2

3

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

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

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

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

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

于 2014-09-06T21:12:53.113 回答
1

如果每个发件人都是单独的(虚拟)机器,就像在我的实现中一样,您可以通过在回复队列名称中使用他们的机器唯一 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();
}
于 2015-05-01T18:50:03.117 回答