<?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</title>
	<atom:link href="http://www.ryanvice.net/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>Simplified Event Raising Pattern in C#</title>
		<link>http://www.ryanvice.net/c/simplified-event-raising-pattern-in-c/</link>
		<comments>http://www.ryanvice.net/c/simplified-event-raising-pattern-in-c/#comments</comments>
		<pubDate>Sat, 30 Jan 2010 13:13:49 +0000</pubDate>
		<dc:creator>Ryan Vice</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Delegate]]></category>
		<category><![CDATA[Event]]></category>

		<guid isPermaLink="false">http://www.ryanvice.net/?p=215</guid>
		<description><![CDATA[When creating events most people do something like this

        public event PropertyChangedEventHandler PropertyChanged; 

        internal void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
A much simpler approach is to instead do this


        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        internal void [...]]]></description>
			<content:encoded><![CDATA[<p>When creating events most people do something like this</p>
<pre class="brush: csharp;">
        public event PropertyChangedEventHandler PropertyChanged; 

        internal void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }</pre>
<p>A much simpler approach is to instead do this</p>
<pre class="brush: csharp;">

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        internal void RaisePropertyChanged(string propertyName)
        {
            // No need for null check because of empty delegate
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }</pre>
<p>which eleminates the need for the null check and eliminates the potential race conditions in multi-threaded code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ryanvice.net/c/simplified-event-raising-pattern-in-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using BackgroundWorker with WPF</title>
		<link>http://www.ryanvice.net/wpf-3-5/using-backgroundworker-with-wpf/</link>
		<comments>http://www.ryanvice.net/wpf-3-5/using-backgroundworker-with-wpf/#comments</comments>
		<pubDate>Tue, 08 Dec 2009 18:17:54 +0000</pubDate>
		<dc:creator>Ryan Vice</dc:creator>
				<category><![CDATA[WPF 3.5]]></category>
		<category><![CDATA[BackgroundWorker]]></category>
		<category><![CDATA[DispatcherSynchronizationContext]]></category>
		<category><![CDATA[SynchronizationContext]]></category>
		<category><![CDATA[Threading]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://www.ryanvice.net/?p=186</guid>
		<description><![CDATA[Download Source
BackgroundWorker is a class that was introduced with in Windows Forms 2.0 to simplify executing work on background threads allowing UI developers to easily keep their UIs responsive by not tying up the UI thread. It&#8217;s a tool that was very useful and if you don&#8217;t already know then you&#8217;ll probably be very pleased [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/12/WpfBackgroundWorker.zip">Download Source</a></p>
<p>BackgroundWorker is a class that was introduced with in Windows Forms 2.0 to simplify executing work on background threads allowing UI developers to easily keep their UIs responsive by not tying up the UI thread. It&#8217;s a tool that was very useful and if you don&#8217;t already know then you&#8217;ll probably be very pleased to find out that you can still use BackgroundWorker in WPF. This is because BackgroundWorker uses AsyncOperationManager which in turn uses SynchronizationContext to marshall work. In Windows Forms AsyncOperationManager gets a WindowsFormsSynchronizationContext class from the Forms application that derives from the SynchronizationContext class and uses it for marshalling. When using WPF a DispatcherSynchronizationContext is fetched by AsyncOperationManager which allows for easy marshalling of calls to background threads using BackgroundWorker.</p>
<p><span id="more-186"></span></p>
<p>Below is sample code for a simple form that will take your name as input and the write out &#8220;Hello &#8221; as output after a 5 second delay. If you run the application you will see that it is responsive during the delay and that you can resize and move the windows around as you should be able to when doing work on background threads. The demo also shows how to pass a value (your name) from the UI to the background thread.</p>
<h2>Xaml</h2>
<pre class="brush: xml;">&lt;Window x:Class=&quot;WpfBackgroundWorker.Window1&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    Title=&quot;Window1&quot; Height=&quot;300&quot; Width=&quot;300&quot;&gt;
    &lt;StackPanel&gt;
        &lt;TextBlock x:Name=&quot;Header&quot; &gt;Enter your name&lt;/TextBlock&gt;
        &lt;TextBox x:Name=&quot;InputTextBox&quot; /&gt;
        &lt;Button x:Name=&quot;DoWorkButton&quot; Content=&quot;Do work&quot; Click=&quot;DoWorkButton_Click&quot; /&gt;
        &lt;TextBlock x:Name=&quot;OutputTextBlock&quot; /&gt;
    &lt;/StackPanel&gt;
&lt;/Window&gt;
</pre>
<h2>Code behind</h2>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Threading;

namespace WpfBackgroundWorker
{
    /// &lt;summary&gt;
    /// Interaction logic for Window1.xaml
    /// &lt;/summary&gt;
    public partial class Window1 : Window
    {
        private BackgroundWorker _backgroundWorker;

        public Window1()
        {
            InitializeComponent();

            // Will use DispatcherSynchronizationContext
            _backgroundWorker = new BackgroundWorker();

            // Wire up event handlers
            _backgroundWorker.DoWork
                += new DoWorkEventHandler(_backgroundWorker_DoWork);
            _backgroundWorker.RunWorkerCompleted
                += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
        }

        void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            string result = (string)e.Result;

            if (e.Cancelled)
            {
                OutputTextBlock.Text = &quot;Cancelled&quot;;
            }
            else if (e.Error != null)
            {
                OutputTextBlock.Text = &quot;Exception: &quot; + e.Error.Message;
            }
            else
            {
                OutputTextBlock.Text = result;
            }
        }

        void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // Wait 5 seconds to simulate long running work
            Thread.Sleep(5000);

            // Assign the result to the Result property
            // of the DoWorkEventArgs
            // object. This is will be available to the
            // RunWorkerCompleted eventhandler.
            e.Result = &quot;Hello &quot; + e.Argument.ToString();
        }

        private void DoWorkButton_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(InputTextBox.Text))
            {
                MessageBox.Show(&quot;You must enter a name.&quot;);
                return;
            }

            // Do work on background thread
            _backgroundWorker.RunWorkerAsync(InputTextBox.Text);
        }
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ryanvice.net/wpf-3-5/using-backgroundworker-with-wpf/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SQL Query to Get Tracking Data in Workflow Foundation 3.5</title>
		<link>http://www.ryanvice.net/wf3-5/sql-query-to-get-tracking-data-in-workflow-foundation-3-5/</link>
		<comments>http://www.ryanvice.net/wf3-5/sql-query-to-get-tracking-data-in-workflow-foundation-3-5/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 14:12:09 +0000</pubDate>
		<dc:creator>Ryan Vice</dc:creator>
				<category><![CDATA[Tracking]]></category>
		<category><![CDATA[WF 3.5]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.ryanvice.net/?p=176</guid>
		<description><![CDATA[Below is a query that will return tracking data when using the SQL

Simply substitue the GUID for the WF instance that you want to find out tracking details about and then fire the query to see the tracking data.

declare  @WorkflowInstanceInternalId   bigint

select   @WorkflowInstanceInternalId = WorkflowInstanceInternalId
from dbo.WorkflowInstance
where
         WorkflowInstanceId = [...]]]></description>
			<content:encoded><![CDATA[<p>Below is a query that will return tracking data when using the SQL</p>
<p><span id="more-176"></span></p>
<p>Simply substitue the GUID for the WF instance that you want to find out tracking details about and then fire the query to see the tracking data.</p>
<pre>
<pre class="brush: sql;">declare  @WorkflowInstanceInternalId   bigint

select   @WorkflowInstanceInternalId = WorkflowInstanceInternalId
from dbo.WorkflowInstance
where
         WorkflowInstanceId = 'E3573C8D-96D7-47C9-AE64-CB3E197A18CE'

select   wie.EventDateTime,
         'Workflow ' + twe.Description [Status],
         wie.EventOrder,
         '' [QualifiedName],
         '' [TypeName],
         '' [UserDataKey],
         '' [UserData_str]
from dbo.WorkflowInstanceEvent wie
   inner join dbo.TrackingWorkflowEvent twe
      on (wie.TrackingWorkflowEventId = twe.TrackingWorkflowEventId)
where wie.WorkflowInstanceInternalId = @WorkflowInstanceInternalId
union
select   se.EventDateTime,
         aes.Description [Status],
         se.EventOrder,
         ai.QualifiedName,
         case when charindex('.',reverse(t.TypeFullName)) &gt; 1
                   then right(t.TypeFullName,charindex('.',reverse(t.TypeFullName))-1)
                   else ''
            end [Type],
         '' [UserDataKey],
         '' [UserData_str]
from dbo.ActivityExecutionStatusEvent se
   inner join dbo.ActivityExecutionStatus aes
      on (se.ExecutionStatusId = aes.ExecutionStatusId)
   inner join dbo.ActivityInstance ai
      on (se.ActivityInstanceId = ai.ActivityInstanceId)
   inner join dbo.WorkflowInstance wi
      on (ai.WorkflowInstanceInternalId = wi.WorkflowInstanceInternalId)
   left join dbo.Activity a
      on (a.WorkflowTypeId = wi.WorkflowTypeId
      and ai.QualifiedName = a.QualifiedName)
   inner join dbo.Type t
      on (a.ActivityTypeId = t.TypeId)
where se.WorkflowInstanceInternalId = @WorkflowInstanceInternalId
union
select   ue.EventDateTime,
         'UserData' [Status],
         ue.EventOrder,
         ai.QualifiedName,
         '' [TypeName],
         ISNULL(ue.UserDataKey, '') [UserDataKey],
         ue.UserData_str
from dbo.vw_UserEvent ue
   inner join dbo.ActivityInstance ai
      on (ue.ActivityInstanceId = ai.ActivityInstanceId)
where ue.WorkflowInstanceInternalId = @WorkflowInstanceInternalId
order by EventOrder,
         EventDateTime</pre>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ryanvice.net/wf3-5/sql-query-to-get-tracking-data-in-workflow-foundation-3-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Oracle Persistence Service for Windows Workflow Foundation 3.5</title>
		<link>http://www.ryanvice.net/wf3-5/oracle-persistence-service-for-windows-workflow-foundation-3-5/</link>
		<comments>http://www.ryanvice.net/wf3-5/oracle-persistence-service-for-windows-workflow-foundation-3-5/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 11:34:44 +0000</pubDate>
		<dc:creator>Ryan Vice</dc:creator>
				<category><![CDATA[Persistence]]></category>
		<category><![CDATA[WF 3.5]]></category>
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://www.ryanvice.net/?p=166</guid>
		<description><![CDATA[guptashail on the WF forum posted this implementation of a oracle persistence service.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using System.Workflow.ComponentModel;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
using System.Data;
using System.Configuration;
using System.IO;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Collections.Specialized;
using System.Transactions;
namespace OracleWorkflowDemoService
{
    class OraclePersistenceService : WorkflowPersistenceService, IPendingWork
    {
        private readonly object _lockTimer;
        private readonly TimeSpan _loadInterval;
        private Timer _loadIntervalTimer;

        public OraclePersistenceService(NameValueCollection parameters)
            : this(parameters[&#34;UnloadOnIdle&#34;] != null ? bool.Parse(parameters[&#34;UnLoadOnIdle&#34;]) [...]]]></description>
			<content:encoded><![CDATA[<p><a href="/Forums/en-US/user/threads?user=guptashail">guptashail</a> on the <a href="http://social.msdn.microsoft.com/Forums/en-US/windowsworkflowfoundation/thread/65f0d9b6-ff81-4677-826b-ae6e01edad1c">WF forum</a> posted this implementation of a oracle persistence service.</p>
<p><span id="more-166"></span></p>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using System.Workflow.ComponentModel;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
using System.Data;
using System.Configuration;
using System.IO;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Collections.Specialized;
using System.Transactions;
namespace OracleWorkflowDemoService
{
    class OraclePersistenceService : WorkflowPersistenceService, IPendingWork
    {
        private readonly object _lockTimer;
        private readonly TimeSpan _loadInterval;
        private Timer _loadIntervalTimer;

        public OraclePersistenceService(NameValueCollection parameters)
            : this(parameters[&quot;UnloadOnIdle&quot;] != null ? bool.Parse(parameters[&quot;UnLoadOnIdle&quot;]) : false,
                parameters[&quot;InstanceOwnershipDuration&quot;] != null ? int.Parse(parameters[&quot;InstanceOwnershipDuration&quot;]) : 0,
                parameters[&quot;LoadInterval&quot;] != null ? int.Parse(parameters[&quot;LoadInterval&quot;]) : 0)
        {
        }

        protected OraclePersistenceService(Boolean unloadOnIdle, int instanceOwnershipDuration, int loadInterval)
        {
            _lockTimer = new object();
            _loadInterval = new TimeSpan(0,0,loadInterval);
        }       

        protected override void Start()
        {
            base.Start();
        }

        protected override void OnStarted()
        {
            try
            {
                base.OnStarted();

                if (_loadInterval &gt; TimeSpan.Zero)
                {
                    lock (_lockTimer)
                    {
                        _loadIntervalTimer = new Timer(LoadExpiredWorkflows, null, _loadInterval, _loadInterval);
                    }
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        protected override void OnStopped()
        {
            base.OnStopped();
        }

        protected override void Stop()
        {
            base.Stop();
        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;scopeId&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;outerActivity&quot;&gt;&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        protected override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity)
        {
            //get the workflow instance ID
            Guid instanceId = WorkflowEnvironment.WorkflowInstanceId;
            Activity activity = Deserialize(instanceId, scopeId, outerActivity);
            if (activity == null)
            {
                RaiseException(instanceId,
                &quot;Unable to deserialize activity&quot;, null);
            }
            return activity;
        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;instanceId&quot;&gt;&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        protected override Activity LoadWorkflowInstanceState(Guid instanceId)
        {
            Activity activity = Deserialize(instanceId, Guid.Empty, null);
            if (activity == null)
            {
                RaiseException(instanceId, &quot;Unable to deserialize workflow&quot;, null);
            }
            return activity;
        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;activity&quot;&gt;&lt;/param&gt;
        protected override void SaveCompletedContextActivity(Activity activity)
        {
            WorkItem workItem = new WorkItem();

            workItem.activity = activity;
            workItem.contextId = (Guid)activity.GetValue(Activity.ActivityContextGuidProperty);
            workItem.instanceId = WorkflowEnvironment.WorkflowInstanceId;
            workItem.State = WorkItem.workflowState.ActiveInstance;

            WorkflowEnvironment.WorkBatch.Add(this, workItem);
        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;rootActivity&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;unlock&quot;&gt;&lt;/param&gt;
        protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
        {
            //get the workflow instance ID
            Guid WFinstanceId = WorkflowEnvironment.WorkflowInstanceId;

            //determine the status of the workflow
            WorkflowStatus status = WorkflowPersistenceService.GetWorkflowStatus(rootActivity);
            WorkItem workItem = new WorkItem();
            workItem.activity = rootActivity;
            workItem.instanceId = WFinstanceId;
            workItem.contextId = Guid.Empty;

            switch (status)
            {
                case WorkflowStatus.Completed:
                case WorkflowStatus.Terminated:
                    workItem.State = WorkItem.workflowState.Completed;
                    break;
                default:
                    workItem.State = WorkItem.workflowState.ActiveInstance;
                    break;
            }

            WorkflowEnvironment.WorkBatch.Add(this, workItem);
        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;activity&quot;&gt;&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        protected override bool UnloadOnIdle(Activity activity)
        {
            //always unload on idle
            return true;
        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;rootActivity&quot;&gt;&lt;/param&gt;
        protected override void UnlockWorkflowInstanceState(Activity rootActivity)
        {

        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;instanceId&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;contextId&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;activity&quot;&gt;&lt;/param&gt;
        private void Serialize(Guid instanceId, Guid contextId, Activity activity)
        {
            OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings[&quot;OraclePersistenceService&quot;].ConnectionString);
            try
            {
                string commandtext = &quot;&quot;;
                string result = &quot;&quot;;

                OracleCommand comd = new OracleCommand();
                comd.Connection = conn;
                comd.BindByName = true;

                TimerEventSubscriptionCollection timerEvent =
                    (TimerEventSubscriptionCollection)activity.GetValue(
                    TimerEventSubscriptionCollection.TimerCollectionProperty);

                DateTime nexttimer = new DateTime();

                if (timerEvent != null)
                {
                    TimerEventSubscription timerEventSubscription = timerEvent.Peek();
                    if (timerEventSubscription != null)
                        nexttimer = timerEventSubscription.ExpiresAt;
                }
                             
               
                OracleParameter param1 = comd.Parameters.Add(&quot;instanceid&quot;, OracleDbType.Char, 36);
                param1.Direction = ParameterDirection.Input;
                param1.Value = instanceId.ToString();

                OracleParameter param2 = comd.Parameters.Add(&quot;state&quot;, OracleDbType.Blob);
                param2.Direction = ParameterDirection.Input;
                param2.Value = GetDefaultSerializedForm(activity);

                OracleParameter param3 = comd.Parameters.Add(&quot;nexttimer&quot;, OracleDbType.TimeStamp);
                param3.Direction = ParameterDirection.Input;
                param3.Value = nexttimer.ToLocalTime();

                commandtext = &quot;Select uidInstanceId from InstanceState where uidInstanceId = '&quot; + instanceId.ToString() + &quot;'&quot;;
                comd.CommandText = commandtext;

                conn.Open();

                result = (string)comd.ExecuteScalar();

                if (result == null)
                {
                    commandtext = &quot; Insert into InstanceState (uidInstanceID,state,Modified,NextTimer) VALUES (:instanceid, :state,sysdate,:nexttimer) &quot;;
                }
                else
                {
                    commandtext = &quot; Update InstanceState set state = :state, Modified = sysdate, NextTimer = :nexttimer where uidInstanceId = :instanceid  &quot;;
                }

                comd.CommandText = commandtext;               
                comd.ExecuteNonQuery();
             

                if (!contextId.Equals(Guid.Empty))
                {
                    commandtext = &quot;Select contextId from ContextState where contextId = '&quot; + contextId.ToString() + &quot;'&quot;;
                    comd.CommandText = commandtext;
                    result = (string)comd.ExecuteScalar();

                    if (result == null)
                    {
                        commandtext = &quot; Insert into ContextState (uidInstanceID,contextId,state,Modified,ActivityName) VALUES (:instanceid, :contextid, :state, sysdate,'&quot; + activity.Name + &quot;') &quot;;
                    }
                    else
                    {
                        commandtext = &quot; Update ContextState set state = :state, Modified = sysdate where uidInstanceId = :instanceid and contextId = :contextid &quot;;
                    }

                    comd.Parameters.Remove(param3);
                    OracleParameter param4 = comd.Parameters.Add(&quot;contextid&quot;, OracleDbType.Char, 36);
                    param4.Direction = ParameterDirection.Input;
                    param4.Value = contextId.ToString();

                    comd.CommandText = commandtext;
                    comd.ExecuteNonQuery();

                }
                   

            }
            catch (Exception ex)
            {
                RaiseException(instanceId,
                &quot;Exception in serialization&quot;, ex);
            }
            finally
            {
                if (conn.State == ConnectionState.Open)
                    conn.Close();

            }
        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;instanceId&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;contextId&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;rootActivity&quot;&gt;&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        private Activity Deserialize(Guid instanceId, Guid contextId, Activity rootActivity)
        {
            Activity activity = null;
            OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings[&quot;OraclePersistenceService&quot;].ConnectionString);
            try
            {

                OracleCommand comd = new OracleCommand();
                string commandtext = &quot;&quot;;

                comd.Connection = conn;
                comd.BindByName = true;

                OracleParameter param1 = comd.Parameters.Add(&quot;state&quot;, OracleDbType.Blob);
                param1.Direction = ParameterDirection.Output;

                OracleParameter param2 = comd.Parameters.Add(&quot;instanceid&quot;, OracleDbType.Char, 36);
                param2.Direction = ParameterDirection.Input;
                param2.Value = instanceId.ToString();

                if (!contextId.Equals(Guid.Empty))
                {
                    commandtext = &quot;Begin SELECT state into :state from ContextState WHERE uidInstanceId = :instanceid and contextId = :contextid; END;&quot;;
                    OracleParameter param3 = comd.Parameters.Add(&quot;contextid&quot;, OracleDbType.Char, 36);
                    param3.Direction = ParameterDirection.Input;
                    param3.Value = contextId.ToString();
                }
                else
                {
                    commandtext = &quot;Begin SELECT state into :state from InstanceState WHERE uidInstanceId = :instanceid; END;&quot;;
                }
                              
                comd.CommandText = commandtext;            
               
                conn.Open();
                comd.ExecuteNonQuery();

                activity = RestoreFromDefaultSerializedForm((byte[])((OracleBlob)(comd.Parameters[0].Value)).Value, rootActivity);               
               
            }
            catch (Exception ex)
            {
                RaiseException(instanceId,
                &quot;Exception in deserialization&quot;, ex);
            }
            finally
            {
                if (conn.State == ConnectionState.Open)
                    conn.Close();

            }
            return activity;
        }

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;instanceId&quot;&gt;&lt;/param&gt;
        private void DeleteWorkflow(Guid instanceId)
        {

            OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings[&quot;OraclePersistenceService&quot;].ConnectionString);
            try
            {
                OracleCommand comd = new OracleCommand(String.Concat(&quot;Delete InstanceState where uidInstanceId = '&quot;, instanceId.ToString(), &quot;'&quot;), conn);

                conn.Open();

                comd.ExecuteNonQuery();

                comd.CommandText = String.Concat(&quot;Delete contextstate where uidInstanceId = '&quot;, instanceId.ToString(), &quot;'&quot;);
                comd.ExecuteNonQuery();

            }
            catch (Exception e)
            {
                RaiseException(instanceId,
                &quot;Exception in deletion&quot;, e);
            }
            finally
            {
                if (conn.State == ConnectionState.Open)
                    conn.Close();

            }
        }

        private void RaiseException(Guid instanceId, String message, Exception ex)
        {
            if (ex == null)
            {
                throw new PersistenceException(
                String.Format(&quot;Workflow: {0} Error: {1}&quot;,
                instanceId, message));
            }
            else
            {
                throw new PersistenceException(
                String.Format(&quot;Workflow: {0} Error: {1}: Inner: {2}&quot;,
                instanceId, message, ex.Message), ex);
            }
        }

        #region IPendingWork Members

        public void Commit(Transaction transaction, System.Collections.ICollection items)
        {
            try
            {
                foreach (WorkItem item in items)
                {
                    if (item.State == WorkItem.workflowState.ActiveInstance)
                        Serialize(item.instanceId, item.contextId, item.activity);
                    else
                        DeleteWorkflow(item.instanceId);

                }
            }
            catch (Exception ex)
            {
                RaiseException(Guid.Empty, &quot;Exception in commit&quot;, ex);
            }
        }

        public void Complete(bool succeeded, System.Collections.ICollection items)
        {

        }

        public bool MustCommit(System.Collections.ICollection items)
        {
            return true;
        }

        #endregion
      

        /// &lt;summary&gt;
        ///
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;state&quot;&gt;&lt;/param&gt;
        private void LoadExpiredWorkflows(object state)
        {
            lock (_lockTimer)
            {
                if (State != WorkflowRuntimeServiceState.Started)
                    return;
               
                OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings[&quot;OraclePersistenceService&quot;].ConnectionString);
                try
                {
                    OracleCommand comd = new OracleCommand(&quot;Select uidInstanceId from InstanceState where nexttimer &lt; sysdate &quot;, conn);

                    conn.Open();

                    OracleDataReader reader = comd.ExecuteReader();

                    while (reader.Read())
                    {
                        Runtime.GetWorkflow(new Guid(reader[&quot;uidInstanceId&quot;].ToString())).Load();
                    }

                }
                catch (Exception ex)
                {
                    RaiseException(Guid.Empty, &quot;Exception in loading expired workflows&quot;, ex);
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }               
            }
        }
    }
     

    class WorkItem
    {
        public Activity activity;
        public Guid instanceId;
        public Guid contextId;
        public workflowState State;

        public enum workflowState
        {
            /// &lt;summary&gt;
            /// Pending work item is for a workflow instance.
            /// &lt;/summary&gt;
            ActiveInstance,
            /// &lt;summary&gt;
            /// Pending work item is for a completed scope.
            /// &lt;/summary&gt;
            Completed
        }
   
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ryanvice.net/wf3-5/oracle-persistence-service-for-windows-workflow-foundation-3-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hosting WorkflowRuntime 3.5 as a Windows Service</title>
		<link>http://www.ryanvice.net/wf3-5/hosting-workflowruntime-3-5-as-a-windows-service/</link>
		<comments>http://www.ryanvice.net/wf3-5/hosting-workflowruntime-3-5-as-a-windows-service/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 20:50:16 +0000</pubDate>
		<dc:creator>Ryan Vice</dc:creator>
				<category><![CDATA[WF 3.5]]></category>
		<category><![CDATA[Hosting]]></category>
		<category><![CDATA[SynchronizationContext]]></category>
		<category><![CDATA[Threading]]></category>
		<category><![CDATA[Windows Service]]></category>
		<category><![CDATA[WPF 3.5]]></category>

		<guid isPermaLink="false">http://www.ryanvice.net/?p=128</guid>
		<description><![CDATA[ Download Source
Hosting in a windows service has a few gotcha&#8217;s to it as I found out on my first WF project and I wanted to share those here to hopefully help others to get things running much quicker than I did.

Introduction
The code to host in a Windows service is the same as in any other [...]]]></description>
			<content:encoded><![CDATA[<p> <a href="http://www.ryanvice.net/wp-content/uploads/2009/11/WorkflowHostService.zip">Download Source</a></p>
<p>Hosting in a windows service has a few gotcha&#8217;s to it as I found out on my first WF project and I wanted to share those here to hopefully help others to get things running much quicker than I did.</p>
<p><span id="more-128"></span></p>
<h2>Introduction</h2>
<p>The code to host in a Windows service is the same as in any other windows application and you can find those details <a href="http://odetocode.com/Articles/457.aspx" target="_blank">here</a>. However, hosting in a Windows service needs some special handling and this is because you need to call <em>WorkflowRuntime.StartRuntime()</em>, <em>WorkflowRuntime.StopRuntime()</em>, and <em>WorkflowRuntime.Dispose()</em> on the same thread and the SCM (<a href="http://msdn.microsoft.com/en-us/library/ms685150(VS.85).aspx" target="_blank">Service Control Manager</a>) which is the Windows service that will call your Windows Services <em>OnStart()</em> and <em>OnStop</em>()<em> </em>methods will call these methods on different threads which is illustrated below. </p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/11/SCMThreading.JPG"><img class="alignnone size-full wp-image-134" title="SCMThreading" src="http://www.ryanvice.net/wp-content/uploads/2009/11/SCMThreading.JPG" alt="SCMThreading" width="837" height="469" /></a></p>
<p>You will want to put <em>WorkflowRuntime.StartRuntime() </em>in your <em>OnStart()</em> method and you will want to put your calls to <em>WorkflowRuntime.StopRuntime()</em> and <em>WorkflowRuntime.Dispose()</em> in the <em>OnStop()</em> method and you will need a way to make sure that all of these calls are preformed on the same thread or you will exprience issues like server hangs on shutdown.</p>
<h2>SyncronizationContext</h2>
<p>A custom SynchronizationContext is the tool that I used to preform calls on the same thread. My code is based on the threading <a href="http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=313446" target="_blank">articles by mikeperetz</a> and I won&#8217;t be covering the threading details in this article so please see Mike&#8217;s articles for those details. I&#8217;ve taken the code in that article series and created my own custom SynchronizationContext called <em>MainThreadSynchronizationContext</em> which is included in the sample code and allows for you to easily marshal calls to the same thread by using the <em>Send</em> method shown below.</p>
<pre class="brush: csharp;">

    public partial class WorkflowServer : ServiceBase
    {
        private MainThreadSynchronizationContext _syncContext = null;
        WorkflowRuntime _runtime = null;

        public WorkflowServer()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            // Create new thread using MainThreadSynchronizationContext and then
            // send message to call Start() on the new &quot;Main WF Thread&quot; thread
            _syncContext = new MainThreadSynchronizationContext(&quot;Main WF Thread&quot;);
            _syncContext.Send(Start, null);
        }

        // Will be called on &quot;Main WF Thread&quot;
        protected void Start(object data)
        {
            _runtime = new WorkflowRuntime();
            _runtime.StartRuntime();

            // Do other WF related processing
        }

        protected override void OnStop()
        {
            // Call Stop() on &quot;Main WF Thread&quot;
            _syncContext.Send(Stop, null);
        }

        // Will be called on &quot;Main WF Thread&quot;
        protected void Stop(object data)
        {
            _runtime.StopRuntime();
            _runtime.Dispose();
        }
    }</pre>
<p>If you use this technique your server will start and stop nicely and you won&#8217;t experience any hangs on shutdown which was something we were seeing a lot on my current project.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ryanvice.net/wf3-5/hosting-workflowruntime-3-5-as-a-windows-service/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Abort on Error in Windows Workflow Foundation 3.5</title>
		<link>http://www.ryanvice.net/wf3-5/abort-on-error-in-windows-workflow-foundation-3-5/</link>
		<comments>http://www.ryanvice.net/wf3-5/abort-on-error-in-windows-workflow-foundation-3-5/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 19:55:53 +0000</pubDate>
		<dc:creator>Ryan Vice</dc:creator>
				<category><![CDATA[WF 3.5]]></category>
		<category><![CDATA[abort]]></category>
		<category><![CDATA[exception]]></category>
		<category><![CDATA[SqlWorkflowPersistenceService]]></category>
		<category><![CDATA[terminate]]></category>

		<guid isPermaLink="false">http://www.ryanvice.net/?p=109</guid>
		<description><![CDATA[The default error handling in WF 3.5 is a bit of a pain point IMHO. Basically when an unhandled exception occurs in a workflow that WFI (WF instance) will be terminated and can&#8217;t be restarted. The model that you use to handle exception in WF is through fault handlers in your WF definitions in the same way [...]]]></description>
			<content:encoded><![CDATA[<p>The default error handling in WF 3.5 is a bit of a pain point IMHO. Basically when an unhandled exception occurs in a workflow that WFI (WF instance) will be terminated and can&#8217;t be restarted. The model that you use to handle exception in WF is through <a href="http://msdn.microsoft.com/en-us/magazine/dd419656.aspx" target="_blank">fault handlers in your WF definitions</a> in the same way you would use exception handlers in a non-WF program. This is not always desired and in many cases it&#8217;d be preferred to be able to abort the WFI instead which allows for you to retry the activity that threw the exception. For example say you have an activity that updates the DB that fails because the connection to the DB was down, you wouldn&#8217;t want to have to restart your workflow and then try and get it back to the same state it was in, it&#8217;d be much better to have it abort and restart from the same point when you load it again. In WF 4.0 they have moved to aborting WFIs when an exception is thrown and my current project required this kind of behavior which I was able to achieve with some help from <a href="http://social.msdn.microsoft.com/Profile/en-US/?user=jimblust&amp;referrer=http%3a%2f%2fsocial.msdn.microsoft.com%2fForums%2fen-US%2fwindowsworkflowfoundation%2fthread%2f1144a689-57a7-44a3-bf15-076aa9d010de%2f&amp;rh=mQJ8NnGztRTd5DQBpH8dCRE8u60DzpnHdLB0jW%2by2lA%3d&amp;sp=forums" target="_blank">jimblust</a> on the WF forum who told me about the technique in this article. He came up with it but never used it himself because he felt it was too much of a hack but my requirements called for this behavior so I used it.</p>
<p><span id="more-109"></span></p>
<h2>Aborting SQL Server</h2>
<p>The way it works is by creating a custom <em>SQLWorkflowPersistenceService</em> by deriving from <em>SQLWorkflowPersistenceService</em> and then overriding the save method as shown below.</p>
<p> </p>
<pre class="brush: csharp;">protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
{
WorkflowStatus workflowStatus = WorkflowPersistenceService.GetWorkflowStatus(rootActivity);
if (workflowStatus == WorkflowStatus.Terminated)
    {
string workflowError = WorkflowPersistenceService.GetSuspendOrTerminateInfo(rootActivity);
if (string.IsNullOrEmpty(workflowError))
            throw new Exception(&quot;Workflow terminated, forcing an abort!&quot;);
    }
base.SaveWorkflowInstanceState(rootActivity, unlock);
}</pre>
<p>  As you can see when the status is <em>WorkflowStatus.Terminated</em>an exception is thrown. When an exception is thrown from the service layer the associated WFI will abort which will effectively roll back to the last persistence point. This will allow you to restart the WFI from the last persistence point by redoing whatever external stimulus that caused it to start running before the exception occurred.</p>
<h2>Gotchas</h2>
<p>There are a few gotchas to be aware of when using this technique.</p>
<h3>Duplicates in Tracking </h3>
<p>You will get duplicate entries in your tracking data. Tracking data is saved with ordinal values that specify the order that the tracked events occured in. When using the <em>SQLTrackingService</em> these ordinal values aren&#8217;t enforced to be unique. What happens is that the tracking service will keep writing until the point that the exception is thrown from your custom SQL persistence service and then when you restart your WFI the tracking service will start again from the same ordinal that it was on when the last persistence point was reached before the error and you will get duplicate entries with the same ordinal numbers. You can code around this and filter by ordinal and date to get a better view of what happened before and after the exception but it is something to be aware of.</p>
<h2>Repeating Activities</h2>
<p>Using this technique will effectively roll back your WFI to the last persistence point but this has the side effect that when you restart the WFI you will repeat all the activities that executed after the last persistence point and up till the activity that threw the error. I got around this on my current project by forcing persists after each activity executes by having my custom activities all derive from a base class that has the <em>PersistOnClose</em> attribute declared on it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ryanvice.net/wf3-5/abort-on-error-in-windows-workflow-foundation-3-5/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<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>5</slash:comments>
		</item>
		<item>
		<title>WF 3.5 Class at TechFest</title>
		<link>http://www.ryanvice.net/wf3-5/techfest-wf/hello-world/</link>
		<comments>http://www.ryanvice.net/wf3-5/techfest-wf/hello-world/#comments</comments>
		<pubDate>Wed, 12 Aug 2009 02:32:18 +0000</pubDate>
		<dc:creator>Ryan Vice</dc:creator>
				<category><![CDATA[TechFest]]></category>
		<category><![CDATA[WF 3.5]]></category>

		<guid isPermaLink="false">http://www.ryanvice.net/?p=1</guid>
		<description><![CDATA[

I taught Windows Workflow Foundation 3.5 at TechFest at the University of Houston this year. It was a great time and I hope everyone who came out enjoyed the class. Below are links for downloading the PowerPoint presentation and also the code samples that I used during this class. I&#8217;m planning to make some proper [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone" title="Ryan teaching at TechFest 2009" src="http://public.blu.livefilestore.com/y1psjQ874I_ybMYwOdsPmqa_OS_h78iOMPdccVzjaXNyMR4P-OAcJfnzyJKfO8QEPjlRqOFl9WI9mMuRrW18WbstQ/20090926_TechFest2009_0043.jpg" alt="" width="600" height="398" /></p>
<p><img class="alignnone size-full wp-image-13" style="border: black 1px solid;" title="Ryan Vice at TechFest" src="http://www.ryanvice.net/wp-content/uploads/2009/08/WorkflowClassSmall.jpg" alt="WorkflowClassSmall" width="640" height="480" /></p>
<p>I taught <a href="http://houstontechfest.com/dotnetnuke/HoustonTechFest/Sessions/tabid/56/CodecampId/1/SessionId/177/Default.aspx" target="_blank">Windows Workflow Foundation 3.5</a> at TechFest at the University of Houston this year. It was a great time and I hope everyone who came out enjoyed the class. Below are links for downloading the PowerPoint presentation and also the code samples that I used during this class. I&#8217;m planning to make some proper articles with the code samples that walk through the same things I walked through in class and hopefully will have that up soon.</p>
<p><a href="http://www.ryanvice.net/wp-content/uploads/2009/08/Windows-Workflow-Foundation-3.pptx">Windows Workflow Foundation 3.5 Presentation</a><br />
<a href="http://www.ryanvice.net/wp-content/uploads/2009/08/TechFestConsoleDemos.zip">Code Samples from TechFest</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ryanvice.net/wf3-5/techfest-wf/hello-world/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
