如何在不使用 Guid 的情况下关联公共交通状态机中的事件?

How can I correlate events in a masstransit state machine without using a Guid?

我在 Masstransit 中定义了以下状态机:

public class OrderStateMachine : MassTransitStateMachine<OrderState>
{
    public OrderStateMachine()
    {
        InstanceState(x => x.Status);

        Event(() => OrderCreated, x => x.CorrelateBy(order => order.OrderCode, ctx => ctx.Message.OrderCode).SelectId(ctx => NewId.NextGuid()));

        //How should I select an id for these events?
        Event(() => OrderProvisioned, x => x.CorrelateBy(order => order.OrderCode, ctx => ctx.Message.OrderCode));
        Event(() => OrderInvoiced, x => x.CorrelateBy(order => order.OrderCode, ctx => ctx.Message.OrderCode));

        State(() => Created);
        State(() => Finished);

        CompositeEvent(() => OrderFinished, order => order.CompositeStatus, OrderProvisioned, OrderInvoiced);

        Initially(
            When(OrderCreated)
                .Then(context => Console.WriteLine("Order created"))
                .TransitionTo(Created));

        During(Created,
            When(OrderFinished)
                .Then(context => Console.WriteLine("Order finished"))
                .TransitionTo(Finished)
                .Finalize());

    }

    public State Created { get; set; }
    public State Finished { get; set; }

    public Event<OrderCreated> OrderCreated { get; set; }
    public Event<OrderProvisioned> OrderProvisioned { get; set; }
    public Event<OrderInvoiced> OrderInvoiced { get; set; }
    public Event OrderFinished { get; set; }

}

public class OrderState : SagaStateMachineInstance
{
    public Guid CorrelationId { get; set; }

    public string OrderCode { get; set; }
    public string Status { get; set; }
    public CompositeEventStatus CompositeStatus { get; set; }

}

public class OrderCreated
{
    public string OrderCode { get; set; }

    public OrderCreated(string orderCode)
    {
        OrderCode = orderCode;
    }
}

public class OrderInvoiced
{
    public string OrderCode { get; set; }

    public OrderInvoiced(string orderCode)
    {
        OrderCode = orderCode;
    }

}

public class OrderProvisioned
{
    public string OrderCode { get; set; }

    public OrderProvisioned(string orderCode)
    {
        OrderCode = orderCode;
    }
}

如何将 OrderProvisoned 和 OrderInvoiced 事件关联到与初始 OrderCreated 事件相同的 OrderState 实例,而无需在我的事件中发送 Guid,并且仅使用订单代码 属性 来关联它们? 如果我 运行 这个例子,如果同时发送了 OrderProvisioned 和 OrderInvoiced,我永远不会得到 OrderFinished 事件,但是如果我将 Guid 添加到事件并根据该 Guid 关联它们,它就会正确执行。

是否有损坏的单元测试可用于查看此行为是否不起作用?从上面编辑过的代码来看,这似乎是我希望它如何关联的方式——使用 OrderCode。购物车示例也是如此。

只有启动状态机的事件才需要 SelectId() 函数,因为这是分配 CorrelationId 的地方。如果其他事件不使用它,则不需要 "select" 它,因为查询(orderCode)会进行关联。

示例中的购物车示例是这样工作的: https://github.com/MassTransit/Sample-ShoppingWeb/blob/master/src/CartTracking/ShoppingCartStateMachine.cs#L15

在你上面的例子中:

Event(() => OrderCreated, x => x.CorrelateBy(order => order.OrderCode, ctx => ctx.Message.OrderCode).SelectId(ctx => NewId.NextGuid()));

Event(() => OrderProvisioned, x => x.CorrelateBy(order => order.OrderCode, ctx => ctx.Message.OrderCode));
Event(() => OrderInvoiced, x => x.CorrelateBy(order => order.OrderCode, ctx => ctx.Message.OrderCode));

这正是我要配置的方式,看来您的方向是正确的。

我解决了,显然您必须在状态机实例上显式设置自定义 correlationid,我希望 masstransit 能为我做到这一点。 所以这是初始状态的改编代码:

            Initially(
            When(OrderCreated)
                .Then(context => context.Instance.OrderCode = context.Data.OrderCode)
                .Then(context => Console.WriteLine("Order created"))
                .TransitionTo(Created));

也可以使用 saga 工厂,但我认为您可以放弃 selectid 逻辑,因为 saga 工厂否决了这一点,但我得到了一个例外。

        Event(() => OrderCreated,
            x =>
            {
                x.CorrelateBy(order => order.OrderCode, ctx => ctx.Message.OrderCode);
                x.InsertOnInitial = true;
                x.SetSagaFactory(context => new OrderState
                {
                    CorrelationId = NewId.NextGuid(),
                    OrderCode = context.Message.OrderCode
                });
                x.SelectId(context => NewId.NextGuid());
            });