Building a declarative WCF service using Workflow Foundation 4 and Content Based Correlation

This blog post accompanies my session on Workflow Foundation 4 programming during the Belgian Tech Days (actually developers and IT-pro days :)). During this session I built a WCF service using Workflow Foundation 4, and I want to show you how to do this on your own… In the first part you’ll learn how to create a simple FlowChart workflow and test it, and then in the second part you’ll learn how to setup correlation so multiple players can play the game… Preparing the lab This lab starts with a new project, so start Visual Studio 2010 and create a new workflow service project (call it NumberGuessingGame): This creates a new solution with a workflow project. Remove Service1.xamlx, we’re going to add a new service with a better name. Right-click the project and add a new item. Select the WCF Workflow Service template and name it GuessIt.xamlx. Creating the initial FlowChart This adds a workflow service with a sequential activity containing a Receive and Send activity. Delete the sequential activity leaving the workflow empty. Open the toolbox and drag a FlowChart activity onto the workflow designer. This should look like this now: Next drag a Receive activity onto the designer, below Start. Name it Start A New Game. Select the receive activity and enter following the OperationName, ServiceContractName and CanCreateInstance properties in the properties window: Next right-click on the receive activity and select the Create SendReply option from the drop-down menu. This add a Send activity to the workflow. The Send is coupled to the receive activity through its Request property: Now connect the activities: Adding variables Now, in the workflow designer open the variables window and add a new variable called player of type String. This will hold the player name received through the “Start A New Game” Receive activity. You will also see a variable of type CorrelationHandle. This is used to connect several receive and send activities through correlation. Rename this to gameHandle.We’ll use this handle later to setup content-based correlation. Now add two new variables theNumber and guess, both of type Int32. The first is the number the user needs to guess, to you need to initialize it to a random number between 0 and 100. Use the Random type to do this: Go back to the first receive activity. Click on the content property. This opens the Content Definition window. Select the player as the message data (and set the Message type to String): Do the same for the send activity, but now use following expression (of type String): 1: player + " guess the number between 0 and 100" You might also get validation errors because you renamed the correlation handle to gameHandle. Change the CorrelationInitilizers property to use gameHandle (click on the … button). Testing the service Press F5 in Visual Studio. The WCF Test Client will start and automatically fetch meta-data from the service. Double click the Begin method. This opens a new tab allowing you to invoke the Begin operation on the service. Enter your name and click Invoke. In the bottom area you should see the result of invoking the begin method. This concludes the first step. Adding the data contracts Let’s add a couple of data contracts to the project, one for a game and another for a guess. Note that both contain the player name, this way our service will be able to distinguish between multiple games, as long as each player uses a unique player name: 1: [DataContract] 2:  3: public class Game 4:  5: { 6:  7: [DataMember] 8:  9: public string PlayerName { get; set; } 10:  11: [DataMember] 12:  13: public string Message { get; set; } 14:  15: } 16:  17: [DataContract] 18:  19: public class Guess 20:  21: { 22:  23: [DataMember(IsRequired = true)] 24:  25: public string PlayerName { get; set; } 26:  27: [DataMember(IsRequired = true)] 28:  29: public int Try { get; set; } 30:  31: } Make the “Send Game Started” send activity use a Game instance as the result. To do this you will need to add another variable of type Game, and initialize it to a new instance: Now add to assign activities after the Begin receive activity, and assign appropriate values to the game: Adding the guessing logic Add another variable, calling it guess of type Guess. Then add another receive activity after the send activity, but now with an operation name called Guess, taking guess variable as its content. Check if the guess was right using a decision shape. If so, congratulate the user. If not, decide whether the guess was too small or large. Confirm this back to the user using three SendReply activities (create each one by right-clicking the Guess receive activity and select Create SendReply). Here is an example of the result: Adding Content-based Correlation Of course we want to make a single player play the same game, but what if multiple players are playing on the same server? We need correlation. In this part we’re going to correlate the guess activity to the Begin activity using the player’s name. That is why our data contract both contain the player’s name (by coincidence the properties have the same name, but this is not required). To do correlation we need a correlation handle. This handle will act like a key to a workflow. If a request comes in, we’re going to find this key through part of the message, in our case the player’s name. So, if you haven’t done so, add a new variable to the workflow called gameHandle of type CorrelationHandle. The make sure that all the first sendReply activity is set to initialize this handle by ensuring the CorrelationInitializer is set like this: When the workflow sends this message, we’re saying that the key of the gameHandle is the player’s name. So when another message arrives, the workflow runtime can then see is the message contains a valid key (again the player’s name), use this key to find the right workflow instance, and then send the message to it. So next step is to set the Guess receive activity’s Correlates On like this: Now you should be able to play a game, making sure that the first and following messages all have the same player name. You can also start two or more games, each with their own player name!

