消息传递活动

消息传递活动允许工作流发送和接收 WCF 消息。 通过将消息传递活动添加到工作流,可以建模任何任意复杂的消息交换模式(MEP)。

消息交换模式

有三种基本消息交换模式:

  • Datagram - 使用数据报 MEP 时,客户端会将消息发送到服务,但服务不会响应。 有时称为“发后不理”(fire and forget)。 “发后不理”交换形式是一种要求带外确认成功传递的交换形式。 消息可能会在传输过程中丢失,并且永远不会到达服务。 如果客户端成功发送消息,则不保证服务已收到消息。 数据报是消息传递的基本构造块,因为您可以基于数据报构建自己的 MEP。

  • 请求-响应 - 使用请求-响应 MEP 时,客户端向服务发送消息时,服务会执行所需的处理,然后将响应发送回客户端。 该模式由请求-响应对组成。 请求响应调用的示例包括远程过程调用(RPC)和浏览器 GET 请求。 此模式也称为半双工。

  • 双工 - 使用双工 MEP 时,客户端和服务可以按任意顺序相互发送消息。 双工 MEP 就像电话通话,所说的每一个字都是一条消息。

使用消息传递活动能够实现这些基本 MEP 中的任何一个以及任意复杂的 MEP。

消息传递活动

.NET Framework 4.6.1 定义以下消息传送活动:

  • Send- 使用 Send 活动发送消息。

  • SendReply - 使用 SendReply 活动向收到的消息发送响应。 实现请求/回复 MEP 时,工作流服务会使用此活动。

  • Receive- 使用 Receive 活动接收消息。

  • ReceiveReply - 使用 ReceiveReply 活动接收回复消息。 实现请求/回复 MEP 时,工作流服务客户端会使用此活动。

消息活动和消息交换模式

数据报 MEP 涉及客户端发送消息和服务接收消息。 如果客户端是工作流,则使用 Send 活动发送消息。 若要在工作流中接收该消息,请使用 Receive 活动。 SendReceive活动各有一个名为Content的属性。 此属性包含要发送或接收的数据。 实现请求-响应 MEP 时,客户端和服务都使用活动对。 客户端使用活动 Send 发送消息和活动 ReceiveReply 来接收来自服务的响应。 这两个活动由 Request 属性相互关联。 此属性设置为 Send 发送原始消息的活动。 服务还使用一对关联的活动:ReceiveSendReply。 这两个活动由 Request 属性关联。 此属性对应于接收原始消息的Receive活动。 ReceiveReplySendReply活动,例如SendReceive,允许您发送Message实例或消息契约类型。

由于工作流具有长时间运行的性质,因此同时支持长时间运行的对话对于双工通信模式非常重要。 若要支持长时间运行的对话,启动对话的客户端必须提供适当的机会,使服务在以后数据变为可用时能够回拨客户端。 例如,已提交采购订单请求等待经理批准,但该请求可能一天、一周甚至一年也未被处理;管理采购订单批准的工作流必须知道在请求得到批准后恢复。 使用相关性的工作流中支持此双工通信模式。 若要实现双工模式,请使用 SendReceive 活动。 在Receive活动中,使用CorrelationHandle初始化关联。 在 Send 活动上,将该相关性句柄设置为 CorrelatesWith 属性值。 有关详细信息,请参阅 Durable Duplex

注释

使用回调相关性的双工(称为“持久双工”)的工作流实现适用于长时间运行的对话。 这与具有回调协定的 WCF 双工不同,在 WCF 双工中,对话是短时间运行的(通道的生存期)。

消息格式设置和消息传送活动

ReceiveReceiveReply活动具有一个名为Content的属性。 此属性的类型为ReceiveContent,表示ReceiveReceiveReply活动接收到的数据。 .NET Framework 定义了两个相关的类,分别叫做 ReceiveMessageContentReceiveParametersContent,这两个类都派生自 ReceiveContent。 将 ReceiveReceiveReply 活动 Content 的属性设置为其中一种类型的实例,以将数据接收到工作流服务中。 要使用的类型取决于活动接收的数据类型。 如果活动收到 Message 对象或消息协定类型,请使用 ReceiveMessageContent。 如果活动收到一组可序列化的数据协定或 XML 类型,请使用 ReceiveParametersContentReceiveParametersContent 允许发送多个参数,而 ReceiveMessageContent 仅允许发送一个对象(或消息协定类型)。

注释

