Tuesday, March 30, 2010

Rock Solid Knowledge on iTunes is live! We’ve taken the feed to our free screencasts and they are now available through iTunes via the following link

http://itunes.apple.com/gb/podcast/rock-solid-knowledge-screencasts/id365244375

Now you can watch them on the move

 |  |  |  |  |  |  | 
Tuesday, March 30, 2010 7:13:22 PM (GMT Daylight Time, UTC+01:00)  #    Comments [5]Trackback
 Wednesday, March 17, 2010

Thanks to everyone who attended my sessions at DevWeek 2010. I’ve now uploaded the demos which you can find at the following locations

A Day of .NET 4.0 Demos

Windows Workflow Foundation 4.0 Demos

Creating WCF Services using WF4 Demos

I’ll be around for the rest of the conference so drop by for a chat at our developer clinic in the exhibition area

 |  |  |  |  | 
Wednesday, March 17, 2010 7:13:59 AM (GMT Standard Time, UTC+00:00)  #    Comments [6]Trackback
 Wednesday, March 10, 2010

In my last post I pointed to a screencast I had recorded that showed how to create a custom message filter to plug your own logic into the WCF 4.0 Routing Service. However, the simple custom filter is only the start – you can actually take control of part of the routing table which allows you to make global decisions about which filters match a particular request. On that basis I have created another screencast that shows how to build one of these more complex custom filters. in this case I use the example of a round robin load balancer where you can use a file on the file system to indicate whether a specific endpoint should be considered part of the load balancing algorithm

You can find this last in the series of screencasts on the routing service, along with all the others here, on the Rock Solid Knowledge site

http://rocksolidknowledge.com/ScreenCasts.mvc

 |  | 
Wednesday, March 10, 2010 12:05:40 PM (GMT Standard Time, UTC+00:00)  #    Comments [6]Trackback
 Monday, March 08, 2010

I’ve just uploaded a new screencast on the the Rock Solid Knowledge site. This one shows you how to plug your own routing logic into the new Routing Service that is part of WCF 4.0. It uses a custom message filter that can be used to supplement the existing set of filters such as matching on XPath and Action.

You can find the screencast (along with the previous ones in the series) here

http://www.rocksolidknowledge.com/ScreenCasts.mvc

 | 
Monday, March 08, 2010 11:37:22 AM (GMT Standard Time, UTC+00:00)  #    Comments [7]Trackback
 Tuesday, March 02, 2010

Continuing my screencast series on the Routing Service in WCF 4.0, I have just uploaded one on Data Dependent Routing

You can get to the latest screencast (and all of the others) here http://rocksolidknowledge.com/ScreenCasts.mvc

 |  | 
Tuesday, March 02, 2010 9:50:18 AM (GMT Standard Time, UTC+00:00)  #    Comments [6]Trackback
 Monday, March 01, 2010

I have just published my second screencast on one of the new features of WCF 4.0 – the Routing Service. This screencast focuses on enabling multicast and failover with the Routing Service

You can get to the screencast from here http://rocksolidknowledge.com/ScreenCasts.mvc

 |  | 
Monday, March 01, 2010 12:16:51 PM (GMT Standard Time, UTC+00:00)  #    Comments [5]Trackback
 Friday, February 26, 2010

Thanks to everyone who attended my two sessions at BASTA! – another thoroughly enjoyable conference. I’ve uploaded the demos

What’s new in Workflow 4.0 – this includes the application with the rehosted designer

Building WCF services with Workflow 4.0

 |  |  | 
Friday, February 26, 2010 9:02:42 AM (GMT Standard Time, UTC+00:00)  #    Comments [5]Trackback
 Sunday, February 14, 2010

I my last post I showed that creating a custom composite activity (one that can have one or more children) requires deriving from NativeActivity. The Retry activity that I showed was fairly simple and in particular didn’t try to share data with its child. There appears to be a catch-22 in this situation when it comes to overriding CacheMetadata: if I add a Variable to the metadata (AddVariable) then it can be used exclusively by its children – i.e. the activity itself can’t manipulate the state; if I add a variable as implementation data to the metadata (AddImplementationVariable) then the children cant see it as its seen as purely used for this activities implementation. How then do we create data that can be both manipulated by the activity and accessed by the parent?

