<?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; terminate</title>
	<atom:link href="http://www.ryanvice.net/tag/terminate/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>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; title: ; notranslate">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>10</slash:comments>
		</item>
	</channel>
</rss>

