WCF Transport Channels with Windows Workflow Foundation

Requirements:


Download Demo: Download

Introduction

The /n software WCF Channels can be used together with the Receive and Send activities in Workflow Foundation 4.0. In this example, we'll use the FTP channel to start a new Workflow instance when files with a specific name are discovered on an FTP server, and then use a Send activity to submit a message as yet another file on the FTP server.

Contents

  1. Creating the Solution
  2. Defining Data Contracts
  3. Creating the Workflow
  4. Response Endpoint Configuration
  5. Creating the Workflow Service Host
  6. Testing the Workflow

Creating the Solution

We'll start by creating a new Workflow Console Application project in Visual Studio 2010:

Creating a new Workflow Console Application in Visual Studio 2010

We'll use this project to define our Workflow Service and host the WorkflowServiceHost instance that will execute our FTP services.

Once the project has been created, we'll add a reference to the WCF FTP transport channel assembly:

Adding a reference to the WCF FTP transport channel assembly

Defining Data Contracts

We now need to define what our data contracts for our messages will look like. For this, we first need to add a reference to System.Runtime.Serialization to our project, and then we'll add a new C# source code file called Contracts.cs to our project.

In it, we'll define a simple message for our incoming message:

[DataContact(Namespace = "urn:ftp-processor:request")]
public class ProcessResponse {
  DataMember(Order = 1)]
  public int ID;
  DataMember(Order = 2)]
  public String Sender;
}

Now let's define another class for our outgoing message:

[DataContact(Namespace = "urn:ftp-processor:request")]
public class ProcessResponse {
  DataMember(Order = 1)]
  public int RequestID;
  DataMember(Order = 2)]
  public String ResponseData;
	  
  public ProcessResponse(int id, String data) {
	  this.RequestID = id;
  this.ResponseData = data;
}

Creating the Workflow

Our workflow process is going to be very simple: We'll receive a new request message, write its contents to the console and then prepare and send a response.

We'll start by opening Workflow1.xaml in the designer and dragging a Sequence activity on it. Then we'll start the sequence with a new Receive activity. The activity properties should be set like this:


Property Value
DisplayName Receive Request
OperationName Process
ServiceContractName IFtpProcessor
Action *
CanCreateInstance True (checked)
Content Message (checked)
Message data: request
Message type: FtpProcessor.ProcessRequest

We need to define a workflow variable named request of type FtpProcess.ProcessRequest in the workflow Variables window, so that it can hold the request message from the receive activity:

FtpProcess.ProcessRequest Workflow Variables Window

Now, let's add a WriteLine activity to log the request contents, right after the Receive activity. We'll configure its properties like this:


Property Value
DisplayName Log Request
Text String.Format("Request ID: {0}. Sender={1}.", request.ID, request.Sender)

Now, let's create the response message. First, let's add a workflow variable named response of type FtpProcessor.ProcessResponse:

FtpProcess.ProcessRequest Workflow Variables Window

Now we'll add an Assign activity with the properties like this:


Property Value
DisplayName Create Response
To Response
Value New ProcessResponse(request.ID, "Message processed")

Now, let's add a new Send activity to send the response over FTP again. We'll configure its properties like this:


Property Value
DisplayName Send Response
EndpointConfigurationName ftpResponse
OperationName Send
ServiceContractName IFtpProcessorResponse
Action Response
Content Message data: response
Message type: FtpProcessor.ProcessResponse

The resulting workflow should look like this:

FtpProcess.ProcessRequest Workflow Variables Window

Response Endpoint Configuration

In the last step in the workflow, we defined the endpoint where the response message should be send will be configured through app.config through the WCF endpoint configuration called "ftpResponse".

Before we can run the workflow, we need to edit App.Config to create this endpoint configuration for our FTP channel, like this:

<system.serviceModel>
  <extensions>
    <bindingExtensions>
      <add name="ftpBinding" type="nsoftware.Wcf.FTP.FTPBindingCollectionElement, nsoftware.Wcf.FTP"/>	       
    </bindingExtensions>
  </extensions>
  <bindings>
    <ftpBinding>
      <binding name="ftpBindingConfig"
               user="<user>"
               password="<password>"
               SSLAcceptServerCertAcceptAny="true"
               overwrite="true"
               textEncoding="utf=8" />
    </ftpBinding>
  </bindings>
  <client>
    <endpoint name="ftpResponse"
              binding="ftpBinding"
              address="ftp://<server_name>/process/response.xml"
              contract="IFtpProcessorResponse"
              bindingConfiguration="ftpBindingConfig" />
  </client>
</system.serviceModel>

Creating the Workflow Service Host

Now that we have the workflow define, let's modify the Main() method in Program.cs to use the System.ServiceModel.Activities.WorkflowServiceHost class. We'll rewrite the method like this:

static void main(string[] args) {
  WorkflowServiceHost host = null;
  try {
    host = new WorkflowServiceHost(new Workflow1());
    Binding binding = GetBinding();
    host.AddServiceEndpoint("IFtpProcess", binding, "ftp://<serverip>");
    host.Open();
    Console.WriteLine("Host read.");
    Console.ReadLine();
  } catch (Exception ex) {
    Console.WriteLine("Error creating WorkflowServiceHost: {0}", ex);
  } finally {
    if (host != null) {
      if (host.State == CommunicationsState.Faulted) {
        host.Abort();
      } else {
        host.Close();
      }
    }
  }
}

We'll also define a GetBinding() method like this:

static  Binding GetBinding() {
  FTPBinding binding = new FTPBinding();
  binding.User = "user;
  binding.Password = "password;
  binding.RemotePath = "process";
  binding.FileMask = "request*.xml";
  binding.Delete = true;
  binding.SSLAcceptServerCertAcceptAny = true;
  binding.TransportLogType = FTPLogTypes.ltFile;
  binding.TransportLogLocation = @"c:\ftp.log";
  binding.TransportLogMode = FTPLogModes.lmDebug;
  binding.PollingInterval = 10;
  return binding;
}

Testing the Workflow

To test the workflow, we'll run the project, and then drop a file named request1.xml to the process/ folder of the FTP server with the contents:

<ProcessRequest xmlns="urn:ftp-processor:request">
  <ID>1</ID>
  <Sender>12330MN23</Sender>
  <ResponseFile>response1.xml</ResponseFile>
</ProcessRequest>

If everything was setup correctly, we should see the workflow processing the message when it is picked up by the WCF channel, as well as the response.xml reply message being sent to the FTP server:

Host ready.
Request ID: 1. Sender=12330MN23.

Get The Demo

You can download the demo here.


We appreciate your feedback.  If you have any questions, comments, or suggestions about this article please contact our support team at kb@nsoftware.com.