The secret to achieving this is a feature called ActivityAction - Matt Winkler talks about it here. The idea is that I can bind an activity to one or more parent defined pieces of data then schedule the activity where it will have access to the data. Its probably best to show this with an example so I have written a ForEachFile activity that you give a directory and then it passes its child the file name of each file in the directory in turn. I’ll show the code in its entirety and then walk through each piece in turn

   1: [ContentProperty("Body")]
   2: [Designer(typeof(ForEachFileDesigner))]
   3: public class ForEachFile : NativeActivity, IActivityTemplateFactory
   4: {
   5:     public InArgument<string> Directory { get; set; }
   6:  
   7:     [Browsable(false)]
   8:     public ActivityAction<string> Body { get; set; }
   9:  
  10:     private Variable<IEnumerator<FileInfo>> files = new Variable<IEnumerator<FileInfo>>("files");
  11:  
  12:     protected override void CacheMetadata(NativeActivityMetadata metadata)
  13:     {
  14:         metadata.AddDelegate(Body);
  15:  
  16:         RuntimeArgument arg = new RuntimeArgument("Directory", typeof(string), ArgumentDirection.In);
  17:         metadata.AddArgument(arg);
  18:  
  19:         metadata.AddImplementationVariable(files);
  20:     }
  21:     protected override void Execute(NativeActivityContext context)
  22:     {
  23:         DirectoryInfo dir = new DirectoryInfo(Directory.Get(context));
  24:  
  25:         IEnumerable<FileInfo> fileEnum = dir.GetFiles();
  26:         IEnumerator<FileInfo> fileList = fileEnum.GetEnumerator();
  27:         files.Set(context, fileList);
  28:  
  29:         bool more = fileList.MoveNext();
  30:  
  31:         if (more)
  32:         {
  33:             context.ScheduleAction<string>(Body, fileList.Current.FullName, OnBodyComplete);
  34:         }
  35:     }
  36:  
  37:     private void OnBodyComplete( NativeActivityContext context, ActivityInstance completedInstance)
  38:     {
  39:         IEnumerator<FileInfo> fileList = files.Get(context);
  40:         bool more = fileList.MoveNext();
  41:  
  42:         if (more)
  43:         {
  44:             context.ScheduleAction<string>(Body, fileList.Current.FullName, OnBodyComplete);
  45:         }
  46:         
  47:     }
  48:  
  49:     #region IActivityTemplateFactory Members
  50:     public Activity Create(DependencyObject target)
  51:     {
  52:         var fef = new ForEachFile();
  53:         var aa = new ActivityAction<string>();
  54:         var da = new DelegateInArgument<string>();
  55:         da.Name = "item";
  56:  
  57:         fef.Body = aa;
  58:         aa.Argument = da;
  59:  
  60:         return fef;
  61:     }
  62:     #endregion
  63: }

Ok lets start with the core functionality then we’ll look at each of the pieces that help make this fully usable. As you can see the class derives from NativeActivity and overrides CacheMetadata and Execute – we’ll look at their implementations in a minute. There are three member variables in the class: the InArgument<string> for the directory; an implementation variable to hold the iterator as we move through the files in the directory; the all important ActivityAction<string> which we will use to pass the current file name to the child activity.

Lets look at CacheMetadata more closely. Because we want to do interesting things with some of the state the default implementation won’t work so we override it. As we don’t call the base class version we need to specify how we use all of the state. We add the ActivityAction as a delegate, we bind the Directory argument to a RuntimeArgument and specify the iterator as an implementation variable – we don’t want the child activity to have access to that directly.

Next lets look at Execute. The first couple of lines are nothing unusual – we get the directory and get hold of the list of files. Now we have to store the retrieved iterator in the implementation variable, fileList. We move to the first file in the iteration, if it returns false the list was empty so as long as MoveNext returned true we want to schedule the child activity passing the current file. To do this we use the ScheduleAction<T> member on the context. However, because we’re going to process each one sequentially, we also need to know when the child is finished so we pass a completion callback, OnBodyComplete.

Now in OnBodyComplete we simply get the iterator, move to the next item in the iteration and as long as we’re not finished iterating re-schedule the child again passing the new item in the iteration.