ReceiveMessageContent 还可以与可以序列化的单个数据协定或 XML 类型一起使用。 将 ReceiveParametersContent 和单个参数一起使用与直接将对象传递给 ReceiveMessageContent 之间的区别在于连网格式。 参数的内容包装在与作名称相对应的 XML 元素中,序列化对象使用参数名称(例如, <Echo><msg>Hello, World</msg></Echo>) 包装在 XML 元素中。 消息内容未被操作名称封装。 相反,序列化的对象使用 XML 限定的类型名称(例如, <string>Hello, World</string>)放置在 XML 元素中。

`Send`和SendReply活动还拥有一个名为Content的属性。 此属性的类型是SendContent,表示SendSendReply活动发送的数据。 .NET Framework 定义了两个相关类型 SendMessageContentSendParametersContent,这两个类型都派生自 SendContent。 将 SendSendReply 活动 Content 的属性设置为其中一种类型的实例,以便从工作流服务发送数据。 要使用的类型取决于活动发送的数据类型。 如果活动发送对象 Message 或消息协定类型,请使用 SendMessageContent。 如果活动发送数据协定类型,则使用 SendParametersContentSendParametersContent 允许发送多个参数,而 SendMessageContent 仅允许发送一个对象、消息(或消息协定类型)。

使用消息传送活动进行命令式编程时,您可以使用泛型InArgument<T>OutArgument<T>来包装分配给SendSendReplyReceiveReceiveReply活动的消息或参数属性的对象。 使用InArgument<T>进行SendSendReply活动,并使用OutArgument<T>进行ReceiveReceiveReply活动。 In 自变量用于发送活动,因为数据将传入到活动。 Out 参数用于接收活动,因为数据将传出到活动之外,如下面的示例所示。

Receive reserveSeat = new Receive
{
    ...
    Content = new ReceiveParametersContent
    {
        Parameters =
        {
            { "ReservationInfo", new OutArgument<ReservationRequest>(reservationInfo) }
        }
    }
};
SendReply reserveSeat = new SendReply
{
    ...
    Request = reserveSeat,
    Content = new SendParametersContent
    {
        Parameters =
        {
            { "ReservationId", new InArgument<string>(reservationId) }
        }
    },
};

实现定义返回 void 的请求/响应操作的工作流服务时,必须实例化SendReply活动,并将Content属性设置为其中一种内容类型(SendMessageContentSendParametersContent)的空实例,如以下示例所示。

Receive rcv = new Receive()
{
ServiceContractName = "IService",
OperationName = "NullReturningContract",
Content = new ReceiveParametersContent( new Dictionary<string, OutArgument>() { { "message", new OutArgument<string>() } } )
};
SendReply sr = new SendReply()
{
Request = rcv
   Content = new SendParametersContent();
};

添加服务引用

从工作流应用程序调用工作流服务时,Visual Studio 2012 会生成自定义消息活动,用以封装请求/回复 MEP 中使用的常规 SendReceiveReply 活动。 若要使用此功能,请在 Visual Studio 中右键单击客户端项目,然后选择 “添加>服务引用”。 在地址框中键入服务的基址,然后单击“转到”。 可用服务显示在 “服务: ”框中。 展开服务节点以显示支持的合同。 选择要调用的合约,并在 操作 框中显示可用操作的列表。 然后,可以为生成的活动指定命名空间,然后单击“ 确定”。 然后,你将看到一个对话框,显示作成功完成,并且生成的自定义活动在重新生成项目后位于工具箱中。 在服务协定上定义的每个操作都有一个对应的活动。 重新生成项目后,可以将自定义活动拖放到工作流上,并在属性窗口中设置任何必需属性。

消息活动模板

为了更轻松地在客户端和服务上设置请求/响应 MEP,Visual Studio 2012 提供了两个消息传递活动模板。 System.ServiceModel.Activities.Design.ReceiveAndSendReply 用于服务,System.ServiceModel.Activities.Design.SendAndReceiveReply 用于客户端。 在这两种情况下,模板都向工作流添加适当的消息传递活动。 在服务上,System.ServiceModel.Activities.Design.ReceiveAndSendReply 先添加 Receive 活动,再添加 SendReply 活动。 该 Request 属性会自动分配给 Receive 活动。 在客户端上,System.ServiceModel.Activities.Design.SendAndReceiveReply 先添加 Send 活动,再添加 ReceiveReply 活动。 该 Request 属性会自动分配给 Send 活动。 若要使用这些模板,只需将相应的模板拖放到工作流中。

消息传递活动和事务

调用工作流服务时,你可能希望将事务流动到服务操作中。 为此,请将 Receive 活动置于 TransactedReceiveScope 活动内。 TransactedReceiveScope 活动包含 Receive 活动和主体。 流向服务的事务在执行 TransactedReceiveScope 的主体的整个过程中保持为环境事务。 事务在执行完主体后完成。 有关工作流和事务的详细信息,请参阅 工作流事务

另请参阅