;

WcfTestClient with WCF Workflow Service wont send DateTime message properties

Posted : Tuesday, 29 November 2011 11:20:00

A while ago I did the MCTS exam for version 3.5 of Windows Workflow Foundation and quite liked it but haven’t had recourse to use it in a production system. Recently a project came up that I thought would be good candidate but since I got my MCTS there has been a new version of Workflow released with quite a few changes so I thought I better get up to speed with the new tech before deciding whether or not to use it. I came up against a pretty nasty problem and couldn’t find anything on the net to suggest a fix, it took a while but I found the cause of the problem. What follows is a brief explanation of the problem followed by the fix that worked for me.

So I created a Workflow Service using the project template and named it SimpleWorkflowService.

image

This service simply takes two dates and calculates the difference between them in days then returns that value to the caller. Obviously this is a trivial example and doesn’t highlight the strengths of the Workflow ecosystem but that is not the point of this post Smile. Next I added a class to the project to represent the Message that will be sent to the service, its basically a simple DTO object with two DateTime properties:

    6     [DataContract]

    7     public class DaysBetweenServiceRequest

    8     {

    9         [DataMember]

   10         public DateTime FromDate { get; set; }

   11         [DataMember]

   12         public DateTime ToDate { get; set; }

   13     }

Next I added a CodeActivity<Int32> derived class which takes an instance of the DaysBetweenServiceRequest class called CalculateDaysDiffActivity. The code is very simple and just calls the Subtract operation on ToDate using FromDate as the method parameter, this returns an instance of a Timespan object representing the difference between the two dates. The Execute operation of the CodeActivity object returns the Days property of the TimeSpan returned by the Subtract operation:

   11     public class CalculateDaysDiffActivity : CodeActivity<int>

   12     {

   13         [RequiredArgument]

   14         public InArgument<DaysBetweenServiceRequest> ServiceRequest { get; set; }

   15 

   16         protected override int Execute(CodeActivityContext context)

   17         {

   18             DateTime date1 = ServiceRequest.Get(context).FromDate.Date;

   19             DateTime date2 = ServiceRequest.Get(context).ToDate.Date;

   20 

   21             return date2.Subtract(date1).Days;

   22         }

   23     }

Next I rebuilt the solution which places any custom activities into the toolbox. I then dragged my CalculateDaysDiffActivity class from the toolbox and dropped it between the ReceiveRequest and SendResponse activities on the workflow designer. The final step was to wire up the inputs and outputs of all the activities to enable the data flow through the service. To do this I had to open the variable pane of the workflow designer. By default there are two variables defined for a workflow service, I altered the type of the one called “data” from Int32 to DaysBetweenServiceRequest. I also added another called “result” of type Int32. Workflow variables are one of the major changes in Workflow 4, previously the output of one activity was mapped to the input of another but in Workflow 4 you map the output of activities to container variables and then map those variables to the inputs of subsequent activities. I wont go through each of the mappings but it should be fairly evident and if not the code is available at the end of this post. My completed service looked like this:

image

So to test the service I selected the service definition file (DaysBetweenService.xamlx) in solution explorer and hit F5, this launches the WcfTestClient which enables easy testing of WCF services by reading the service definition files and providing a GUI to collect and return appropriately shaped data. By default in the WcfTestClient any date fields will default to today so I altered the ToDate parameter to a date in the future (how long till Christmas – given I’ve done nothing yet do I really want to know this?):

image

I hit invoke and got rather a strange result:

image

I know its soon (26 days at time of writing) but I definitely have more time than 0 days! After a bit of debugging I found that no dates were begin sent across the wire. I started by adding breakpoints into the code activity in which both dates were showing up as 01/01/0001 00:00:00 and then working forward through the service from there to the popint where the date wasn’t even being passed to the ReceiveRequest activity. I haven’t used the WcfTestClient much before but while trying to work out why the dates weren’t being sent I noticed the XML tab:

image

The <DaysBetweenServiceRequest> node didn’t contain any children? I could not work out why, I spent ages Googling but found nothing, there were a few similar posts that referred to timezones but this only seemed to affect clients and services in different timezones. What seemed a bit odd was that both DateTimes were being set to their minimum value which suggested maybe the service was inserting a default value for them? I then had a bit of a brainwave, I altered the Message definition as follows:

    6     [DataContract]

    7     public class DaysBetweenServiceRequest

    8     {

    9         [DataMember(IsRequired = true)]

   10         public DateTime FromDate { get; set; }

   11         [DataMember(IsRequired = true)]

   12         public DateTime ToDate { get; set; }

   13     }

As you can see I added the IsRequired parameter to the DataMember attributes. I rebuilt the solution, hit F5, entered the values then hit invoke:

image

And the XML:

image

Nice, 26 days until Christmas. This may just be a problem with the WcfTestClient but I haven’t tested any other service clients. It also only seems to affect WCF Workflow Services as when I tried the same with a regular WCF service the dates were sent fine. Workflow services offer a lot of promise but things like this are just annoying and definitely hit developer productivity. Hopefully this post will help someone, let me know if it does.

Right I gotta go shopping…

  • (This will not appear on the site)