<?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; Persistence</title>
	<atom:link href="http://www.ryanvice.net/category/wf3-5/persistence/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ryanvice.net</link>
	<description>Implementation notes and development techniques</description>
	<lastBuildDate>Sun, 10 Oct 2010 12:34:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<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.]]></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; title: ; notranslate">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>9</slash:comments>
		</item>
	</channel>
</rss>

