我正在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; }
}
没有,不幸的是,Rebus的sagas中目前没有对发起人函数的回复。不过,您可以很容易地做到这一点,当您的传奇故事被创建时,通过存储发起者的端点(在所有可以启动传奇故事的消息的Handle
方法中):
if (IsNew) {
Data.Originator = MessageContext.GetCurrent().ReturnAddress;
}
然后当你想回复发起者时:
bus.Advanced.Routing.Send(Data.Originator, new HelloThereMyFriend());
不过,我经常考虑将其添加到Rebus中,要么作为ISagaData
上的一个额外字段,要么作为一个额外的接口ISagaDataWithOriginator
,您可以选择将其应用于您的传奇数据,但我自己从未有过(足够的)需求。
如果每个发送者都是一个单独的(虚拟)机器,就像在我的实现中一样,你可以通过在回复队列名称中使用他们的机器唯一ID或MAC地址来获得对发起者的保证回复,如下所示:
Bus = Configure.With(adapter)
.Transport(t => t.UseSqlServer(DbConfiguration.DatabaseConnectionString,
sInstanceId, sInstanceId + ".Error")
.EnsureTableIsCreated())
...
如果每个发起方都有一个唯一的队列ID,那么消费者只需使用Bus.reply.就可以回复发起方
唯一的机器id可以使用System.Management:确定
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();
}