<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ryan Vice&#039;s Blog &#187; Communication</title>
	<atom:link href="http://www.ryanvice.net/tag/communication/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ryanvice.net</link>
	<description>Implementation notes and development techniques</description>
	<lastBuildDate>Thu, 11 Feb 2010 13:43:14 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Using ExternalDataExchange Service in WF 3.5</title>
		<link>http://www.ryanvice.net/wf3-5/using-externaldataexchange-service-in-wf-3-5/</link>
		<comments>http://www.ryanvice.net/wf3-5/using-externaldataexchange-service-in-wf-3-5/#comments</comments>
		<pubDate>Fri, 09 Oct 2009 02:09:34 +0000</pubDate>
		<dc:creator>Ryan Vice</dc:creator>
				<category><![CDATA[ExternalDataExchange]]></category>
		<category><![CDATA[WF 3.5]]></category>
		<category><![CDATA[Communication]]></category>

		<guid isPermaLink="false">http://www.ryanvice.net/?p=24</guid>
		<description><![CDATA[Source Code Download
Every program answers two questions &#8220;what to do&#8221; and &#8220;when to do it.&#8221; Windows Workflow Foundation or WF is a part of the WinFX suite of tools which allows programmers to seperate the &#8220;what to do&#8221; and the &#8220;when to do it&#8221; and specifically allows you to declaratively model the &#8220;when to do [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/Echo.zip">Source Code Download</a></p>
<p>Every program answers two questions &#8220;what to do&#8221; and &#8220;when to do it.&#8221; Windows Workflow Foundation or WF is a part of the WinFX suite of tools which allows programmers to seperate the &#8220;what to do&#8221; and the &#8220;when to do it&#8221; and specifically allows you to declaratively model the &#8220;when to do it&#8221; allowing for easy creation of visual tools for working with the workflow logic. When using WF in this way one of the things you will need to learn to do is how to communicate back and forth between your WF code and your client code. This post will be covering the ExternalDataExchange service and how you can use it with built in activities to provide easy client\WF communications.</p>
<p><span id="more-24"></span></p>
<h2>Background</h2>
<p>Communication in WF is handled under the hood through queues which is out of the scope of this article but covered quite well in <span id="btAsinTitle"><a href="http://www.amazon.com/Essential-Windows-Workflow-Foundation-Dharma/dp/0321399838" target="_blank">Essential Windows Workflow Foundation</a>. For the purpose of this article we will be covering communication using built in WF services that take advantage of WF queuing abilities to communicate between client code and WF instances (WFIs) without you having to know the details. The way this works is show below. </span></p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/RegisteredLocalServicesSmall.jpg"><img title="Communicating Using Services" src="http://www.ryanvice.net/wp-content/uploads/2009/10/RegisteredLocalServicesSmall.jpg" alt="Communicating Using Services" width="445" height="270" /></a></p>
<p>Communication from the host (client) to the WFIs works by the host application calling into registered WF services to raise events that are then raised into WFIs. WFIs communicate with the host by calling methods on WF services which then turn around and call methods on the client. There are of course some details to work through here, like how to register services and how to wire up those services so that they can support this type of communication. The easiest way to do these things is to use the ExternalDataExchange service which is one of the core services that is included with WF. ExternalDataExchange allows you to register your own custom services with it and then provides all the plumbing needed to allow you to raise events from your services into workflows and allows your WFIs to call methods on your service for communicating back to your client code by mostly using interfaces and attributes. I will demonstrate this by showing the implementation of the ConsoleService.</p>
<h2>ConsoleService</h2>
<p>The ConsoleService is a contrived custom WF service that I&#8217;ve created that allows for writing to and reading from the console. The architecture of this service is shown below.</p>
<p> <a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService.jpg"><img class="alignnone size-full wp-image-57" title="ConsoleService" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService.jpg" alt="ConsoleService" width="445" height="279" /></a></p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService.jpg"></a></p>
<p>As you can see our Host Process will contain 3 components that will communicate with each other</p>
<ol>
<li>Console &#8211; System.Console class which will write to and read from the console
<ol>
<li>Calls ConsoleService.RaiseReadLine() to pass</li>
</ol>
</li>
<li>WorkflowRuntime &#8211; this is the heart of WF and will be responsible for creating and running WFIs and then providing services for those WFIs to use. One of these services will be the ConsoleService.</li>
<li>WorkflowInstance &#8211; a running workflow</li>
</ol>
<p>For this implementation the we will register the ExternalDataExchange service with the WorkflowRuntime and then we will create our ConsoleService and register it with the ExternalDataExchange service to allow us to communicate through our service to and from the System.Console from WFIs. One thing to keep in mind is that there are several ways of hosting the WorkflowRuntime and covering those is out of the scope of this article. You would most likely not host the WorkflowRuntime in a console applicaiton in production code. Let&#8217;s start by starting Visual Studio and creating a new Sequential Workflow Console Application project from under the Workflow project templates in visual studio.</p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ProjectTemplate1.jpg"><img class="alignnone size-full wp-image-44" title="ProjectTemplate" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ProjectTemplate1.jpg" alt="ProjectTemplate" width="445" height="315" /></a></p>
<p>This will generate the following code which I&#8217;ve commented to describe what each piece does</p>
<pre class="brush: csharp;">   class Program
   {
      static void Main(string[] args)
      {
         using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
         {
            // Thread wait handle used to block main thread until WFI thread completes
            AutoResetEvent waitHandle = new AutoResetEvent(false);

            // Wire up the WorkflowCompleted and WorkflowTerminated events on the WorkflowRuntime
            // and Set() the wait handle to allow main thread to be notified when this WFI completes
            workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); };
            workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
            {
               Console.WriteLine(e.Exception.Message);
               waitHandle.Set();
            };

            // Create a workflow instance using the CreateWorkflow overload that allows creating a
            // WFI from a .Net type
            WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(Echo.Workflow1));

            // Start the WFI
            instance.Start();

            // Wait for it to complete
            waitHandle.WaitOne();
         }
      }
   }
