WF 4.0 Beta 1 : How to Create a Declarative Sequential Service Library
Wow! It's been a long time since I've blogged about anything! It seems every time I think of something to blog about, I find some other blog that already talks about the same thing. I guess it's best I get over this because you never know who will find who's blog.
After being in the trenches for so long with WF 3.0/3.5, SharePoint WF and WCF, I have finally had the opportunity to start digging into WF 4 & Visual Studio 2010 Beta 1. Workflow is headed for a very bright and exciting future, but like all new things, it's going to take some getting used to.
So today, let's start by creating a 'Declarative Sequential Service Library' (workflow exposed as a WCF service). But first, lets understand a few things about this type of service.
- Remember this is beta 1 and some functionality that might make this easier to implement does not yet exist.
- Remember that a declarative service is all about creating a workflow, exposed as a WCF service. This is something that takes a bit of effort in WF 3.5.
- Remember that when we say declarative, we mean, no code. And that is one of the key things here that tripped me up, because I kept trying to do things in code….and I couldn't.
What will this example service represent?
Since spend a week every year at summer camp, I've decided to create a simple service that will confirm space in merit badge classes for summer camp. In our case to keep this simple, we will simply confirm space for any merit badge request. We will not be doing any sort of correlation in this example, we'll save that for later blog entries.
Creating the Service
- Open Visual Studio 2010 Beta 1 and select File | New | Project | Visual C# | WCF | Declarative Sequential Service Library. Give your project the name 'ConfirmMeritBadge' and select OK. What you will be presented with is the new WF 4.0 designer surface with a sequence activity that contains a receive and send activity that work together somewhat as a unit.
As it stands at this point, you'll notice that you have an Operation Name of GetData, a Value of 'data' and no Correlates with value. You may recall from Visual Studio (2008/2010) that if you were to have selected just to create a WCF service, it would provide for you a contract named IService with an operation named GetData. This is the same sort of thing that is happening here. We are going to change these values though.
Here is the data type we will be referencing within our service (I created this by creating a class library named MeritBadgeType and putting it in the same Visual Studio solution):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
namespace MeritBadgeType
{
[DataContract]
public class MeritBadge
{
private string _mBadgeName = default(string);
private Int16 _mBadgeSession = default(Int16);
[DataMember]
public string BadgeName
{
get { return _mBadgeName; }
set { _mBadgeName = value; }
}
[DataMember]
public Int16 BadgeSession
{
get { return _mBadgeSession; }
set { _mBadgeSession = value; }
}
}
}
Right click the Service1.xamlx file in the Visual Studio solution and rename it to MeritBadgeService.xamlx.
Add a reference to the assembly (MeritBadgeType) to the declarative service. I do this by selecting 'Add Reference' and then selecting my MeritBadgeType project in the same Visual Studio solution.
Build the solution. This may sound odd at this point, but if you don't do a build, you will not be able to see your referenced data type when you create your workflow variable.
Click in the workflow designer where you see an activity named 'Sequential Service' . This will highlight the entire sequence activity. In the properties window, set the DisplayName property to 'Confirm Badge' .
We need to create two workflow scoped level variables to hold our merit badge object and a boolean confirmation. With the Confirm Badge activity still selected, in the lower left hand corner of the workflow designer, select the 'Variables' button.
Create two variables by selecting 'Add New Variable':
Variable Name | Type |
wfMeritBadge | To set the type, select the drop-down in the Variable Type column and select 'Browse for Types'. A 'type' browser dialog box will appear and you will need to select the 'MeritBadgeType.MeritBadge' data type. Select Ok. |
wfBadgeConfirm | The type will be a boolean that you can just select from the Variable Type drop-down. |
Click on the Receive Request receive activity to highlight it. Change it's DisplayName to 'Receive Badge Request' .
Click on the SendResponse send activity and set it's DisplayName to 'Badge Reply' .
Setting up the Activities
Now that we have everything named like we want it, we need to start setting up our internal activities to have operation and contract names like we wish for it to have. Select the Receive Badge Request activity.
Set the Operation Name property to 'ReserveBadgeSpace'.
Set the ServiceContractName property to 'IConfirmBadge'.
Set the Value property to 'wfMeritBadge'
Click on the Badge Reply Send activity.
Set the Value property to 'wfBadgeConfirm'.
At this point, you may be asking, what did we just do here? Why couldn't I just browse to a contract or operation name? Well, in Beta 1, you do not have the capability to physically add your own contract, in code, and then browse to it. You also cannot browse to a referenced contract type. Basically, when you put this information into the properties of the Receive activity, the service contract and operation will be created on the fly, sort of like the Workflow First approach that was implemented in .Net 3.5.
Now comes the tricky part. If I were to go and try to add a service reference to this service in a client app, what it would show me is that my actually service name is IService1, not IConfirmService. So how do we get this to work?
- Drag and drop an Assign activity below the Receive Badge Request activity. Set the DisplayName to Confirmed.
- In the Assign activity, set the To property to wfBadgeConfirm and the Value property to True. There is of course a lot more we could do in this service…we could go out to a database to figure out if there is room left for more students etc, but for now, I'll just set the return to true.
In the end, your declarative service should look something like this:
Setting up the Service Name
- In the ConfirmMeritBadge project, open up the web.config file. I'll just do it with an XML editor instead of the WCF Configuration Editor. You will see this:
Notice that in the config file, we need to change the name of the service being referenced to 'MeritBadgeService' which is the same name as the .xamlx file. Another thing you might notice is that you don't see an endpoint configured with an address or binding type. This is because, out of the box, this declarative service assumes you will be using basicHttpBinding and the address will be https://localhost:<someport>/MeritBadgeService.xamlx. Also notice that metadata exposure is enabled.
Save the web.config file and close it.
Close the MeritBadgeService.xamlx file.
Right click on the MeritBadgeService.xamlx file in the solution explorer and choose Open With.
Choose XML Editor and select Ok.
- Change the ConfigurationName and Name settings to MeritBadgeService. Save the file and close it.
What we just did here (remember this is Beta 1 bits) is, to change the exposed service name, we had to go into the source code and change the service name. To re-open the MeritBadgeService.xamlx file in the workflow designer, double-click on it in the solution explorer. Rebuild the entire solution.
Testing the Service
First we perform a simple test just to make sure the service will work. Here, we are hosting via IIS, so right click on the ConfirmMeritBadge project and select 'View In Browser' .
You will be presented with a directory listing of your service. You cannot click on the .xamlx file and view it in the browser because there is no menu item for this. You could just type in the address to the .xamlx file if you know the Visual Studio generated port number, but I'll do it this way first to see what port number will be used.
In the browser window, click on the MeritBadgeService.xamlx file. What you should see (if everything is working right is)
…and if you click on the wsdl link, you'll be able to see that indeed the service name is 'MeritBadgeService':
What about a real test?
For a real test, you can pretty much choose any type of client where you can add a service reference to (and that can call a basicHttp endpoint). What you need to do is add a service reference to the address: https://localhost:1068/MeritBadgeService.xamlx from the above example and the service reference will be added to your project. More info in the next post about how to set this up.