That really is the “functional” part of the activity – everything else is there to support the designer. So why does the designer need help? Well lets look at what we would have to do to build this activity correctly if we were going to execute it from main

   1: Activity workflow = new ForEachFile
   2: {
   3:   Body = new ActivityAction<string>
   4:   {
   5:     Argument = new DelegateInArgument<string>
   6:     {
   7:       Name = "item",
   8:     },
   9:     Handler = new WriteLine
  10:     {
  11:       Text = new VisualBasicValue<string>("item")
  12:     }
  13:   },
  14:   Directory = @"c:\windows"
  15: };

As you can see, its not a matter of simply creating the ForEachFile, we have to build the internal structure too – something needs to create that structure for the designer - this is the point of IActivityTemplateFactory. When you drag an activity on to the design surface normally it just creates the XAML for that activity. However, before it does that it does a speculative cast for IActivityTemplateFactory and if the activity supports that it calls the interface’s Create method instead and serializes the resulting activity to XAML.

So going back to the ForEachFile activity, you can see it implements IActivityTemplateFactory and therefore, as far as the designer is concerned, this is the interesting functionality – lets take a look at the Create method.We create the ForEachFile and wire an ActivityAction<string> to its Body property. ActivityAction<string> needs a slot to store the data to be presented to the child activity. This is modelled by DelegateArgument<string> and this gets wired to the Argument member of the ActvityAction. We also name the argument as we want a default name for the state so the child activity can use it. Notice, however, we don’t specify the child activity itself (it would be a pretty useless composite if we hard coded this). The child will be placed on the Handler property of the ActivityAction but that will be done in the ActivityDesigner using data binding.

Before we look at the designer lets highlight a couple of “polishing” features of the code: the class declared a ContentProperty via an attribute – that just makes the XAML parsing cleaner as the child doesn’t need to be specified using property element syntax; the Body is set to non-browsable – we don’t want the activities user to try to set this value in the property grid.

OK on to the designer. If you read my previous article there are a couple of new things here. Lets look at the markup – again there is no special code in the code behind file, everything is achieved using data binding

   1: <sap:ActivityDesigner x:Class="ActivityLib.ForEachFileDesigner"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:s="clr-namespace:System;assembly=mscorlib"
   5:     xmlns:conv="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"
   6:     xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
   7:     xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
   8:     xmlns:me="clr-namespace:ActivityLib">
   9:     <sap:ActivityDesigner.Resources>
  10:         <conv:ArgumentToExpressionConverter x:Key="expressionConverter"/>
  11:     </sap:ActivityDesigner.Resources>
  12:  
  13:     <Grid>
  14:         <Grid.RowDefinitions>
  15:             <RowDefinition Height="Auto"/>
  16:             <RowDefinition Height="*"/>
  17:         </Grid.RowDefinitions>
  18:         
  19:         <StackPanel Orientation="Horizontal" Margin="2">
  20:             <TextBlock Text="For each file "/>
  21:             <TextBox Text="{Binding ModelItem.Body.Argument.Name}" MinWidth="50"/>
  22:             <TextBlock Text=" in "/>
  23:             <sapv:ExpressionTextBox Expression="{Binding Path=ModelItem.Directory, Converter={StaticResource expressionConverter}}"
  24:                                     ExpressionType="s:String"
  25:                                     OwnerActivity="{Binding ModelItem}"/>
  26:         </StackPanel>
  27:         <sap:WorkflowItemPresenter Item="{Binding ModelItem.Body.Handler}"
  28:                                    HintText="Drop activity"
  29:                                    Grid.Row="1" Margin="6"/>
  30:  
  31:     </Grid>
  32:     
  33: </sap:ActivityDesigner>

Here’s what this looks like in the designer

ForEachFile

So the TextBox at line 21 displays the argument name that our IActivityTemplateFactory implementation set up. The ExpressionTextBox is bound to the directory name but allows VB.NET expressions to be used. The WorkflowItemPresenter is bound to the Handler property of the Body ActivityAction, This designer is then associated with the activity using the [Designer] attribute.

So as you can see, ActivityAction and IActivityTemplateFactory work together to allow us to build rich composite activities with design time support

 |  | 
Sunday, February 14, 2010 12:54:30 PM (GMT Standard Time, UTC+00:00)  #    Comments [2]Trackback