Configuring your WFC and WF4 services using AppFabric

Configuring your services Normally I configure my services using Visual Studio (and type-ing in the configuration as Xml) or using the WCF Service Configuration tool. AppFabric also allows you to configure your services, directly from IIS (making it a nice integrated experience!). The difference is in that AppFabric exposes the stuff an it-pro needs to look at the health of an application more… Developers are more interested in making it work, productions is more interested in keeping it working… <grin> You can setup a persistance and tracking store (actually databases) to make your services trackable and durable. This will also make it easier (or less hard) to see why your service is no longer functioning the way it should. Of course you can still setup the System.Diagnostics tracing, but this again is more for developers. Some preparations are needed AppFabric uses the net.pipe protocol to manage your services (through standard endpoints), so you might need to enable this on IIS. Select your site, then select Edit Bindings… The following window should open:   If net.pipe is not listed, hit the Add… button and select net.pipe. Use * for Binding information. Then go to your service and select Advanced Settings… The dialog should open: Add net.pipe to the list of Enabled Protocols. You might also need to run the AppFabric system-level configuration. To do this, go to Start->All Programs->Windows Server AppFabric->Configure AppFabric. The configuration utility should launch: Hit Next: Here you can configure the monitoring and persistance databases. Check the Set Monitoring configuration check-box, select the account you want to use and the provider (there is one default, which will store everything in a SQL server database: Hit the Configure… button. Configure as follows (replacing Peter-PC with your domain/machine name): Hit Ok. Check the results. You might get an ‘the database already exists’ kind of warning. Simply continue… Continue through the wizard… Configuring a WCF service In IIS, select your site or service (and most of this can also be done at other levels), and then in the actions pane select “Manage WCF and WF Service->Configure…” This opens the “Configure WCF and WF for Site” dialog: Check the “Enable metadata over HTTP” to set the ServiceMetadata behavior. Over to the Monitoring tab:   Keep the checkbox checked if you want monitoring records written to the monitoring database. Using the level you can change from monitoring everything to nothing… You can also configure the usual WCF tracing and message logging here. The throttling tab allows you to limit the number of requests and service instances, while the security tab allows you to set/change the service certificate. A later post will be about configuring WCF and Workflow services…

Windows Server AppFabric Beta 2: Deploying services

Microsoft released Visual Studio 2010 RC a while ago, but unfortunately this broke Windows Server AppFabric beta 1. Luckily march 1 MS released beta 2, which works with VS 2010 RC. I’ve installed it and will now try to show you a couple of things. So what is AppFabric? To be honest, there is another AppFabric, the one for Azure, and that is not the one I am talking about. What is Windows Server AppFabric? AppFabric makes installing, administering, monitoring and fixing problems in WCF 4 (!Yes, only starting at .NET 4) services a lot easier by extending IIS and WAS (Windows Activation Services, which are used to host non-HTTP WCF services in IIS). It also adds a distributed caching mechanism (also known as Project Velocity) to make it easier to scale ASP.NET and WCF services. If you’re familiar with BizTalk 2006/2009, you’ll know that the BizTalk Administration application shows you each BizTalk application’s health, what went wrong, how many were executed, etc… AppFabric gives you the same but now for WCF and WF 4 services. Look at this screen shot: As you can see, after installing AppFabric IIS is now showing these new icons: AppFabric Dashboard, Endpoints and Services. The dashboard will show you the current status of your services (running, stopped, with errors, etc…). Endpoints and Services allow you to list and configure the endpoints and services. Deploying using AppFabric AppFabric Hosting Services provides easier deployment of services: First thing you need to do is to package your WCF service. To do this go to the project properties and select the new Package/Publish tab: You can now select where to create the package (and if your want it as a .zip file) and how to deploy it in IIS. Now you need to create the deployment package in Visual Studio 2010: Now we can import the application using IIS: This will open the Import Application Package dialog. Use the browse button to open the package .zip file: Hit next: And Next again: Note that the service name is taken from the package properties. Hit next again, hopefully your services will deploy successfully. To verify this, you can go to your site in IIS: And click on Services. You should see your service listed (for example I have three services running here): You can also click on Endpoints to see the list of endpoints: Because of WCF default endpoints you get 4 different endpoints per service; you can modify which types of default endpoints you want, but that is now what I’ll be showing you here.   A note on using your own application pool with AppFabric During my experiments I created a new AppPool for my services. When testing my service, I would always get the following error: HTTP Error 503. The service is unavailable. First I thought the solution would be easy. My application pool was stopped. Starting it should fix the problem. But it didn’t. So I investigated a little further. Seems that my new application pool tries to use .NET 4 version 21006 (beta 2?). I could see this in the Event Viewer: The worker process failed to pre-load .Net Runtime version v4.0.21006. I think something didn’t (un)install during my migration to .NET 4 RC. So I’m now using the ASP.NET 4 application pool…

Techdays 2010

I’m happy to say I’ll be speaking at TechDays 2010 in Belgium and DevDays 2010 in the Netherlands. In Belgium I’ll be doing one session on “What is new in WCF 4” and one session on “Workflow Foundation 4”. In the Netherlands I’ll do on session on “What is new in WCF4” and one on “Developing for Windows 7 with the Windows API code pack”.

Using Workflow4 extensions

Workflow Foundation 4 allows you to add your own custom activities in code. You have a choice of CodeActivity, AsyncCodeActivity and NativeActivity.  CodeActivity is ideal if you want to add a simple activity that doesn’t block. AsyncCodeActivity is great if you need an activity that needs to do some lengthy processing and you can support the IAsyncResult pattern. But if you require some lengthy business process that needs to wait for some external input you need a NativeActivity and a Bookmark. Most samples you can find use the main method of the workflow host to send the required input for the bookmark, but this puts the burden on the host; it is way better to use an activity with an extension. The activity can then delegate the long work to the extension. In this post I will build a simple activity that uses an extension like this. Start by building a GetNameActivity that derives from NativeActivity: 1: public class GetNameActivity : NativeActivity 2: { 3: public const string GetNameBookmark = "GetName"; 4:  5: protected override bool CanInduceIdle 6: { 7: get 8: { 9: return true; 10: } 11: } 12:  13: public OutArgument<string> Name { get; set; } 14:  15: protected override void Execute(NativeActivityContext context) 16: { 17: Bookmark bookmark = 18: context.CreateBookmark(GetNameActivity.GetNameBookmark, BookmarkCompleted); 19: // Done 20: } 21:  22: protected void BookmarkCompleted(NativeActivityContext context, Bookmark bookmark, object value) 23: { 24: context.SetValue(Name, (string)value); 25: } 26: } This activity works the way you find in a lot of samples. Also note that a NativeActivity that used bookmarks needs to override the CanInduceIdle property to return true. The idea is that in the host you wait for the workflow to go idle, then code it so you ask the user for the name, and then you resume the bookmark.  Let’s NOT do this, but instead use a workflow extension. Add another class called GetNameExtension, implementing the IWorkflowInstanceExtension interface: 1: public class GetNameExtension : IWorkflowInstanceExtension 2: { 3: private WorkflowInstance Instance { get; set; } 4:  5: public void GetName(Bookmark bookmark) 6: { 7: ThreadPool.QueueUserWorkItem( 8: (ignore) => 9: { 10: Console.Write("Your name please: "); 11: string name = Console.ReadLine(); 12: Instance.BeginResumeBookmark(bookmark, name, 13: (ticket) => { Instance.EndResumeBookmark(ticket); }, null); 14: } 15: ); 16: } 17:  18: public IEnumerable<object> GetAdditionalExtensions() 19: { 20: yield break; 21: } 22:  23: public void SetInstance(WorkflowInstance instance) 24: { 25: Instance = instance; 26: } 27: } This class has a simple GetName method, taking the bookmark as an argument. It then starts some background processing to perform a lengthy operation, in this case getting some input from the console. Once it has the input it resumes the bookmark. The GetAdditionalExtensions is implement to return an empty collection (using yield break) and the SetInstance is implemented to store the current workflow instance (although not really required for this example). Now let’s use the extension. The execute method should now be implemented to retrieve this extension, and then call its GetName method with the bookmark: 1: protected override void Execute(NativeActivityContext context) 2: { 3: GetNameExtension ext = context.GetExtension<GetNameExtension>(); 4: if (ext == null) 5: throw new InvalidOperationException("This activity requires a GetNameExtension"); 6:  7: Bookmark bookmark = 8: context.CreateBookmark(GetNameActivity.GetNameBookmark, BookmarkCompleted); 9: ext.GetName(bookmark); 10:  11: // Done 12: } So how do we get this extension installed? There are two ways; first we can install the extension in the host code: 1: WorkflowApplication wf = new WorkflowApplication(new Workflow1()); 2: wf.Extensions.Add(new GetNameExtension()); 3: wf.Run(); This is almost as bad as having the host resume the bookmark; so what is better? Let’s make the activity create the extension itself; we can do this in the CacheMetadata method: 1: protected override void CacheMetadata(NativeActivityMetadata metadata) 2: { 3: base.CacheMetadata(metadata); 4: metadata.AddDefaultExtensionProvider( () => new GetNameExtension() ); 5: } This way, when the activity gets created, it can install the extension itself. Using an extension this way is ideal if you have a number of activities that need to talk to some backend system like a database. The extension can then be used to model the connection, while the activity itself models the command. All activities in the workflow instance then share the command… Don’t worry, the workflow runtime will ensure only one instance of this extension is created for the workflow.

Workflow 4 parallel and compensation activities

So I’m looking into workflow foundation 4 (using Visual Studio 2010 Beta 2). Let’s look at the parallel activity included within. The parallel activity will schedule all of its child activities asynchronously and then wait until all children have completed or the CompletionCondition evaluates to True. Let’s do a little experiment: Start Visual Studio and create a new workflow console application. Drag a Sequence activity to the designer. In it add a WriteLine activity and a Parallel activity. Drag a sequence activity inside the parallel activity. It will automatically split up to allow other branches: Rename this sequence to left, then add a WriteLine activity, a Delay and another WriteLine activity. Repeat this for the right branch, calling it Right. Now we only need to add two variables to time the delays. Select the Start sequence, and on the bottom of the designer click on the variables button. This will open the variables window: In here define two variables leftDelay and rightDelay and make them of type TimeSpan using the dropdown combobox and select “Browse for Types…”. This should open the “Browse and Select a .NET Type” dialog. One of the new things I like about this window is that you can search for a type: Finally we should end up with this: Run and you should get this: As you can see the parallel activity will now execute both left and right branches. But what if you want one of the branches to stop because another branch has done all that is needed? For that we can use the Parallel’s activity CompletionCondition. When one of the branches of the parallel activity completes, the parallel activity will check its CompletionCondition. If set to false, it will allow other braches to continue. Otherwise it will cancel the other, still running, branches. So let’s test this. Click on the parallel activity and add a new boolean variable called stopProcessing (I’ve renamed the parallel activity Race, so that’s set as the stopProcessing variable’s scope): Now set the parallel activity CompletionCondition to this variable by clicking the activity and using the property window: Next add to each branch an assignment activity after the last writeline to set the stopProcessing to true: Run: you should see one branch complete while the other never does: And what about doing something when you get cancelled? To do this we need to use a CancellationScope. A CancellationScope allows you to define what needs to be done when a branch gets cancelled, for example in a parallel activity because another branch completed with the CompletionCondition set to True. Let’s try this. Inside the parallel activity drag a CancellationScope. Then drag the left branch in it. Repeat with a new CancellationScope for the right branch. Drag a WriteLine activity into each CancellationScope’s CancellationHandler. For example the left side should write “Left was cancelled” in the CancellationHandler: Run again: You should now see one side complete, and the other being cancelled: WARNING: Although you might think it is a good idea to schedule as much work as possible in parallel, this will not make your orchestration faster. WF will still schedule all activities on the same thread, so if your activities never go idle, it will take the same amount of time as if you’re using a sequence. Only if each branch in the parallel activity needs to wait on some response will using the parallel activity make a difference.