<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Jason Prickett's Blog : Workflow</title><link>http://blogs.msdn.com/jpricket/archive/tags/Workflow/default.aspx</link><description>Tags: Workflow</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>WF - Creating an Activity Base Class</title><link>http://blogs.msdn.com/jpricket/archive/2008/04/23/wf-creating-an-activity-base-class.aspx</link><pubDate>Wed, 23 Apr 2008 20:58:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8419524</guid><dc:creator>Jason Prickett</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/jpricket/comments/8419524.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jpricket/commentrss.aspx?PostID=8419524</wfw:commentRss><description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;(or Designing Your Workflow Activity Class Hierarchy)&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;One of the questions that we've had to consider when designing our Workflow Activity Class Hierarchy is whether it is valuable to have our own Activity base class (derived from Activity and inherited by all of our activity classes).&lt;/p&gt;  &lt;p&gt;Our answer was &amp;quot;Yes&amp;quot;. We decided that there were several good reasons to create our own Activity base class. Here are the reasons and some explanation.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;Implement the Asynchronous Activity pattern for all our activities&lt;/strong&gt; - I described this pattern and the reasons that you want to do this in a &lt;a href="http://blogs.msdn.com/jpricket/archive/2008/01/25/wf-the-asynchronous-activity-service-pattern.aspx"&gt;previous post&lt;/a&gt;. Basically, the idea is that we want all our activities to do their work on a background thread so that they are cancelable. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Shared properties&lt;/strong&gt; - there were a few properties that we felt like we wanted on all our activities. I won't get into the specifics of them, but this is a reason to create any base class.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Common tracking and logging&lt;/strong&gt; - we wrote a little bit of code associated with Activity tracking and logging information about the workflow. We wanted to be consistent in the way that we logged about activities starting and stopping, so we put this code into the base class. We even have some generic code that logs all the Properties for our activities using the property collection that is inherited from the actual Activity class.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;strong&gt;Our base activity class gives us all this but here's the rub...&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;There are actually two Workflow Activity base classes. If you want to create a Composite activity (one that contains other activities), you have to derive that class from CompositeActivity instead of Activity. This is extremely unfortunate for us, because there were several activities that we wanted to create that were composite activities. But this means that they couldn't derive from our other base class. So, we had to re-implement some of the base classes functionality in our Composite activity class. This is why when I am designing a tree structure, I try not to make a separate base class for the tree nodes and the leaf nodes. Because, it screws up inheritance, polymorphism and a few other fancy OO words I can't recall.&lt;/p&gt;  &lt;p&gt;Keep this gotcha in mind when you start planning your Activity class hierarchy!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8419524" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jpricket/archive/tags/Workflow/default.aspx">Workflow</category></item><item><title>WF - The Asynchronous Activity/Service Pattern</title><link>http://blogs.msdn.com/jpricket/archive/2008/01/25/wf-the-asynchronous-activity-service-pattern.aspx</link><pubDate>Fri, 25 Jan 2008 19:14:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7242017</guid><dc:creator>Jason Prickett</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/jpricket/comments/7242017.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jpricket/commentrss.aspx?PostID=7242017</wfw:commentRss><description>&lt;p&gt;In my previous blog post (&lt;a href="http://blogs.msdn.com/jpricket/archive/2008/01/25/wf-creating-an-asynchronous-workflow-activity.aspx"&gt;Creating an Asynchronous Workflow Activity&lt;/a&gt;), I explained why your custom activities should either be really fast or run asynchronously. But, I didn't give you a real world example of how to do this. In this post I provide an example of the pattern that my team uses when creating a custom activity.&lt;/p&gt;  &lt;p&gt;Pattern:&lt;/p&gt;  &lt;p&gt;1) Create a service that actually does the work&lt;/p&gt;  &lt;p&gt;2) Create a custom activity that uses the service and has a Queue listener event handler to get a message back from the service when the work is done.&lt;/p&gt;  &lt;p&gt;Instead of walking you through this one, I just want to present you with the code, commented as much as I could :)&lt;/p&gt;  &lt;pre class="code"&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;DoSomethingAsyncService&lt;/span&gt; : &lt;span style="color: rgb(43,145,175)"&gt;WorkflowRuntimeService
&lt;/span&gt;    {
        &lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Random&lt;/span&gt; m_random;

        &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; DoSomethingAsyncService()
        {
            m_random = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Random&lt;/span&gt;();
        }

        &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; DoSomethingAsync(&lt;span style="color: rgb(43,145,175)"&gt;Guid&lt;/span&gt; instanceId, &lt;span style="color: rgb(43,145,175)"&gt;Guid&lt;/span&gt; queueId)
        {
            &lt;span style="color: rgb(43,145,175)"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;span style="color: rgb(0,0,255)"&gt;delegate&lt;/span&gt;(&lt;span style="color: rgb(43,145,175)"&gt;Object&lt;/span&gt; state)
                {
                    &lt;span style="color: rgb(0,128,0)"&gt;// Fake a call to a WebService (let's say it takes 10 seconds)
&lt;/span&gt;                    &lt;span style="color: rgb(43,145,175)"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;Making webservice call.&amp;quot;&lt;/span&gt;);
                    &lt;span style="color: rgb(43,145,175)"&gt;Thread&lt;/span&gt;.Sleep(10000);

                    &lt;span style="color: rgb(0,128,0)"&gt;// Create the QueueItem
&lt;/span&gt;                    &lt;span style="color: rgb(43,145,175)"&gt;QueueItem&lt;/span&gt; item = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;QueueItem&lt;/span&gt;();
                    item.ReturnCode = m_random.Next(0, 10);
                    item.Message = &lt;span style="color: rgb(43,145,175)"&gt;String&lt;/span&gt;.Format(&lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;The return code is {0}.&amp;quot;&lt;/span&gt;, item.ReturnCode);

                    &lt;span style="color: rgb(0,0,255)"&gt;try
&lt;/span&gt;                    {
                        &lt;span style="color: rgb(0,128,0)"&gt;// Now send this item to the appropriate queue
&lt;/span&gt;                        &lt;span style="color: rgb(43,145,175)"&gt;WorkflowInstance&lt;/span&gt; instance = Runtime.GetWorkflow(instanceId);
                        instance.EnqueueItem(queueId, item, &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;);
                    }
                    &lt;span style="color: rgb(0,0,255)"&gt;catch&lt;/span&gt; (&lt;span style="color: rgb(43,145,175)"&gt;InvalidOperationException&lt;/span&gt;)
                    {
                        &lt;span style="color: rgb(0,128,0)"&gt;// Catch any InvalidOperationExceptions that occur due to the 
&lt;/span&gt;                        &lt;span style="color: rgb(0,128,0)"&gt;// workflow having already completed, etc.
&lt;/span&gt;                    }
                });
        }
    }

    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;QueueItem