</pre>
<p>Next we need to create our ConsoleService. The key to being able to communicate back and forth with WFIs is implementing ExternalDataExchange attributed interface. Next add two interface, IReadLine and IWriteLine, to your project with the following definition. Make sure to add a reference to System.Workflow.Activities<span style="font-size: x-small;">.</span></p>
<pre class="brush: csharp;">[ExternalDataExchange]
   public interface IReadLine
   {
      event EventHandler&lt;ReadLineEventArgs&gt; LineRead;
      void ReadLine();
   }</pre>
<p> </p>
<pre class="brush: csharp;">[ExternalDataExchange]
 public interface IWriteLine
 {
      void WriteLine(string text);
 }</pre>
<p>The ExternalDataExchange attribute is all that you need to add to be able to raise events into WFIs and to be able to call methods from a WFI to a client. Any methods or events declared on the interface are ready for WF. Next we need to implement interfaces in our ConsoleService. Add a new class to your project called ConsoleService and add the code shown below.</p>
<pre class="brush: csharp;">   [Serializable]
   public class ConsoleService : IWriteLine, IReadLine
 {
      #region IWriteLine

      /// &lt;summary&gt;
      /// Allows WF instances to write a line of text to the console
      /// &lt;/summary&gt;
      ///
&lt;param name=&quot;text&quot;&gt;Specfies text to be written out.&lt;/param&gt;
      public void WriteLine(string text)
      {
         Console.WriteLine(text);
      }

      #endregion // IWriteLine

      #region IReadLine

      /// &lt;summary&gt;
      /// Raised to communicate that a line was read from the console and
      /// be delievered in the ReadLineEventArgs.Text
      /// &lt;/summary&gt;
      public event EventHandler&lt;ReadLineEventArgs&gt; LineRead;

      /// &lt;summary&gt;
      /// Will read a line of text from the console and then raise the LineReadEvent
      /// &lt;/summary&gt;
      ///
&lt;param name=&quot;instanceId&quot;&gt;Specfies instance ID of the WF instance that the LineRead event
      /// will be raised on.&lt;/param&gt;
      public void ReadLine()
      {
         RaiseLineRead(WorkflowEnvironment.WorkflowInstanceId, Console.ReadLine());
      }

      /// &lt;summary&gt;
      /// Allows WF clients to raise LineRead event for WF instances
      /// &lt;/summary&gt;
      ///
&lt;param name=&quot;instanceId&quot;&gt;Specifies the instanceId of the target WF instance&lt;/param&gt;
      ///
&lt;param name=&quot;text&quot;&gt;Specifies line of text read from client&lt;/param&gt;
      private void RaiseLineRead(Guid instanceId, string text)
      {
         if (LineRead != null)
         {
            LineRead(this, new ReadLineEventArgs(instanceId, text));
         }
      }

      #endregion // IReadLine
   }</pre>
