Messaging activities
Messaging activities allow workflows to send and receive WCF messages. By adding messaging activities to a workflow you can model any arbitrarily complex message exchange patterns (MEP).
Message exchange patterns
There are three basic message exchange patterns:
Datagram - When using the datagram MEP the client sends a message to the service, but the service does not respond. This is sometimes called "fire and forget". A fire and forget exchange is one that requires out-of-band confirmation of successful delivery. The message might be lost in transit and never reach the service. If the client successfully sends a message, it does not guarantee that the service has received the message. The datagram is a fundamental building block for messaging, as you can build your own MEPs on top of it.
Request-Response - When using the request-response MEP the client sends a message to the service, the service does the required processing, and then sends a response back to the client. The pattern consists of request-response pairs. Examples of request-response calls are remote procedure calls (RPC) and browser GET requests. This pattern is also known as half-duplex.
Duplex - When using the duplex MEP the client and service can send messages to each other in any order. The duplex MEP is like a phone conversation, where each word being spoken is a message.
The messaging activities allow you to implement any of these basic MEPs as well as any arbitrarily complex MEP.
Messaging activities
The .NET Framework 4.6.1 defines the following messaging activities:
SendReply - Use the SendReply activity to send a response to a received message. This activity is used by workflow services when implementing a request/reply MEP.
ReceiveReply - Use the ReceiveReply activity to receive a reply message. This activity is used by workflow service clients when implementing a request/reply MEP.
Messaging activities and message exchange patterns
A datagram MEP involves a client sending a message and a service receiving the message. If the client is a workflow use a Send activity to send the message. To receive that message in a workflow, use a Receive activity. The Send and Receive activities each have a property named Content
. This property contains the data being sent or received. When implementing the request-response MEP both the client and the service use pairs of activities. The client uses a Send activity to send the message and a ReceiveReply activity to receive the response from the service. These two activities are associated with each other by the Request property. This property is set to the Send activity that sent the original message. The service also uses a pair of associated activities: Receive and SendReply. These two activities are associated by the Request property. This property is set to the Receive activity that received the original message. The ReceiveReply and SendReply activities, like Send and Receive allow you to send a Message instance or a message contract type.
Because of the long-running nature of workflows, it is important for the duplex pattern of communication to also support long-running conversations. To support long-running conversations, clients who initiate the conversation must provide the service with an opportunity to call it back at a later time when the data becomes available. For example, a purchase order request is submitted for manager approval, but it might not be processed for a day, a week, or even a year; the workflow that manages the purchase order approval must know to resume after the approval is given. This pattern of duplex communication is supported in workflows using correlation. To implement a duplex pattern, use Send and Receive activities. On the Receive activity, initialize a correlation using CorrelationHandle. On the Send activity set that correlation handle as the CorrelatesWith property value. For more information, see Durable Duplex.
Note
Workflow’s implementation of duplex using a callback correlation ("Durable Duplex") is intended for long-running conversations. This is not the same as WCF duplex with callback contracts where the conversation is short-running (the lifetime of the channel).
Message formatting and messaging activities
The Receive and ReceiveReply activities have a property named Content
. This property is of type ReceiveContent and represents data the Receive or ReceiveReply activity receives. The .NET Framework defines two related classes called ReceiveMessageContent and ReceiveParametersContent both of which are derived from ReceiveContent. Set the Receive or ReceiveReply activity’s Content
property to an instance of one of these types to receive data into a workflow service. The type to use depends upon the type of data the activity receives. If the activity receives a Message
object or a message contract type, use ReceiveMessageContent. If the activity receives a set of data contract or XML types that can be serialized, use ReceiveParametersContent. ReceiveParametersContent allows you to send multiple parameters, whereas ReceiveMessageContent only allows you to send one object, the message (or message contract type).
Note
ReceiveMessageContent can also be used with a single data contract or XML type that can be serialized. The difference between using ReceiveParametersContent with a single parameter and the object passed directly to ReceiveMessageContent is the wire-format. The parameter’s content is wrapped in an XML element that corresponds to the operation name and the serialized object is wrapped in an XML element using the parameter name (for example, <Echo><msg>Hello, World</msg></Echo>
). The message content is not wrapped by the operation name. Instead, the serialized object is placed within an XML element using the XML-qualified type name (for example, <string>Hello, World</string>
).
The Send and SendReply activities also have a property named Content
. This property is of type SendContent and represents data the Send or SendReply activity sends. The .NET Framework defines two related types called SendMessageContent and SendParametersContent both of which are derived from SendContent. Set the Send or SendReply activity’s Content
property to an instance of one of these types to send data from a workflow service. The type to use depends upon the type of data the activity sends. If the activity sends a Message
object or a message contract type, use SendMessageContent. If the activity sends a data contract type use SendParametersContent. SendParametersContent allows you to send multiple parameters, whereas SendMessageContent only allows you to send one object, the message (or the message contract type).
When programming imperatively with the messaging activities, you use the generic InArgument<T> and OutArgument<T> to wrap the objects you assign to the message or parameters properties of the Send, SendReply, Receive, and ReceiveReply activities. Use InArgument<T> for the Send and SendReply activities and OutArgument<T> for Receive and ReceiveReply activities. In
arguments are used with the send activities because the data is being passed into the activities. Out
arguments are used with the receive activities because data is being passed out of the activities, as shown in the following example.
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) }
}
},
};
When implementing a workflow service that defines a request/response operation that returns void, you must instantiate a SendReply activity and set the Content property to an empty instance of one of the content types (SendMessageContent or SendParametersContent) as shown in the following example.
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();
};
Add service reference
When calling a workflow service from a workflow application, Visual Studio 2012 generates custom messaging activities that encapsulate the usual Send and ReceiveReply activities used in a request/reply MEP. To use this feature, right-click the client project in Visual Studio and select Add > Service Reference. Type the base address of the service in the address box and click Go. The available services are displayed in the Services: box. Expand the service node to display the contracts supported. Select the contract you want to call and the list of available operations is displayed in the Operations box. You can then specify the namespace for the generated activity and click OK. You then see a dialog that says the operation completed successfully and that the generated custom activities are in the toolbox after you have rebuilt the project. There is one activity for each operation defined on the service contract. After rebuilding the project you can drag and drop the custom activities onto your workflow and set any required properties in the properties window.
Messaging activity templates
To make setting up a request/response MEP on the client and service easier, Visual Studio 2012 provides two messaging activity templates. System.ServiceModel.Activities.Design.ReceiveAndSendReply
is used on the service and System.ServiceModel.Activities.Design.SendAndReceiveReply
is used on the client. In both cases the templates add the appropriate messaging activities to your workflow. On the service, the System.ServiceModel.Activities.Design.ReceiveAndSendReply
adds a Receive activity followed by a SendReply activity. The Request property is automatically set to the Receive activity. On the client, the System.ServiceModel.Activities.Design.SendAndReceiveReply
adds a Send activity followed by a ReceiveReply. The Request property is automatically set to the Send activity. To use these templates, just drag and drop the appropriate template onto your workflow.
Messaging activities and transactions
When a call is made to a workflow service you may want to flow a transaction to the service operation. To do this place the Receive activity within a TransactedReceiveScope activity. The TransactedReceiveScope activity contains a Receive
activity and a body. The transaction flowed to the service remains ambient throughout the execution of the body of the TransactedReceiveScope. The transaction is completed when the body finishes executing. For more information about workflows and transactions see Workflow Transactions.