<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">Say wwhhhaaaat?</title><subtitle type="html">Visual Studio Team Foundation Server Build - North Carolina</subtitle><id>http://blogs.msdn.com/b/patcarna/atom.aspx</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/b/patcarna/atom.aspx" /><generator uri="http://telligent.com" version="5.6.583.17018">Telligent Community 5.6.583.17018 (Build: 5.6.583.17018)</generator><updated>2009-02-06T17:16:00Z</updated><entry><title>Windows Communication Foundation - The Basics (Part 1)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2011/08/03/windows-communication-foundation-the-basics-part-1.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2011/08/03/windows-communication-foundation-the-basics-part-1.aspx</id><published>2011-08-03T10:07:00Z</published><updated>2011-08-03T10:07:00Z</updated><content type="html">&lt;p&gt;No matter how much I read about WCF in online forums and blog posts, I still couldn’t grasp the whole idea behind the extensibility model until I was able to play with it myself. What I discovered along the way is how the entire channel model works and how the binding and endpoint address fit into the equation. Although this may seem like I’m diving in details quickly, I personally find it very useful to illustrate real world scenarios to really show you the power of the API. On that note, I’d like to dive right in to how WCF generates your proxy channel for you at runtime and how the binding fits into this model. With this knowledge we will be able to create our own custom channel implementation that provides a sort of “message replay” ability in the face of connectivity issues.&lt;/p&gt;  &lt;h3&gt;Binding&lt;/h3&gt;  &lt;p&gt;The way I think about the binding class is that it is nothing more than the actual networking stack implementation. If you have any background in computer networking, you should be fully aware that the low-level TCP/IP network protocols are layered on top of each other. In this example, IP is the core transport protocol and TCP packets are simply carried as a payload. If we view this layering of protocols by analyzing the flow of packets, we find something like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Sender: TCP –&amp;gt; IP ……. Receiver: IP –&amp;gt; TCP&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;As you can see, on the way out the IP layer is the last to see the packets, and on the way in the IP layer is the first to receive the packets. In order for this system to work the two layers need to play by the rules, meaning they conform to a common set of rules and restrictions. Much in this same way, the &lt;em&gt;Binding &lt;/em&gt;object provides the ability to layer protocols on top of one another, just at a higher level than the previous example. This provides a generic way to model a networking stack, where each layer performs some function and typically delegates further behavior to the next layer down in the stack. From a binding, you can build a &lt;em&gt;IChannelFactory&amp;lt;TChannel&amp;gt;&lt;/em&gt; instance where &lt;em&gt;TChannel&lt;/em&gt; is one of the built-in channel shapes (e.g. &lt;em&gt;IRequestChannel&lt;/em&gt;, &lt;em&gt;IOutputChannel&lt;/em&gt;, etc). Depending on how you order the binding elements in the binding, you wind up with a different layering of the channels involved. &lt;/p&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;The main purpose of the &lt;em&gt;Binding &lt;/em&gt;object is to construct the lower level networking stack, which by itself this is not completely useful since we are still communicating with remote services at a very low level. We still need to handle formatting incoming and outgoing messages manually, which typically isn’t the most desirable thing to do. This is where the next layer of the WCF model comes in, which provides this mapping of service methods to messages and understands how to format both requests and responses to and from the remote service.&lt;/p&gt;    &lt;p&gt;Next time we’ll take a look at the &lt;em&gt;ServiceChannel &lt;/em&gt;object and how it uses the &lt;em&gt;Binding&lt;/em&gt; to provide us with a usable client service. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10192448" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Windows Communication Foundation–The Journey Begins ..</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2010/09/09/windows-communication-foundation-the-journey-begins.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2010/09/09/windows-communication-foundation-the-journey-begins.aspx</id><published>2010-09-09T00:19:12Z</published><updated>2010-09-09T00:19:12Z</updated><content type="html">&lt;p&gt;The 2010 release provided a dramatic shift in the build platform. Previous releases were built on top of MSBuild, providing integration through custom tasks and a special logger for tracking events during a build. Current and future releases are built on Windows Workflow Foundation, providing a design experience in Visual Studio and the ability to orchestrate a build process across multiple machines. During the product development cycle I learned quite a bit about workflow (having access to the architect didn’t hurt), since I was essentially forced to do so by the collective direction of my team. Once the product cycle was over I took some of my down time to post knowledge gained during the process to (hopefully) help others learn. &lt;/p&gt;  &lt;p&gt;Now we’re developing the next release and I have been driven down a similar, yet different, path of making extensive use of the Windows Communication Foundation libraries. Through many long nights (sadly enough I actually found that I missed them) I have been slowly expanding my knowledge base in this area of the .NET framework. I must admit that upon first glance the API seems extremely complicated. The size of the library is enormous and there are so many customization points it becomes tough to determine the appropriate hook. However, once you understand the pieces and how they fit together you have infinite possibilities at your disposal. &lt;/p&gt;  &lt;p&gt;Sorry to spoil the fun, but this isn’t the first installment …. soon though, very soon.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10059580" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Busy busy busy ...</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2010/06/01/busy-busy-busy.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2010/06/01/busy-busy-busy.aspx</id><published>2010-06-01T18:45:09Z</published><updated>2010-06-01T18:45:09Z</updated><content type="html">&lt;p&gt;I apologize to my reader or so&amp;nbsp;for the lack of updates recently. I have been knee deep in work for our next release and have not had much spare time. I will also be fixing my code segments soon which are now cut off due to the re-theming of our blogs.&lt;/p&gt;
&lt;p&gt;Patrick&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10018394" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Windows Workflow 4.0 – Workflow Instance Extensions</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2010/01/19/windows-workflow-4-0-workflow-instance-extensions.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2010/01/19/windows-workflow-4-0-workflow-instance-extensions.aspx</id><published>2010-01-19T19:01:00Z</published><updated>2010-01-19T19:01:00Z</updated><content type="html">&lt;P&gt;&lt;STRONG&gt;Update 01/20/2009: Since I failed to mention this before I wanted to make something clear about these workflow posts.&amp;nbsp;All information in these posts is based on the knowledge I gained through&amp;nbsp;developing a framework based on&amp;nbsp;Windows Workflow 4.0. I am not a member of the team nor is this information in any way endorsed by the team.&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In the previous posts we covered one way you could implement a producer-consumer pattern in workflow. This approach used composition and attempted to hide the complexities of the underlying operations inside of the respective activities through composition. However, one scenario in particular this model does not allow you to implement involves modeling of existing .NET events in a workflow. For instance, if we want to implement a &lt;A href="http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(VS.100).aspx"&gt;FileSystemWatcher&lt;/A&gt; activity we need to provide some way for consumers to hook into the events exposed by the .NET object. The only way to accomplish our goal is to hook up to the .NET events and schedule workflow actions from our event handler – but how would this be implemented? Let’s take a look at some more pieces of the workflow framework that will allow us to accomplish this goal.&lt;/P&gt;
&lt;H4&gt;Workflow Extensions&lt;/H4&gt;
&lt;P&gt;Each workflow instance has a collection of objects known as extensions that are able to interface with both the workflow and the host. By default no extensions exist, but they may be added to an instance by the host prior to calling the run method using the &lt;A href="http://msdn.microsoft.com/en-us/library/system.activities.hosting.workflowinstanceextensionmanager(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.activities.hosting.workflowinstanceextensionmanager(VS.100).aspx"&gt;WorkflowInstanceExtensionManager&lt;/A&gt;. Both &lt;A href="http://msdn.microsoft.com/en-us/library/system.activities.workflowapplication(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.activities.workflowapplication(VS.100).aspx"&gt;WorkflowApplication&lt;/A&gt; and &lt;A href="http://msdn.microsoft.com/en-us/library/system.activities.workflowinvoker(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.activities.workflowinvoker(VS.100).aspx"&gt;WorkflowInvoker&lt;/A&gt; provide access to the extension manager by a property named &lt;EM&gt;Extensions&lt;/EM&gt;. There are two distinct ways to attach an extension to a workflow instance using this property:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd780994(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/dd780994(VS.100).aspx"&gt;WorkflowInstanceExtensionManager.Add(Object singletonExtension)&lt;/A&gt; – Allows you to add a singleton instance of an object to the workflow instance. This is useful if you intend to share a particular extension across instances. It is up to the host to manage the lifetime of the service, although the workflow will remove references to your service. &lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/ee473669(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/ee473669(VS.100).aspx"&gt;WorkflowInstanceExtensionManager.Add&amp;lt;T&amp;gt;(Func&amp;lt;T&amp;gt; extensionCreationFunction)&lt;/A&gt; – Allows you to provide an anonymous function to create your extension on demand. Services created through this mechanism are owned by the workflow instance so the lifetime is managed by the instance as well. If the service object implements &lt;EM&gt;IDisposable&lt;/EM&gt; then the dispose method will be invoked when the instance is unloaded. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;There is a third way to add extensions to a workflow instance, and is typically used when an activity requires an extension for correct function. If you have been following through these posts, you may recall our usage of the method &lt;EM&gt;NativeActivity.CacheMetadata(NativeActivityMetadata)&lt;/EM&gt; when implementing the ParallelItemScheduler&amp;lt;T&amp;gt;. In addition to providing a location to declare your arguments and variables, you may also use the method for validation warnings/errors and more importantly providing extension creation functions for required extensions.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/ee473628(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/ee473628(VS.100).aspx"&gt;NativeActivityMetadata.AddDefaultExtensionProvider&amp;lt;T&amp;gt;(Func&amp;lt;T&amp;gt; extensionProvider) where T : class&lt;/A&gt; – Allows an activity to inform the runtime to create the specified extension using the provided function if the extension does not already exist. The host may or may not provide this particular extension, so the runtime ensures that only one instance of this extension type is created. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Another related scenario for the &lt;EM&gt;CacheMetadata&lt;/EM&gt; method is to inform the runtime that you require an extension that is not provided by you. The following two APIs allow you to specify extension types that you require for an activity to function correctly. If the extension does not exist at runtime a validation error is created informing the user that a required extension does not exist.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/ee473617(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/ee473617(VS.100).aspx"&gt;NativeActivityMetadata.RequireExtension&amp;lt;T&amp;gt;()&lt;/A&gt; – Informs the runtime that an extension of type &lt;EM&gt;T&lt;/EM&gt; is required for this activity to work. &lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/ee473624(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/ee473624(VS.100).aspx"&gt;NativeActivityMetadata.RequireExtension(Type extensionType)&lt;/A&gt; – Informs the runtime that an extension of type &lt;EM&gt;extensionType&lt;/EM&gt; is required for this activity to work. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;If you take a quick look back at the API for adding extensions you’ll notice that an extension is just an &lt;EM&gt;Object&lt;/EM&gt; and is not restricted to any particular base class or type. However, there are some scenarios where the extension may need to interact with the workflow via bookmarks, and in order to do that we need some way to get the &lt;EM&gt;WorkflowInstanceProxy&lt;/EM&gt; (a trimmed down version of &lt;EM&gt;WorkflowApplication&lt;/EM&gt; that provides limited method access from inside a workflow) so we can resume bookmarks. This is where the interface &lt;A href="http://msdn.microsoft.com/en-us/library/system.activities.hosting.iworkflowinstanceextension(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.activities.hosting.iworkflowinstanceextension(VS.100).aspx"&gt;IWorkflowInstanceExtension&lt;/A&gt; comes in handy! This interface is defined as follows:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;namespace &lt;/SPAN&gt;System.Activities.Hosting
{
    &lt;SPAN style="COLOR: blue"&gt;public interface &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;IWorkflowInstanceExtension
    &lt;/SPAN&gt;{
        &lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Object&lt;/SPAN&gt;&amp;gt; GetAdditionalExtensions();
        &lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;SetInstance(&lt;SPAN style="COLOR: #2b91af"&gt;WorkflowInstanceProxy &lt;/SPAN&gt;instance);
    }
}&lt;/PRE&gt;
&lt;P&gt;Any time an extension is attached (though either mechanism) that implements the above interface the runtime will invoke both methods. The first method provides an entry point for creating additional extensions. The second method is the more interesting one for our current discussion, as it provides the extension with the owning workflow instance proxy. A typical implementation for this method is to simply store the provided parameter into a member variable for later use by the extension. For illustration purposes, and since it leads us to our next destination, I have pasted an example of how we might design an item scheduling extension for interfacing with our ParallelItemScheduler&amp;lt;T&amp;gt; activity.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ItemSchedulerExtension&lt;/SPAN&gt;&amp;lt;T&amp;gt; : &lt;SPAN style="COLOR: #2b91af"&gt;IWorkflowInstanceExtension
&lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;internal &lt;/SPAN&gt;ItemSchedulerExtension()
    {
    }

    &lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Object&lt;/SPAN&gt;&amp;gt; &lt;SPAN style="COLOR: #2b91af"&gt;IWorkflowInstanceExtension&lt;/SPAN&gt;.GetAdditionalExtensions()
    {
        &lt;SPAN style="COLOR: blue"&gt;return null&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;IWorkflowInstanceExtension&lt;/SPAN&gt;.SetInstance(&lt;SPAN style="COLOR: #2b91af"&gt;WorkflowInstanceProxy &lt;/SPAN&gt;instance)
    {
        m_instance = instance;
    }

    &lt;SPAN style="COLOR: blue"&gt;public void &lt;/SPAN&gt;Schedule(&lt;SPAN style="COLOR: #2b91af"&gt;Bookmark &lt;/SPAN&gt;bookmark, T item)
    {
        m_instance.BeginResumeBookmark(bookmark, item, s_timeout, &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCallback&lt;/SPAN&gt;(OnEndResumeBookmark), &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;);
    }

    &lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;OnEndResumeBookmark(&lt;SPAN style="COLOR: #2b91af"&gt;IAsyncResult &lt;/SPAN&gt;result)
    {
        &lt;SPAN style="COLOR: blue"&gt;try
        &lt;/SPAN&gt;{
            &lt;SPAN style="COLOR: #2b91af"&gt;BookmarkResumptionResult &lt;/SPAN&gt;resumptionResult = m_instance.EndResumeBookmark(result);
            &lt;SPAN style="COLOR: #2b91af"&gt;Debug&lt;/SPAN&gt;.Assert(resumptionResult == &lt;SPAN style="COLOR: #2b91af"&gt;BookmarkResumptionResult&lt;/SPAN&gt;.Success, &lt;SPAN style="COLOR: #a31515"&gt;"Error resuming bookmark. Reason: " &lt;/SPAN&gt;+ resumptionResult);
        }
        &lt;SPAN style="COLOR: blue"&gt;catch &lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;Exception &lt;/SPAN&gt;ex)
        {
            &lt;SPAN style="COLOR: #2b91af"&gt;Debug&lt;/SPAN&gt;.Fail(&lt;SPAN style="COLOR: #a31515"&gt;"Exception occurred while resuming bookmark."&lt;/SPAN&gt;, ex.ToString());
        }
    }

    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;WorkflowInstanceProxy &lt;/SPAN&gt;m_instance;
    &lt;SPAN style="COLOR: blue"&gt;static readonly &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;TimeSpan &lt;/SPAN&gt;s_timeout = &lt;SPAN style="COLOR: #2b91af"&gt;TimeSpan&lt;/SPAN&gt;.FromMinutes(2);
}&lt;/PRE&gt;
&lt;P&gt;As you can see the implementation of this particular extension is minimal and straightforward. We do not have additional extensions so we can simply return null. Our SetInstance implementation simply stores the workflow instance proxy into our member variable so we can use it in our &lt;EM&gt;Schedule &lt;/EM&gt;implementation. Finally, the schedule method simply resumes a bookmark using the asynchronous pattern for the &lt;EM&gt;ResumeBookmark&lt;/EM&gt; method. &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Note: I would like to point out that the synchronous versions of the bookmark methods are intentionally missing from the proxy object, since resuming a bookmark requires the workflow thread to be free. If an activity attempts to resume a bookmark on an asynchronous thread (using this extension) and the workflow thread is busy, the synchronous call blocks until the workflow thread becomes available to schedule the bookmark resumption in the queue. In order to encourage better programming practices and reduce confusion regarding which method to invoke the synchronous methods have been removed.&lt;/EM&gt;&lt;/P&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;H4&gt;Conclusion&lt;/H4&gt;
&lt;P&gt;In this article we discussed workflow extensions, how the lifetime is managed, and how to attach them to a workflow instance. We also discussed how an activity can provide an extension by providing information in the &lt;EM&gt;CacheMetadata(*ActivityMetadata) &lt;/EM&gt;family of methods. If you recall from the introduction I alluded to modeling a .NET event-driven object in a workflow activity. So far we have covered the first piece of the puzzle – next post I plan on revising the producer-consumer model, illustrating a different way to implement the &lt;EM&gt;CopyDirectory&lt;/EM&gt; activity using this new model.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9950475" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="Workflow" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Workflow/" /></entry><entry><title>Windows Workflow 4.0 – CopyDirectory (Part 3 of 3)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2010/01/08/windows-workflow-4-0-copydirectory-part-3-of-3.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="20041" href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-09-94-58-92/BuildExtensions.zip" /><id>http://blogs.msdn.com/b/patcarna/archive/2010/01/08/windows-workflow-4-0-copydirectory-part-3-of-3.aspx</id><published>2010-01-08T20:10:00Z</published><updated>2010-01-08T20:10:00Z</updated><content type="html">&lt;P&gt;So far we have written &lt;A href="http://blogs.msdn.com/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-1-of-3.aspx" mce_href="http://blogs.msdn.com/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-1-of-3.aspx"&gt;ParallelItemScheduler&amp;lt;T&amp;gt;&lt;/A&gt;, which is a generic activity that goes dormant and schedules actions based on input via bookmark resumption. We then used this activity to design &lt;A href="http://blogs.msdn.com/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-2-of-3.aspx" mce_href="http://blogs.msdn.com/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-2-of-3.aspx"&gt;ProducerConsumer&amp;lt;T&amp;gt;&lt;/A&gt;, which takes this idea a little further and provides a generic mechanism for running a producer thread that can pump data into a consumer thread. In the last part of this series we finally have all required building blocks to design our highly efficient and parallel copy directory activity! &lt;/P&gt;
&lt;P&gt;As with any activity, the first thing we need to determine is what the inputs and outputs should be. Since this is simply a copy operation, there will be no outputs. The inputs I have chosen are as follows:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;InArgument&amp;lt;String&amp;gt; Source 
&lt;UL&gt;
&lt;LI&gt;The source directory for the copy operation. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;InArgument&amp;lt;String&amp;gt; Target 
&lt;UL&gt;
&lt;LI&gt;The target directory for the copy operation. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;InArgument&amp;lt;Int32&amp;gt; FileCopyBufferSize 
&lt;UL&gt;
&lt;LI&gt;The buffer size which should be used for individual copy operations. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;InArgument&amp;lt;Int32&amp;gt; FileCopyThreadCount 
&lt;UL&gt;
&lt;LI&gt;The number of concurrent copies that should be allowed. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Now that we have our inputs, we can move onto the producer and the consumer for our directory copy activity.&lt;/P&gt;
&lt;H4&gt;Implementing CopyDirectory&lt;/H4&gt;
&lt;P&gt;The producer of our copy directory activity is what will actually walk the source hierarchy and accumulate files for consumption. I will not be posting the code in-line here, but I will describe the implementation so the rest of this makes sense without having to download an attachment. Basically the producer maintains a queue or stack (depending on how the copy operation should work, breadth-first or depth-first respectively) and begins by pushing the root directory onto the list. It then begins a loop that retrieves the next directory from the list, finds the files and directories that are immediate children, pushes the directories onto the aforementioned list and then queues the files for consumption by our consumer (which will be discussed next). In order to help illustrate this concept, I have rewritten it into an outline form.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Get the next directory &lt;/LI&gt;
&lt;LI&gt;Calculate the target directory by removing &lt;EM&gt;Source&lt;/EM&gt; and replacing it with &lt;EM&gt;Target&lt;/EM&gt; &lt;/LI&gt;
&lt;LI&gt;Create the target directory &lt;/LI&gt;
&lt;LI&gt;Asynchronously walk the current directory to find all immediate child objects &lt;/LI&gt;
&lt;LI&gt;For-each directory 
&lt;UL&gt;
&lt;LI&gt;Push directory into our list &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;For-each file 
&lt;UL&gt;
&lt;LI&gt;Queue a &lt;EM&gt;Tuple&amp;lt;String, String&amp;gt;&lt;/EM&gt; with &lt;EM&gt;Item1 &lt;/EM&gt;set to the source file and &lt;EM&gt;Item2 &lt;/EM&gt;set to the target file &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Although it’s not entirely necessary the directory/file discovery activity is asynchronous to allow for maximum parallelism between the producer and the consumer. Just like our activity needs a source and target for the operation, so does our consumer which will be the &lt;A href="http://blogs.msdn.com/patcarna/archive/2010/01/04/windows-workflow-4-0-copyfile.aspx" mce_href="http://blogs.msdn.com/patcarna/archive/2010/01/04/windows-workflow-4-0-copyfile.aspx"&gt;CopyFile&lt;/A&gt; activity. For this reason we will use the &lt;EM&gt;ProducerConsumer&amp;lt;Tuple&amp;lt;String, String&amp;gt;&amp;gt;&lt;/EM&gt; in our implementation below. &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Note: The activities Enqueue, Dequeue, CreateDirectory and GetFilesAndDirectories have been omitted for length. I have attached a full project that includes all code and supporting classes that you may download.&lt;/EM&gt;&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CopyDirectory &lt;/SPAN&gt;: &lt;SPAN style="COLOR: #2b91af"&gt;Activity
&lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;CopyDirectory()
    {
        &lt;SPAN style="COLOR: blue"&gt;base&lt;/SPAN&gt;.Implementation = () =&amp;gt; CreateBody();

        m_fileCopyBufferSize = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;VisualBasicValue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"1024 * 1024 * 8"&lt;/SPAN&gt;));
        m_fileCopyThreadCount = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;VisualBasicValue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"System.Environment.ProcessorCount * 2"&lt;/SPAN&gt;));
    }

    [&lt;SPAN style="COLOR: #2b91af"&gt;RequiredArgument&lt;/SPAN&gt;]
    [&lt;SPAN style="COLOR: #2b91af"&gt;DefaultValue&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)]
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; Source
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    [&lt;SPAN style="COLOR: #2b91af"&gt;RequiredArgument&lt;/SPAN&gt;]
    [&lt;SPAN style="COLOR: #2b91af"&gt;DefaultValue&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)]
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; Target
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }


    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt; FileCopyBufferSize
    {
        &lt;SPAN style="COLOR: blue"&gt;get
        &lt;/SPAN&gt;{
            &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;m_fileCopyBufferSize;
        }
        &lt;SPAN style="COLOR: blue"&gt;set
        &lt;/SPAN&gt;{
            m_fileCopyBufferSize = &lt;SPAN style="COLOR: blue"&gt;value&lt;/SPAN&gt;;
            m_fileCopyBufferSizeSet = &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;;
        }
    }

    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt; FileCopyThreadCount
    {
        &lt;SPAN style="COLOR: blue"&gt;get
        &lt;/SPAN&gt;{
            &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;m_fileCopyThreadCount;
        }
        &lt;SPAN style="COLOR: blue"&gt;set
        &lt;/SPAN&gt;{
            m_fileCopyThreadCount = &lt;SPAN style="COLOR: blue"&gt;value&lt;/SPAN&gt;;
            m_fileCopyThreadCountSet = &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;;
        }
    }

    [&lt;SPAN style="COLOR: #2b91af"&gt;EditorBrowsable&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;EditorBrowsableState&lt;/SPAN&gt;.Never)]
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean &lt;/SPAN&gt;ShouldSerializeFileCopyBufferSize()
    {
        &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;m_fileCopyBufferSizeSet;
    }

    [&lt;SPAN style="COLOR: #2b91af"&gt;EditorBrowsable&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;EditorBrowsableState&lt;/SPAN&gt;.Never)]
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean &lt;/SPAN&gt;ShouldSerializeFileCopyThreadCount()
    {
        &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;m_fileCopyThreadCountSet;
    }

    &lt;SPAN style="COLOR: #2b91af"&gt;Activity &lt;/SPAN&gt;CreateBody()
    {
        &lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; bookmarkName = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"bookmarkName"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; sourceDirectory = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"sourceDirectory"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; targetDirectory = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"targetDirectory"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt; pendingDirectories = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"pendingDirectories"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt; childDirs = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"childDirs"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt; childFiles = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"childFiles"&lt;/SPAN&gt;);

        &lt;SPAN style="COLOR: #2b91af"&gt;DelegateInArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; childDirArgument = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;DelegateInArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"childDirArgument"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #2b91af"&gt;DelegateInArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; childFileArgument = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;DelegateInArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"childFileArgument"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #2b91af"&gt;DelegateInArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt; fileCopyArgument = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;DelegateInArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"fileCopyArgument"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #2b91af"&gt;DelegateOutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;&amp;gt; childFileCollection = 
            &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;DelegateOutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"childFileCollection"&lt;/SPAN&gt;);

        &lt;SPAN style="COLOR: blue"&gt;return new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Sequence
        &lt;/SPAN&gt;{
            Variables = 
            {
                pendingDirectories,
            },
            Activities =
            {
                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Assign&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;
                {
                    Value = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(env =&amp;gt; &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;[] { Source.Get(env) })),
                    To = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;OutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(pendingDirectories),
                },
                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ProducerConsumer&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;
                {
                    ConsumerCount = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; FileCopyThreadCount.Get(env)),
                    ContinueProducing = &lt;SPAN style="COLOR: #2b91af"&gt;ExpressionServices&lt;/SPAN&gt;.Convert&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; pendingDirectories.Get(env).Count &amp;gt; 0),
                    Consumer = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActivityAction&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;
                    {
                        Argument = fileCopyArgument,
                        Handler = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CopyFile
                        &lt;/SPAN&gt;{
                            Source = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; fileCopyArgument.Get(env).Item1),
                            Target = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; fileCopyArgument.Get(env).Item2),
                            BufferSize = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; FileCopyBufferSize.Get(env)),
                        },
                    },
                    Producer = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActivityFunc&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;&amp;gt;
                    {
                        Result = childFileCollection,
                        Handler = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Sequence
                        &lt;/SPAN&gt;{
                            Variables = 
                            {
                                childDirs,
                                childFiles,
                                sourceDirectory,
                                targetDirectory,
                            },
                            Activities = 
                            {
                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Dequeue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;
                                {
                                    Queue = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(pendingDirectories),
                                    Result = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;OutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(sourceDirectory),
                                },
                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Assign&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;
                                {
                                    Value = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; System.IO.&lt;SPAN style="COLOR: #2b91af"&gt;Path&lt;/SPAN&gt;.Combine(Target.Get(env),
                                                                 sourceDirectory.Get(env).Remove(0, Source.Get(env).Length).TrimStart(&lt;SPAN style="COLOR: #a31515"&gt;'/'&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #a31515"&gt;'\\'&lt;/SPAN&gt;))),
                                    To = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;OutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(targetDirectory),
                                },
                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;If
                                &lt;/SPAN&gt;{
                                    Condition = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; !System.IO.&lt;SPAN style="COLOR: #2b91af"&gt;Directory&lt;/SPAN&gt;.Exists(targetDirectory.Get(env))),
                                    Then = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CreateDirectory
                                    &lt;/SPAN&gt;{
                                        Directory = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(targetDirectory),
                                    },
                                },
                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;GetFilesAndDirectories
                                &lt;/SPAN&gt;{
                                    Directory = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(sourceDirectory),
                                    Files = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;OutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(childFiles),
                                    Directories = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;OutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(childDirs),
                                },
                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ForEach&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;
                                {
                                    Values = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(childDirs),
                                    Body = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActivityAction&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;
                                    {
                                        Argument = childDirArgument,
                                        Handler = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Enqueue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;
                                        {
                                            Queue = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(pendingDirectories),
                                            Item = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(childDirArgument),
                                        },
                                    },
                                },
                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Assign&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;&amp;gt;
                                {
                                    To = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;OutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;&amp;gt;(childFileCollection),
                                    Value = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;&amp;gt;(env =&amp;gt; &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;()),
                                },
                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ForEach&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;
                                {
                                    Values = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(childFiles),
                                    Body = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActivityAction&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;
                                    {
                                        Argument = childFileArgument,
                                        Handler = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;AddToCollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;
                                        {
                                            Collection = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;&amp;gt;(childFileCollection),
                                            Item = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;&amp;gt;(env =&amp;gt; 
                                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Tuple&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(
                                                    childFileArgument.Get(env), 
                                                    System.IO.&lt;SPAN style="COLOR: #2b91af"&gt;Path&lt;/SPAN&gt;.Combine(targetDirectory.Get(env), System.IO.&lt;SPAN style="COLOR: #2b91af"&gt;Path&lt;/SPAN&gt;.GetFileName(childFileArgument.Get(env))))),
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            },
        };
    }

    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean &lt;/SPAN&gt;m_fileCopyBufferSizeSet;
    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean &lt;/SPAN&gt;m_fileCopyThreadCountSet;
    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt; m_fileCopyBufferSize;
    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt; m_fileCopyThreadCount;
}&lt;/PRE&gt;
&lt;P&gt;As you can see from our implementation, the code matches exactly (almost) what was outlined in the bulleted list. When this activity executes it will begin walking the source directory hierarchy and discover files and directories. While it’s performing this discovery operation it can have &lt;EM&gt;FileCopyThreadCount&lt;/EM&gt; files being copied at any given time. Since this implementation uses a &lt;EM&gt;Queue&amp;lt;String&amp;gt;&lt;/EM&gt; for the directories the files will be copied in breadth-first fashion. Another thing I would like to point out about this activity is its inherent ability to be canceled. Since everything is modeled in workflow, the framework will handle cancelation of our composite activity for us in between any of the workflow “statements” above. We also modeled our &lt;EM&gt;CopyFile&lt;/EM&gt; activity to support cancelation in between reading from/writing to the file (in blocks of size &lt;EM&gt;FileCopyBufferSize&lt;/EM&gt;), so if the activity is canceled we can gracefully and quickly respond to the request.&lt;/P&gt;
&lt;P&gt;There are quite a few more improvements we could add to this activity to make it much more robust, such as the ability to specify behavior when the target file exists or provide the ability to retry a failed file copy operation up to some configurable amount of times. I will leave this as an exercise to the reader as it does nothing to further your knowledge on workflow.&lt;/P&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;H4&gt;Conclusion&lt;/H4&gt;
&lt;P&gt;Over the past 3 posts we have developed a much more efficient directory copy activity that may be reused in the workflow. Along the way we also developed &lt;EM&gt;CopyFile, ParallelItemScheduler&amp;lt;T&amp;gt;, ProducerConsumer&amp;lt;T&amp;gt;&lt;/EM&gt;, and various other supporting activities. In the beginning we started out very low level as we required scheduling functionality that was not built into the framework. After that initial hump, however, you should notice that we very rarely dropped back to code and typically composed all of our logic using standard workflow activities. There are numerous benefits to building activities this way, one of which I have tried to harp on, such as:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Automatic support for cancelation by the framework (if a cancel requests comes in during a short running code activity then when it finishes the parent will automatically clean up)&lt;/LI&gt;
&lt;LI&gt;We verified our lower level activities by reusing them in our own activity library&lt;/LI&gt;
&lt;LI&gt;We have small modular pieces of workflow logic that is now reusable in other, similar activities (this will most likely not be the only producer-consumer model you will need to implement)&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Hopefully as you read through this 3 part series you got a better feel for how to design activities as well as a taste of the more advanced behaviors you can model with Windows Workflow. I have attached a zip file that includes this activity library along with a sample executable that links to and utilizes the CopyDirectory activity that we just developed. Enjoy!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9945892" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="Workflow" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Workflow/" /></entry><entry><title>Windows Workflow 4.0 – CopyDirectory (Part 2 of 3)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-2-of-3.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-2-of-3.aspx</id><published>2010-01-07T21:40:00Z</published><updated>2010-01-07T21:40:00Z</updated><content type="html">&lt;P&gt;In my previous &lt;A href="http://blogs.msdn.com/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-1-of-3.aspx" mce_href="http://blogs.msdn.com/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-1-of-3.aspx"&gt;post&lt;/A&gt; I introduced you to &lt;EM&gt;NativeActivity&lt;/EM&gt; and walked through the design and implementation of a class named &lt;EM&gt;ParallelItemScheduler&amp;lt;T&amp;gt;&lt;/EM&gt;. In part 2 of this series we will be utilizing the aforementioned activity to build a new composed activity named &lt;EM&gt;ProducerConsumer&amp;lt;T&amp;gt;&lt;/EM&gt;. Once we have completed this task we will have a framework for building our final activity, &lt;EM&gt;CopyDirectory&lt;/EM&gt;.&lt;/P&gt;
&lt;H4&gt;Building Activities Through Composition&lt;/H4&gt;
&lt;P&gt;Unlike the previous activity, the &lt;EM&gt;ProducerConsumer&amp;lt;T&amp;gt;&lt;/EM&gt; activity may be built using composition. This means that we will be using &lt;EM&gt;Activity&lt;/EM&gt; as a sub-class and providing an implementation using initializer syntax and numerous built-in and custom activities that we have been working on. Before we start designing our activity, however, lets go back to the producer-consumer diagram from the previous post to make sure we get it right.&lt;/P&gt;
&lt;P&gt;Parallel&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Producer 
&lt;UL&gt;
&lt;LI&gt;While &lt;EM&gt;&lt;STRONG&gt;continue-producing&lt;/STRONG&gt;&lt;/EM&gt; 
&lt;UL&gt;
&lt;LI&gt;Invoke &lt;EM&gt;&lt;STRONG&gt;producer&lt;/STRONG&gt; &lt;/EM&gt;to generate items &lt;/LI&gt;
&lt;LI&gt;For each of the items produced, notify the &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; that a new item is available &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Notify the &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; to shut down &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Consumer 
&lt;UL&gt;
&lt;LI&gt;Wait for next item &lt;/LI&gt;
&lt;LI&gt;If &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; is available 
&lt;UL&gt;
&lt;LI&gt;Then 
&lt;UL&gt;
&lt;LI&gt;Invoke &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; to handle item &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Else 
&lt;UL&gt;
&lt;LI&gt;Queue the item and wait for a &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; to complete &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;The pieces in bold are the configurable properties, so lets break down what we will need to provide and what workflow classes will support our implementation.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;InArgument&amp;lt;Int32&amp;gt; ConsumerCount 
&lt;UL&gt;
&lt;LI&gt;Allows users to specify how many concurrent consumers should be scheduled for handling items &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;ActivityAction&amp;lt;T&amp;gt; Consumer 
&lt;UL&gt;
&lt;LI&gt;Allows users to specify custom &lt;STRONG&gt;&lt;EM&gt;consumer&lt;/EM&gt;&lt;/STRONG&gt; logic for processing items produced by the &lt;EM&gt;&lt;STRONG&gt;producer&lt;/STRONG&gt;&lt;/EM&gt; &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Activity&amp;lt;Boolean&amp;gt; ContinueProducing 
&lt;UL&gt;
&lt;LI&gt;Allows users to specify a custom condition to determine when to stop running the &lt;STRONG&gt;&lt;EM&gt;producer&lt;/EM&gt;&lt;/STRONG&gt; loop &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;ActivityFunc&amp;lt;ICollection&amp;lt;T&amp;gt;&amp;gt; Producer 
&lt;UL&gt;
&lt;LI&gt;Specifies custom &lt;STRONG&gt;&lt;EM&gt;producer &lt;/EM&gt;&lt;/STRONG&gt;logic for feeding items into the &lt;STRONG&gt;&lt;EM&gt;consumer&lt;/EM&gt;&lt;/STRONG&gt; &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;What is ActivityFunc&amp;lt;T&amp;gt;?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Much like &lt;EM&gt;ActivityAction&amp;lt;T&amp;gt;&lt;/EM&gt; is synonymous to the delegate type &lt;EM&gt;Action&amp;lt;T&amp;gt;&lt;/EM&gt;, &lt;EM&gt;ActivityFunc&amp;lt;T&amp;gt; &lt;/EM&gt;is synonymous to the delegate type &lt;EM&gt;Func&amp;lt;T&amp;gt;&lt;/EM&gt;. Providing a hook for an &lt;EM&gt;ActivityFunc&amp;lt;&amp;gt;&lt;/EM&gt; class provides a customizable hook for users of the activity to provide custom logic that returns a value and may or may not take parameters. In our particular scenario, we need to provide a custom mechanism for producing items to queue up for our consumer and do not require any arguments, so we use &lt;EM&gt;ActivityFunc&amp;lt;ICollection&amp;lt;T&amp;gt;&amp;gt;&lt;/EM&gt; as our producer definition. As you will see in the implementation that follows, you can schedule &lt;EM&gt;ActivityAction/ActivityFunc&lt;/EM&gt; objects using the &lt;EM&gt;InvokeAction/InvokeFunc &lt;/EM&gt;activities in composition or by using the methods &lt;EM&gt;NativeActivityContext.ScheduleAction/NativeActivityContext.ScheduleFunc &lt;/EM&gt;if you are scheduling from a native activity.&lt;/P&gt;
&lt;H4&gt;Implementing the ProducerConsumer&lt;/H4&gt;
&lt;P&gt;When using composition there is one major difference to how you build the activity vs. another type of activity. Rather than providing an &lt;EM&gt;Execute&lt;/EM&gt; method to determine the logic, you provide what is called the activity &lt;EM&gt;Implementation&lt;/EM&gt;, which is defined as:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;protected virtual &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Func&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Activity&lt;/SPAN&gt;&amp;gt; Implementation { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }&lt;/PRE&gt;
&lt;P&gt;We developed a pattern internally that will be shown below, but essentially every activity that uses &lt;EM&gt;Activity&lt;/EM&gt; as a base class has a private method called &lt;EM&gt;CreateBody()&lt;/EM&gt; that returns the logic as workflow generated with initializer syntax. In the constructor we simply set the implementation to the result of an anonymous delegate that invokes this method. Keeping this in mind I have pasted the implementation of the activity below, with an explanation that follows.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ProducerConsumer&lt;/SPAN&gt;&amp;lt;T&amp;gt; : &lt;SPAN style="COLOR: #2b91af"&gt;Activity
&lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;ProducerConsumer()
    {
        &lt;SPAN style="COLOR: blue"&gt;base&lt;/SPAN&gt;.Implementation = () =&amp;gt; CreateBody();
    }

    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt; ConsumerCount
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActivityAction&lt;/SPAN&gt;&amp;lt;T&amp;gt; Consumer
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Activity&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean&lt;/SPAN&gt;&amp;gt; ContinueProducing
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActivityFunc&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;T&amp;gt;&amp;gt; Producer
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;CacheMetadata(&lt;SPAN style="COLOR: #2b91af"&gt;ActivityMetadata &lt;/SPAN&gt;metadata)
    {
        &lt;SPAN style="COLOR: blue"&gt;base&lt;/SPAN&gt;.CacheMetadata(metadata);

        &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(Consumer == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
        {
            metadata.AddValidationError(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ValidationError&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"Consumer must be set"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #a31515"&gt;"Consumer"&lt;/SPAN&gt;));
        }

        &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(ContinueProducing == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
        {
            metadata.AddValidationError(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ValidationError&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"ContinueProducing condition must be set"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #a31515"&gt;"ContinueProducing"&lt;/SPAN&gt;));
        }

        &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(Producer == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
        {
            metadata.AddValidationError(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ValidationError&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"Producer must be set"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #a31515"&gt;"Producer"&lt;/SPAN&gt;));
        }
    }

    &lt;SPAN style="COLOR: #2b91af"&gt;Activity &lt;/SPAN&gt;CreateBody()
    {
        &lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; queueName = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;();
        &lt;SPAN style="COLOR: #2b91af"&gt;DelegateInArgument&lt;/SPAN&gt;&amp;lt;T&amp;gt; itemToProduce = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;DelegateInArgument&lt;/SPAN&gt;&amp;lt;T&amp;gt;();
        &lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;T&amp;gt;&amp;gt; itemsProduced = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;T&amp;gt;&amp;gt;();

        &lt;SPAN style="COLOR: blue"&gt;return new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Sequence
        &lt;/SPAN&gt;{
            Variables = 
            {
                queueName,
            },
            Activities =
            {
                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Assign&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;
                {
                    Value = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; &lt;SPAN style="COLOR: #2b91af"&gt;Guid&lt;/SPAN&gt;.NewGuid().ToString(&lt;SPAN style="COLOR: #a31515"&gt;"D"&lt;/SPAN&gt;)),
                    To = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;OutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(queueName),
                },
                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Parallel
                &lt;/SPAN&gt;{
                    Branches = 
                    {
                        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ParallelItemScheduler&lt;/SPAN&gt;&amp;lt;T&amp;gt;
                        {
                            QueueName = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(queueName),
                            MaxConcurrency = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; ConsumerCount.Get(env)),
                            Body = &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.Consumer,
                        },
                        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;TryCatch
                        &lt;/SPAN&gt;{
                            Try = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;While
                            &lt;/SPAN&gt;{
                                Condition = &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.ContinueProducing,
                                Body = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Sequence
                                &lt;/SPAN&gt;{
                                    Variables =
                                    {
                                        itemsProduced,
                                    },
                                    Activities =
                                    {
                                        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InvokeFunc&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;T&amp;gt;&amp;gt;
                                        {
                                            Func = &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.Producer,
                                            Result = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;OutArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;ICollection&lt;/SPAN&gt;&amp;lt;T&amp;gt;&amp;gt;(itemsProduced),
                                        },
                                        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;If
                                        &lt;/SPAN&gt;{
                                            Condition = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean&lt;/SPAN&gt;&amp;gt;(env =&amp;gt; itemsProduced.Get(env) != &lt;SPAN style="COLOR: blue"&gt;null &lt;/SPAN&gt;&amp;amp;&amp;amp; itemsProduced.Get(env).Count &amp;gt; 0),
                                            Then = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ForEach&lt;/SPAN&gt;&amp;lt;T&amp;gt;
                                            {
                                                Values = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;T&amp;gt;&amp;gt;(itemsProduced),
                                                Body = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActivityAction&lt;/SPAN&gt;&amp;lt;T&amp;gt;
                                                {
                                                    Argument = itemToProduce,
                                                    Handler = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ParallelItemScheduler&lt;/SPAN&gt;&amp;lt;T&amp;gt;.&lt;SPAN style="COLOR: #2b91af"&gt;Enqueue
                                                    &lt;/SPAN&gt;{
                                                        QueueName = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(queueName),
                                                        Value = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;T&amp;gt;(itemToProduce),
                                                    },
                                                },
                                            },
                                        },
                                    },
                                },
                            },
                            Finally = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ParallelItemScheduler&lt;/SPAN&gt;&amp;lt;T&amp;gt;.&lt;SPAN style="COLOR: #2b91af"&gt;Shutdown
                            &lt;/SPAN&gt;{
                                QueueName = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt;(queueName),
                            },
                        },
                    },
                },
            },
        };
    }
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;As you can see above, for the most part the workflow framework provides the building blocks for our implementation. If you compare the outline for the activity above with the construction of the activity logic, you should see that it lines up almost exactly. What we have done is create a parallel activity with two branches, one is the producer and the other is the consumer. The consumer thread simply waits for input and then schedules the provided &lt;STRONG&gt;&lt;EM&gt;consumer&lt;/EM&gt;&lt;/STRONG&gt; each time an available slot is available. The &lt;STRONG&gt;&lt;EM&gt;producer&lt;/EM&gt;&lt;/STRONG&gt; thread loops and continually calls the provided callback, pushing the produced items into the consumer for scheduling. Once the producer is finished, we have the entire block wrapped in a &lt;EM&gt;TryCatch&lt;/EM&gt; so we can ensure to invoke the &lt;EM&gt;ParallelItemScheduler&amp;lt;T&amp;gt;.Shutdown&lt;/EM&gt; activity.&lt;/P&gt;
&lt;P&gt;For all intents and purposes, the queue name (really the bookmark name) simply has to be unique. In an attempt to keep things simple I have chosen to create a queue name by generating a new GUID. There are many other ways to generate queue names, but this was the easiest way to ensure there are not any conflicts. One important thing about the queue, however, is that the &lt;STRONG&gt;&lt;EM&gt;consumer&lt;/EM&gt;&lt;/STRONG&gt; is first in the parallel and the &lt;STRONG&gt;&lt;EM&gt;producer&lt;/EM&gt;&lt;/STRONG&gt; is second. This activity may not work the other way around since the &lt;STRONG&gt;&lt;EM&gt;consumer&lt;/EM&gt;&lt;/STRONG&gt; is what creates the bookmark that the &lt;STRONG&gt;&lt;EM&gt;producer&lt;/EM&gt;&lt;/STRONG&gt; will be resuming it. As it turns out, the built-in &lt;EM&gt;Parallel&lt;/EM&gt; activity is not strictly parallel. What I mean by that is since the workflow scheduler works off of a single thread, the ability of concurrent work to occur is completely dependent on the child activities that it is invoking. If we did not design our &lt;EM&gt;ParallelItemScheduler&amp;lt;T&amp;gt; &lt;/EM&gt;to use the bookmark and go idle, for instance, then the &lt;STRONG&gt;&lt;EM&gt;producer&lt;/EM&gt;&lt;/STRONG&gt; would never run since the scheduler would never have a chance to execute it while it’s blocked on the aforementioned activity. Using this knowledge, we can guarantee that the first branch in the parallel will invoke its first child &lt;STRONG&gt;BEFORE&lt;/STRONG&gt; the second child is invoked, and so on down the list in sequential order. The parallelism occurs when an activity goes idle using bookmarks or &lt;EM&gt;AsyncCodeActivity&lt;/EM&gt;, which allows the scheduler to move onto the next item in the queue while execution of the previous activity continues off of the workflow thread.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Note: See Nate Talbert's &lt;A href="http://blogs.msdn.com/advancedworkflow/archive/2006/02/23/538160.aspx" mce_href="http://blogs.msdn.com/advancedworkflow/archive/2006/02/23/538160.aspx"&gt;post&lt;/A&gt; on the WF 3.5 ParallelActivity and how it works for a more complete explanation of how parallelism works in a workflow instance.&lt;/EM&gt;&lt;/P&gt;
&lt;H4&gt;Validation Errors&lt;/H4&gt;
&lt;P&gt;The previous post introduced one of the mechanisms for &lt;EM&gt;CacheMetadata&lt;/EM&gt;, and this one introduces another use for overriding this method. Workflow validation occurs against the workflow definition and not against the runtime inputs, so all you can validate are things like the activity hierarchy, check for the existence of properties, and other things that belong to the activity definition and are not runtime-specific. What I have done here is add validation errors to the workflow if any properties required for property execution are not set. You can test the behavior in this scenario by trying to run this activity without one, two, or all three of the required properties set.&lt;/P&gt;
&lt;H4&gt;Conclusion&lt;/H4&gt;
&lt;P&gt;This part of the 3 part series introduced you to activity composition, activity functions, and basic activity validation. At this point in time we have all of the building blocks necessary to build more activities that follow the model of producer-consumer. As you probably guessed, the &lt;EM&gt;CopyDirectory&lt;/EM&gt; activity that I will be going over in part 3 is one such activity. Given the proper inputs a directory copy operation that walks the hierarchy while simultaneously copying discovered files &lt;EM&gt;N&lt;/EM&gt; at a time can provide large performance gains when network latency is large. Since we’re using workflow, we have not and will not need to make any use of synchronization primitives or do anything to handle cancelation of the operation! Hopefully, if not yet, by the next post you will start seeing the benefits of writing workflow in small and reusable modules rather than trying to implement everything in code.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9945410" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="Workflow" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Workflow/" /></entry><entry><title>Windows Workflow 4.0 – CopyDirectory (Part 1 of 3)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-1-of-3.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2010/01/07/windows-workflow-4-0-copydirectory-part-1-of-3.aspx</id><published>2010-01-07T20:04:00Z</published><updated>2010-01-07T20:04:00Z</updated><content type="html">&lt;P&gt;In my last couple of posts I have lead you through some basic introduction to workflow as well as a real world example of how to implement a cancelable &lt;A href="http://blogs.msdn.com/patcarna/archive/2010/01/04/windows-workflow-4-0-copyfile.aspx" mce_href="http://blogs.msdn.com/patcarna/archive/2010/01/04/windows-workflow-4-0-copyfile.aspx"&gt;CopyFile&lt;/A&gt; activity. The next thing I would like to do is dive into a much more involved example utilizing the previous activity. The purpose of this post is to introduce the class &lt;EM&gt;NativeActivity&lt;/EM&gt;, since we will need to implement a custom activity for driving the consumers. We will also be working toward using our &lt;A href="http://en.wikipedia.org/wiki/Producer-consumer_problem" mce_href="http://en.wikipedia.org/wiki/Producer-consumer_problem"&gt;producer-consumer&lt;/A&gt; activity to eventually develop a parallelizable &lt;EM&gt;CopyDirectory&lt;/EM&gt; activity, which I plan to cover in a subsequent posts.&lt;/P&gt;
&lt;H4&gt;Producer-Consumer&lt;/H4&gt;
&lt;P&gt;The first thing I want to do is step back and determine how we might go about modeling this as a reusable model that may be extended through composition. Our basic structure will be something along the lines of the following:&lt;/P&gt;
&lt;P&gt;Parallel&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Producer 
&lt;UL&gt;
&lt;LI&gt;While &lt;EM&gt;&lt;STRONG&gt;continue-producing&lt;/STRONG&gt;&lt;/EM&gt; 
&lt;UL&gt;
&lt;LI&gt;Invoke &lt;EM&gt;&lt;STRONG&gt;producer&lt;/STRONG&gt; &lt;/EM&gt;to generate items &lt;/LI&gt;
&lt;LI&gt;For each of the items produced, notify the &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; that a new item is available &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Notify the &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; to shut down &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Consumer 
&lt;UL&gt;
&lt;LI&gt;Wait for next item &lt;/LI&gt;
&lt;LI&gt;If &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; is available 
&lt;UL&gt;
&lt;LI&gt;Then 
&lt;UL&gt;
&lt;LI&gt;Invoke &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; to handle item &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Else 
&lt;UL&gt;
&lt;LI&gt;Queue the item and wait for a &lt;EM&gt;&lt;STRONG&gt;consumer&lt;/STRONG&gt;&lt;/EM&gt; to complete &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Typically the coordination between the producer and the consumer would be handled through mutexes, monitors, or some other cross-thread synchronization mechanism. The nice thing about workflow, however, is that we do not need to worry about this synchronization between threads as long as we make sure that all access to the common objects are handled on the workflow thread. If you were worried by my earlier posts that a single thread is dedicated to running a workflow, perhaps now it will make more sense. What this allows us to do is model complex, multi-threaded operations without having to deal with thread synchronization issues! However, there is one critical piece of the puzzle that is not already done for us – modeling the consumer scheduling behavior across threads. In order to run the consumer scheduling in parallel to the producer we will need to dive into the wonderful world of &lt;EM&gt;NativeActivity&lt;/EM&gt; and &lt;EM&gt;Bookmark&lt;/EM&gt;.&lt;/P&gt;
&lt;P&gt;Activity classes which derive from &lt;EM&gt;NativeActivity &lt;/EM&gt;are typically attempting to provide some sort of custom scheduling logic that is not available through composition of existing framework activities. In our scenario, for instance, we need an activity that can:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Wait for items to be pushed into a queue (this is what we need the bookmark for) &lt;/LI&gt;
&lt;LI&gt;Schedule some maximum number of handlers in parallel and ensure that maximal use of these handlers is obtained &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;The remainder of the post will be dedicated to walking through how to design this activity, using &lt;EM&gt;NativeActivity&lt;/EM&gt;. &lt;/P&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;P&gt;&lt;STRONG&gt;What is a Bookmark?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;A &lt;A href="http://msdn.microsoft.com/en-us/library/system.activities.bookmark(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.activities.bookmark(VS.100).aspx"&gt;bookmark&lt;/A&gt;, for lack of a better definition, is exactly what it sounds like. For those of you unfamiliar with the previous workflow framework, a bookmark is essentially like a piece of paper you put inside of a book to mark your place. When an activity creates a bookmark, it is creating a named “resumption point” so it may go dormant and other activities may “wake it up” by resuming the bookmark. If you are familiar with Workflow from the .NET 3.5 Framework, a bookmark provides similar functionality to a queue. A bookmark is how we will handle making the consumer scheduling thread go idle while waiting for items in the queue.&lt;/P&gt;
&lt;H4&gt;Implementing the ParallelItemScheduler&lt;/H4&gt;
&lt;P&gt;The parallel item scheduler is a generic and reusable class we will be developing to add to our slowly growing library of custom activities. This will be the class (well, the main class) that I will be discussing which derives from &lt;EM&gt;NativeActivity&lt;/EM&gt;. As we already mentioned, the purpose of this activity is to invoke a &lt;EM&gt;user-defined callback &lt;/EM&gt;for each item in the queue, with up to &lt;EM&gt;N&lt;/EM&gt; running simultaneously. We will need some mechanism for pushing items from the &lt;EM&gt;producer&lt;/EM&gt; into the &lt;EM&gt;consumer&lt;/EM&gt;, which means we will need some sort of a queue (represented by a &lt;EM&gt;bookmark&lt;/EM&gt;). We should also allow users of our activity to control how many consumers may run in parallel. Using this information we can come up with a stub for our activity.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ParallelItemScheduler&lt;/SPAN&gt;&amp;lt;T&amp;gt; : &lt;SPAN style="COLOR: #2b91af"&gt;NativeActivity
&lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;ParallelItemScheduler()
    {
        m_maxConcurrency = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;VisualBasicValue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"1"&lt;/SPAN&gt;));
    }

    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActivityAction&lt;/SPAN&gt;&amp;lt;T&amp;gt; Body
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt; MaxConcurrency
    {
        &lt;SPAN style="COLOR: blue"&gt;get
        &lt;/SPAN&gt;{
            &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;m_maxConcurrency;
        }
        &lt;SPAN style="COLOR: blue"&gt;set
        &lt;/SPAN&gt;{
            m_maxConcurrency = &lt;SPAN style="COLOR: blue"&gt;value&lt;/SPAN&gt;;
            m_maxConcurrencySet = &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;;
        }
    }

    [&lt;SPAN style="COLOR: #2b91af"&gt;RequiredArgument&lt;/SPAN&gt;]
    [&lt;SPAN style="COLOR: #2b91af"&gt;DefaultValue&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)]
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; QueueName
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;protected override &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean &lt;/SPAN&gt;CanInduceIdle
    {
        &lt;SPAN style="COLOR: blue"&gt;get
        &lt;/SPAN&gt;{
            &lt;SPAN style="COLOR: blue"&gt;return true&lt;/SPAN&gt;;
        }
    }

    [&lt;SPAN style="COLOR: #2b91af"&gt;EditorBrowsable&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;EditorBrowsableState&lt;/SPAN&gt;.Never)]
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean &lt;/SPAN&gt;ShouldSerializeMaxConcurrency()
    {
        &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;m_maxConcurrencySet;
    }

    &lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;CacheMetadata(&lt;SPAN style="COLOR: #2b91af"&gt;NativeActivityMetadata &lt;/SPAN&gt;metadata)
    {
        &lt;SPAN style="COLOR: blue"&gt;base&lt;/SPAN&gt;.CacheMetadata(metadata);
        metadata.AddImplementationVariable(m_itemQueue);
        metadata.AddImplementationVariable(m_hasCompleted);
        metadata.AddImplementationVariable(m_concurrencyCount);
    }

    &lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;Execute(&lt;SPAN style="COLOR: #2b91af"&gt;NativeActivityContext &lt;/SPAN&gt;context)
    {
        context.CreateBookmark(QueueName.Get(context), &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;BookmarkCallback&lt;/SPAN&gt;(OnItemAdded), &lt;SPAN style="COLOR: #2b91af"&gt;BookmarkOptions&lt;/SPAN&gt;.MultipleResume);

        m_concurrencyCount.Set(context, 0);
        m_itemQueue.Set(context, &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;T&amp;gt;());
    }

    &lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;OnItemAdded(&lt;SPAN style="COLOR: #2b91af"&gt;NativeActivityContext &lt;/SPAN&gt;context, &lt;SPAN style="COLOR: #2b91af"&gt;Bookmark &lt;/SPAN&gt;bookMark, &lt;SPAN style="COLOR: #2b91af"&gt;Object &lt;/SPAN&gt;data)
    {
        &lt;SPAN style="COLOR: blue"&gt;throw new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;NotImplementedException&lt;/SPAN&gt;();
    }

    &lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;OnChildCompleted(&lt;SPAN style="COLOR: #2b91af"&gt;NativeActivityContext &lt;/SPAN&gt;context, &lt;SPAN style="COLOR: #2b91af"&gt;ActivityInstance &lt;/SPAN&gt;activity)
    {
        &lt;SPAN style="COLOR: blue"&gt;throw new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;NotImplementedException&lt;/SPAN&gt;();
    }

    &lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Enqueue &lt;/SPAN&gt;: &lt;SPAN style="COLOR: #2b91af"&gt;NativeActivity &lt;/SPAN&gt;{ … }

    &lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Shutdown &lt;/SPAN&gt;: &lt;SPAN style="COLOR: #2b91af"&gt;NativeActivity &lt;/SPAN&gt;{ … }

    &lt;SPAN style="COLOR: blue"&gt;private static &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Object &lt;/SPAN&gt;s_shutdownItem = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Object&lt;/SPAN&gt;();

    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean &lt;/SPAN&gt;m_maxConcurrencySet;
    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt; m_maxConcurrency;
    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;T&amp;gt;&amp;gt; m_itemQueue = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;T&amp;gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"itemQueue"&lt;/SPAN&gt;);
    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean&lt;/SPAN&gt;&amp;gt; m_hasCompleted = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"hasCompleted"&lt;/SPAN&gt;);
    &lt;SPAN style="COLOR: blue"&gt;private &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt; m_concurrencyCount = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Variable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Int32&lt;/SPAN&gt;&amp;gt;(&lt;SPAN style="COLOR: #a31515"&gt;"concurrencyCount"&lt;/SPAN&gt;);
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;Before I progress any more I would like to step back and break down some new pieces of this activity definition. &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;EM&gt;ActivityAction&amp;lt;T&amp;gt; &lt;/EM&gt;is the workflow version of the framework delegate type &lt;EM&gt;Action&amp;lt;T&amp;gt;&lt;/EM&gt;. This type allows you provide a pluggable mechanism for a single-argument callback, just like the framework counterpart (there are also ActivityAction&amp;lt;T1, T2…&amp;gt; types up to 16 arguments or so). &lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;MaxConcurrency&lt;/EM&gt; and its use of the Boolean field. Since the type of the property is &lt;EM&gt;InArgument&amp;lt;Int32&amp;gt;&lt;/EM&gt; you cannot use the &lt;EM&gt;DefaultValueAttribute &lt;/EM&gt;to specify the default and have the serializer automatically pick it up. Instead, if you want to provide a default value that should not be serialized to XAML then you need to do it the XAML way by keeping track of whether or not the property has been set and providing a method called &lt;EM&gt;ShouldSerializeXXXX&lt;/EM&gt; (where &lt;EM&gt;XXXX&lt;/EM&gt; is the name of the property) that returns a value indicating whether or not to serialize the property. &lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;CacheMetadata &lt;/EM&gt;and why it exists. Typically when designing activities you do not need to provide your own implementation since the default behavior uses reflection to discover the arguments, variables, activities, etc., of your activity. However, in certain scenarios like the one we are dealing with, you may have the requirement to create private variables for data storage (workflow calls these &lt;EM&gt;implementation&lt;/EM&gt; variables). Since the reflection logic only picks up public properties of certain types we need to manually inform the runtime of these variables so we can use them. Why do we need variables? If you recall my previous post about data flow, C# fields and workflow variables are not the same – one is activity definition storage, the other is activity instance storage. We need the latter, since there may be multiple of this type of activity running within a workflow or the same definition may be shared across multiple workflow instances. &lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;CanInduceIdle&lt;/EM&gt; is a necessary override if you are writing an activity that can cause the workflow scheduler to become idle (this allows the runtime to perform certain validations to ensure correctness when composing activities together). In this case, since we are using a bookmark to “sleep,” we have the potential to induce an idle event on the workflow instance so we need to return true here. &lt;/LI&gt;
&lt;LI&gt;The &lt;EM&gt;Execute&lt;/EM&gt; method of our activity has an easy task. It simply needs to create the bookmark used to notify it of items (sort of like a mutex being signaled) and set up some initial state for the private variables. You’ll notice that we pass &lt;EM&gt;BookmarkOptions.MultipleResume&lt;/EM&gt; when creating it, which means that we expect to have the bookmark resumed more than one time and we will handle cleaning it up on shutdown. As there is a bookmark active for our activity the workflow runtime is smart enough to leave this activity running even when the &lt;EM&gt;Execute&lt;/EM&gt; method returns, so by doing this we have effectively gone to sleep waiting for input. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;The basic logic of &lt;EM&gt;OnItemAdded&lt;/EM&gt;, which is invoked when an item is placed into our bookmark queue, is to store the item into our implementation variable and then determine if we have any available slots for scheduling. While we are not at our maximum consumer count we should schedule a new consumer for each item that exists in the queue. Once we have finished scheduling items, we store the current concurrency count and return. It should be noted that the call to &lt;EM&gt;NativeActivityContext.ScheduleAction&lt;/EM&gt; here does not actually begin execution of the action – it merely places an entry into the workflow instance’s scheduler queue and returns. The only other thing we can do in this method is remove the bookmark if the producer has signaled completion by queuing our “shutdown item.”&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;OnItemAdded(&lt;SPAN style="COLOR: #2b91af"&gt;NativeActivityContext &lt;/SPAN&gt;context, &lt;SPAN style="COLOR: #2b91af"&gt;Bookmark &lt;/SPAN&gt;bookMark, &lt;SPAN style="COLOR: #2b91af"&gt;Object &lt;/SPAN&gt;data)
{
    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(m_hasCompleted.Get(context))
    {
        &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: #2b91af"&gt;Int32 &lt;/SPAN&gt;concurrencyCount = m_concurrencyCount.Get(context);
    &lt;SPAN style="COLOR: #2b91af"&gt;Int32 &lt;/SPAN&gt;maxConcurrentCount = MaxConcurrency.Get(context);

    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(data &lt;SPAN style="COLOR: blue"&gt;is &lt;/SPAN&gt;T)
    {
        &lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;T&amp;gt; itemQueue = m_itemQueue.Get(context);
        itemQueue.Enqueue((T)data);

        &lt;SPAN style="COLOR: blue"&gt;while &lt;/SPAN&gt;(itemQueue.Count &amp;gt; 0 &amp;amp;&amp;amp; concurrencyCount &amp;lt; maxConcurrentCount)
        {
            concurrencyCount++;
            context.ScheduleAction&amp;lt;T&amp;gt;(Body, itemQueue.Dequeue(), &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CompletionCallback&lt;/SPAN&gt;(OnChildCompleted));
        }

        m_concurrencyCount.Set(context, concurrencyCount);
    }
    &lt;SPAN style="COLOR: blue"&gt;else if &lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;Object&lt;/SPAN&gt;.ReferenceEquals(data, s_shutdownItem))
    {
        context.RemoveBookmark(QueueName.Get(context));
    }
}&lt;/PRE&gt;
&lt;P&gt;The last order of business for this particular activity is the &lt;EM&gt;OnChildCompleted&lt;/EM&gt; callback which is hooked above. This method is invoked when a child completes execution, either successfully or via cancelation. Much like the previous method this also handles consumer scheduling. As consumers complete we need to see if there are any more items which may be scheduled, and if there are we should schedule the new item using the slot of the consumer that just finished. The major difference between this method and &lt;EM&gt;OnItemAdded &lt;/EM&gt;is the handling of activity cancelation. If a child activity is canceled and we have a pending cancellation request then we mark ourselves complete by storing it into our private variable and then mark the activity itself canceled via &lt;EM&gt;NativeActivityContext.MarkCanceled&lt;/EM&gt;. Once we have done this once, as other children are canceled or complete they will see that the activity has already completed and immediately return.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;void &lt;/SPAN&gt;OnChildCompleted(&lt;SPAN style="COLOR: #2b91af"&gt;NativeActivityContext &lt;/SPAN&gt;context, &lt;SPAN style="COLOR: #2b91af"&gt;ActivityInstance &lt;/SPAN&gt;activity)
{
    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(m_hasCompleted.Get(context))
    {
        &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(activity.State != &lt;SPAN style="COLOR: #2b91af"&gt;ActivityInstanceState&lt;/SPAN&gt;.Closed &amp;amp;&amp;amp; context.IsCancellationRequested)
    {
        m_hasCompleted.Set(context, &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;);
        context.MarkCanceled();
    }
    &lt;SPAN style="COLOR: blue"&gt;else
    &lt;/SPAN&gt;{
        &lt;SPAN style="COLOR: #2b91af"&gt;Int32 &lt;/SPAN&gt;concurrencyCount = m_concurrencyCount.Get(context);
        &lt;SPAN style="COLOR: #2b91af"&gt;Int32 &lt;/SPAN&gt;maxConcurrencyCount = &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.MaxConcurrency.Get(context);

        &lt;SPAN style="COLOR: green"&gt;// Subtract one since an activity just finished
        &lt;/SPAN&gt;concurrencyCount--;

        &lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;T&amp;gt; itemQueue = m_itemQueue.Get(context);
        &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(concurrencyCount &amp;lt; maxConcurrencyCount &amp;amp;&amp;amp; itemQueue.Count &amp;gt; 0)
        {
            concurrencyCount++;
            context.ScheduleAction&amp;lt;T&amp;gt;(Body, itemQueue.Dequeue(), &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CompletionCallback&lt;/SPAN&gt;(OnChildCompleted));
        }

        m_concurrencyCount.Set(context, concurrencyCount);
    }
}&lt;/PRE&gt;
&lt;P&gt;The final classes that have not been shown here are &lt;EM&gt;ParallelItemScheduler&amp;lt;T&amp;gt;.Enqueue&lt;/EM&gt; and &lt;EM&gt;&lt;EM&gt;ParallelItemScheduler&lt;/EM&gt;&amp;lt;T&amp;gt;.Shutdown.&lt;/EM&gt; The former simply resumes the bookmark with the specified data and the latter queues the item stored in &lt;EM&gt;s_shutdownItem&lt;/EM&gt; so the call to &lt;EM&gt;Object.ReferenceEquals&lt;/EM&gt; will succeed and remove the bookmark.&lt;/P&gt;
&lt;H3&gt;&lt;/H3&gt;
&lt;H4&gt;Conclusion&lt;/H4&gt;
&lt;P&gt;Today we have learned how to write custom scheduling logic by extending &lt;EM&gt;NativeActivity&lt;/EM&gt;. We designed a custom class, &lt;EM&gt;ParallelItemScheduler&amp;lt;T&amp;gt;&lt;/EM&gt;, that may be used in a workflow to model a consumer scheduler which schedules &lt;EM&gt;N&lt;/EM&gt; concurrent consumers. The consumer is an attachable &lt;EM&gt;ActivityAction&amp;lt;T&amp;gt;&lt;/EM&gt; class that is pluggable by consumers of the activity, and it is generic so highly reusable in a variety of scenarios. Although I would have liked to cover it all in a single post, this one is already becoming quite long and I would like to provide the ability to allow this information to soak in before continuing onto the next piece. Once we design our &lt;EM&gt;ProducerConsumer&amp;lt;T&amp;gt; &lt;/EM&gt;activity you will hopefully gain a better understanding of how this activity is intended to be used. Until then, enjoy your newfound knowledge of the workflow framework and happy coding!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9945364" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="Workflow" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Workflow/" /></entry><entry><title>Windows Workflow 4.0 - CopyFile</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2010/01/04/windows-workflow-4-0-copyfile.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2010/01/04/windows-workflow-4-0-copyfile.aspx</id><published>2010-01-04T20:50:00Z</published><updated>2010-01-04T20:50:00Z</updated><content type="html">&lt;P&gt;It has recently come to my attention that there is unrest regarding our inclusion of a &lt;EM&gt;CopyDirectory&lt;/EM&gt; activity without a &lt;EM&gt;CopyFile &lt;/EM&gt;activity. Therefore, I decided to take this opportunity to introduce everyone to the sub-class &lt;EM&gt;AsyncCodeActivity&lt;/EM&gt; and how you can utilize it with a real world example – a cancelable file copy operation. As you may recall from my previous workflow posts, &lt;EM&gt;CodeActivity&lt;/EM&gt; does provide a mechanism for cancelation while the &lt;EM&gt;AsyncCodeActivity&lt;/EM&gt; does facilitate this need. If you are not familiar with asynchronous programming in .NET then you should probably read the &lt;A href="http://msdn.microsoft.com/en-us/library/ms228969.aspx" mce_href="http://msdn.microsoft.com/en-us/library/ms228969.aspx"&gt;following article&lt;/A&gt; to brush up before continuing.&lt;/P&gt;
&lt;H4&gt;.NET API Overview&lt;/H4&gt;
&lt;P&gt;The .NET API for &lt;EM&gt;System.IO.File&lt;/EM&gt; does not provide a way to asynchronously copy a file, so we will need to provide our own mechanism using the asynchronous APIs provided on &lt;A href="http://msdn.microsoft.com/en-us/library/system.io.filestream(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.io.filestream(VS.100).aspx"&gt;System.IO.FileStream&lt;/A&gt; (&lt;EM&gt;BeginRead/BeginWrite&lt;/EM&gt; and &lt;EM&gt;EndRead/EndWrite &lt;/EM&gt;respectively&lt;EM&gt;)&lt;/EM&gt;. I have provided the documentation for the aforementioned APIs below to aid in development of our activity.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;public IAsyncResult BeginRead(Byte[] array, Int32 offset, Int32 numBytes, AsyncCallback userCallback, Object stateObject) &lt;/LI&gt;
&lt;LI&gt;public Int32 EndRead(IAsyncResult asyncResult) &lt;/LI&gt;
&lt;LI&gt;public IAsyncResult BeginWrite(Byte[] array, Int32 offset, Int32 numBytes, AsyncCallback userCallback, Object stateObject) &lt;/LI&gt;
&lt;LI&gt;public void EndWrite(IAsyncResult asyncResult) &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Just so we’re all on the same page, the parameters serve the following purpose:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;array – The array of bytes that should be written to the file stream or a user allocated buffer in which to place bytes read from the file stream &lt;/LI&gt;
&lt;LI&gt;offset – The offset in the array that reading or writing should occur &lt;/LI&gt;
&lt;LI&gt;numBytes – The number of bytes from the offset that should be read or written &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Also, it’s probably important to mention that the return value from &lt;EM&gt;EndRead&lt;/EM&gt; returns the number of bytes that were &lt;STRONG&gt;actually&lt;/STRONG&gt; read from the stream, which may be equal to or less than the range provided by (numBytes – offset). When the return value is less than the range provided to &lt;EM&gt;BeginRead&lt;/EM&gt; you are at the end of the file. Now that we have this basic introduction out of the way, lets see how this all fits into the &lt;EM&gt;AsyncCodeActivity&lt;/EM&gt; framework.&lt;/P&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;H4&gt;AsyncCodeActivity API Overview&lt;/H4&gt;
&lt;H1&gt;&lt;/H1&gt;
&lt;P mce_keep="true"&gt;The workflow framework provides the base classes, &lt;EM&gt;AsyncCodeActivity/AsyncCodeActivity&amp;lt;T&amp;gt;&lt;/EM&gt;, which we will be using in this post. This activity provides 3 important methods for overriding that I have broken down.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, Object asyncState) 
&lt;UL&gt;
&lt;LI&gt;The synchronous entry point at which time all values required for asynchronous execution should be extracted using the provided context and stored into a custom result or state. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;void EndExecute(AsyncCodeActivityContext context, IAsyncResult result) 
&lt;UL&gt;
&lt;LI&gt;The synchronous exit point at which time all values for the workflow, such as OutArgument&amp;lt;T&amp;gt; and InOutArgument&amp;lt;T&amp;gt;, should be set using the provided context. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;void Cancel(AsyncCodeActivityContext context) 
&lt;UL&gt;
&lt;LI&gt;The synchronous entry point invoked from workflow to begin the cancelation process. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;In the next section we will be diving a little deeper into how each of these may be implemented in a real world activity.&lt;/P&gt;
&lt;H4&gt;Writing the CopyFile Activity&lt;/H4&gt;
&lt;P&gt;The first thing we should do when designing out custom activity is to determine the type of flexibility we would like to provide to consumers of our activity. At the very least, copying a file will require a &lt;EM&gt;Source&lt;/EM&gt; and a &lt;EM&gt;Target&lt;/EM&gt;. This is where we will start, but we will continue evaluating other values we may like to promote to configurable properties. So, to begin we have the following activity outline:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CopyFile &lt;/SPAN&gt;: &lt;SPAN style="COLOR: #2b91af"&gt;AsyncCodeActivity
&lt;/SPAN&gt;{
    [&lt;SPAN style="COLOR: #2b91af"&gt;RequiredArgument&lt;/SPAN&gt;]
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; Source
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    [&lt;SPAN style="COLOR: #2b91af"&gt;RequiredArgument&lt;/SPAN&gt;]
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; Target
    {
        &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
        &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;protected override &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;IAsyncResult &lt;/SPAN&gt;BeginExecute(&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCodeActivityContext &lt;/SPAN&gt;context, &lt;SPAN style="COLOR: #2b91af"&gt;AsyncCallback &lt;/SPAN&gt;callback, &lt;SPAN style="COLOR: #2b91af"&gt;Object &lt;/SPAN&gt;state)
    {
        &lt;SPAN style="COLOR: blue"&gt;throw new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;NotImplementedException&lt;/SPAN&gt;();
    }

    &lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;Cancel(&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCodeActivityContext &lt;/SPAN&gt;context)
    {
        &lt;SPAN style="COLOR: blue"&gt;base&lt;/SPAN&gt;.Cancel(context);
    }

    &lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;EndExecute(&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCodeActivityContext &lt;/SPAN&gt;context, &lt;SPAN style="COLOR: #2b91af"&gt;IAsyncResult &lt;/SPAN&gt;result)
    {
        &lt;SPAN style="COLOR: blue"&gt;throw new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;NotImplementedException&lt;/SPAN&gt;();
    }
}&lt;/PRE&gt;
&lt;P&gt;&lt;EM&gt;Note: For the remainder of this section we will be investigating the implementation of the activity and simply refer to the individual method we are currently writing.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;The first caveat I would like to point out is that the &lt;EM&gt;BeginRead &lt;/EM&gt;API takes a buffer and an offset/length to determine how much data to read. Since there is no possible way we can know up-front how much data we will be streaming from the file, we will most likely be making multiple calls back into &lt;EM&gt;BeginRead &lt;/EM&gt;each time we have copied the pending buffer into the target location. On top of this, when the callback provided to &lt;EM&gt;BeginExecute&lt;/EM&gt; is invoked the workflow framework queues an operation on the workflow execution thread to invoke the &lt;EM&gt;EndExecute&lt;/EM&gt; method – once this method completes the activity has completed execution. With this knowledge, we know that we will need to provide our own callback(s) to &lt;EM&gt;BeginRead/BeginWrite&lt;/EM&gt; and only invoke the callback provided by the workflow framework once the entire copy operation has completed. The other important caveat you may have noticed is that there is no way to cancel an ongoing call to &lt;EM&gt;BeginRead/BeginWrite&lt;/EM&gt;, as the built-in &lt;EM&gt;IAsyncResult&lt;/EM&gt; interface does not provide a mechanism to get this feedback to the asynchronous operation. So, in order to properly support cancellation we should just read/write in a small enough buffer such that we can check a flag on our asynchronous copy state and stop the process once the ongoing read or write operation completes. &lt;/P&gt;
&lt;P&gt;So, in summary, we will follow a pattern similar to the following:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Set up our async state in BeginExecute and start the first read operation by invoking FileStream.BeginRead &lt;/LI&gt;
&lt;LI&gt;When the first read operation completes, if we have not been cancelled then begin the first write operation using the buffer from (1) &lt;/LI&gt;
&lt;LI&gt;When the write operation completes, if we have not been cancelled begin the next read operation if we are not at the end of the file. If we are at the end of the file, invoke the callback provided by the workflow framework to trigger the EndExecute method. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;I realize that this was a lot of information to ingest but hopefully it will start making sense as we start writing the method implementations.&lt;/P&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;P&gt;&lt;STRONG&gt;Asynchronous State&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The first thing we will need to define is our asynchronous state, which I have included for reference below. As it turns out, all we need is the original callback and state, a buffer, and the source and target file streams opened with the appropriate permissions and flags (some of the fields required by &lt;EM&gt;IAsyncResult&lt;/EM&gt; have been omitted for space).&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult &lt;/SPAN&gt;: &lt;SPAN style="COLOR: #2b91af"&gt;IAsyncResult
&lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Exception &lt;/SPAN&gt;Exception { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Boolean &lt;/SPAN&gt;Canceled { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Byte&lt;/SPAN&gt;[] Buffer { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;FileStream &lt;/SPAN&gt;ReadStream { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;FileStream &lt;/SPAN&gt;WriteStream { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
}&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;Implementation&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Now that we have defined the data we will need to retain for our operation, we can start implementing the logic&lt;EM&gt; &lt;/EM&gt;of our activity. Using steps 1-3 above, we come to something similar to the following:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;protected override &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;IAsyncResult &lt;/SPAN&gt;BeginExecute(&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCodeActivityContext &lt;/SPAN&gt;context, &lt;SPAN style="COLOR: #2b91af"&gt;AsyncCallback &lt;/SPAN&gt;callback, &lt;SPAN style="COLOR: #2b91af"&gt;Object &lt;/SPAN&gt;state)
{
    &lt;SPAN style="COLOR: #2b91af"&gt;String &lt;/SPAN&gt;source = &lt;SPAN style="COLOR: #2b91af"&gt;Path&lt;/SPAN&gt;.GetFullPath(Source.Get(context));
    &lt;SPAN style="COLOR: #2b91af"&gt;String &lt;/SPAN&gt;target = &lt;SPAN style="COLOR: #2b91af"&gt;Path&lt;/SPAN&gt;.GetFullPath(Target.Get(context));

    &lt;SPAN style="COLOR: #2b91af"&gt;Int32 &lt;/SPAN&gt;bufferSize = BufferSize.Get(context);

    &lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult &lt;/SPAN&gt;copyFileResult = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult
    &lt;/SPAN&gt;{
        AsyncState = state,
        AsyncCallback = callback,
        Buffer = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Byte&lt;/SPAN&gt;[bufferSize],
        ReadStream = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;FileStream&lt;/SPAN&gt;(source, &lt;SPAN style="COLOR: #2b91af"&gt;FileMode&lt;/SPAN&gt;.Open, &lt;SPAN style="COLOR: #2b91af"&gt;FileAccess&lt;/SPAN&gt;.Read, &lt;SPAN style="COLOR: #2b91af"&gt;FileShare&lt;/SPAN&gt;.Read, bufferSize, &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;),
        WriteStream = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;FileStream&lt;/SPAN&gt;(target, &lt;SPAN style="COLOR: #2b91af"&gt;FileMode&lt;/SPAN&gt;.CreateNew, &lt;SPAN style="COLOR: #2b91af"&gt;FileAccess&lt;/SPAN&gt;.Write, &lt;SPAN style="COLOR: #2b91af"&gt;FileShare&lt;/SPAN&gt;.None, bufferSize, &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;),
    };

    context.UserState = copyFileResult;
    copyFileResult.ReadStream.BeginRead(copyFileResult.Buffer,
                                        0,
                                        copyFileResult.Buffer.Length,
                                        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCallback&lt;/SPAN&gt;(OnEndRead),
                                        copyFileResult);

    &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;copyFileResult;
}

&lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;Cancel(&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCodeActivityContext &lt;/SPAN&gt;context)
{
    ((&lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult&lt;/SPAN&gt;)context.UserState).Canceled = &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;;
}

&lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;EndExecute(&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCodeActivityContext &lt;/SPAN&gt;context, &lt;SPAN style="COLOR: #2b91af"&gt;IAsyncResult &lt;/SPAN&gt;result)
{
    &lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult &lt;/SPAN&gt;copyFileResult = result &lt;SPAN style="COLOR: blue"&gt;as &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult&lt;/SPAN&gt;;
    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(copyFileResult == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
    {
        &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(copyFileResult.AsyncWaitHandle != &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
    {
        ((&lt;SPAN style="COLOR: #2b91af"&gt;IDisposable&lt;/SPAN&gt;)copyFileResult.AsyncWaitHandle).Dispose();
    }

    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(copyFileResult.Exception != &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
    {
        &lt;SPAN style="COLOR: blue"&gt;throw &lt;/SPAN&gt;copyFileResult.Exception;
    }
}

&lt;SPAN style="COLOR: blue"&gt;static void &lt;/SPAN&gt;OnEndRead(&lt;SPAN style="COLOR: #2b91af"&gt;IAsyncResult &lt;/SPAN&gt;result)
{
    &lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult &lt;/SPAN&gt;copyFileResult = result.AsyncState &lt;SPAN style="COLOR: blue"&gt;as &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult&lt;/SPAN&gt;;
    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(copyFileResult == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
    {
        &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: #2b91af"&gt;Int32 &lt;/SPAN&gt;bytesRead = 0;

    &lt;SPAN style="COLOR: blue"&gt;try
    &lt;/SPAN&gt;{
        bytesRead = copyFileResult.ReadStream.EndRead(result);
    }
    &lt;SPAN style="COLOR: blue"&gt;catch &lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;Exception &lt;/SPAN&gt;ex)
    {
        copyFileResult.Exception = ex;
        OnCopyCompleted(copyFileResult);
    }

    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(copyFileResult.Canceled || bytesRead == 0)
    {
        OnCopyCompleted(copyFileResult);
    }
    &lt;SPAN style="COLOR: blue"&gt;else
    &lt;/SPAN&gt;{
        &lt;SPAN style="COLOR: green"&gt;// Start the next write operation using the current write offset and the bytes read.
        &lt;/SPAN&gt;copyFileResult.WriteStream.BeginWrite(copyFileResult.Buffer,
                                              0,
                                              bytesRead,
                                              &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCallback&lt;/SPAN&gt;(OnEndWrite),
                                              copyFileResult);
    }
}

&lt;SPAN style="COLOR: blue"&gt;static void &lt;/SPAN&gt;OnEndWrite(&lt;SPAN style="COLOR: #2b91af"&gt;IAsyncResult &lt;/SPAN&gt;result)
{
    &lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult &lt;/SPAN&gt;copyFileResult = result.AsyncState &lt;SPAN style="COLOR: blue"&gt;as &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult&lt;/SPAN&gt;;
    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(copyFileResult == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
    {
        &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;;
    }

    &lt;SPAN style="COLOR: blue"&gt;try
    &lt;/SPAN&gt;{
        copyFileResult.WriteStream.EndWrite(result);

        &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(copyFileResult.Canceled ||
            (copyFileResult.WriteStream.Length == copyFileResult.ReadStream.Length &amp;amp;&amp;amp;
             copyFileResult.ReadStream.Position == copyFileResult.ReadStream.Length))
        {
            OnCopyCompleted(copyFileResult);
        }
        &lt;SPAN style="COLOR: blue"&gt;else 
        &lt;/SPAN&gt;{
            copyFileResult.ReadStream.BeginRead(copyFileResult.Buffer, 
                                                0,
                                                copyFileResult.Buffer.Length, 
                                                &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;AsyncCallback&lt;/SPAN&gt;(OnEndRead), 
                                                copyFileResult);
        }
    }
    &lt;SPAN style="COLOR: blue"&gt;catch &lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;Exception &lt;/SPAN&gt;ex)
    {
        copyFileResult.Exception = ex;
        OnCopyCompleted(copyFileResult);
    }
}

&lt;SPAN style="COLOR: blue"&gt;static void &lt;/SPAN&gt;OnCopyCompleted(&lt;SPAN style="COLOR: #2b91af"&gt;CopyFileAsyncResult &lt;/SPAN&gt;copyFileResult)
{
    copyFileResult.ReadStream.Dispose();
    copyFileResult.WriteStream.Dispose();

    copyFileResult.AsyncWaitHandle.Set();

    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(copyFileResult.AsyncCallback != &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
    {
        copyFileResult.AsyncCallback(copyFileResult);
    }
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;As you can see from the code above, essentially we loop back and forth between &lt;EM&gt;OnEndRead&lt;/EM&gt; and &lt;EM&gt;OnEndWrite &lt;/EM&gt;allowing the framework to handle threading for us. We determine the process is completed in a few ways – an exception is thrown, a cancellation request is made, or the read stream and write stream have equal lengths and our position in the read stream is at the end (as seen in &lt;EM&gt;OnEndWrite&lt;/EM&gt;). Asynchronous APIs should not throw exceptions on the background thread, including callbacks, since an unhandled exception on a background thread may have the unintended consequences of shutting down the application domain or the entire process. What should occur instead, as you can see by the try/catch blocks in &lt;EM&gt;OnEndRead&lt;/EM&gt; and &lt;EM&gt;OnEndWrite&lt;/EM&gt;, is that an exception simply ends the read/write loop and completes the operation. Once the &lt;EM&gt;EndExecute&lt;/EM&gt; method is invoked by the framework we check for an exception that was saved in our state, and if one exists we throw it on the foreground thread provided by the workflow runtime. Something else that’s important to point out is that we store our state into the &lt;EM&gt;AsyncCodeActivityContext.UserState&lt;/EM&gt; property, which is how we retrieve it when the activity is canceled (see the &lt;EM&gt;Cancel&lt;/EM&gt; method above).&lt;/P&gt;
&lt;P&gt;For those of you paying close attention you may be noticed the introduction of an &lt;EM&gt;InArgument&amp;lt;Int32&amp;gt; &lt;/EM&gt;&lt;EM&gt;BufferSize&lt;/EM&gt; which is used in the &lt;EM&gt;BeginExecute&lt;/EM&gt; method to construct our in-memory buffer. Although I didn’t cover this initially I wanted to provide this functionality as a configurable property so we do not lose flexibility provided by the standard file copy APIs.&lt;/P&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;H4&gt;Conclusion&lt;/H4&gt;
&lt;P&gt;Although this article is quite wordy, hopefully it introduced the workflow APIs and provided an understandable and realistic example of how to utilize asynchronous APIs and cancellation in the workflow framework. Since this activity is asynchronous, it may be used as a branch of a &lt;EM&gt;Parallel &lt;/EM&gt;or the body of a &lt;EM&gt;ParallelForEach&amp;lt;T&amp;gt;&lt;/EM&gt; for copying multiple files in parallel to more efficiently saturate the network when high latency is involved. In fact, I plan on illustrating how you might use this activity to build a more efficient &lt;EM&gt;CopyDirectory&lt;/EM&gt; than what we ship in the box for copying a configurable number of files in parallel. However, this will involve a more complex implementation since the standard &lt;EM&gt;ParallelForEach&amp;lt;T&amp;gt;&lt;/EM&gt; provides no mechanism for capping the parallel branches at a maximum number, and providing this functionality requires us to derive from &lt;EM&gt;NativeActivity&lt;/EM&gt;. &lt;/P&gt;
&lt;P&gt;I hope this article serves as a starting point for the development of more complex activities, perhaps using this as a building block to develop that parallel directory copy I referred to above!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9943575" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="Workflow" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Workflow/" /></entry><entry><title>I'm a ramblin' wreck from Georgia Tech and a helluva engineer!</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2009/12/06/i-m-a-ramblin-wreck-from-georgia-tech-and-a-helluva-engineer.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2009/12/06/i-m-a-ramblin-wreck-from-georgia-tech-and-a-helluva-engineer.aspx</id><published>2009-12-06T08:47:00Z</published><updated>2009-12-06T08:47:00Z</updated><content type="html">&lt;p&gt;This particular post has nothing to do with technology. I'm an avid college football fan and have always cheered for my alma mater, the Georgia Tech Yellow Jackets. Tonight, for the first time since I have been actively following them, we beat Clemson for the 2nd time this season (39-34) and earned a berth in the BCS Orange Bowl!!&amp;nbsp;&lt;/p&gt;&lt;p&gt;Not to downplay Clemson, however, as they put up a really good fight both times and it came down to who had the ball last. The first game was equally amazing to watch and ended with a field goal to beat the Tigers 30-27. This game we won on a touchdown by Jonathan Dwyer! He's the man! Speaking of the man, I think C. J. Spiller deserves to go to New York and be in the running for the Heisman. Amazing athlete who I'm sure will do well in the NFL.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;Ok, I'm done gloating ... hopefully this will earn the ACC more respect. Now on to the Orange Bowl!&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;One more thing .. of course I can't leave Paul Johnson hanging high and dry in recognition. He has done an amazing job as head coach of GT, taking a team that went 7-5 to 9-4 and now 11-2 with a BCS berth, first appearance in the Orange Bowl since the early 60's!&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9933105" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Introduction to Windows Workflow 4.0</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2009/12/04/introduction-to-windows-workflow-4-0.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2009/12/04/introduction-to-windows-workflow-4-0.aspx</id><published>2009-12-04T18:54:00Z</published><updated>2009-12-04T18:54:00Z</updated><content type="html">&lt;P&gt;&lt;EM&gt;Note: I apologize in advance if this first post seems unorganized. There is a lot of material to cover and I couldn’t find a really good way to order the topics.&lt;/EM&gt; &lt;EM&gt;Hang in there and hopefully it will start making sense.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;In order to help everyone get up to speed with build customization, I wanted to take a few posts to share our collective knowledge on the Workflow framework in .NET 4.0. In this first post I plan to tackle the different base classes that may be used when designing your own custom activities, along with typical usage scenarios. Other topics, such as extensions, tracking, and more advanced customization will be covered later. I will also be keeping an eye on comments to help point me in the right direction. So without further adieu, on with the code!&lt;/P&gt;
&lt;H4&gt;The Core Activity Classes&lt;/H4&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;P&gt;There are 4 base classes that you should become very familiar with in the framework. Each class has a corresponding generic version, which informs the workflow runtime that it returns a result of the specified type (more on this later). I have listed out the 4 base classes below, along with general information on when you might choose to utilize each one.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;System.Activities.Activity&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;This class serves as the base class for all of the other activities in included in the framework, as well as the class you will be extending for activities composed in code. Most of our activities in TFS 2010 are derived from this activity or &lt;EM&gt;Activity&amp;lt;T&amp;gt;&lt;/EM&gt;, which is simply an activity that returns a result of type &lt;EM&gt;T&lt;/EM&gt;.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;System.Activities.CodeActivity&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;CodeActivity&lt;/EM&gt;, along with &lt;EM&gt;CodeActivity&amp;lt;T&amp;gt;&lt;/EM&gt;, provide a simple mechanism for providing the implementation of an activity as .NET code. Classes that utilize this as a base class should not perform long running operations as there is no way to cancel the execution of this activity.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;System.Activities.AsyncCodeActivity&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;AsyncCodeActivity &lt;/EM&gt;and &lt;EM&gt;AsyncCodeActivity&amp;lt;T&amp;gt;&lt;/EM&gt; are very similar to the &lt;EM&gt;CodeActivity&lt;/EM&gt; classes but are intended to perform long running operations. If you need perform I/O or would like to provide the ability to cancel the execution of your activity, you should derive from the asynchronous variety. Most of the code activities in TFS 2010 utilize the &lt;EM&gt;AsyncCodeActivity&lt;/EM&gt; classes so a build may be stopped cleanly during an operation.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;System.Activities.NativeActivity&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This particular activity, in conjunction with &lt;EM&gt;NativeActivity&amp;lt;T&amp;gt;&lt;/EM&gt;, are not intended for heavy use. In fact, the workflow framework even makes somewhat limited use of this activity as a base class. Typically you should only use this activity if you would like to define your own scheduling behavior or need to interact with bookmarks and external services. &lt;/P&gt;
&lt;H4&gt;The Core Data Classes&lt;/H4&gt;
&lt;P&gt;&lt;STRONG&gt;System.Activities.Variable&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;A variable in represents the same concept as it does in code when you declare an integer or string. The purpose of variables is to act as a data storage mechanism within a particular visibility scope. Much like you cannot declare two variables of the name ‘foo’ in C# without a compiler error, you cannot successfully run a workflow that attempts to define two variables in the same scope with the same name.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;System.Activities.Argument&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;An argument represents the flow of data, and does not actually have the ability to store anything (the actual storage mechanism for an argument is typically a variable or top-level input to the workflow). There are 3 important sub-classes of argument that you will need to become familiar with:&lt;/P&gt;
&lt;OL&gt;
&lt;OL&gt;
&lt;LI&gt;System.Activities.InArgument&amp;lt;T&amp;gt; 
&lt;UL&gt;
&lt;LI&gt;The value is meant to flow into the method. Much like a pointer in C, the pointer itself cannot be changed but if a complex object is passed as an argument then fields of that object may be changed. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;System.Activities.OutArgument&amp;lt;T&amp;gt; 
&lt;UL&gt;
&lt;LI&gt;The value is meant to flow out of the method. This argument type is synonymous to the ‘out’ keyword in C#. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;System.Activities.InOutArgument&amp;lt;T&amp;gt; 
&lt;UL&gt;
&lt;LI&gt;The value is meant to flow in and possibly be modified as an output. This argument type is synonymous to the ‘ref’ keyword in C#. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/OL&gt;&lt;/OL&gt;
&lt;H4&gt;Designing Your First Activity&lt;/H4&gt;
&lt;P&gt;For simplicity, we’re going to start with the age-old example of “Hello, World!” but accomplish the task with workflow. For this introduction we just need to load up visual studio and create a new C# ‘Console Application’ project. Normally you would select a ‘Workflow Console Application’ for the project type, but I’d rather go through the steps manually to hopefully aid in your understanding of the framework. Once you have the project created, add a reference to &lt;EM&gt;System.Activities&lt;/EM&gt; using the ‘.NET’ tab. Now we need to create our first activity for interacting with the console for output. Create a new C# class called ‘WriteLine’ and paste the following code into the file.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;using &lt;/SPAN&gt;System;
&lt;SPAN style="COLOR: blue"&gt;using &lt;/SPAN&gt;System.Activities;
&lt;SPAN style="COLOR: blue"&gt;using &lt;/SPAN&gt;System.ComponentModel;
&lt;SPAN style="COLOR: blue"&gt;using &lt;/SPAN&gt;System.IO;

&lt;SPAN style="COLOR: blue"&gt;namespace &lt;/SPAN&gt;HelloWorkflow
{
    &lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;WriteLine &lt;/SPAN&gt;: &lt;SPAN style="COLOR: #2b91af"&gt;CodeActivity
    &lt;/SPAN&gt;{
        [&lt;SPAN style="COLOR: #2b91af"&gt;Browsable&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;)]
        [&lt;SPAN style="COLOR: #2b91af"&gt;RequiredArgument&lt;/SPAN&gt;]
        [&lt;SPAN style="COLOR: #2b91af"&gt;DefaultValue&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)]
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;TextWriter&lt;/SPAN&gt;&amp;gt; TextWriter
        {
            &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
            &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
        }

        [&lt;SPAN style="COLOR: #2b91af"&gt;Browsable&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;)]
        [&lt;SPAN style="COLOR: #2b91af"&gt;RequiredArgument&lt;/SPAN&gt;]
        [&lt;SPAN style="COLOR: #2b91af"&gt;DefaultValue&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)]
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;InArgument&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;&amp;gt; Text
        {
            &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;;
            &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;;
        }

        &lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;Execute(&lt;SPAN style="COLOR: #2b91af"&gt;CodeActivityContext &lt;/SPAN&gt;context)
        {
            &lt;SPAN style="COLOR: #2b91af"&gt;String &lt;/SPAN&gt;text = Text.Get(context);
            &lt;SPAN style="COLOR: #2b91af"&gt;TextWriter &lt;/SPAN&gt;textWriter = TextWriter.Get(context);

            &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(textWriter == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
            {
                &lt;SPAN style="COLOR: blue"&gt;throw new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ArgumentException&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"The provided text writer is invalid"&lt;/SPAN&gt;);
            }

            textWriter.WriteLine(text);
        }
    }
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;What we have done is created an activity, called WriteLine, that takes a TextWriter and some Text as arguments and writes the text to the writer. I know this may seem overly simple but it works pretty well for explaining the general concepts of data flow. If you think about this a little bit, you may notice that this mimics code quite a bit! For instance, we could write this using C# instead in the following way:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public static void &lt;/SPAN&gt;WriteLine(&lt;SPAN style="COLOR: #2b91af"&gt;TextWriter &lt;/SPAN&gt;textWriter, &lt;SPAN style="COLOR: #2b91af"&gt;String &lt;/SPAN&gt;text)
{
    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(textWriter == &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;)
    {
        &lt;SPAN style="COLOR: blue"&gt;throw new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ArgumentNullException&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"textWriter"&lt;/SPAN&gt;);
    }

    textWriter.WriteLine(text);
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;Taking a moment to analyze the correlation between these two approaches, we notice a couple of similarities. First, the &lt;EM&gt;CodeActivity.Execute(CodeActivityContext) &lt;/EM&gt;method is nothing more than the private implementation of the C# method. Second, the input arguments are nothing more than properties on the activity of type &lt;EM&gt;System.Activities.InArgument&amp;lt;T&amp;gt;&lt;/EM&gt;. Although there isn’t always a direct 1-to-1 mapping as illustrated by this simple example, you should approach your development of activities in much the same way. Activities are meant to be modular, reusable pieces of code that may be composed into more complex functionality, exactly like functions/methods in written code.&lt;/P&gt;
&lt;P&gt;Now that we have our activity, let’s see how we can use it. Go back to your Program.cs file, or where your Main method exists, and make it look similar to the following.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;static void &lt;/SPAN&gt;Main(&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;[] args)
{
    &lt;SPAN style="COLOR: #2b91af"&gt;WorkflowInvoker &lt;/SPAN&gt;invoker = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;WorkflowInvoker&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;WriteLine&lt;/SPAN&gt;());
    
    &lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;Object&lt;/SPAN&gt;&amp;gt; inputs = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;Object&lt;/SPAN&gt;&amp;gt;();
    inputs.Add(&lt;SPAN style="COLOR: #a31515"&gt;"TextWriter"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;Console&lt;/SPAN&gt;.Out);
    inputs.Add(&lt;SPAN style="COLOR: #a31515"&gt;"Text"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #a31515"&gt;"Hello, Workflow!"&lt;/SPAN&gt;);

    invoker.Invoke(inputs);
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;If you now run this program you should see the text “Hello, Workflow!” output to the standard output stream of the console window! Ok, I know that wasn’t all that exciting, but you always need to start somewhere to understand the basic concepts before we can move on to the better stuff. Let’s take a second to go through the main method and explain what it does. First we allocate a &lt;EM&gt;WorkflowInvoker &lt;/EM&gt;object, which is very useful for running simple workflows (most hosting environments, including TFS Build 2010, will most likely utilize the &lt;EM&gt;WorkflowApplication&lt;/EM&gt; class instead), specifying the activity &lt;STRONG&gt;definition&lt;/STRONG&gt; we would like to use. Next, we set up some inputs which map to the argument names on our activity, which define the execution environment for the runtime. Last, we invoke the workflow which will execute our activity with the provided input environment. &lt;/P&gt;
&lt;H4&gt;Activity Definition vs. Activity Instance&lt;/H4&gt;
&lt;H4&gt;&lt;/H4&gt;
&lt;P&gt;One particularly interesting area I would like to point out is the separation of the activity &lt;STRONG&gt;definition&lt;/STRONG&gt; from the activity &lt;STRONG&gt;instance&lt;/STRONG&gt;. When you load a workflow for execution and provide an instance of a C# class, in this case the WriteLine activity, you are actually supplying what is known as the activity &lt;STRONG&gt;definition&lt;/STRONG&gt;. The definition defines the inputs, outputs, control flow, and everything else you would expect that remains static, much like a class definition in code. Each time the activity is executed it reuses the same C# class instance of the definition – &lt;STRONG&gt;once again, each time the activity is executed it reuses the same C# class instance of the definition&lt;/STRONG&gt;. Why did I say this twice? I want to make it extremely clear why it’s important to differentiate between properties that belong to the &lt;STRONG&gt;definition&lt;/STRONG&gt; and properties that belong to the individual execution &lt;STRONG&gt;instance&lt;/STRONG&gt;. Instance-level storage is accomplished with the mechanisms provided by the workflow runtime (Variable&amp;lt;T&amp;gt;, InArgument&amp;lt;T&amp;gt;, InOutArgument&amp;lt;T&amp;gt;, etc), while definition-level storage is accomplished via standard class properties. If you take a look back at our &lt;EM&gt;WriteLine&lt;/EM&gt; activity, the execute method obtains the values for the inputs using the provided &lt;EM&gt;CodeActivityContext&lt;/EM&gt;. Along with providing mechanisms to interact with the tracking participant and the ability to get extensions, the activity context also provides the storage for the current instance environment visible to the activity. So, if you want to retrieve the value for one of the inputs to the activity you must have access to the activity context to retrieve the value. If you would like to experiment with this more, try adding an integer as a regular field or property to the class and increment it each time the workflow is run. &lt;/P&gt;
&lt;H4&gt;Wrapping It Up&lt;/H4&gt;
&lt;P&gt;Reading this post should introduce you to basic concepts of workflow, how data flows in a workflow, and how to get started writing your own activity. I plan on continuing this series with regular updates on progressively more advanced and cumulative topics, so if you’re looking to make use of this framework in your own programs or are simply attempting to extend your build process keep an eye out! My current plan is to cover &lt;EM&gt;AsyncCodeActivity &lt;/EM&gt;and composition through &lt;EM&gt;Activity&lt;/EM&gt; in the following posts, but feel free to steer me in a different direction.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9932700" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="Workflow" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Workflow/" /></entry><entry><title>TFS 2010 – Customizing Build Information (Part 2)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2009/11/19/tfs-2010-customizing-build-information-part-2.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2009/11/19/tfs-2010-customizing-build-information-part-2.aspx</id><published>2009-11-19T19:18:00Z</published><updated>2009-11-19T19:18:00Z</updated><content type="html">
&lt;p&gt;My &lt;a href="http://blogs.msdn.com/patcarna/archive/2009/11/17/tfs-2010-customizing-build-information.aspx" mce_href="http://blogs.msdn.com/patcarna/archive/2009/11/17/tfs-2010-customizing-build-information.aspx"&gt;previous post&lt;/a&gt; introduced the basics of how the tracking participant may be used to create custom build information through the activity context. However, as pointed out at the end of the article, the best practice for creating custom activities in Workflow 4.0 is to do so through composition, meaning that you should derive from &lt;i&gt;Activity&lt;/i&gt; or &lt;i&gt;Activity&amp;lt;T&amp;gt;&lt;/i&gt;. In compliance with this model we supply activities that allow you to perform the same custom information creation through activity composition rather than from code. The intention of this article is to lead you through how you might make this type of functionality available, as well as introduce you to composing custom build information into your own build processes.&lt;/p&gt;
&lt;h4&gt;&lt;/h4&gt;
&lt;h4&gt;&lt;b&gt;Tracking Custom Build Information using Activity Composition&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;As you may recall, we previously introduced a custom tracking record, &lt;i&gt;BuildInformationRecord&amp;lt;T&amp;gt;&lt;/i&gt;, for sending instructions to the tracking participant to create custom information. In order to keep things generic, we want to allow users of our activity to have the same flexibility with our new activity that they have when interacting directly with the activity context. Since our activity will need to perform the interaction with the activity context on behalf of the workflow writer, we need to create a custom &lt;i&gt;CodeActivity&lt;/i&gt;, which may be defined similarly to the class below.&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;public sealed class &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;WriteBuildInformation&lt;/span&gt;&amp;lt;T&amp;gt; : &lt;span style="color: rgb(43, 145, 175);"&gt;CodeActivity&lt;br&gt;&lt;/span&gt;{&lt;br&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;WriteBuildInformation()&lt;br&gt;    {&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    [&lt;span style="color: rgb(43, 145, 175);"&gt;RequiredArgument&lt;/span&gt;]&lt;br&gt;    [&lt;span style="color: rgb(43, 145, 175);"&gt;Browsable&lt;/span&gt;(&lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;br&gt;    [&lt;span style="color: rgb(43, 145, 175);"&gt;DesignerSerializationVisibility&lt;/span&gt;(&lt;span style="color: rgb(43, 145, 175);"&gt;DesignerSerializationVisibility&lt;/span&gt;.Visible)]&lt;br&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;InArgument&lt;/span&gt;&amp;lt;T&amp;gt; Value { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br&gt;&lt;br&gt;    &lt;span style="color: blue;"&gt;protected override void &lt;/span&gt;Execute(&lt;span style="color: rgb(43, 145, 175);"&gt;CodeActivityContext &lt;/span&gt;context)&lt;br&gt;    {&lt;br&gt;        context.Track(&lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;BuildInformationRecord&lt;/span&gt;&amp;lt;T&amp;gt;() { Value = Value.Get(context) });&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;As you can see, our activity is simply a thin wrapper around the code we previously explored. However, there are a couple of advantages I’d like to point out when using this approach over the strict code approach.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Since execution is very short lived, the tracking participant gets a chance to receive the record and take action once the method completes. &lt;/li&gt;

&lt;li&gt;Gives consumers of the activity a chance to incorporate custom information by building activities through composition in either XAML or code. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This activity should only be considered a utility activity that serves as the base for special purpose activities. The reason I propose limited use of this activity directly is because the XAML for it can get relatively tedious fairly quickly. For example, if we step back and model our example of writing a build message in XAML using this activity, we will end up with something very similar to the XAML below.&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;&amp;lt;my:&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;WriteBuildInformation &lt;/span&gt;&lt;span style="color: red;"&gt;x:TypeArguments&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;my:BuildMessage&lt;/span&gt;" &lt;span style="color: red;"&gt;xmlns:my&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;http://mycustomschema.company.com&lt;/span&gt;" &lt;span style="color: red;"&gt;xmlns:x&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;http://schemas.microsoft.com/winfx/2006/xaml&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;br&gt;  &amp;lt;my:&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;WriteBuildInformation.Value&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;    [New BuildMessage() With {.Importance = BuildMessageImportance.Normal, .Message = "This is a custom message" }]&lt;br&gt;  &lt;span style="color: blue;"&gt;&amp;lt;/my:&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;WriteBuildInformation.Value&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br&gt;&amp;lt;/my:&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;WriteBuildInformation&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Judging by the XAML, the verbosity could be greatly reduced if we didn’t need to specify the &lt;i&gt;x:TypeArguments&lt;/i&gt; or construct the &lt;i&gt;Value&lt;/i&gt; parameter with a visual basic expression; this is where activity composition comes in handy. We can provide any number of specialized wrapper activities that simplify the usage of this activity for particular information types. Once again, for the sake of consistency, we will revisit the &lt;i&gt;BuildMessage&lt;/i&gt; for an example. What we would ultimately like to provide for users of our activity library is a single, specialized activity for writing build messages. Users should be able to set the &lt;i&gt;Importance&lt;/i&gt; and the &lt;i&gt;Message&lt;/i&gt; as arguments to the activity, just as they would when constructing the XAML above. Given this small set of requirements, we might end up with an activity that looks similar to the following:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;public sealed class &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;WriteBuildMessage &lt;/span&gt;: &lt;span style="color: rgb(43, 145, 175);"&gt;Activity&lt;br&gt;&lt;/span&gt;{&lt;br&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;WriteBuildMessage()&lt;br&gt;    {&lt;br&gt;        &lt;span style="color: blue;"&gt;base&lt;/span&gt;.Implementation = () =&amp;gt; CreateBody();&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    [&lt;span style="color: rgb(43, 145, 175);"&gt;RequiredArgument&lt;/span&gt;]&lt;br&gt;    [&lt;span style="color: rgb(43, 145, 175);"&gt;Browsable&lt;/span&gt;(&lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;br&gt;    [&lt;span style="color: rgb(43, 145, 175);"&gt;DesignerSerializationVisibility&lt;/span&gt;(&lt;span style="color: rgb(43, 145, 175);"&gt;DesignerSerializationVisibility&lt;/span&gt;.Visible)]&lt;br&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;InArgument&lt;/span&gt;&amp;lt;&lt;span style="color: rgb(43, 145, 175);"&gt;String&lt;/span&gt;&amp;gt; Message { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br&gt;&lt;br&gt;    [&lt;span style="color: rgb(43, 145, 175);"&gt;Browsable&lt;/span&gt;(&lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;br&gt;    [&lt;span style="color: rgb(43, 145, 175);"&gt;DesignerSerializationVisibility&lt;/span&gt;(&lt;span style="color: rgb(43, 145, 175);"&gt;DesignerSerializationVisibility&lt;/span&gt;.Visible)]&lt;br&gt;    &lt;span style="color: blue;"&gt;public &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;InArgument&lt;/span&gt;&amp;lt;&lt;span style="color: rgb(43, 145, 175);"&gt;BuildMessageImportance&lt;/span&gt;&amp;gt; Importance { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br&gt; &lt;br&gt;    &lt;span style="color: rgb(43, 145, 175);"&gt;Activity &lt;/span&gt;CreateBody()&lt;br&gt;    {&lt;br&gt;        &lt;span style="color: blue;"&gt;return new &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;WriteBuildInformation&lt;/span&gt;&amp;lt;&lt;span style="color: rgb(43, 145, 175);"&gt;BuildMessage&lt;/span&gt;&amp;gt;&lt;br&gt;        {&lt;br&gt;            Value = &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;InArgument&lt;/span&gt;&amp;lt;&lt;span style="color: rgb(43, 145, 175);"&gt;BuildMessage&lt;/span&gt;&amp;gt;(ctx =&amp;gt; &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;BuildMessage&lt;/span&gt;() { Message = Message.Get(ctx), Importance = Importance.Get(ctx) }),&lt;br&gt;        };&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;There a few things I would like to point out about the code above, just in case not everyone is familiar with lambda syntax and activity composition in general. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The single line in the constructor is one of the most important lines. The way composed activities work is you provide a &lt;i&gt;Func&amp;lt;Activity&amp;gt;&lt;/i&gt;, exposed as the property &lt;i&gt;Implementation&lt;/i&gt;, that returns the private implementation of your activity (synonymous to the implementation of a method or function in code). If you forget to set this, the activity will not produce an error and will produce no output. &lt;/li&gt;

&lt;li&gt;The &lt;i&gt;InArgument&amp;lt;T&amp;gt;&lt;/i&gt; type has a few constructors. In this particular scenario we want to construct an object at runtime based on the incoming arguments. The syntax we must use in this case is the constructor that takes a &lt;i&gt;Func&amp;lt;ActivityContext, T&amp;gt;&lt;/i&gt; so we can utilize the activity context handed to us by the runtime to extract the values of the arguments for our &lt;i&gt;BuildMessage&lt;/i&gt;. Since Workflow 4.0 is very new and still in beta, I plan on covering general topics regarding activity design and best practices we learned through our use of the framework in TFS 2010 in coming posts. If you don’t quite understand what I’m talking about just be patient, for soon you will be a Workflow Master (probably not, but you’ll understand it better than you do now)! &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have our specialized activity for writing build messages, we can express the equivalent XAML we saw earlier with the following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;my:WriteBuildMessage &lt;/span&gt;&lt;span style="color: red;"&gt;xmlns:my&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;http://mycustomschema.company.com&lt;/span&gt;" &lt;span style="color: red;"&gt;Importance&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;[BuildMessageImportance.Normal]&lt;/span&gt;" &lt;span style="color: red;"&gt;Message&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;This is a custom message&lt;/span&gt;" &lt;span style="color: blue;"&gt;/&amp;gt; &lt;br&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;As you can see the syntax is much more concise than the previous example. It also takes the burden off the user of your activity to create an instance of the appropriate type and use initializer-syntax to set the property values. Although this simplifies the XAML you should probably use good judgment when writing these specialized activities to keep your library to a reasonable size. You will find the following activities exposed in the library that shipped with TFS 2010 Beta 2:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WriteBuildError &lt;/li&gt;

&lt;li&gt;WriteBuildMessage &lt;/li&gt;

&lt;li&gt;WriteBuildWarning &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these activities you can, you guessed it, write messages, warnings, and errors. These particular information types are special in that they are well understood by our build report, however, and will show up with warning or error icons next to the message automatically when viewing the build log. &lt;a href="http://blogs.msdn.com/jpricket" mce_href="http://blogs.msdn.com/jpricket"&gt;Jason Prickett&lt;/a&gt; should be making a follow-up post soon describing how you can extend the build report to display your custom information. I’ll be sure to notify everyone once this happens so we can bring all of the customizations together and show off the entire scenario.&lt;/p&gt;

&lt;p&gt;After writing these past 2 articles I have come to the realization that it would probably be very helpful to go over Workflow 4.0 in general so everyone can get up to speed on these topics. My next few posts will focus on development of activities and design practices with the 4.0 APIs, so keep reading for more in-depth explanations of the underlying framework.&lt;/p&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9925676" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="Build" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Build/" /><category term="TFS" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/TFS/" /><category term="VSTS2010" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/VSTS2010/" /><category term="TFS2010" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/TFS2010/" /><category term="Workflow" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Workflow/" /></entry><entry><title>TFS 2010 – Customizing Build Information (Part 1)</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2009/11/17/tfs-2010-customizing-build-information.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2009/11/17/tfs-2010-customizing-build-information.aspx</id><published>2009-11-17T23:10:00Z</published><updated>2009-11-17T23:10:00Z</updated><content type="html">&lt;P&gt;Before reading this post, you should take a moment to read Aaron Hallberg’s &lt;A href="http://blogs.msdn.com/aaronhallberg/archive/2009/06/01/writing-custom-activities-for-tfs-build-2010-beta-1.aspx" mce_href="http://blogs.msdn.com/aaronhallberg/archive/2009/06/01/writing-custom-activities-for-tfs-build-2010-beta-1.aspx"&gt;post&lt;/A&gt; on build process customization in TFS 2010 Beta 1. Now that you fully understand custom activities in Windows Workflow 4.0 (just kidding), I would like to focus on how we have made it much easier to customize the information created and stored along with the build. There are currently multiple mechanisms for getting additional information into the build process, made possible by some activities, extension methods, and integration with the tracking participant (synonymous to the MSBuild logger for those familiar with that framework). This post will focus on using the activity context to create custom information from code.&lt;/P&gt;
&lt;H4&gt;&lt;STRONG&gt;Build Information (VERY quick primer)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;Build information is simply a hierarchical data store that is extensible. Each node in the hierarchy has a &lt;EM&gt;Type&lt;/EM&gt; and a set of &lt;EM&gt;Fields&lt;/EM&gt; (name/value pairs as strings). All information created since TFS 2008, including task logging, build steps, and compilation details, are stored using this mechanism. Since its introduction into the API this hierarchy has always been extensible, but with the introduction of Windows Workflow 4.0 we have tried to make it easier.&lt;/P&gt;
&lt;H4&gt;&lt;STRONG&gt;Tracking Custom Build Information using the ActivityContext&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;Tracking in Windows Workflow is the mechanism that a workflow may use to communicate information to the tracking participant(s). For each workflow run in TFS Build 2010 we hook in a custom implementation of a tracking participant, the BuildTrackingParticipant. Along with tracking general activity in the workflow, such as activity execution, we also provide a way to inject custom build information during the workflow in a safe manner by interaction with the tracking participant. In order to facilitate this we have provided a custom tracking record defined as follows (certain classes in the hierarchy have been omitted):&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;BuildInformationRecord&lt;/SPAN&gt;&amp;lt;T&amp;gt;&lt;SPAN style="COLOR: #2b91af"&gt;
&lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;T Value { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This specialized record should be used for writing all custom build information during a workflow. The tracking participant creates information nodes from these records by analyzing the enclosed type via designer-based reflection and converts the object into an &lt;EM&gt;IDictionary&amp;lt;String, String&amp;gt;&lt;/EM&gt; for storage. If complete customization of the data conversion is desired you may provide a custom TypeConverter for &lt;EM&gt;T&lt;/EM&gt; which can take the object and convert it to an &lt;EM&gt;IDictionary&amp;lt;String, String&amp;gt;&lt;/EM&gt; (in most instances this level of customization will not be necessary, but the hook exists if the need arises). The information node type name is extracted from the name of the managed type (e.g. &lt;EM&gt;typeof(T).Name&lt;/EM&gt;), so there is no need to provide this explicitly. This mechanism of writing build information is how all built-in information nodes are written to the build log, excluding the activity tracking nodes themselves. &lt;/P&gt;
&lt;P&gt;Illustration by example is typically the easiest way to understand, so next I will describe how we write information nodes of type &lt;EM&gt;BuildMessage &lt;/EM&gt;to the log using this tracking record. The first thing we will need to do is define a class that describes the data we will be storing for a message: &lt;EM&gt;Message &lt;/EM&gt;and&lt;EM&gt; Importance&lt;/EM&gt;. You will find the definition of this class below.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;BuildMessage
&lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;String &lt;/SPAN&gt;Message { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;BuildMessageImportance &lt;/SPAN&gt;Importance { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
}&lt;/PRE&gt;
&lt;P&gt;As you can see, all we had to do is define a class with a type name and set of properties matching the information type we would like to create. Now, in order to inject a &lt;EM&gt;BuildMessage&lt;/EM&gt; information node into the build log all we need to do is call the appropriate &lt;EM&gt;CodeActivityContext.Track(CustomTrackingRecord)&lt;/EM&gt; or &lt;EM&gt;NativeActivityContext.Track(CustomTrackingRecord) &lt;/EM&gt;method from code, depending on which activity type your custom activity derives. For instance, if you would like to track a message from a code activity you could do the following:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public sealed class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;WriteMessage &lt;/SPAN&gt;: &lt;SPAN style="COLOR: #2b91af"&gt;CodeActivity
&lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;protected override void &lt;/SPAN&gt;Execute(&lt;SPAN style="COLOR: #2b91af"&gt;CodeActivityContext &lt;/SPAN&gt;context)
    {
        context.Track(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;BuildInformationRecord&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;BuildMessage&lt;/SPAN&gt;&amp;gt;()
        {
            Value = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;BuildMessage&lt;/SPAN&gt;()
            {
                Importance = &lt;SPAN style="COLOR: #2b91af"&gt;BuildMessageImportance&lt;/SPAN&gt;.Normal,
                Message = &lt;SPAN style="COLOR: #a31515"&gt;"This is a custom information node"&lt;/SPAN&gt;,
            },
        });
    }
}&lt;/PRE&gt;
&lt;P&gt;When the tracking participant receives this record, it will essentially perform the following steps:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Find the closest activity tracking node in scope (more details on how this is managed in a later post), using the root node of the current &lt;EM&gt;IBuildDetail &lt;/EM&gt;if none is found.&lt;/LI&gt;
&lt;LI&gt;Create a new &lt;EM&gt;IBuildInformationNode&lt;/EM&gt; as a child of the node from (1) with a type name of “BuildMessage” (derived from &lt;EM&gt;typeof(T).Name&lt;/EM&gt; as described earlier).&lt;/LI&gt;
&lt;LI&gt;Retrieve the &lt;EM&gt;TypeDescriptor&lt;/EM&gt; for &lt;EM&gt;T. &lt;/EM&gt;If the type converter can convert directly to an &lt;EM&gt;IDictionary&amp;lt;String, String&amp;gt;&lt;/EM&gt;, it simply allows the converter to do the heavy lifting. If the converter cannot perform this conversion, an information field will be created from each &lt;EM&gt;PropertyDescriptor&lt;/EM&gt; retrieved from a call to &lt;EM&gt;TypeDescriptor.GetProperties(Object)&lt;/EM&gt;, converting each value to a &lt;EM&gt;String&lt;/EM&gt; using the converter of the &lt;EM&gt;PropertyDescriptor&lt;/EM&gt;. In most cases this will simply invoke the &lt;EM&gt;ToString()&lt;/EM&gt; method of the type. However, we provide explicit converter implementations which cannot be overridden for &lt;EM&gt;DateTime&lt;/EM&gt; and &lt;EM&gt;Byte[]&lt;/EM&gt; properties to ensure appropriate and consistent conversions of these data types.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;While this mechanism works fine there is a pretty important caveat with tracking custom information from within a &lt;EM&gt;CodeActivity &lt;/EM&gt;that you should be aware of. With the exception of the &lt;EM&gt;AsyncCodeActivity&lt;/EM&gt;, every operation in a single workflow instance is executed on the same thread, including tracking. So, if you have a long-running execute method where you are attempting to track progress by logging multiple messages you will be surprised when nothing shows up until the activity completes. This behavior is due to the single thread; since your execute method is using the thread the tracking records will not be flushed to the tracking participant until your method returns. As a general rule of thumb, we have tried to keep away from creating long-running and complex code activities in favor of producing much smaller, more modular behavior that we then build into an activity through composition. Most of our activities in the shipping library derive from &lt;EM&gt;Activity&lt;/EM&gt; or &lt;EM&gt;Activity&amp;lt;T&amp;gt;&lt;/EM&gt;, with workflow driving the majority of the logical constructs. Due to this design we needed a way to create build information through composition, which drove us to create some custom activities for exactly this purpose. I plan to explore these activities and how to use them in a future post. Stay tuned …&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9923929" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="Build" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Build/" /><category term="TFS" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/TFS/" /><category term="VSTS2010" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/VSTS2010/" /><category term="TFS2010" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/TFS2010/" /><category term="Workflow" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/Workflow/" /></entry><entry><title>TFS 2010 - An Introduction to Gated Check-in</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2009/06/29/an-introduction-to-gated-check-in.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2009/06/29/an-introduction-to-gated-check-in.aspx</id><published>2009-06-30T01:50:00Z</published><updated>2009-06-30T01:50:00Z</updated><content type="html">&lt;P&gt;In TFS 2008 we made quite a few improvements to build, such as scheduled builds and continuous integration. The continuous integration feature is nice for detecting failures in the build as soon as possible to ensure minimal downtime and reduce the chance of generating a bad nightly build. However, it’s not a perfect solution since even when the build fails it is possible for others to submit unrelated changes and keep the build broken. As a first measure to aid this scenario, Buck Hodges wrote a check-in policy that would determine which, if any, build definitions would be affected by the changes being checked in – if the last build for the definition failed, the policy would not allow the user to check-in without overriding it. But there are quite a few issues with this approach, the main one being that it requires the users to install the policy and only override it when honestly submitting fixes for the build break. At this point you may be asking yourself “what if there were a way to stop people from submitting broken source code into the repository on the server?” This is exactly what gated check-in offers, and I intend to explore the features around gated check-in in the following paragraphs.&lt;/P&gt;
&lt;H3&gt;Setting Up Gated Check-in&lt;/H3&gt;
&lt;P&gt;&lt;FONT size=2&gt;Gated check-in is merely an extension of the check-in trigger for a build definition, so it should be easy to setup for those familiar continuous integration. In TFS 2008, we provided ‘Manual’, ‘Continuous Integration’, ‘Rolling builds’, and ‘Schedule’ (along with the option to force builds on that schedule even if no changes occurred since the last build). When viewing the build definition properties in TFS 2010, you will see the same options (with the addition of ‘Gated Check-in’):&lt;/FONT&gt;&lt;/P&gt;
&lt;P align=center&gt;&lt;A href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Definition_Triggers_2.jpg" mce_href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Definition_Triggers_2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Definition_Triggers border=0 alt=Definition_Triggers src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Definition_Triggers_thumb.jpg" width=627 height=335 mce_src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Definition_Triggers_thumb.jpg"&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P align=left&gt;When this trigger is selected for a build definition, any check-in that is made to a file that is mapped in the associated workspace will trigger a verification build. If the build succeeds, the changes will be submitted to the repository. If the build fails, the changes are not allowed to be submitted and must be fixed and resubmitted.&lt;/P&gt;
&lt;H2&gt;&lt;/H2&gt;
&lt;H3&gt;Submitting a Gated Check-in&lt;/H3&gt;
&lt;P&gt;When a user attempts to submit changes to a version control path that is mapped by a build definition with the ‘Gated Check-in’ trigger, they will be presented with the following dialog:&lt;/P&gt;
&lt;P align=center&gt;&lt;A href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_2.jpg" mce_href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Gated_Confirmation border=0 alt=Gated_Confirmation src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_thumb.jpg" width=525 height=360 mce_src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_thumb.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The first thing to point out here is that the check-in been automatically converted to a shelveset. In this particular scenario, the shelveset has been named ‘Gated_2009-06-29_02.49.00.9801’. The check-in notes, associated work items, etc., are all replicated into the shelveset and will be included in the changeset upon a successful build. The second piece of the dialog to pay attention to is the build definition selection. If there were only a single build definition that was considered affected by the changes, the combo box would be disabled and you would not be provided any options. If, however, there is more than one build definition that maps the changes being submitted, the user you will be presented with the list of build definitions as shown in the following image:&lt;/P&gt;
&lt;P align=center&gt;&lt;A href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_Dropdown_2.jpg" mce_href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_Dropdown_2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Gated_Confirmation_Dropdown border=0 alt=Gated_Confirmation_Dropdown src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_Dropdown_thumb.jpg" width=412 height=133 mce_src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_Dropdown_thumb.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;It’s important to note here that the actual definition selected to perform the check-in does not matter here, as both have been determined to map at least some subset of changes included in the check-in. However, it’s possible that ‘Gated Definition 1’ only maps a single file in the check-in, while ‘Gated Definition 2’ could map all the files or a larger subset. Currently we do not provide any indication as to what percentage of the changes are mapped by any given build definition. Once you have selected a build definition, you have the ability to specify some extra options. For example, it is entirely possible that you are a build administrator and wish to submit a fix directly rather than waiting for the verification build. However, this option will only be enabled for a selected build definition if you have the appropriate permission, ‘Override Check-in Validation by Build’. If you have the appropriate permission, we have provided the ability to bypass build verification as shown in the following image (although it’s disabled in this particular shot since no build definition is currently selected):&lt;/P&gt;
&lt;P align=center&gt;&lt;A href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_Options_2.jpg" mce_href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_Options_2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Gated_Confirmation_Options border=0 alt=Gated_Confirmation_Options src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_Options_thumb.jpg" width=515 height=352 mce_src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_Confirmation_Options_thumb.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The other option available in the ‘Show Options’ section of the dialog is ‘Preserve my pending changes locally’. This allows the user to decide whether or not the changes being submitted should be left in the workspace or undone once the ‘Build Changes’ button is clicked &lt;EM&gt;(if the changes are left in the workspace, there is an entry point that we will explore later in the article to reconcile the submitted changes with those in your workspace)&lt;/EM&gt;. Once you are satisfied with the options on this dialog and ‘Build Changes’ is clicked, you will be redirected to the build explorer where the build just queued will be highlighted for easy discovery as shown here: &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_BuildExplorer_2.jpg" mce_href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_BuildExplorer_2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: block; FLOAT: none; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN-LEFT: auto; BORDER-LEFT-WIDTH: 0px; MARGIN-RIGHT: auto" title=Gated_BuildExplorer border=0 alt=Gated_BuildExplorer src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_BuildExplorer_thumb.jpg" width=719 height=126 mce_src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_BuildExplorer_thumb.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Now I know there is only one build in this particular queue so it wouldn’t be very difficult to locate the build, but imagine there is a team of 50-60 people all submitting changes to the same build definition, or even multiple definitions all sharing the same build controller. :-) Anyway, moving along to the successful gated check-in, you can see from the following build report that the submitted changeset is associated with the gated build, just like changesets would be associated with a non-gated build by comparing the labels and analyzing the differences.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_BuildDetail_Successful_2.jpg" mce_href="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_BuildDetail_Successful_2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: block; FLOAT: none; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN-LEFT: auto; BORDER-LEFT-WIDTH: 0px; MARGIN-RIGHT: auto" title=Gated_BuildDetail_Successful border=0 alt=Gated_BuildDetail_Successful src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_BuildDetail_Successful_thumb.jpg" width=514 height=463 mce_src="http://blogs.msdn.com/blogfiles/patcarna/WindowsLiveWriter/Gatedcheckin_A274/Gated_BuildDetail_Successful_thumb.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Now that the build has completed successfully, you may have some further actions to perform if you chose not to preserve pending changes in your workspace. The entry point for this functionality is in build explorer, which is available via the context menu of the build detail entry in the ‘Completed Builds’ tab or the queued build entry in the ‘Queued Builds’ tab. If you only have a single workspace on the current machine then a workspace will be automatically selected for you. If, however, you have more than one workspace on the machine, you will be prompted to select the workspace which you would like to reconcile changes with. We currently do not support storing the source workspace from which the shelveset originated, so we cannot automatically determine the workspace used to create the shelveset. However, this feature is on a backlog and we are looking at including this functionality in a future version. The second entry point is from the gated check-in notification window in the build notification system tray application, which is included with the product in TFS 2010.&lt;/P&gt;
&lt;P&gt;This has been a very targeted and simple walk-through of the new gated check-in functionality available in TFS 2010. I will be covering more advanced scenarios surrounding permissions, integration with the build notification system tray application, and more in future postings. Stay tuned!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9810208" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author><category term="VSTS2010" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/VSTS2010/" /><category term="TFS2010" scheme="http://blogs.msdn.com/b/patcarna/archive/tags/TFS2010/" /></entry><entry><title>The access control list is not canonical</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2009/02/09/the-access-control-list-is-not-canonical.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2009/02/09/the-access-control-list-is-not-canonical.aspx</id><published>2009-02-09T16:02:00Z</published><updated>2009-02-09T16:02:00Z</updated><content type="html">&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Developing a program that does not require administrative privileges requires quite a bit of work up-front during the install. You need to make sure you do things like write registry keys to HKLM, create file system entries, and most importantly ensure that your ACLs (Access Control List) are correct to ensure smooth operation of your program while running under that non-admin account. However, sometimes this last step fails with a rather cryptic error, mentioning something along the lines of "The Access Control List is not canonical". After searching the web for solutions to this error, I couldn't find a definitive answer. One thing I did notice is if you open the 'security' dialog of the object that exhibits this issue, the Windows UI will actually recognize that there is an issue and ask if you would like to correct it. So obviously there is a way to fix this problem, but for my scenario requiring user intervention was just not good enough .. so I returned to searching. I finally came across an algorithm, buried in the depths of MSDN, which described how to fix the ordering of a DACL (Discretionary Access Control List). There was only one problem: it was written in VB. So, after a lot of hard work converting the code (just kidding, it was quite simple to convert), I produced the following helper method to attempt fixing the order of a DACL.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;   internal static void &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;CanonicalizeDacl(&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;NativeObjectSecurity &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;objectSecurity)
   {
       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;if &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;(objectSecurity == &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;null&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;)
       {
           &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;throw new &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;ArgumentNullException&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;(&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #a31515"&gt;"objectSecurity"&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;);
       }

       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;if &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;(objectSecurity.AreAccessRulesCanonical)
       {
           &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;return&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;;
       }

       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: green"&gt;// A canonical ACL must have ACES sorted according to the following order:
        //   1. Access-denied on the object
        //   2. Access-denied on a child or property
        //   3. Access-allowed on the object
        //   4. Access-allowed on a child or property
        //   5. All inherited ACEs 
        &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;RawSecurityDescriptor &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;descriptor = &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;RawSecurityDescriptor&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;(objectSecurity.GetSecurityDescriptorSddlForm(&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;AccessControlSections&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;.Access));

       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt; implicitDenyDacl = &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt;();
       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt; implicitDenyObjectDacl = &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt;();
       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt; inheritedDacl = &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt;();
       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt; implicitAllowDacl = &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt;();
       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt; implicitAllowObjectDacl = &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;&amp;gt;();

       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;foreach &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;(&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;CommonAce &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;ace &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;in &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;descriptor.DiscretionaryAcl)
       {
           &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;if &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;((ace.AceFlags &amp;amp; &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;AceFlags&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;.Inherited) == &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;AceFlags&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;.Inherited)
           {
               inheritedDacl.Add(ace);
           }
           &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;else
            &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;{
               &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;switch &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;(ace.AceType)
               {
                   &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;case &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;AceType&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;.AccessAllowed:
                       implicitAllowDacl.Add(ace);
                       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;break&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;;

                   &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;case &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;AceType&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;.AccessDenied:
                       implicitDenyDacl.Add(ace);
                       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;break&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;;

                   &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;case &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;AceType&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;.AccessAllowedObject:
                       implicitAllowObjectDacl.Add(ace);
                       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;break&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;;

                   &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;case &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;AceType&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;.AccessDeniedObject:
                       implicitDenyObjectDacl.Add(ace);
                       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;break&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;;
               }
           }
       }

       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;Int32 &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;aceIndex = 0;
       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;RawAcl &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;newDacl = &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;RawAcl&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;(descriptor.DiscretionaryAcl.Revision, descriptor.DiscretionaryAcl.Count);
       implicitDenyDacl.ForEach(x =&amp;gt; newDacl.InsertAce(aceIndex++, x));
       implicitDenyObjectDacl.ForEach(x =&amp;gt; newDacl.InsertAce(aceIndex++, x));
       implicitAllowDacl.ForEach(x =&amp;gt; newDacl.InsertAce(aceIndex++, x));
       implicitAllowObjectDacl.ForEach(x =&amp;gt; newDacl.InsertAce(aceIndex++, x));
       inheritedDacl.ForEach(x =&amp;gt; newDacl.InsertAce(aceIndex++, x));

       &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;if &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;(aceIndex != descriptor.DiscretionaryAcl.Count)
       {
           System.Diagnostics.Debug.Fail(&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #a31515"&gt;"The DACL cannot be canonicalized since it would potentially result in a loss of information"&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;);
           &lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: blue"&gt;return&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;;
       }

       descriptor.DiscretionaryAcl = newDacl;
       objectSecurity.SetSecurityDescriptorSddlForm(descriptor.GetSddlForm(&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white; COLOR: #2b91af"&gt;AccessControlSections&lt;/SPAN&gt;&lt;SPAN style="BACKGROUND: white"&gt;.Access));
   }&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;I hope this code saves someone out there a lot of trouble and time. Until next time …&lt;/P&gt;
&lt;P&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9408860" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Hello, World</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/patcarna/archive/2009/02/06/hello-world.aspx" /><id>http://blogs.msdn.com/b/patcarna/archive/2009/02/06/hello-world.aspx</id><published>2009-02-06T20:16:00Z</published><updated>2009-02-06T20:16:00Z</updated><content type="html">&lt;P&gt;What software developer can start anything new without the proverbial "Hello, World". Since I'm new to this side of things, this will serve as my introduction. My name is Patrick Carnahan, and I'm currently a developer on a product called Team Foundation Server, of which I focus on the&amp;nbsp;Build Automation functionality. More specifically, I&amp;nbsp;mainly design and work on the server code, including web services, data access, and SQL. This isn't where I started my almost&amp;nbsp;4 year career at Microsoft, however. I was originally hired on to the Version Control team within the same server product in June of 2005. At that point in time I knew nothing about .NET application development, ASP.NET web services, and very little about SQL development. This product has allowed me to interact with these technologies much more than I ever would have working on projects for myself. I have become proficient in SQL, including query performance analysis and debugging. My knowledge of .NET libraries continues to grow every day. I deal with distributed programming models all the time, which keeps my job extremely interesting. &amp;nbsp;&lt;/P&gt;
&lt;P&gt;I am very passionate about the product that I work on and hope to deliver compelling releases in the future. Hopefully this spot will serve as a more general discussion of programming topics, but I will most likely include targeted posts helping users of Team Foundation Server get the most out of the product. I have learned quite a bit since starting my tenure with this company, and hopefully I can begin to share my knowledge with others.&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9402731" width="1" height="1"&gt;</content><author><name>patcarna</name><uri>http://blogs.msdn.com/patcarna/ProfileUrlRedirect.ashx</uri></author></entry></feed>