<p>Fist thing to note is that any class that is used to communicate with WFIs needs to be serializable which is accomplished by adding the Serializable attribute. Also, As you can see ConsoleService implements both IReadLine and IWriteLine. WriteLine is pretty self explanitory. This method can now becalled from a WFI by using a CallExternalMethodActivity, but more on that later. ReadLine takes a little more work because it requires two-way communication which requires both a method (WFI to client) and an event (client to WFI). The WFI will indicate to the console service that it wants to read a line by calling ReadLine() as shown below.</p>
<pre class="brush: csharp;">public void ReadLine()
      {
         RaiseLineRead(WorkflowEnvironment.WorkflowInstanceId, Console.ReadLine());
      }</pre>
<p>This function grabs the currently running WFIs InstanceId using WorkflowEnvironment.WorkflowInstanceId and then passes as it to RaiseLineRead() along with the second argument which will be whatever text is read from the console using Console.ReadLine().</p>
<pre class="brush: csharp;">private void RaiseLineRead(Guid instanceId, string text)
      {
         if (LineRead != null)
         {
            LineRead(this, new ReadLineEventArgs(instanceId, text));
         }
      }</pre>
<p>RaiseLineRead first checks to make sure that there are subscribers to the LineRead event which there will be as soon as the ConsoleService is registered with the WorkflowRuntime&#8217;s ExternalDataExchangeService. It then raises the event passing a this refernece as the sender and a new ReadLineEventArgs as the second argument which gets the target WFIs instanceId and the text that was written as the second argument. Now add a new class called ReadLineEventArgs to your project and add the following code.</p>
<pre class="brush: csharp;">   [Serializable]
   public class ReadLineEventArgs : ExternalDataEventArgs
 {
      private string m_text;

      public string Text
      {
         get { return m_text; }
         set { m_text = value; }
      }

      public ReadLineEventArgs(Guid instanceId, string text)
         : base(instanceId)
      {
         Text = text;
      }
 }