&lt;/span&gt;    {
        &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; ReturnCode;
        &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;String&lt;/span&gt; Message;
    }&lt;/pre&gt;

&lt;pre class="code"&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;DoSomethingAsyncActivity&lt;/span&gt; : &lt;span style="color: rgb(43,145,175)"&gt;Activity
&lt;/span&gt;    {
        &lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Guid&lt;/span&gt; m_queueId;

        &lt;span style="color: rgb(0,0,255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;override&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;ActivityExecutionStatus&lt;/span&gt; Execute(&lt;span style="color: rgb(43,145,175)"&gt;ActivityExecutionContext&lt;/span&gt; executionContext)
        {
            &lt;span style="color: rgb(0,128,0)"&gt;// Create my queue
&lt;/span&gt;            m_queueId = &lt;span style="color: rgb(43,145,175)"&gt;Guid&lt;/span&gt;.NewGuid();
            &lt;span style="color: rgb(43,145,175)"&gt;WorkflowQueuingService&lt;/span&gt; queuingService = (&lt;span style="color: rgb(43,145,175)"&gt;WorkflowQueuingService&lt;/span&gt;)executionContext.GetService(&lt;span style="color: rgb(0,0,255)"&gt;typeof&lt;/span&gt;(&lt;span style="color: rgb(43,145,175)"&gt;WorkflowQueuingService&lt;/span&gt;));
            &lt;span style="color: rgb(43,145,175)"&gt;WorkflowQueue&lt;/span&gt; queue = queuingService.CreateWorkflowQueue(m_queueId, &lt;span style="color: rgb(0,0,255)"&gt;true&lt;/span&gt;);

            &lt;span style="color: rgb(0,128,0)"&gt;// Hook the item available event. This event will be triggered when our
&lt;/span&gt;            &lt;span style="color: rgb(0,128,0)"&gt;// service enqueues an item.
&lt;/span&gt;            queue.QueueItemAvailable += &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;EventHandler&lt;/span&gt;&amp;lt;&lt;span style="color: rgb(43,145,175)"&gt;QueueEventArgs&lt;/span&gt;&amp;gt;(QueueItemAvailable);

            &lt;span style="color: rgb(0,128,0)"&gt;// Call the service to perform the async work.
&lt;/span&gt;            &lt;span style="color: rgb(43,145,175)"&gt;DoSomethingAsyncService&lt;/span&gt; service = (&lt;span style="color: rgb(43,145,175)"&gt;DoSomethingAsyncService&lt;/span&gt;)executionContext.GetService(&lt;span style="color: rgb(0,0,255)"&gt;typeof&lt;/span&gt;(&lt;span style="color: rgb(43,145,175)"&gt;DoSomethingAsyncService&lt;/span&gt;));
            service.DoSomethingAsync(WorkflowInstanceId, m_queueId);

            &lt;span style="color: rgb(0,128,0)"&gt;// Return Executing to let the workflow know that we are still working.
&lt;/span&gt;            &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;ActivityExecutionStatus&lt;/span&gt;.Executing;
        }

        &lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; QueueItemAvailable(&lt;span style="color: rgb(0,0,255)"&gt;object&lt;/span&gt; sender, &lt;span style="color: rgb(43,145,175)"&gt;QueueEventArgs&lt;/span&gt; e)
        {
            &lt;span style="color: rgb(0,128,0)"&gt;// The activity execution context is always passed in as the sender.
&lt;/span&gt;            &lt;span style="color: rgb(43,145,175)"&gt;ActivityExecutionContext&lt;/span&gt; context = sender &lt;span style="color: rgb(0,0,255)"&gt;as&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;ActivityExecutionContext&lt;/span&gt;;

            &lt;span style="color: rgb(0,128,0)"&gt;// Checking for a null context just in case something really strange is happening.
&lt;/span&gt;            &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt; (context != &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;)
            {
                &lt;span style="color: rgb(0,128,0)"&gt;// Get the queue service so we can get the Queue object.
&lt;/span&gt;                &lt;span style="color: rgb(0,128,0)"&gt;// Note: you cannot salt away the actual queue object, the Workflow runtime does not allow it.
&lt;/span&gt;                &lt;span style="color: rgb(43,145,175)"&gt;WorkflowQueuingService&lt;/span&gt; queuingService = context.GetService&amp;lt;&lt;span style="color: rgb(43,145,175)"&gt;WorkflowQueuingService&lt;/span&gt;&amp;gt;();

                &lt;span style="color: rgb(0,128,0)"&gt;// Make sure the queue exists before going any further.
&lt;/span&gt;                &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt; (queuingService.Exists(m_queueId))
                {
                    &lt;span style="color: rgb(43,145,175)"&gt;WorkflowQueue&lt;/span&gt; queue = queuingService.GetWorkflowQueue(m_queueId);

                    &lt;span style="color: rgb(0,128,0)"&gt;// Dequeue the item that was queued by the service.
&lt;/span&gt;                    &lt;span style="color: rgb(43,145,175)"&gt;QueueItem&lt;/span&gt; item = queue.Dequeue() &lt;span style="color: rgb(0,0,255)"&gt;as&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;QueueItem&lt;/span&gt;;
                    &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt; (item != &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;)
                    {
                        &lt;span style="color: rgb(0,128,0)"&gt;// We only expect one thing to ever be put into our Queue;
&lt;/span&gt;                        &lt;span style="color: rgb(0,128,0)"&gt;// so, now we remove the queue.
&lt;/span&gt;                        queue.QueueItemAvailable -= QueueItemAvailable;
                        queuingService.DeleteWorkflowQueue(m_queueId);

                        &lt;span style="color: rgb(0,128,0)"&gt;// Finally inspect the results and do something with them.
&lt;/span&gt;                        &lt;span style="color: rgb(43,145,175)"&gt;Console&lt;/span&gt;.WriteLine(item.Message);

                        &lt;span style="color: rgb(0,128,0)"&gt;// Once we have finished our mission, we close this activity
&lt;/span&gt;                        context.CloseActivity();
                        &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt;;
                    }
                }
            }

            &lt;span style="color: rgb(0,128,0)"&gt;// We should not get here if everything works as we expect.
&lt;/span&gt;            &lt;span style="color: rgb(0,128,0)"&gt;// So, throw an exception so the workflow will be terminated.
&lt;/span&gt;            &lt;span style="color: rgb(0,0,255)"&gt;throw&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Exception&lt;/span&gt;(&lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;Something unexpected was placed in the Queue.&amp;quot;&lt;/span&gt;);
        }
    }&lt;/pre&gt;

