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

时间:2016-02-05 14:32:45

标签: masstransit saga automatonymous

我在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实例,而不在我的事件中发送Guids并仅使用ordercode属性来关联它们? 如果我运行这个例子,如果发送了OrderProvisioned和OrderInvoiced,我永远不会得到OrderFinished事件,但是如果我将Guids添加到事件中并根据Guid将它们关联起来,它就会被正确执行。

2 个答案:

答案 0 :(得分:2)

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

import static javafx.scene.layout.Region.USE_PREF_SIZE;

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author Naoghuman
 */
public class ExtendedComponentsMCVE extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        ExtendedTextField extendedTextField = new ExtendedTextField();

//        OnlyAnchorPane oap = new OnlyAnchorPane(extendedTextField);
//        Scene scene = new Scene(oap, 800, 600);

        TabAnchorPane tap = new TabAnchorPane(extendedTextField);
        Scene scene = new Scene(tap, 800, 600);

        primaryStage.setTitle("Demo Extended Components");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    // ExtendedTextField #######################################################
    class ExtendedTextField extends HBox {

        private BooleanProperty configureCheckBoxProperty;
        private BooleanProperty configureLeftLabelProperty;
        private BooleanProperty configureTopLabelProperty;

        private CheckBox cbReadOnly;
        private Label lLeft;
        private Label lTop;
        private TextField tfText;
        private VBox vBox;

        private String lastUserInput = ""; // NOI18N

        ExtendedTextField() {
            super();

            this.init();
        }

        private void init() {
            // vbox
            super.setAlignment(Pos.BOTTOM_LEFT);
            super.setStyle("-fx-background-color: lightgreen;");

            // left label
            configureLeftLabelProperty = new SimpleBooleanProperty(Boolean.TRUE);
            lLeft = new Label("<left>"); // NOI18N
            lLeft.setMaxHeight(USE_PREF_SIZE);
            lLeft.setMinHeight(USE_PREF_SIZE);
            lLeft.visibleProperty().bind(configureLeftLabelProperty);
            lLeft.managedProperty().bind(configureLeftLabelProperty);
            super.getChildren().add(lLeft);

            // checkbox
            configureCheckBoxProperty = new SimpleBooleanProperty(Boolean.TRUE);
            cbReadOnly = new CheckBox();
            cbReadOnly.setMaxHeight(USE_PREF_SIZE);
            cbReadOnly.setMinHeight(USE_PREF_SIZE);
            cbReadOnly.visibleProperty().bind(configureCheckBoxProperty);
            cbReadOnly.managedProperty().bind(configureCheckBoxProperty);
            super.getChildren().add(cbReadOnly);

            // vbox
            vBox = new VBox();
            HBox.setHgrow(vBox, Priority.ALWAYS);

            // top label
            configureTopLabelProperty = new SimpleBooleanProperty(Boolean.TRUE);
            lTop = new Label("<top>"); // NOI18N
            lTop.visibleProperty().bind(configureTopLabelProperty);
            lTop.managedProperty().bind(configureTopLabelProperty);
            vBox.getChildren().add(lTop);

            // textfield
            tfText = new TextField(lastUserInput);
            tfText.disableProperty().bind(cbReadOnly.selectedProperty().not());
            lLeft.prefHeightProperty().bind(tfText.heightProperty());
            cbReadOnly.prefHeightProperty().bind(tfText.heightProperty());
            vBox.getChildren().add(tfText);

            super.getChildren().add(vBox);
        }

        public void setCheckBoxSelected(Boolean selected) {
            cbReadOnly.setSelected(selected);

            if (selected) {
                tfText.setText(lastUserInput);
            }
            else {
                lastUserInput = tfText.getText();
                tfText.setText(null);
            }
        }

        public void setCheckBoxVisibleManaged(Boolean visible) {
            configureCheckBoxProperty.setValue(visible);
        }

        public void setLeftLabelVisibleManaged(boolean selected) {
            configureLeftLabelProperty.setValue(selected);
        }

        public void setTopLabelVisibleManaged(boolean selected) {
            configureTopLabelProperty.setValue(selected);
        }

    }
    // ExtendedTextField #######################################################

    // OnlyAnchorPane ##########################################################
    class OnlyAnchorPane extends AnchorPane {
        OnlyAnchorPane(ExtendedTextField extendedTextField) {
            super();
            super.setStyle("-fx-background-color: BLANCHEDALMOND;");

            // hbox
            HBox hbox = new HBox();
            hbox.setStyle("-fx-background-color: KHAKI;");
            hbox.setSpacing(7.0d);
            hbox.setPrefWidth(Double.MAX_VALUE);

            // extendedTextField
            VBox vbox = new VBox();
            vbox.getChildren().add(extendedTextField);
            HBox.setHgrow(vbox, Priority.ALWAYS);
            hbox.getChildren().add(vbox);

            // menu
            MenuVBox menu = new MenuVBox(extendedTextField);
            hbox.getChildren().add(menu);

            AnchorPane.setBottomAnchor(hbox, 14d);
            AnchorPane.setLeftAnchor(hbox, 14d);
            AnchorPane.setTopAnchor(hbox, 14d);
            AnchorPane.setRightAnchor(hbox, 14d);
            super.getChildren().add(hbox);
        }
    }
    // OnlyAnchorPane ##########################################################

    // TabAnchorPane ###########################################################
    class TabAnchorPane extends AnchorPane {
        TabAnchorPane(ExtendedTextField extendedTextField) {
            super();
            super.setStyle("-fx-background-color: BLANCHEDALMOND;");

            // tabpane
            TabPane tp = new TabPane();

            // tab
            Tab t = new Tab("TextField");
            t.setClosable(false);
            tp.getTabs().add(t);

            // hbox
            HBox hbox = new HBox();
            hbox.setStyle("-fx-background-color: KHAKI;");
            hbox.setSpacing(7.0d);
            hbox.setPrefWidth(Double.MAX_VALUE);

            // extendedTextField
            VBox vbox = new VBox();
            vbox.getChildren().add(extendedTextField);
            HBox.setHgrow(vbox, Priority.ALWAYS);
            hbox.getChildren().add(vbox);

            // menu
            MenuVBox menu = new MenuVBox(extendedTextField);
            hbox.getChildren().add(menu);
            t.setContent(hbox);

            AnchorPane.setBottomAnchor(tp, 14d);
            AnchorPane.setLeftAnchor(tp, 14d);
            AnchorPane.setTopAnchor(tp, 14d);
            AnchorPane.setRightAnchor(tp, 14d);
            super.getChildren().add(tp);
        }    
    }
    // TabAnchorPane ###########################################################

    // MenuVBox ################################################################
    class MenuVBox extends VBox {

        MenuVBox(ExtendedTextField extendedTextField) {
            super();
            super.setStyle("-fx-background-color: HONEYDEW;");

            super.setSpacing(7.0d);
            super.setMaxWidth(200.0d);
            super.setMinWidth(200.0d);
            super.setPrefWidth(200.0d);

            // show top label
            CheckBox cb1 = new CheckBox("Show top label");
            cb1.setSelected(true);
            cb1.setOnAction((ActionEvent event) -> {
                extendedTextField.setTopLabelVisibleManaged(cb1.isSelected());
            });
            super.getChildren().add(cb1);

            // show left label
            CheckBox cb2 = new CheckBox("Show left label");
            cb2.setSelected(true);
            cb2.setOnAction((ActionEvent event) -> {
                extendedTextField.setLeftLabelVisibleManaged(cb2.isSelected());
            });
            super.getChildren().add(cb2);

            // seperator
            super.getChildren().add(new Separator());

            // select checkbox
            CheckBox cb3 = new CheckBox("Select checkbox");
            cb3.setSelected(false);
            cb3.setOnAction((ActionEvent event) -> {
                extendedTextField.setCheckBoxSelected(cb3.isSelected());
            });
            super.getChildren().add(cb3);

            // show checkbox
            CheckBox cb4 = new CheckBox("Show checkbox");
            cb4.setSelected(true);
            cb4.setOnAction((ActionEvent event) -> {
                extendedTextField.setCheckBoxVisibleManaged(cb4.isSelected());
            });
            super.getChildren().add(cb4);

        }
    }
    // MenuVBox ################################################################
}

同样使用一个传奇工厂,但我认为你可以放弃选择逻辑,因为传奇工厂否决了这个,但我得到了一个例外。

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

答案 1 :(得分:1)

是否存在可用于查看此行为是否无效的单元测试损坏?从上面编辑的代码中,这似乎是我期望它如何相关 - 使用OrderCode。这就是购物车示例的工作原理。

只有启动状态机的事件才需要SelectId()函数,因为这是分配CorrelationId的地方。如果它没有被其他事件使用,则无需选择&#34;因为Query(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));

这正是我配置它的方式,看起来你正走在正确的轨道上。