</pre>
<p>Again we must make our class serializable using the Serializable attribute and then for this EventArgs to work with ExternalDataExchange we mush derive our custom Event args from ExternalDataEventArgs which is also in the System.Workflow.Activities namespace. When an event is raised against the ExternalDataExchange service, the service will use the instanceId which is passed to the constructor to deliever the event to the correct WFI. I&#8217;ve added a Text property to ReadLineEventArgs which will be populated with the text entered at the console and delievered to the WFI via an instance of ReadLineEventArgs. Next we need to add our service to the WorkflowRuntime.</p>
<h2>Registering ConsoleService</h2>
<p>Now we will update our host program to register the ConsoleService. The full host code is shown below.</p>
<pre class="brush: csharp;">
   class Program
   {
      static void Main(string[] args)
      {
         using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
         {
            // Thread wait handle used to block main thread until WFI thread completes
            AutoResetEvent waitHandle = new AutoResetEvent(false);

            // Wire up the WorkflowCompleted and WorkflowTerminated events on the WorkflowRuntime
            // and Set() the wait handle to allow main thread to be notified when this WFI completes
            workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); };
            workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
            {
               Console.WriteLine(e.Exception.Message);
               waitHandle.Set();
            };

            // Add ExternalDataExchangeService for communications
            ExternalDataExchangeService externalDataExchangeService
               = new ExternalDataExchangeService();
            workflowRuntime.AddService(externalDataExchangeService);
            // Add ConsoleService to externalDataExchangeService service for commincation back
            // to the client
            ConsoleService consoleService = new ConsoleService();
            externalDataExchangeService.AddService(consoleService);

            // Create a workflow instance using the CreateWorkflow overload that allows creating a
            // WFI from a .Net type
            WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(Echo.Workflow1));

            // Start the WFI
            instance.Start();

            // Wait for it to complete
            waitHandle.WaitOne();
         }
      }
   }
</pre>
<p>The code that registers that ConsoleService is shown below.</p>
<pre class="brush: csharp;">
            // Add ExternalDataExchangeService for communications
            ExternalDataExchangeService externalDataExchangeService
               = new ExternalDataExchangeService();
            workflowRuntime.AddService(externalDataExchangeService);
            // Add ConsoleService to externalDataExchangeService service for commincation back
            // to the client
            ConsoleService consoleService = new ConsoleService();
            externalDataExchangeService.AddService(consoleService);