&lt;p&gt;Try creating a workflow that contains a Parallel activity and add this activity to both branches. If you really want to run activities in parallel, this is how it needs to be done.&lt;/p&gt;

&lt;p&gt;Don't forget to add the service to the runtime!&lt;/p&gt;

&lt;p&gt;Happy flowing!&lt;/p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7242017" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jpricket/archive/tags/Workflow/default.aspx">Workflow</category></item><item><title>WF - Creating an Asynchronous Workflow Activity</title><link>http://blogs.msdn.com/jpricket/archive/2008/01/25/wf-creating-an-asynchronous-workflow-activity.aspx</link><pubDate>Fri, 25 Jan 2008 17:57:40 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7241179</guid><dc:creator>Jason Prickett</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/jpricket/comments/7241179.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jpricket/commentrss.aspx?PostID=7241179</wfw:commentRss><description>&lt;p&gt;What a silly topic for a blog post! Workflow already runs my whole activity tree on a another thread, I don't have to worry about being Async, Do I? Yes, you do. While it is true that each Workflow gets its own thread (in the default setup), that thread can be easily blocked by a long running or hung activity. Let's look at an example...&lt;/p&gt;  &lt;p&gt;Create a Sequential Workflow Console application in Visual Studio with the following Activity tree:&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;Sequential Workflow&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;&amp;#160;&amp;#160;&amp;#160; WhileActivity (set the condition to true so it runs forever)&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CodeActivity (the code should just do a Console.WriteLine(&amp;quot;Hello World&amp;quot;)&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;So, now go to the Program.cs file or wherever the code is that Starts the workflow instance.&lt;/p&gt;  &lt;p&gt;Add a Thead.Sleep(1000) after the instance.Start() call and then an instance.Terminate(&amp;quot;kill workflow&amp;quot;) to stop the workflow.&lt;/p&gt;  &lt;p&gt;When you run the workflow, you should notice that you get a few &amp;quot;Hello World&amp;quot; lines and one &amp;quot;kill workflow&amp;quot; line. Here, terminate works just as you expect it to. But now let's change our workflow so that the while is done in the code activity...&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;Sequential Workflow&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;&amp;#160;&amp;#160;&amp;#160; CodeActivity (the code should contain &lt;font color="#ffff00"&gt;while(true) Console.WriteLine(&amp;quot;Hello World&amp;quot;)&lt;/font&gt;)&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;When you run the workflow this time, it will never end :(&lt;/p&gt;  &lt;p&gt;If you put a break point on the instance.Terminate line, it does get called. So, why doesn't the Workflow terminate? Well, like all other actions that happen in the workflow instance, the terminate action goes through a queue and waits for the background thread to dequeue it and do it. Unfortunately, the queue is only processed in between activities executing. So, the termination request remains in the workflow queue forever in our example. &lt;/p&gt;  &lt;p&gt;If you are running complex workflows that may need to actually be stopped in the middle (like we do) then you need to avoid code activities that have loops and start writing asynchronous custom activities. So, how do we write a custom activity so that it is stoppable? The first thing you have to do is create a workflow runtime service that can do the actual work for the activity. This means for every custom activity you need a new custom service or at least a new method on your custom service. Here's a sample service:&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;&amp;#160;&amp;#160;&amp;#160; public class HelloWorldService : WorkflowRuntimeService     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; public void WriteHelloWorldForeverAsync()      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ThreadPool.QueueUserWorkItem(delegate(Object state)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; while (true) Console.WriteLine(&amp;quot;Hello World&amp;quot;);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; });      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;This service will now do the work for us. But to use it, we need a custom activity. Here's the simplest custom activity you could make:&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;&amp;#160;&amp;#160;&amp;#160; public class WriteHelloWorldActivity : Activity     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; HelloWorldService service = (HelloWorldService)executionContext.GetService(typeof(HelloWorldService));      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; service.WriteHelloWorldForeverAsync();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return ActivityExecutionStatus.Executing;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;The key thing to note here is that the activity calls a method on the service that returns immediately after starting its background thread. The activity then returns Executing. This allows the workflow to dequeue items from the queue, but not move on to the next activity. Until this activity returns Closed, the next activity will not start.&lt;/p&gt;  &lt;p&gt;Oops! before you try and run this you need to create your service, add it to the runtime and add your custom activity to the workflow. In Program.cs, add the following line right after you create the runtime service:&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;workflowRuntime.AddService(new HelloWorldService());&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Then change the workflow to look like this:&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;Sequential Workflow&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#80ffff"&gt;&amp;#160;&amp;#160;&amp;#160; WriteHelloWorldActivity&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Now, you can run it and see that Terminate works again! Of course, in a real application you need more code than this, because you have to shut down the background thread when you get terminated, and you need to call back to your activity when the background work is finished! Tune in for my next post, where I will show you a real example of of an activity and service that do it all :)&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7241179" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jpricket/archive/tags/Workflow/default.aspx">Workflow</category></item><item><title>Stopping a Build -&gt; Cancelling a Workflow</title><link>http://blogs.msdn.com/jpricket/archive/2007/11/01/stopping-a-build-cancelling-a-workflow.aspx</link><pubDate>Thu, 01 Nov 2007 15:11:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5813300</guid><dc:creator>Jason Prickett</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/jpricket/comments/5813300.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jpricket/commentrss.aspx?PostID=5813300</wfw:commentRss><description>&lt;P&gt;This post continues my quest to learn more about Windows Workflow and share that experience with you. It assumes knowledge of Windows Workflow. If you don't understand some of the concepts please take a look at one of the books that I mentioned in &lt;A class="" href="http://blogs.msdn.com/jpricket/archive/2007/10/09/my-introduction-to-windows-workflow-foundation-wf.aspx" mce_href="http://blogs.msdn.com/jpricket/archive/2007/10/09/my-introduction-to-windows-workflow-foundation-wf.aspx"&gt;my first WF post&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;One of the operations that we require is the ability to Stop a Build that is in progress. This corresponds to Terminating a workflow. However, in our investigation of how WF handles Terminate, we discovered that it isn't what we really want. Termination of a workflow does not end the workflow immediately. That's not so bad, but it also doesn't give the workflow a chance to clean up anything (i.e. there are no handlers for termination). So, we looked into Cancellation of a workflow instead of using terminate.&lt;/P&gt;
&lt;P&gt;We found that it is really hard to cancel a workflow. First of all there is not a WorkflowInstance.Cancel method. So, if you plan to cancel the workflow from outside the instance, you have a hurdle to jump already. But if your workflow is like ours and you can put your own Activity class at the root, you can leap the hurdle pretty easily. What we did was to have the root activity create a Queue (we called it the cancellation queue) with a well known name (a hard coded Guid). From there it seemed obvious that we could Queue an item to this well known Queue and from within the instance call CancelActivity on the root. But alas, that is not allowed. You can only call CancelActivity on the currently executing activity. Bummer! So, we tried cancelling the executing activity, but that ended up just continuing the execution of the next activity after it which wasn't cancelled. Double Bummer!&lt;/P&gt;
&lt;P&gt;So, our final solution was to Throw when we got something in the Queue. Throwing automatically causes all activities to cancel including the active one. It also gives the workflow a place to do any clean up that needs to be done by catching the CancellationException at the top of the workflow.&lt;/P&gt;
&lt;P&gt;It wasn't pretty, but we were able to accomplish what we wanted. Here is a summary of the steps that actually worked for us:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;In the root level activity (which is our own class derived from one of the WF activities) we create a special Queue just for this situation. The Queue has a constant GUID for the name&lt;/LI&gt;
&lt;LI&gt;From outside the workflow, we get the WorkflowInstance and Enqueue an item into this special Queue.&lt;/LI&gt;
&lt;LI&gt;When an item is enqueued, our activity class Throws a special exception. That causes everything to get cancelled.&lt;/LI&gt;
&lt;LI&gt;Our cancellation handlers can do any clean up.&lt;/LI&gt;
&lt;LI&gt;We have a special fault handler that also catches this special exception and eats it, so that the workflow completes normally.&lt;/LI&gt;&lt;/OL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5813300" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jpricket/archive/tags/Team+Build/default.aspx">Team Build</category><category domain="http://blogs.msdn.com/jpricket/archive/tags/Workflow/default.aspx">Workflow</category></item><item><title>My Introduction to Windows Workflow Foundation (WF)</title><link>http://blogs.msdn.com/jpricket/archive/2007/10/09/my-introduction-to-windows-workflow-foundation-wf.aspx</link><pubDate>Tue, 09 Oct 2007 14:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5381694</guid><dc:creator>Jason Prickett</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/jpricket/comments/5381694.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jpricket/commentrss.aspx?PostID=5381694</wfw:commentRss><description>&lt;P&gt;Team Build is a build workflow tool. It manages how and when builds are performed. Currently (in VS2005 and VS2008), that workflow was written in the language of MSBuild. This allows us a lot of flexibility and power on the machine that runs the build. However, modifying the MS.TF.Build.Targets file that contained the description of the workflow was heavily discouraged and by no means easy. So, how can we make changing the workflow of the build easier. The first step (we believe) is to change the language that the workflow is described in. Windows Workflow is a natural choice. As we look at using Windows Workflow within Team Build, I will attempt to write some useful posts on things that we have discovered or realized.&amp;nbsp;Mostly things that the books don't talk about. This is my first attempt...&lt;/P&gt;
&lt;P&gt;First let me tell you about the books that I have read on WF. I read Bruce Bukovics' "Pro WF" first. This is a great starter for a developer wanting to write WF solutions. Bruce covers all of the functionality you would need to know. But, if you want to host WF and allow your users to manipulate the workflow directly, you need more details about how it works. The second and last book that I read on WF was "Essential Windows Workflow Foundation" by Dharma Shukla and Bob Schmidt. The Essentials book is really brief, but explains how WF Activities really work. If you plan on writing your own custom activities, this book is very useful.&lt;/P&gt;
&lt;P&gt;So, what did I learn. More importantly, what have I learned that I didn't get from the books. Well the first thing you should know is that you can represent a workflow in many different ways. The workflow is basically a tree of classes derived from Activity. There are two ways to represent the tree in the Visual Studio world: in code; and in XAML (basically XML). Workflow uses the extension XOML, however, to let VS know that its a workflow and not some kind of WPF stuff (more on WPF in another post). Working with code is the most natural way to deal with the Activity tree. In fact, even if you choose to create your workflow in XOML, VS will create a code behind file for you and compile your XOML into a dll.&lt;/P&gt;
&lt;P&gt;The first lesson we learned was... If you want to use XOML only and not do any code behind, you must create the XOML yourself or hand edit the XOML created by Visual Studio. When Visual Studio creates the XOML file, it assumes you will compile it. To compile XOML you need a special attribute on the root element in the XOML that tells the compiler to create a class. The attribute is "&lt;FONT color=#ff0000 size=2&gt;x:Class&lt;/FONT&gt;". If you create a XOML workflow in Visual Studio and open that XOML in the XML editor or in notepad, this should be the first attribute of the root element.&lt;/P&gt;
&lt;P&gt;When you load a workflow in the workflow runtime, there are two ways to do it. Call load with a type, this implies that the XOML or straight code workflow is compiled. Or you can call load with an xml reader, that has the XOML loaded. If you choose the xml reader option and that x:Class attribute is in the XOML, an error will be thrown by the runtime. However, if you try to compile XOML without that attribute, compilation will fail. So, the first choice you have to make in using XOML files is "To compile or not to compile" - that is the question ;)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5381694" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jpricket/archive/tags/Team+Build/default.aspx">Team Build</category><category domain="http://blogs.msdn.com/jpricket/archive/tags/Workflow/default.aspx">Workflow</category></item></channel></rss>