Note: This blog post is written using the .NET framework 4.0 RC 1
Using Workflow Foundation 4 the NativeActivity is the powerhouse when it comes to building native activities. One of its many capabilities is around error handling. Every so often I run into one of these things where things don’t quite work the way I expect them to and this is one of these cases.
The basics of error handling when scheduling child activities.
Whenever a NativeActivity is executed it is passed an instance of the NativeActivityContext which it can use to schedule other activities using the ScheduleActivity() function. This ScheduleActivity() function has a few overloads, one of them using an FaultCallback. This FaultCallback is called when some kind of exception occurs while executing the child activity being scheduled. The fault handling function is called with a couple of parameters including a NativeActivityFaultContext and the exception that is unhandled. The NativeActivityFaultContext contains a HandleFault() function used to indicate that the fault was handled. Not quite as straightforward as a try/catch block but given the asynchronous nature of workflow that would not work.
So I expected the following activity to catch any exceptions and continue.
public sealed class MyActivity : NativeActivity
{
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(Body, FaultHandler);
}
private void FaultHandler(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
Console.WriteLine(propagatedException.Message);
faultContext.HandleFault();
}
}
Do not use, this code has a serious error!
Lets test this code by executing the following workflow:
private static Activity CreateWorkflow()
{
return new Sequence
{
Activities =
{
new WriteLine { Text = "Start outer sequence." },
new MyActivity
{
Body = new Sequence
{
Activities =
{
new WriteLine { Text = "Start inner sequence." },
new Throw { Exception = new InArgument<Exception>(ctx => new DivideByZeroException()) },
new WriteLine { Text = "End inner sequence." }
}
}
},
new WriteLine { Text = "End outer sequence." }
}
};
}
Given this workflow I would expect the following output:
However what really happens is something else as I receive the following output:
As we can see the second inner WriteLine still executes even though the exception is caught at a higher level!
This behavior reminds me of the infamous VB6 On Error Resume Next where an error would just be ignored and the next statement executed. Not really what I was expecting or want.
So the fix is easy. All that is needed is to explicitly cancel the child activity being executed using the CancelChild() function. Below the correct version of my NativeActivity.
public sealed class MyActivity : NativeActivity
{
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(Body, FaultHandler);
}
private void FaultHandler(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
Console.WriteLine(propagatedException.Message);
faultContext.HandleFault();
faultContext.CancelChild(propagatedFrom);
}
}
The correct fault handler
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
During last years CodeCamp in Rotterdam I recorded my presentation on doing iPhone development using jQTouch and ASP.NET MVC. After looking at several options I have posted the recording on Vimeo. You can view the Dutch language recording here.
If you are interested in doing iPhone development but don’t want to get started using Objective-C that jQTouch might just be what you need. Its a cool way to build HTML 5 and JavaScript application for the iPhone. And, thanks to HTML 5, it will even let you take the application and data offline if you want that. Best of all you can deploy them without going through the Apple AppStore if you prefer not to. And if you still want to go the AppStore route a product like PhoneGap will even let you do that.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
In this previous blog post I showed how to create an asynchronous activity using the NativeActivity and CreateBookmark to pause a workflow execution. Using that in a WorkflowApplication was easy but what about WorkflowInvoker or WorkflowServiceHost?
So what about using a WorkflowInvoker or a WorkflowServiceHost?
Neither the WorkflowInvoker not the WorkflowServiceHost contain a ResumeBookmark function so how do we resume a bookmark using either of those execution hosts? The trick is to use a IWorkflowInstanceExtension.
Using a IWorkflowInstanceExtension
Workflow extensions can be of any type you want, there is no base class or interface requirement. But that also means they are not aware of the workflow runtime environment and can’t do much more that respond to calls from a workflow. The way do be able to do a little more is by implementing the IWorkflowInstanceExtension interface. This interface has just two methods. One of those, the SetInstance, is passed a wrapper object around the running workflow allowing us do do some more work. The most important is that this also lets us resume bookmarks.
My workflow extension basically waits for the activity to call it and once done wait one second and resume the bookmark. A
class MyExtension : IWorkflowInstanceExtension
{
private WorkflowInstanceProxy _instance;
public IEnumerable<object> GetAdditionalExtensions()
{
return null;
}
public void SetInstance(WorkflowInstanceProxy instance)
{
_instance = instance;
}
public void WaitSome(Bookmark bookmark)
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.Sleep(1000);
var ias = _instance.BeginResumeBookmark(bookmark, 42, null, null);
var result = _instance.EndResumeBookmark(ias);
Console.WriteLine("BookmarkResumptionResult: '{0}'", result);
});
}
}
Note that the GetAdditionalExtensions() function just returns null as we are not adding extra extensions.
The new version of the activity
With the required extension done we still need to make sure it gets added to the workflow runtime of choice. The easiest option is to let the activity itself do so in the CacheMetadata() function by using the AddDefaultExtensionProvider() function. The new activity looks like this:
public class MyBookmarkedActivity : NativeActivity
{
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
metadata.AddDefaultExtensionProvider<MyExtension>(() => new MyExtension());
}
protected override bool CanInduceIdle
{
get { return true; }
}
protected override void Execute(NativeActivityContext context)
{
var bookmark = context.CreateBookmark("MyBookmark", BookmarkResumed);
var extension = context.GetExtension<MyExtension>();
extension.WaitSome(bookmark);
}
private void BookmarkResumed(NativeActivityContext context, Bookmark bookmark, object value)
{
Console.WriteLine("Bookmark resumed with '{0}'.", value);
}
}
Now this is all we need to run the activity as it will automatically add the required extension:
WorkflowInvoker.Invoke(new MyBookmarkedActivity());
or when using a WorkflowServiceHost
var wsh = new WorkflowServiceHost(new MyBookmarkedActivity());
wsh.AddDefaultEndpoints();
wsh.Open();
Console.WriteLine("Listening");
Console.ReadLine();
wsh.Close();
And just in case you where wondering, neither of these last two use any configuration file.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
Windows Workflow Foundation 4 introduces the concept of bookmarks to temporarily pause activities. A bookmark is basically a named pause point in an activity. The result is that the workflow runtime doesn’t consider an activity to be finished until all its bookmarks are either resumed or removed.
That last statement isn’t completely true though as it is only the case when the optional BookmarkOptions aren’t specified or specified as None. With BookmarkOptions.MultipleResume a bookmark can be resumed multiple times, de default is just once, so just resuming a bookmark isn’t enough it actually needs to be removed. The other option is BookmarkOptions.NonBlocking which means that the activity is finished even if the bookmark was never resumed. This last option is useful when you want to be able to receive messages while child activities are executing but you don’t need to receive the message per se. The BookmarkOptions enum is a flag so you can combine both NonBlocking and MultipleResume if you so desire.
One annoying thing with using bookmarks is that you need to use a NativeActivity and you have to override the CanInduceIdle property and return True as the default of False doesn’t permit bookmarks to be created, even when the NonBlocking option is used.
public class MyBookmarkedActivity : NativeActivity
{
protected override bool CanInduceIdle
{
get { return true; }
}
protected override void Execute(NativeActivityContext context)
{
var bookmark = context.CreateBookmark("MyBookmark", BookmarkResumed);
}
private void BookmarkResumed(NativeActivityContext context, Bookmark bookmark, object value)
{
Console.WriteLine("Bookmark resumed with '{0}'.", value);
}
}
Running the workflow and resuming a bookmark is easy when using a WorkflowApplication as seen below.
var wa = new WorkflowApplication(new MyBookmarkedActivity());
wa.Run();
var data = Console.ReadLine();
wa.ResumeBookmark("MyBookmark", data);
Console.ReadLine();
Nice and easy right?
Well yes except we also have WorkflowInvoker and WorkflowServiceHost to host our activity and neither contains a ResumeBookmark function. More about that later.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
When I create custom activity designers the icon that appears is usually one of the first things I want to change. Doing so in WF4 isn’t hard once you know where to look but if you don’t can be a bit of a challenge.
Suppose I have a simple write line activity like this:
[Designer(typeof(MyWriteLineDesigner))]
public sealed class MyWriteLine : CodeActivity
{
// Define an activity input argument of type string
public InArgument<string> Text { get; set; }
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override void Execute(CodeActivityContext context)
{
// Obtain the runtime value of the Text input argument
string text = context.GetValue(this.Text);
Console.WriteLine(text);
}
}
I have used the Designer attribute to attach my own designer to this activity.
The standard designer looks like this:
<sap:ActivityDesigner x:Class="WorkflowConsoleApplication3.MyWriteLineDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">
<Grid>
</Grid>
</sap:ActivityDesigner>
And dropping that on a workflow designer surface results in the following:
So far so good except now I want to change the icon that appears at the top left of the designer.
The designer has an Icon property. Unfortunately the property sheet doesn’t do us a lot of good here.
In order to change the icon we need to add some XAML to the designer telling it what to draw. The new designer looks like this
<sap:ActivityDesigner x:Class="WorkflowConsoleApplication3.MyWriteLineDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">
<sap:ActivityDesigner.Icon>
<DrawingBrush>
<DrawingBrush.Drawing>
<ImageDrawing>
<ImageDrawing.Rect>
<Rect Location="0,0" Size="16,16" ></Rect>
</ImageDrawing.Rect>
<ImageDrawing.ImageSource>
<BitmapImage UriSource="Clipboard_edit.png" ></BitmapImage>
</ImageDrawing.ImageSource>
</ImageDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</sap:ActivityDesigner.Icon>
<Grid>
</Grid>
</sap:ActivityDesigner>
Inside of the sap:ActivityDesigner.Icon element we need to add a DrawingBrush using an BitmapImage pointing to a file. The file, Clipboard_edit.png in this case, has been added to the project and its Build Action has been changed to “Resource”.
Once this has been done and the project rebuild the new icon will show up on the design surface.
Sweet 
The topic of Visual Basic expression in Windows Workflow Foundation 4 seems to be a bit of an item for some people as you can see in the comments to my blog posts about it here. Now personally I don’t think it is such a big deal as it only concerns the expressions entered in the workflow, the main project can still be C# if you so desire.
Anyway the team responsible at Microsoft have created a survey asking for feedback on the subject. So if you have an opinion, and many seem to, please take 5 minutes go here and complete survey.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
With Windows Workflow Foundation 3 it was possible to rehost the workflow designer in your own application. But possible is about all there was to say about it as it was pretty hard to do anything beyond the basics.
With Windows Workflow Foundation 4 live has become much better on the rehosting front
In fact it is possible to create the fully functional and useful workflow editor below in about 200 lines of code. Now that is more like it!
The WorkflowDesigner
The WorkflowDesigner is the main class to work with. This exposes the actual design surface through the View property and the linked property sheet through the PropertyInspectorView property. Both these properties point to ready to use WPF UIElement’s so, as long as the host used WPF, adding them to a form is easy. And loading or saving a workflow is easy to, all it takes is a Load() and Save() function pointing to a XAML file. The code that does this part is below:
_workflowDesigner = new WorkflowDesigner();
_workflowDesigner.Load(_fileName);
var view = _workflowDesigner.View;
Grid.SetColumn(view, 1);
Grid.SetRow(view, 1);
LayoutGrid.Children.Add(view);
var propInspector = _workflowDesigner.PropertyInspectorView;
Grid.SetColumn(propInspector, 2);
Grid.SetRow(propInspector, 1);
LayoutGrid.Children.Add(propInspector);
DesignerMetadata
One thing that is needed is to register the workflow activity designer metadata. It is just a single call but leaving it out means all activities are just a small collapsed shape and won’t expand.
new DesignerMetadata().Register();
Displaying the toolbox with activities
The toolbox on the left if another standard WPF control called the ToolboxControl. Again easy to add to any WPF form. Add to it ToolboxItemWrapper with the activity type to add and you are good to go. Dragging controls onto the design surface just works, no extra work required. In the code below I just scan through all types in a few assemblies and if they are valid activities I add them to the toolbox. Again nice and easy.
var toolbox = new ToolboxControl();
var cat = new ToolboxCategory("Standard Activities");
var assemblies = new List<Assembly>();
assemblies.Add(typeof(Send).Assembly);
assemblies.Add(typeof(Delay).Assembly);
assemblies.Add(typeof(ReceiveAndSendReplyFactory).Assembly);
var query = from asm in assemblies
from type in asm.GetTypes()
where type.IsPublic &&
!type.IsNested &&
!type.IsAbstract &&
!type.ContainsGenericParameters &&
(typeof(Activity).IsAssignableFrom(type) ||
typeof(IActivityTemplateFactory).IsAssignableFrom(type))
orderby type.Name
select new ToolboxItemWrapper(type);
query.ToList().ForEach(ti => cat.Add(ti));
toolbox.Categories.Add(cat);
Grid.SetColumn(toolbox, 0);
Grid.SetRow(toolbox, 1);
LayoutGrid.Children.Add(toolbox);
The current selection
At the top of the form I display the currently selected activity and its parents. The WorkflowDesigner has an Items collection with a bunch of useful objects in there. One of these is a Selection object. We could periodically check this Selection but its even easier to subscribe to chances using the Subscribe() function and passing in a handler that is called whenever the selection changes. Setting up the subscription is another one-liner.
_workflowDesigner.Context.Items.Subscribe<Selection>(SelectionChanged);
The handler itself isn’t very complex either.
private void SelectionChanged(Selection selection)
{
var modelItem = selection.PrimarySelection;
var sb = new StringBuilder();
while (modelItem != null)
{
var displayName = modelItem.Properties["DisplayName"];
if (displayName != null)
{
if (sb.Length > 0)
sb.Insert(0, " - ");
sb.Insert(0, displayName.ComputedValue);
}
modelItem = modelItem.Parent;
}
CurrentActivityName.Text = sb.ToString();
}
Validating the workflow
It would be nice to let the user know if the workflow is valid. Again quite easy to do by adding a IValidationErrorService to the WorkflowDesigner services collection. In this case I added a listbox to the form and let the IValidationErrorService add each error to the ListBox items. No need to call anything, the IValidationErrorService is automatically called as soon as anything in the workflow changes.
var validationErrorService = new ValidationErrorService(WorkflowErrors.Items);
_workflowDesigner.Context.Services.Publish<IValidationErrorService>(validationErrorService);
The IValidationErrorService consists of a single function that gets the list of errors as a parameter.
public class ValidationErrorService : IValidationErrorService
{
private IList _errorList;
public ValidationErrorService(IList errorList)
{
_errorList = errorList;
}
public void ShowValidationErrors(IList<ValidationErrorInfo> errors)
{
_errorList.Clear();
foreach (var error in errors)
{
_errorList.Add(error.Message);
}
}
}
Running the workflow
Just to be able to run the workflow I added a bit of code that uses a WorkflowApplication to run the workflow. Loading it is also easy, just call the ActivityXamlServices.Load() passing in the file and it will return a DynamicActivity ready to run.
var writer = new StringWriter();
var workflow = ActivityXamlServices.Load(_fileName);
var wa = new WorkflowApplication(workflow);
wa.Extensions.Add(writer);
wa.Completed = WorkflowCompleted;
wa.OnUnhandledException = WorkflowUnhandledException;
wa.Run();
So all together I have a working application that I can use to edit and run workflows. So who still needs Visual Studio 2010?
Sweet 
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
One of the things that wasn’t possible in Windows Workflow Foundation 3 was flowing transaction over a WCF service request into a workflow. We could have transactions on the client, we could have transactions on the server but they would not be able to cooperate.
Fortunately that is one the problems that Windows Workflow Foundation 4 solves for us. 
In WF4 we can use the ReceiveAndSendreply template to configure a workflow as a service and accept WCF calls. That works just fine but doesn’t allow for transactions. If we want to use transactions we need to add the TransactedReceiveScope to the workflow. Move the ReceiveRequest activity into the Request part and the SendResponse activity into the Body part. Don’t forget the last part because leaving the SendResponse below the TransactedReceiveScope means things will not work and the error message will be less that helpful 
This is enough to make all work done during the message receive part of a transaction. To show what is happening with transactions I am using the following code to record and return the transactional status:
using System.Text;
using System.Transactions;
public class TransactionReport
{
public static string GetReport()
{
var sb = new StringBuilder();
if (Transaction.Current == null)
{
sb.Append("No transaction");
}
else
{
sb.AppendFormat("TransactionInformation\n");
sb.AppendFormat("\tLocalIdentifier {0}\n", Transaction.Current.TransactionInformation.LocalIdentifier);
sb.AppendFormat("\tDistributedIdentifier {0}\n", Transaction.Current.TransactionInformation.DistributedIdentifier);
sb.AppendFormat("\tStatus {0}\n", Transaction.Current.TransactionInformation.Status);
sb.AppendFormat("\tIsolationLevel {0}\n", Transaction.Current.IsolationLevel);
}
return sb.ToString();
}
}
Adding a console application with a service reference with the following code:
using System;
using Client.ServiceReference1;
namespace Client
{
class Program
{
static void Main(string[] args)
{
var proxy = new ServiceClient();
var result = proxy.PostData();
Console.WriteLine(result);
Console.ReadLine();
}
}
}
Produces the following output:
No big surprises there. The only thing I am missing is the ability to control the IsolationLevel which seems to be fixed at Serializable.
Flowing transactions from the client
The first step we need to take for client transactions to flow to the service is do the service call inside of a transaction using this client code:
using System;
using System.Transactions;
using Client.ServiceReference1;
namespace Client
{
class Program
{
static void Main(string[] args)
{
using (var tx = new TransactionScope())
{
Console.WriteLine(TransactionReport.GetReport());
var proxy = new ServiceClient();
var result = proxy.PostData();
Console.WriteLine(result);
Console.WriteLine(TransactionReport.GetReport());
}
Console.ReadLine();
}
}
}
If we run the code now we get the following output:
The transaction is there on the client but DistributedIdentifier is still empty so the transaction doesn’t flow to the service yet.
Before transactions will flow we need to do two things. First of all we need a WCF binding that can flow transactions. So far we have been using the BasicHttpBinding, the default for an HTTP endpoint in the .NET 4 default configuration, which doesn’t support transactions. So we need to switch to something like WSHttpBinding that does. Next we need to enable transaction flow because it is disabled by default. All of this can be done by adding a little extra configuration to the web.config file.
<bindings>
<wsHttpBinding>
<binding transactionFlow="true"/>
</wsHttpBinding>
</bindings>
<services>
<service name="Service1">
<endpoint address=""
binding="wsHttpBinding"
contract="IService" />
</service>
</services>
With this in place all we need to do is update the client service reference and transactions will flow from the client to the service.
Keep in mind that flowing transactions across a network boundary is a very powerful but also a very dangerous concept. You might be letting someone else, from a different organization, place locks on your database. So make sure you understand the implications of flowing transactions before you open up a whole can of worms!
Nice 
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
In my previous post about Windows Workflow Foundation 4 I used the CorrelationScope activity to arrange for the activity correlation between a Send and the related ReceiveReply activities. That is quite easy to do and personally I find things nice and easy to arrange with both messaging activities nested in the CorrelationScope activity . The default templates use a slightly different approach though and use a RequestReplyCorrelationInitializer. The end result is the same though so just use what you think best.
Just for comparison below is the code to create the same workflow with a RequestReplyCorrelationInitializer.
static Activity CreateWorkflow()
{
var getDataResult = new Variable<string>();
var handel = new Variable<CorrelationHandle>();
var send = new Send()
{
CorrelationInitializers =
{
new RequestReplyCorrelationInitializer()
{
CorrelationHandle = handel
}
},
OperationName = "GetData",
ServiceContractName = "IService1",
Endpoint = new Endpoint()
{
Binding = new BasicHttpBinding(),
AddressUri = new Uri("http://localhost:8080/GetDataService/")
},
Content = new SendParametersContent()
{
Parameters =
{
{"value", new InArgument<int>(42)}
}
}
};
var receive = new ReceiveReply()
{
Request = send,
Content = new ReceiveParametersContent
{
Parameters =
{
{"GetDataResult", new OutArgument<string>(getDataResult)}
}
}
};
var workflow = new Sequence()
{
Variables = { getDataResult, handel },
Activities =
{
send,
receive,
new WriteLine() { Text = getDataResult }
}
};
return workflow;
}
The workflow is even a little simpler because there are fewer activities involved. And this is effectively the same as the SendAndReceiveReply and ReceiveAndSendReply templates generate in WF4.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
There are two types of correlation to think about in Windows Workflow Foundation:
- Message correlation
Basically sending multiple requests to the same workflow. - Activity correlation
Making sure two activities work together.
In this post I am going to show activity correlation
Activity correlation is used when multiple activities form a single logical action. Think about the Send and ReceiveReply activities. Two distinct activities but they work together because the first, the Send activity, send a WCF request somewhere and the second, the ReceiveReply activity, receives the response. The same goes when receiving messages.
The good thing is that when we use the ReceiveAndSendReply or SendAndReceiveReply templates everything will be done for us and the required activity correlation will be configured automatically. However sometimes we might need to do so ourselves because we create a workflow in a different way, like using regular code.
So when we start using the Send and ReceiveReply or the Receive and SendReply activities from code we need to do a bit more work. How much varies and depends on both the workflow and the hosting environment we use. The big exception to the rule is when we use the WorkflowServiceHost and no parallel or overlapping messaging activities. In that case life is simple and the WorkflowServiceHost takes care of all required correlation for us. Nice 
That does leave for quite a few scenarios where we do need to add activity correlation though. The obvious one is using the WorkflowApplication or WorkflowInvoker to run our workflows. Fortunately this produces an System.InvalidOperationException with a message like:
The Send activity is configured with a request/reply Operation 'GetData', however, there is no ReceiveReply activity paired with it. Please pair Send with ReceiveReply and correlate them using a CorrelationHandle.
There are different ways to configure activity correlation but the easiest way is to wrap the activity pair in a CorrelationScope activity. The CorrelationScope will automatically create the required correlation handle and the messaging activities will use this handle.
Show me the code
The code below calls a very standard and basic WCF service passing in the value if 42 and prints the result. The important part is that the send are receive actions are done inside of a CorrelationScope activity so this workflow can run in any host.
static Activity CreateWorkflow()
{
var getDataResult = new Variable<string>();
var send = new Send()
{
OperationName = "GetData",
ServiceContractName = "IService1",
Endpoint = new Endpoint()
{
Binding = new BasicHttpBinding(),
AddressUri = new Uri("http://localhost:8080/GetDataService/")
},
Content = new SendParametersContent()
{
Parameters =
{
{"value", new InArgument<int>(42)}
}
}
};
var receive = new ReceiveReply()
{
Request = send,
Content = new ReceiveParametersContent
{
Parameters =
{
{"GetDataResult", new OutArgument<string>(getDataResult)}
}
}
};
var workflow = new Sequence()
{
Variables = { getDataResult },
Activities =
{
new CorrelationScope()
{
Body = new Sequence()
{
Activities = { send, receive }
}
},
new WriteLine() { Text = getDataResult } }
};
return workflow;
}
Update: See here for the code when using a RequestReplyCorrelationInitializer.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Attached are the PowerPoint sheets and samples from my online Window Workflow Foundation 4 presentation today.
Let me know if you have any questions.
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
In Windows Workflow Foundation 4 there are a number of “activities” in the designer that aren’t really activities but activity templates. The most obvious of there are the ReceiveAndSendReply and the SendAndReceiveReply in the Messaging section of the toolbox.
If you search for either of these activities you are not going to find them. Their real name is ReceiveAndSendReplyFactory and SendAndReceiveReplyFactory respectively and they aren’t activities but activity templates.
So how to create an activity template?
Quite simply create a class and implement the IActivityTemplateFactory interface. This interface is simple and consists of a single Create function that returns the activity to be added to the workflow. Need to create multiple activities like the messaging activities do? Just wrap them in a Sequence activity and return that.
So what does that look like? Well in the case of the ReceiveAndSendReplyFactory the Create() looks like this according to Reflector:
public Activity Create(DependencyObject target)
{
string str = ActivityDesignerHelper.GenerateUniqueVariableNameForContext(target, "__handle");
Variable<CorrelationHandle> variable = new Variable<CorrelationHandle>
{
Name = str
};
VisualBasicSettings settings = new VisualBasicSettings
{
ImportReferences =
{
new VisualBasicImportReference
{
Assembly = requiredAssemblyName,
Import = requiredNamespace
}
}
};
Receive receive = new Receive
{
OperationName = "Operation1",
ServiceContractName = XName.Get("IService", "http://tempuri.org/"),
CorrelationInitializers =
{
new RequestReplyCorrelationInitializer
{
CorrelationHandle = new VisualBasicValue<CorrelationHandle>
{
ExpressionText = str,
Settings = settings
}
}
}
};
return new Sequence
{
Variables = { variable },
Activities =
{
receive,
new SendReply
{
DisplayName = "SendReplyToReceive",
Request = receive
}
}
};
}
Nice to know what is happening behind the scenes and IActivityTemplateFactory is a nice interface to have when you start creating your own complex activities.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Tomorrow I will be doing an online presentation about Windows Workflow Foundation 4. The meeting lasts 1 hour and starts at 4PM European time, 3PM UTC or 7AM PST.
The goal is to provide an overview of WF4 and how to get started with it in Visual Studio 2010.
I will be doing the meeting using LiveMeeting and you can register here.
During the meeting I will also be tracking the Twitter hash tag #dmwf4 for additional questions and feedback.
“See” you there tomorrow 
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
I can’t say I am a fan of the way the TryCatch activity is implemented in Windows Workflow Foundation 4.
For starters there is a Finally block where you can add some activities you want to execute. Sounds nice and very much like the try/catch/finally code construct we have in C# or Visual Basic. Except that it behaves in a subtlety different way. With the C# try/catch/finally the finally code will always run, whether you catch the exception or not. In fact you can just use a try/finally and it will work just fine.
With WF4 this is not the case though 
The finally activity will only execute if the try block or one of the catch blocks completes. This means that an exception that is unhandled which bubbles terminating the workflow up will not cause the finally block to execute unless the host application forces it to do so by returning UnhandledExceptionAction.Cancel from the OnUnhandledException instead of UnhandledExceptionAction.Terminate (the default). A subtle difference and one that is likely to bite people because the normal code path is usually to have the try activity to complete normally.
Another issue I have is with the catch blocks and the cause of the exception.
As with a code catch block you get a reference to the exception. However where you normally would use the stack trace to see where the error occurred this is useless in Windows Workflow Foundation. After all that is only going to show you a few methods in the ActivityExecutor and the activity that was executed, not which instance and where in the activity tree. And by default there is no way to get to the offending activity 
Turns out that Darren Headrick created a rather nice way to get to the offending activity through workflow tracking. Quite a nice solution but not entirely obvious and I am sad that a solution like this is needed. Still nice work from Darren though 
public class WhosFaultWasThat : TrackingParticipant
{
public string Name { get; set; }
protected override void Track(TrackingRecord trackingRecord, TimeSpan timeout)
{
if (trackingRecord is FaultPropagationRecord)
{
Name = ((FaultPropagationRecord)trackingRecord).FaultSource.Name;
}
}
}
Besides the FaultSource you also get the Fault and a FaultHandler property which will tell you if there is a TryCatch activity that might handle it. I say might because while you can see that there is a TryCatch you can’t quite see its catch blocks so you don’t know if it will be caught or not.
This neat trick does show one important thing though.
If you want to know what is going on with your workflow and activities you need to use a TrackingParticipant and add it to the Extensions collections. No matter which execution module you choose, WorkflowInvoker, WorkflowApplication or WorkflowServiceHost, they all support this mechanism.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
If you are looking for the demo files from my CodeCamp presentation in the Netherlands you can download the notes here and the complete sample code here. No PowerPoint, after all this was a CodeCamp 
And when my ISP is fully operational again
the demo can be viewed online here.
Enjoy, I enjoyed organizing the CodeCamp and doing this presentation.
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Note: This blog post is written using the .NET framework 4.0 Beta 2
The whole persistence model has changed quite a but for WF4.
The persistence class out of the box is called SqlWorkflowInstanceStore and as the name suggests it saves workflow data in either SQL Server 2005 or 2008. It is based on the InstanceStore class to if you prefer some other store all you need to do is subclass the InstanceStore and create your own.
So what can we do with the SqlWorkflowInstanceStore?
We can attach it to either a WorkflowApplication or a WorkflowServiceHost and persist workflows when we want. Notice I left out the WorkflowInvoker. This can be used to run only short lived workflows and doesn’t support persistence.
The case of the WorkflowApplication is quite simple.
var instanceStore = new SqlWorkflowInstanceStore(connStr);
WorkflowApplication app = new WorkflowApplication(workflow);
app.InstanceStore = instanceStore;
app.Run();
Okay its a little more involved then that.
First of all you need to create a database to store the workflow state in. There are a couple of SQL files in the “C:\Windows\Microsoft.NET\Framework\v4.0.21006\SQL\en” folder. The two you need are SqlWorkflowInstanceStoreSchema.sql and SqlWorkflowInstanceStoreLogic.sql. I created a batch file to quickly recreate my persistence database like this:
osql -E -S .\sqlexpress -Q "Drop Database WorkflowInstanceStore"
osql -E -S .\sqlexpress -Q "Create Database WorkflowInstanceStore"
osql -E -S .\sqlexpress -d WorkflowInstanceStore -i SqlWorkflowInstanceStoreSchema.sql
osql -E -S .\sqlexpress -d WorkflowInstanceStore -i SqlWorkflowInstanceStoreLogic.sql
So with all this in place we still need to tell the WorkflowApplication when to persist the workflow. There are several ways to to this but one is to use the PersistableIdle callback. This will only fire when an InstanceStore has been provided. Options are to persist and unload the workflow, just unload the workflow or do nothing at all. The callback is just another function so you can make whatever decisions you like.
app.PersistableIdle = e => PersistableIdleAction.Persist;
Another option is to use the Persist activity. This will allow the workflow to decide on extra persistence points regardless of the workflow being idle.
How about the WorkflowServiceHost?
With the WorkflowServiceHost we get a couple of different choices. First of all we can just create a SqlWorkflowInstanceStore and set it like this:
var workflow = new Workflow1();
var baseAddress = new Uri("http://localhost:8080/MyWorkflow");
var host = new WorkflowServiceHost(workflow, baseAddress);
var connStr = @"Data Source=.\sqlexpress;Initial Catalog=WorkflowInstanceStore;Integrated Security=True;Pooling=False";
var instanceStore = new SqlWorkflowInstanceStore(connStr);
host.DurableInstancingOptions.InstanceStore = instanceStore;
host.Open();
Console.WriteLine("Listening...");
Console.ReadLine();
host.Close();
Simple but it doesn’t give us any control over when workflows are persisted. We don’t get quite the same control as with a WorkflowApplication in this case, all we can do is set a few timeout values using the WorkflowIdleBehavior like this:
var workflowIdleBehavior = new WorkflowIdleBehavior();
workflowIdleBehavior.TimeToPersist = TimeSpan.FromSeconds(10);
workflowIdleBehavior.TimeToUnload = TimeSpan.FromMinutes(1);
host.Description.Behaviors.Add(workflowIdleBehavior);
We can’t make any decisions based, just set time the workflow is idle before it is persisted and the same before it is unloaded.
Suppose we want some more control over the way the SqlWorkflowInstanceStore behaves. We can using the SqlWorkflowInstanceStoreBehavior. This is actually the same class as is used through the config file.
var connStr = @"Data Source=.\sqlexpress;Initial Catalog=WorkflowInstanceStore;Integrated Security=True;Pooling=False";
var behavior = new SqlWorkflowInstanceStoreBehavior(connStr);
behavior.InstanceCompletionAction = InstanceCompletionAction.DeleteNothing;
behavior.InstanceLockedExceptionAction = InstanceLockedExceptionAction.AggressiveRetry;
behavior.InstanceEncodingOption = InstanceEncodingOption.None;
host.Description.Behaviors.Add(behavior);
So that is all there is to it?
Not quite there is a little complexity when it comes to using the same SqlWorkflowInstanceStore with multiple WorkflowApplication instances. Note that the WorkflowServiceHost automatically takes care of this so no need to worry about that.
By default a SqlWorkflowInstanceStore will only work with a single WorkflowApplication. If you try to use it with mutiple workflow you can get a InstancePersistenceCommandException with the following message:
SqlWorkflowInstanceStore does not support creating more than one lock owner concurrently. Consider setting InstanceStore.DefaultInstanceOwner to share the store among many applications.
The trick is to set the DefaultInstanceOwner of the SqlWorkflowInstanceStore. The code isn’t hard but not exactly obvious either.
var instanceStore = new SqlWorkflowInstanceStore(connStr);
var instanceHandle = instanceStore.CreateInstanceHandle();
var createOwnerCmd = new CreateWorkflowOwnerCommand();
var view = instanceStore.Execute(instanceHandle, createOwnerCmd, TimeSpan.FromSeconds(30));
instanceStore.DefaultInstanceOwner = view.InstanceOwner;
// Do whatever needs to be dome with multiple WorkflowApplications
var deleteOwnerCmd = new DeleteWorkflowOwnerCommand();
instanceStore.Execute(instanceHandle, deleteOwnerCmd, TimeSpan.FromSeconds(30));
The key is the CreateWorkflowOwnerCommand that needs to be executed at the start. And when you use the CreateWorkflowOwnerCommand just make sure not to forget the DeleteWorkflowOwnerCommand otherwise all workflow will remain locked by the owner and can’t be reloaded by another SqlWorkflowInstanceStore
Quite a but more flexible than we had before but, specially with the WorkflowApplication, also quite a bit more work and not always as obvious as I would like it.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
This one bit me today a bit unexpectedly.
I was comparing two Uri’s and was getting unexpected matches between two Uri’s that where quite clearly not the same. Turns out the when comparing Uri’s the Fragment, or anchor or part after the #, is not part of the comparison.
So the following unit test passes even though I would have expected it to fail!
[TestMethod]
public void TestTwoEqualUrisWithDifferentAnchorShouldNotBeEqual()
{
var baseUri = new Uri("http://www.test.com");
var uri1 = new Uri(baseUri, "#anchor1");
var uri2 = new Uri(baseUri, "#anchor2");
Assert.AreEqual(uri1, uri2);
Assert.AreNotEqual(uri1.ToString(), uri2.ToString());
}
Note that when comparing uri1 and uri2 they are equal even though they use two different anchor tags. Comparing the ToString() results does show the difference though. Wasted another bit of time on this piece of trivia 
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
recently I had to send a bunch of identical email messages for the CodeCamp we are organizing. Now there are plenty of ways to do this but I decided to write a little program using C# to send them. And just to make sure I can find the code next year 
var from = new MailAddress("<<your email>>", "<<your name??");
var to = new MailAddress("<<destination address>>", "<<their name>>");
var message = new MailMessage(from, to);
message.Subject = "The subject";
message.Body = "The message body";
message.IsBodyHtml = true;
var host = "smtp.gmail.com";
var client = new SmtpClient(host, 587);
client.EnableSsl = true;
client.Credentials = new NetworkCredential("<<your username>>", "<<your password>>");
client.Send(message);
Easy as that.
Few things to note. I used a different sender address as we wanted all replies to end up in a shared mailbox instead of mine. Worked just fine even though I used my own account details to send.
There is a check on the number of messages send in a short time span. Not sure what the limit is, it seemed something like 100 per minute, but I had to add some sleep time between messages in order to send them all. No big deal but something to keep in mind.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Als eerste: de sessies voor de CodeCamp 2009 zijn bekend en staan online op http://www.codecamp.nl We denken dat het een erg interessante mix van sessies is, met genoeg sessies voor iedereen om een aantal interessante onderwerpen voor iedereen. De agenda ziet er nu als volgt uit:
09:30 - 10:45
Around .net framework 4.0 in an hour (Ronald Guijt)
ASP.Net - MVC 2.0 (Sander Gerz)
Windows Mobile en het werken met data (Arjan van Huizen)
11:00 - 12:15
ADO.NET EF 4.0 (Kurt Claeys)
SharePoint Nightmares (Marianne van Wanrooij)
iPhone development met jQTouch (Maurice de Beijer)
13:15 - 14.30
VSTO 2010 met Office 2010 (Hassan Fadili)
Modulaire Silverlight apps met Prism (Timmy Kokke)
Microsoft Surface Development (Freena Eijffinger & Dennis Vroegop)
14:45 - 16:00
VSTS 2010 (Pieter de Bruijn)
Windows Identity Foundation (Michiel van Otegem)
SQL Azure (Marcel Meijer)
Naast deze sessies hebben we ook nog de OpenSpace sessies. Daar hebben we geen agenda voor maar dat ligt nu eenmaal in de aard van een OpenSpace gebeuren. In het kort komt het neer op het volgende: als je iets hebt waar je graag met een aantal mensen over wilt discussieren, schrijf je dat 's ochtends op een flip-over. Mochten mensen dat interessant vinden, dan kunnen ze een stem uitbrengen op dat onderwerp. In de lunchtijd (van 12:15 - 13:15) is dan de keuze aan de mensen waar ze heen gaan en aan welke discussie ze mee willen gaan doen. Heeft jouw sessie genoeg stemmen dan komen de mensen vanzelf wel naar je toe, zo niet: dan is je sessie blijkbaar niet interessant voor een grote groep. Het idee is dat we een aantal van deze sessies tegelijkertijd hebben zodat mensen kunnen kiezen wat ze doen. De inhoud van de lunch sessies laten we dus volledig aan de bezoekers over!
Denk eens na over sessies of onderwerpen en discussieer mee met je mede-ontwikkelaars over jouw favoriete onderwerp!
Ik kan haast niet wachten tot het 21 november is..
More Posts
Next page »