</pre>
<p>First we create an ExternalDataExchange instance and add it to the workflowRuntime instance via the AddServiceMethod. Now that the externalDataExchange instance is added to the WorkflowRuntime&#8217;s registered services we can now create an instance of the ConsoleService and add it to the externalDataExchange instance which will make the ConsoleService available for use by the WFIs that are hosted by this WorkflowRuntime. We do this using externalDataExchange.AddService().</p>
<h2>Creating the Echo Workflow</h2>
<p>Next we will update Workflow1 which was created when we created our project to add activites that allow us to create a simple console echo program that will write out whatever text is written in. To get started open Workflow1.CS in the designer by double clicking it in solution explorer. Next drag and drop a CallExternalMethodActivity from the toolbox onto the designer&#8217;s surface and look at it&#8217;s properties in the property window.</p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService1.jpg"><img class="alignnone size-full wp-image-78" title="Click to see full sized image" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService1.jpg" alt="Click to see full sized image" width="987" height="597" /></a></p>
<p>As you can see in this image, the UI will display validation errors for you both on the activity on the designer surface as well as next to the properties that need to be addressed. For our demo we want to write out &#8220;Please enter text to echo: &#8221; to the console and so we need to select our <em>IWriteLine</em> interface for the <em>InterfaceType</em> and <em>WriteLine</em> for the <em>MethodName</em>. To do this first build your project then click on right side of <em>InterfaceType</em> and a button &#8216;&#8230;&#8221; will be displayed. Click that button then browse to the <em>IWriteLine</em> interface and select it as shown below.</p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService2.jpg"><img class="alignnone size-full wp-image-84" title="Click to see full sized image" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService2.jpg" alt="Click to see full sized image" width="822" height="622" /></a></p>
<p>After selecting the <em>InterfaceType</em> clicking on the <em>MethodName</em> text box will display a drop down of available methods and from the list select <em>WriteLine</em>. Once you select <em>WriteLine</em> notice that the parameters are dynamically added to the property window and you can now set the <em>text</em> parameter of <em>WriteLine</em>. Go ahead and set that to <em>Please enter text to echo:</em> and then set a more user friendly name for this activity like <em>PromptForEchoText</em>. Your property window should now look like this.</p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService3.jpg"><img class="alignnone size-full wp-image-87" title="Property window" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService3.jpg" alt="Property window" width="383" height="415" /></a></p>
<p>Go ahead and run the demo by clicking <em>CTRL+F5</em> and you should see your text displayed to the command line window. So now we have sucessfully communicated from the WFI to the client now lets try and bring some data back into the WFI. To do this add one more CallExternalMethodActivity to your workflow definition in the designer with</p>
<p><strong>(Name)</strong><br />
ReadLine</p>
<p><strong>InterfaceType<br />
</strong>IReadLine</p>
<p><strong>MethodName</strong><br />
ReadLine</p>
<p>Then add another activity but this time add a HandleExternalEventActivity and set the properties to:</p>
<p><strong>(Name)<br />
</strong>HandleLineRead</p>
<p><strong>InterfaceType<br />
</strong>IReadLine</p>
<p><strong>EventName<br />
</strong>LineRead</p>
<p>And now your WF definition should look like this.</p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService4.jpg"><img class="alignnone size-full wp-image-91" title="ConsoleService4" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService4.jpg" alt="ConsoleService4" width="153" height="266" /></a></p>
<p>What we have now will</p>
<ol>
<li>Ask for text</li>
<li>Call a <em>ConsoleService.ReadLine</em> to send a <em>Console.ReadLine </em>to the console</li>
<li>Handle the <em>ConsoleService.ReadLine</em> event that will be raised from the <em>ConsoleService</em> in  response to step 2</li>
</ol>
<p>So now you might be wondering where is the <em>Console.ReadLine</em> text and how can we write it back out. For that lets start by taking a look at dynamic properties that popped up on the <em>HandleLineRead </em>activity. In the group you will see <em>e</em>. This is <em>ReadLineEventArgs</em> which was the <em>ExternalDataEventArgs</em> derived class that contains a <em>Text</em> property and this is where the text that was read from the console is got to be now. That makes the next question how do we get this value to another <em>CallExternalMethod</em> so that we can write back out to the console. For that we will use property binding and bind to a new property on the base class.</p>
<p>Start by clicking the &#8220;&#8230;&#8221; button in the <em>HandleReadLine.e</em> text box to open the property binding dialog. Select the <em>Bind to a new member</em> tab and then set it like below.</p>
<p> <a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService5.jpg"><img class="alignnone size-full wp-image-94" title="Click image to see larger version" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService5.jpg" alt="Click image to see larger version" width="602" height="470" /></a></p>
<p>Now add a new <em>CallExternalMethod </em>activity to the end of the workflow with the following settings.</p>
<p><strong>(Name)</strong><br />
EchoText</p>
<p><strong>InterfaceType<br />
</strong>IWriteLine</p>
<p><strong>MethodName</strong><br />
WriteLine</p>
<p>Next we will again use property binding to get <em>ReadLineEventArg.Text</em> written out to the console. To do this click the &#8220;&#8230;&#8221; button in <em>EchoText.text</em> to open the property bind dialog and then browse to <em>ReadLineEventArg.Text</em> as shown below.</p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService6.jpg"><img class="alignnone size-full wp-image-97" title="Click image to see larger version" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService6.jpg" alt="Click image to see larger version" width="602" height="470" /></a></p>
<p> Now run the program by clicking <em>CTRL+F5.</em></p>
<p><em><a href="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService7.jpg"><img class="alignnone size-full wp-image-99" title="Click to see larger image" src="http://www.ryanvice.net/wp-content/uploads/2009/10/ConsoleService7.jpg" alt="ConsoleService7" width="677" height="340" /></a></em></p>
<h2>Conclusion</h2>
<p>Now you have the basics that are needed to communicate back and forth with clients through the <em>ExternalDataExchange</em> service. There are other options for communications including web services and WCF and you can roll your own with custom activites and services but <em>ExternalDataExchange</em> can be very handy and very quick to use.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ryanvice.net/wf3-5/using-externaldataexchange-service-in-wf-3-5/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
