Adventures with Windows Workflow – Hosting a Workflow with Tracing and Persistence
The great thing about my job is being able to work with cutting edge / brand spanking new technologies that still have the “new car smell”. The one I’m currently working with is Windows Workflow.
I have been doing a lot of presentations on this topic recently and some of the key features I discuss is WF’s built-in capabilities for tracking and persistence.
- Workflow tracking: The ability to look inside an executing or executed workflow and see what is happening. This is a key feature for workflow reporting and troubleshooting.
- Workflow persistence: When a workflow is executing… it occupies CPU and memory. If the workflow is long running (hours, days, years)… you don’t want it to continually occupy CPU and RAM. Persistence allows the workflow instance to be saved (aka “persisted”) to something (eg file, SQL, toilet paper roll) for resumption at a later time.
These are key features of any workflow engine. Hmm… this begs the next question… “How do I use / enable these features”?
Windows Workflow’s full name is Windows Workflow Foundation (WF for short). All the current emphasis has been on “Workflow” and not “Foundation”. WF is not a server product. Instead, it is a foundation that provides workflow functionality that can be consumed by your existing / new apps. As to how it is consumed… it is up to you (build your own server or integrate into your existing app or whatever else you can think of).
So the first point is … you need to create something that will host the workflow. In my demos, a simple command line app acts as my host:
1. Create the workflow runtime (WorkflowRuntime)
2. Create an instance of the workflow in question and start execution
When you create a “Sequential / State Machine Workflow Console Application” workflow project, it auto-generates all this code in the command line app for you.
You’ll notice some code about delegates… this just tells the command line app to stick around until the workflow runtime is complete. The runtime is asynchronous so without the delegates, after you kick up the workflowruntime… the command line app will finish and shutdown thereby killing the still executing workflow runtime.
OK. That’s great but how do you enable tracking or persistence? You do this by specifying tracking and persistence parameters when you instantiate the workflow runtime. The rough process looks like:
1. Create the workflow runtime (WorkflowRuntime)
2. Set up tracking for the runtime
3. Set up persistence for the runtime
4. Create an instance of the workflow in question and start execution
I wrote a simple to use host that demonstrates how you to enable tracking and persistence. Here it is:
static void Main(string[] args)
{
// You need to reference the foll
owing namespaces for this method
// using System.Workflow.Runtime;
// using System.Workflow.Runtime.Tracking;
// using System.Threading;
// — Configure this FIRST ————————
Type workflowType = typeof(WorkflowProject1.TestWF1);
bool enableTracking = true;
string sqlTrackingDbConnString = “Initial Catalog=Tracking;Data Source=localhost;Integrated Security=SSPI;”;
bool enablePersistence = true;
string sqlPersistenceDbConnString = “Initial Catalog=Persistence;Data Source=localhost;Integrated Security=SSPI;”;
// ————————————————
// Crank up a runtime
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
// Add Tracking abilities
if (enableTracking)
{
workflowRuntime.AddService(new SqlTrackingService(sqlTrackingDbConnString));
}
// Add Persistence abilities
if (enablePersistence)
{
workflowRuntime.AddService(new SqlWorkflowPersistenceService(sqlPersistenceDbConnString, true, new TimeSpan(0, 0, 30), new TimeSpan(0, 2, 0)));
}
// Some other magic
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); };
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
// Create an instance of the workflow and start it up
WorkflowInstance instance = workflowRuntime.CreateWorkflow(workflowType);
instance.Start();
// Clean up
waitHandle.WaitOne();
}
Take note that in my example, you need to specify a SQL database for tracking and one for persistence. The Windows Workflow SDK provides .sql scripts that will create the tables and stored procs. You just need to create a DB then run the two scripts.
For Tracking:
C:\WINDOWS\WinFX\v3.0\Windows Workflow Foundation\SQL\EN
Tracking_Schema.sql
Tracking_Logic.sql
For Persistence:
C:\WINDOWS\WinFX\v3.0\Windows Workflow Foundation\SQL\EN
SqlPersistenceService_Schema.sql
SqlPersistenceService_Logic.sql
More details on tracking can be found:
http://blogs.msdn.com/moustafa/archive/2006/03/15/552184.aspx
(there is an error with the “enable track” C# code… should be a space between the words data source)
http://windowssdk.msdn.microsoft.com/library/default.asp?url=/library/en-us/wf_samples/html/4f70c1c5-f82d-4d5f-8b7d-943b9f99f8e2.asp
(explains how the sample
works and what the UpdateV1DefaultTrackingProfile.sql file does)
More details on persistence can be found:
http://weblogs.asp.net/gsusx/archive/2005/10/05/426699.aspx
http:// 4:50 pm on November 8, 2007 Permalink |
Chewy:Great little piece of code – very helpful and almost exactly what I was looking for however I have a problem:Q: I’m running on an exchange server so my Inbox is not local. The code as written directs all mail to a specified folder under the primary inbox folder (in your code it was “_Reviewed”). How do I change the macro to move the message to an archive folder under my “Personal Folders” which are stored on my local drive?Set objFolder = objInbox.Folders(“_Reviewed”)Any insight (or better yet an example of code) would be much appreciated.Thanks.
http:// 6:50 pm on March 24, 2008 Permalink |
This is an AWESOME macro. One question though. I access Gmail via IMAP in Outlook 2007. Then I have loaded all of my other POP accounts into Gmail and set-up a label that labels each message when it comes in based on the account it comes in through. This effectively turns all of my POP e-mail accounts into IMAP accounts.This does two great things for me: allows me to “file” mail via Gmail’s web-based interface and not have to file it again when I get back to my computer (like I would have to do with most POP-based accounts with web access) and it allows me to “file” mail via Gmail’s mobile application on my Blackberry (unless you are using the Blackberry Enterprise Server for Outlook–which I am not–the current Blackberry mail system does not allow you to file mail from the device). So both of those save me a TON of time. I can be sitting in a cab and reading/filing messages and then get back to my desk and not have to deal with them a second time.So, here’s my question. This macro ROCKS, but is there a way to tell it to file the message into the “All Mail” folder in the “Gmail” PST rather than the “Archive” folder in the “Personal Folders” PST?If anyone can figure that out, you are awesome!
http:// 2:58 am on July 31, 2008 Permalink |
We’ve got about 1000 users that currently have their Auto Archive folder set to their profile location and we need to move it to a mapped drive on M:\ArchiveMail.pst. Is this possible through a Macro that could run at Outlook start up?Thanks,Bill
CAMURPHY 2:56 pm on October 2, 2008 Permalink |
RE: Moving to Personal Folders…Replacing:Set objFolder = objInbox.Folders(“_Reviewed”)withSet objFolder = objNS.Folders.Item(“Personal Folders”).Folders.Item(“Archive”).Folders.Item(“2008″)works for me. Assuming you wish to push the mail into “Personal Folders -> Archive -> 2008″HTH
CAMURPHY 2:56 pm on October 2, 2008 Permalink |
RE: Moving to Personal Folders…Replacing:Set objFolder = objInbox.Folders(“_Reviewed”)withSet objFolder = objNS.Folders.Item(“Personal Folders”).Folders.Item(“Archive”).Folders.Item(“2008″)works for me. Assuming you wish to push the mail into “Personal Folders -> Archive -> 2008″HTH
steve_B 5:44 pm on October 28, 2008 Permalink |
I am trying out this macro in office 2007 and have noticed that when I use my nifty buttons the time and date stamps of the messages are not preserved. Also, when opening the message it opens as a message that “has not yet been sent.” Is there a way to have the macro use Outlook’s built in “move to a folder” function or another way to preserve this information?
http:// 1:45 am on May 12, 2009 Permalink |
Hello, I am using your code it works fantastic. I have been trying to utilize it on a microsoft exchange mailbox that is NOT the default mailbox and I can not get it to work… I think the problem is with the following code: Set objNS = Application.GetNamespace(“MAPI”) Set objInbox = objNS.GetDefaultFolder (olFolderInbox)The name of the mailbox I need to move the message from is “Mailbox – Phoenix, CPC” (FYI: this is not the default mailbox) Set objFolder = objInbox.Folders(“_Inbox to be worked”)I can get the message to move from the above mailbox, but it will only move to the folder if it is a default mailbox folder such as:Mailbox – Caleb>_Inbox to be workedIt will not move to from the “Mailbox – Phoenix, CPC” inbox to the folder that is titled “_Inbox to be worked” within that mailboxI have been digging for weeks to get this done. ANY help would be extreemly welcome
http:// 6:21 pm on May 14, 2009 Permalink |
This is great, can you create a macro to move email to a folder when I close outlook?e.g. Move emails from helpdesk@me.com to a folder called !HelpDesk
http:// 12:57 am on August 27, 2009 Permalink |
If you want to move email to a nested folder, replace Set objFolder = objInbox.Folders(“_Reviewed”) with Set objFolder = objInbox.Folders.Item(“Level_1_Folder_Name”).Folders.Item(“Level_1_Folder_Name”).Folders.Item(“Level_1_Folder_Name”)
http:// 3:16 pm on September 17, 2009 Permalink |
how would you replace the below if you wanted to move the message into a Public Folder instead of a personal folder?Set objFolder = objNS.Folders.Item(“Personal Folders”).Folders.Item(“Archive”).Folders.Item(“2008″)
http:// 3:27 pm on September 17, 2009 Permalink |
Also curious, how would you move from one public folder to another public folder?Thanks guys!
http:// 8:23 pm on December 9, 2009 Permalink |
The macro works great but I have a problem. How do you move a Read and/or delivery receipt email. Those emails(reports)don’t move.
http:// 4:47 pm on February 2, 2010 Permalink |
Hii moved my mails to my desired folder but it also changes original date and time when i received the mail. how can i retain my original date and time of mail while moving all my mail to my other folder
Chewy Chong 10:35 pm on February 28, 2010 Permalink |
hey there! wow, i’m suprised people are still finding this post. i have been struggling with the huge piles of emails I get daily (hence my dab with coding) but recently found a free tool called “clearcontext”. it does all the email moving around that I need and maybe something you might find handy. give it a try and let me know what you think (no need to write any code).
http://www.clearcontext.com
Kassoe 12:22 pm on April 26, 2010 Permalink
Hmm, Clearcontext does not support IMAP folders
Chris 12:37 am on June 24, 2010 Permalink
Hi
I have two mailboxes for my work. Both these mailboxes we have five/six folders each. And I want the mails to move from one mailbox to another without me having to move the mails. All the folders in the mailboxes have exact same names AND I tried using the auto archive feature but it didnt work for all the mails. I want all the mails which is 1 day old to be automatically moved to another pst/folder. For eg : Today is 23rd June I want all the mails which are dated 22nd June to be moved to another folder
Any VBA code for this
Serge 11:34 am on June 4, 2010 Permalink |
Here is another good post showing how to sort messages with keyboard shortcuts in Outlook 2007 without touching Visual Basic: http://lifehacker.com/381966/tweak-microsoft-outlook-to-empty-your-inbox-faster
Sreehari 8:53 pm on July 20, 2010 Permalink |
hai
This code is working nicely. I have a problem that is I need to move a particular mail from inbox to my personal folder in particular drive. Could you please reply for this query
thomas 2:11 am on July 21, 2010 Permalink |
hey 4 years later this still helped me out. Just for those who are copy pasting this code, somehow some letters are copied italic that need to be not. So replace the italic ‘ in the comments and also inverted commas whith the correct ones. Otherwise the macro will not work.
thanks for this