07 July 2010

Using MVVM Light to drive a Windows Phone 7 / Silverlight 4 map viewer

Updated for Windows Phone 7 beta tools!

Traditionally, the first application any developer tries out on a new platform is "Hello World". Working with spatial data daily, I tend to take this a wee bit more literal than most people. So when I wanted to try out MVVM and Windows Phone 7 at the same time, I went for the less-than-trivial task of making a generic map viewer from scratch, based upon the MultiScaleImage which – fortunately – is available on Windows Phone 7 as well. For an encore, to prove the point of MVVM, this viewer’s model should be usable by an ‘ordinary’ Silverlight application as well. My intention was to make a case study for MVVM in a less-than-ordinary environment, but I ended up with a more or less fully functional – although pretty limited – application.

Prerequisites

This example uses:
  1. Visual Studio 2010 Professional
  2. Windows Phone 7 Developer Tools Beta
  3. Silverlight 4 SDK
  4. Silverlight 4 tools for Visual Studio 2010
  5. The MVVM Light framework by Laurent Bugnion, both for Windows Phone 7 and for Silverlight 4. The parts you need are already include in the sample.

On my machine I also have the Silverlight 4 Toolkit April 2010 installed as well but I don’t think that is necessary for this sample.

Download, compile and run the source code

Solution structurSince the application itself contains a bit more code than my usual samples (as well as a bucketload of XAML), I cannot write out all source code in the sample. In order be able to follow what is going on, you will need to download the code first, see if it runs and compiles on your machine, and then read the rest of this article. You will end up with a solution that, with the proper parts expanded and collapsed, will look like the solution as displayed to the right. In the Binary Dependencies solutions folder you will see Laurent’s stuff (Galasoft.*), both for Windows Phone 7 and Silverlight 4, as well as System.Windows.Interactivity, which comes from the Blend SDK. The bottom to projects, SLViewer.Web and WP7Viewer, are the actual startup projects. If you fire up one , you will get one of these screens below:

 MobileMapLoader Silverlight screen Now that’s what I call “Hello World”!

Using the applications

Double-tapping (or clicking) anywhere on the map on both applications zooms in on the location of the double-tap. If you (single) tap/click on the text “Double tap zooms in” it will toggle with “Double tap zooms out” and then double tap… you guessed it.
In addition, you can move the map around by dragging it – either with your finger or the mouse. By tapping/clicking on the map name (initially it will show the Open Source Map OsmaRender) you can change the map you are viewing: OSM OsmaRender, OSM Mapnik, Google Maps Street, Satellite, and Hybrid, and Bing Maps Road and Aerial. The Silverlight application just responds to a click and moves to the next map – the Windows Phone 7 more or less supports swipes and you can go to the next or the previous map my moving your finger from right to left or left to right over the map title. At least, it does so when I use the mouse, lacking a proper test device it is of course impossible to test how it behaves in the real world.

Solution structure

From top to bottom you will see:

  • LocalJoost.Models, this is a Silverlight 4 class library without any content, only links to source files in LocalJoost.Model.WP7
  • LocalJoost.Model.WP7, a Windows Phone 7 class library, this contains the actual model and additional items as well as the definition of attached dependency properties needed to drive the map,
  • LocalJoost.TileSource, again a codeless Silverlight class library, with links only to
  • LocalJoost.TileSource.WP7, a Windows Phone 7 class library, containing classes that translate requests from the MultiScaleImage to the image structure for various Tile Map Servers
  • SLViewer, the Silverlight 4 application
  • SLViewer.Web, the web application hosting SLViewer
  • WP7Viewer, the Windows Phone 7 application

Since LocalJoost.Models and LocalJoost.TileSource only contain links to source files in the Windows Phone 7 counterparts, both class libraries have identical code.

Tile sources

MultiScaleImage features a property Source of type MultiScaleTileSource. This class sports an abstract method GetTileLayers(int tileLevel, int tilePositionX, int tilePositionY, IList<object>tileImageLayerSources) that you can override. Each descendant essentially tells the MultiScaleImage: if you are on zoomlevel tileLevel, and need to have the Xth horizontal tile and the Yth vertical tile, then I will add an URI to the tileImageLayerSources where you can find it. So all classes in the LocalJoost.TileSource.WP7 are simply translations from what the MultiScaleImage asks into URIs of actual map images on various map servers on the internet. Nice if you are into it (like me), but not essential to understand the workings of MVVM as a driver for this application

Binding properties and commands

The key thing about MVVM is that nothing, or at least very little, ends up in what ASP.NET WebForms veterans like me tend to call the ‘codebehind file’ of the XAML. The idea is that you make your controls in XAML, and let them communicate by binding to properties and commands of the model. You click on a button or whatever, the button sends a command to the model, the model responds by changing some properties, and via the magic of INotifyPropertyChanged they automatically end up being displayed on the user interface.

Problem 1: In Silverlight you only have events, and you cannot bind events to a model. You need commands
Problem 2: The MultiScaleImage control is mostly driven by methods, to which you cannot bind, and for some reason the Source property does not want to bind to MultiScaleTileSource either (I get an error “Object does not match target type”).

The solution for problem 1 is MVVM Light. The solution for problem 2 are attached dependency properties.

Attached dependency properties for driving the MultiScaleImage

To get this application to work, there are quite some dependency properties necessary. They are all in the class BindingHelpers in LocalJoost.Models.WP7. From top to bottom you will see:

  • MapTileSource: used to bind a MultiScaleTileSource to the Source property of a MultiScaleImage
  • ZoomEventPoint: used to bind the result of an event (the location where the user tapped on the MultiScaleImage and the zoom factor) to the MultiScaleImage.
  • StartDragEventData: when the user starts dragging the map, the event starting of the dragging is stored in here. Doubles as state setting: if this property is not set, the user is not dragging. The callback method of this property also stores data in the next property:
  • DragData: stores the position and offset where the user started the dragging. This property is for storage only and you will not see it bound to anything in XAML.
  • MoveEventData: stores the event when the user actually moves the map – in conjunction with the data stored in DragData the new map origin is calculated, and the ViewportOrigin of the MultiScaleImage gets a kick to the right place.

Using MVVM Light to kick the model

If you look at the XAML of MainPage.xaml of WP7Viewer, there are a few things you should take notice of:

<phone:PhoneApplicationPage 
  x:Class="WP7Viewer.MainPage"
  <!--- omitted stuff --->
  xmlns:MapMvvm="clr-namespace:LocalJoost.Models;assembly=LocalJoost.Models"
  xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
  xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7">

This way, I add my own assembly, with the model and the dependency property types, to be used in XAML with prefix “MapMvvm”. I also add System.Windows.Interactivity to be used with prefix “i” and MVVMLight with prefix “cmd”. And now the place where it all happens:

<MultiScaleImage x:Name="msi" 
   ViewportOrigin ="{Binding ViewportOrigin}"
   MapMvvm:BindingHelpers.MapTileSource="{Binding CurrentTileSource.TileSource}" 
   MapMvvm:BindingHelpers.ZoomEventPoint="{Binding ZoomEventPoint}"
   MapMvvm:BindingHelpers.StartDragEventData="{Binding StartMoveEvent}"
   MapMvvm:BindingHelpers.MoveEventData="{Binding EndMoveEvent}">

 <i:Interaction.Triggers>
   <i:EventTrigger EventName="MouseLeftButtonDown">
     <cmd:EventToCommand Command="{Binding MouseLeftButtonDown}"
      PassEventArgsToCommand="True" />
   </i:EventTrigger>
   <i:EventTrigger EventName="MouseLeftButtonUp">
     <cmd:EventToCommand Command="{Binding MouseLeftButtonUp}"
      PassEventArgsToCommand="True" />
    </i:EventTrigger>
    <i:EventTrigger EventName="MouseMove">
      <cmd:EventToCommand Command="{Binding MouseMove}"
       PassEventArgsToCommand="True" />
     </i:EventTrigger>
   </i:Interaction.Triggers>
</MultiScaleImage>

In the top part, I bind my MapTileSource, ZoomEventPoint, StartDragEventData and MoveEventData attached dependency properties of the MultiScaleImage to properties in the model, enabling the model to communicate stuff to the View – of which the MultiScaleImage is part -without having to resort to calling actual methods of the MultiScaleImage.

Now to enable the View to communicate back to the model – remember I wrote earlier that you have only events in Silverlight, no proper commands? Look at the bottom part where Laurent’s magic comes into play: I capture the event using an EventTrigger from System.Windows.Interactivity, and by using the EventToCommand from MVVM Light I can bind that to an actual command in the model – and optionally pass the parameters to the model as well. For instance, the event MouseLeftButtonDown is passed to the command MouseLeftButtonDown in MapViewModel:

public ICommand MouseLeftButtonDown
{
  get
  {
    return new RelayCommand<MouseEventArgs>(e =>
    {
      var t = DateTime.Now - _lastMouseDown;
      if (t < _timeSpanForDoubleClick)
      {
        // assume double click - Zoom
        ZoomEventPoint = 
          new ZoomEventPoint 
           { Event = e, ZoomFactor = ZoomAction.ZoomFactor };
      }
      else
      {
        // Assume start of dragging 
        StartMoveEvent = e;
      }
      _lastMouseDown = DateTime.Now;
    });
  }
}

Thus the model can communicate with the view via properties (albeit attached dependency properties) and the view can notify the model to do something by binding to its commands. The circle is closed and nothing needs to be in your ‘code behind’ file anymore. Well, almost nothing.

Instantiating the model

A minor detail: before I can bind a view to a model, there must be a model to bind to. I instantiate the model in the ‘classic’ MVVM way, via XAML only. In the phone:PhoneApplicationPage.Resources I instantiate the model like this:

<phone:PhoneApplicationPage.Resources>
  <Storyboard x:Name="LayoutrootStartup">
  <!-- ommitted stuff -->
  </Storyboard>
  <MapMvvm:MapViewModel x:Key="MapViewerModel" />
</phone:PhoneApplicationPage.Resources>
The model constructor is fired, and the list of maps (_allTileSources) and zoomactions (_zoomActions) are initialized. Then I set the model as data context for the layout root:
<Grid x:Name="LayoutRoot" 
  Background="Transparent" 
    DataContext="{StaticResource MapViewerModel}">
  <!-- ommitted stuff-->
</Grid>
and the application is off to go. There are other way of doing this: I watched Dennis Vroegop once writing code instantiating the model in the constructor in the ‘code behind file’ of the user control and then setting the data context by code - this enables passing the Dispatcher as a parameter which is necessary if you bind stuff coming from another thread. Dennis himself, by the way, is currently in the process of writing an excellent introduction to MVVM – the first two parts (in Dutch) you can find here and here.

Implementing the ‘swipe’

As I wrote earlier, in the Windows Phone 7 application it is possible to select the next or the previous map by ‘swiping’ over the map title. There are probably better ways to do this, but I did it as follows: first, I trap the ManipulationCompleted event and pass it to the model using the same trick as before:

<TextBlock x:Name="PageTitle"
  Text="{Binding CurrentTileSource.MapName}" 
  Margin="-3,-8,0,0"
  Style="{StaticResource PhoneTextTitle1Style">
   <i:Interaction.Triggers>
    <i:EventTrigger EventName="ManipulationCompleted" >
      <cmd:EventToCommand Command="{Binding SetNextMapCommandWp7}" 
        PassEventArgsToCommand="True"/>                            
    </i:EventTrigger>
  </i:Interaction.Triggers>
</TextBlock>
and then I go on processing it like this:
/// <summary>
/// Called by the Windows Phone client
/// when the user swipes over the map tile
/// </summary>
public ICommand SetNextMapCommandWp7
{
  get
  {
    return 
      new RelayCommand<ManipulationCompletedEventArgs>(SetNextMapWp7);
  }
}

/// <summary>
/// Determine to select previous or next map
/// </summary>
/// <param name="e"></param>
public void SetNextMapWp7(ManipulationCompletedEventArgs e)
{
  if (e.TotalManipulation.Translation.X > 0)
  {
    SetPreviousMap();
  }
  else
  {
    SetNextMap();
  }
}

/// <summary>
/// Move to the next map
/// </summary>
public void SetNextMap()
{
 var currentNode = _allTileSources.Find(CurrentTileSource);
 if (currentNode != null)
 {
  CurrentTileSource =
   currentNode.Next != null ? 
    currentNode.Next.Value : _allTileSources.First.Value;
 }
}

/// <summary>
/// Move to the previous map
/// </summary>
public void SetPreviousMap()
{
 var currentNode = _allTileSources.Find(CurrentTileSource);
 if (currentNode != null)
 {
  CurrentTileSource =
   currentNode.Previous != null ? 
     currentNode.Previous.Value : _allTileSources.Last.Value;
 }
}

/// <summary>
/// Command called by Silverlight 4 client
/// when user clicks on map title
/// </summary>
public ICommand SetNextMapCommand
{
  get
  {
    return new RelayCommand(SetNextMap);
  }
}

by checking the TotalManipulation.Translation.X property of the ManipulationCompletedEvent I can calculate if the user swiped from left to right or from right to left, thus showing the next or the previous map type. The types themselves, by the way, are stored in a LinkedList – that’s the first time I found use for that one – but that’s is not important for the way this works. Notice the last method – the simple SetNextCommand method – that is called by the Silverlight 4 client, where it traps a simple MouseLeftButtonDown event, which allows you only to select the next map – not the previous. ManipulationCompletedEvent seems not to be available in Silverlight 4. This is the only allowance I had to make to get the application to work from ‘plain’ Silverlight 4 as well.

Conclusion

This application is maybe somewhat unusual and still very limited - I don’t start any story board from the model showing fancy animations (which I would like to when the user swipes over the map title to select another map, but I have not found out yet how to do that). Still, I think it’s safe to say MVVM Light used in conjunction with attached dependency properties makes it possible to bind virtually anything, even a MultiScaleImage, to a model. In addition, it’s possible to reuse a lot – if not all – model code by linking source files form Windows Phone 7 libraries to Silverlight 4 libraries and vice versa which makes making applications that run both on Windows Phone 7 and Silverlight 4 (and in the near future, maybe even on Symbian) quite feasible. All in all, from an architectural standpoint, MVVM Light and attached dependency properties are a real winning team.

Credits, disclaimers and legal stuff

The algorithms for loading tiles from the Google servers and OSM are a slight adaptation from stuff to be found in the DeepEarth codebase on CodePlex, while the Bing algorithm actually comes from Microsoft itself. This code loads maps directly from Google Maps and Bing Maps servers bypassing any kind of licenses, TOSses and APIs, and is in this sense probably illegal. This is done for demonstration purposes only, to show how seamlessly the MultiScaleImage works together with multiple map servers. I do by no means encourage or endorse this code to be used other than in demo settings only, and will take no responsibility for any consequences if you choose to act otherwise. So beware. If you use the Google and Bing code in production settings, don’t come knocking on my door after the map owners have come around to kick in yours. :-P

I nicked the algorithm for dragging the map and calculating new positions somewhere from the internet, but for the life I cannot remember where, and since I heavily refactored it for use in dependency properties Google Bing cannot find it back either. If anyone recognizes his/her code and feels I shortchanged him/her in the credits, please let me know and I will correct ASAP.

11 June 2010

Making internals unit testable

When creating - or attempting to create ;-) - reusable components, it’s common practice to hide the gory details of your implementation – not only on class level, but also on assembly level. The drawback of this approach is that you cannot write unit tests to test low-level operations of your component – invisible to the world means invisible to your assembly with unit tests as well.

One approach is to make the component that is to be tested public after all – I admit I did it a couple of times in my wee days before I learned of this trick that actually dates back to .NET 2.0 if I am correct.

Let us assume you have a library MyCompany.GreatObjects.dll, in which you have a component MyCompany.GreatObjects.Internals.MyInternalComponent, and a test library in MyCompany.GreatObjects.Test.dll.

1. Strongly name your test project

Say what? No, I am getting older but I am still not senile (or at least no-one dared to tell me yet). If you don’t know what I mean with strong naming, follow the procedure described here. You might want to strongly name your project to be tested as well, when you are at it ;-) And then build your solution again.

2. Open a Visual Studio Command Prompt

Open the command prompt belonging to the version of Visual Studio you are currently using to develop and test your components. Navigate to the bin/debug subdirectory of your MyCompany.GreatObjects project.

3. Retrieve the public key of your component

Enter the following command:
sn –Tp MyCompany.GreatObjects.dll

This will give two answers – the first one, preceded by the text “Public key is” is the one you are after. It will span something like four and a bit lines and look like this:
0024000004800000940000000602000000240000525341310004000001000100dfb0f05568ca56
3e3ae7449a48d8060be86bc091a88e915a29270a43417aa82c73dea3184beab7e4dfdfca865380
dcda1d8ca2c472b5bd7f889a0f5e77d5ec0b9990a4ca03fb71c881a51585416b1e58be6da0875b
42a2d754911fbfa1daa60884c6a6ff14f636530e197c61310f622794b0f4fbd36ade16b9ea6fa3
b850febd

Copy that code into a text file and carefully remove all line breaks, so that all these characters end up in one line. Take care not to remove any other character or your name is mud.

4. Edit the AssemblyInfo.cs of the component project

This file sits in the “Properties” application folder of your MyCompany.GreatObjects project.  Add the following line (where does not matter, but the end is a logical place):
[assembly: InternalsVisibleTo("MyCompany.GreatObjects.Test, PublicKey=****")]
replace the **** by the actual value for the public key you retrieved – on one line.
Rebuild the MyCompany.GreatObjects project, and you are done. You can now test MyCompany.GreatObjects.Internals.MyInternalComponent and other objects marked as internal, of course - from MyCompany.GreatObjects.Test. But only from MyCompany.GreatObjects.Test. For the rest of the world the internals are still safely invisible.

Purists might say that you only need to test external behavior of your component, but I can think of plenty of scenarios in which you want to change the working of an internal piece of code and still want to be able to verify its behavior – internal or not.

Credits go to my colleague Valentijn Makkenze for pointing this out to me first

03 May 2010

Attached dependency properties for dummies

Recently I tried to make my first attached dependency property and it struck me as odd that I could find a lot of articles on dependency properties – but it still took me quite some time to piece together the how and the why. And basically they all parrot the same few samples. So I decided to try my own take on the subject.

So what is an attached dependency property, then?

It helped me a lot to think of an attached dependency property as being the property equivalent of an extension method. You basically attach a new property to an existing object. Without actually modifying the object definition.

What is it good for?

About the same as an extension method: you can add extra properties to existing objects, without having to go trough the hoopla of inheritance. Which is especially handy when inheritance is not possible, like in sealed objects. More importantly, these properties can play along in the WPF en Silverlight data binding. The most important application, as far as I am concerned, is that you can make something bindable that is not bindable out of the box. If some value(s) a GUI component can only be set by a method, you cannot use it from MVVM, for example. By making an attached dependency property that passes on the new value to said method you work around that. See below for how you make such a callback.

In fact, attached dependency properties is part of the magic of that makes Laurent Bugnion’s MVVM Light toolkit go, at least where the ButtonBaseExtensions class is concerned, and reading the code in this class actually (and finally) made the penny drop for me.

So how do you make an attached dependency property?

You make a static class, in which the property is declared and 'hosted', as I call it. The general form is like this:

public static class DependencyPropertyHoster
{
  public static readonly DependencyProperty MyPropertyNameProperty =
    DependencyProperty.RegisterAttached("MyPropertyName", 
    typeof(TargetPropertyType), 
    typeof(DependencyPropertyHoster), 
    new PropertyMetadata(CallBackWhenPropertyIsChanged));

  // Called when Property is retrieved
  public static TargetPropertyType GetMyPropertyName(DependencyObject obj)
  {
    return obj.GetValue(MyPropertyNameProperty) as TargetPropertyType;
  }

  // Called when Property is set
  public static void SetMyPropertyName(
     DependencyObject obj, 
     TargetPropertyType value)
  {
    obj.SetValue(MyPropertyNameProperty, value);
  }

  // Called when property is changed
  private static void CallBackWhenPropertyIsChanged(
   object sender, 
   DependencyPropertyChangedEventArgs args)
  {
    var attachedObject = sender as ObjectTypeToWhichYouWantToAttach;
    if (attachedObject != null )
    {
      // do whatever is necessary, for example
      // attachedObject.CallSomeMethod( 
      // args.NewValue as TargetPropertyType);
    }
   }
}
This is roughly the equivalent of
public partial class ObjectTypeToWhichYouWantToAttach
{
  TargetPropertyType _myPropertyName;
  TargetPropertyType MyPropertyName
 {
   get
   {
     return _myPropertyName;
   }
   set
   {
     if( _myPropertyName != value )
     {
        //CallBackWhenPropertyIsChanged...
     }
   }
  }
}

The whole thing works by naming convention. So if you call your property "MyPropertyName", then:

  • Your DependecyProperty needs to be called MyPropertyNameProperty
  • Your Set method needs to be called SetMyPropertyName
  • Your Get method needs to be called GetMyPropertyName
When you register your property the way I do, the members in the RegisterAttached method call are, from left to right:
  • The name of your property (as a string, yes)
  • Property value type (here “TargetPropertyType”, but of course that can be anything)
  • Type of the hosting class (i.e. DependencyPropertyHoster in this case)
  • Callbackmethod to be called when the property is changed.

How do you use it from XAML?

First, you need to declare its namespace and possibly its assembly. Suppose my class DependencyPropertyHoster was in namespace LocalJoost.Binders, and in a separate assembly called LocalJoost, I would need to declare it as

xmlns:MyPrefix="clr-namespace:LocalJoost.Binders;assembly=LocalJoost"
and if you want to use it in binding, you use
MyPrefix:DependencyPropertyHoster.MyPropertyName="{Binding whatever}" 

I am currently making a small mapping application using a MultiScaleImage for showing Bing Maps that heavily depends on this trickery. Stay tuned, an example of this will probably follow shortly.

But wait, where is the actual data stored if not in the object itself?

To be honest, I don’t really know. An explanation is provided in the first comment by Dennis Vroegop (thanky you!). But to be even more honest, for now I don’t really have to know. If it works, it works. That's the real beauty of abstraction :-)

Update: for the real lazybones, a code snippet

Unzip this file in your code snippet directory. You will find this in Libraries\Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets. From now on, if you type “adp” followed by a tab it will automatically insert an attached dependency property for you

27 April 2010

A very basic MEF sample using ImportMany

If you have been programming since the mid-80’s and have been a IT professional for over 17 years it does not happen often anymore that you get mesmerized by a beautiful piece of architecture, but recently it happened twice to me in a very short time, and one of the causes was the Managed Extensibility Framework or MEF. Almost everyone has built some or other extensible architecture at one point but never before I have seen something as simple, elegant and universally applicable as this.

This article describes the setup of a very basic MEF driven application, using VS2010 Pro and .NET 4. It’s kind of abstract: a hosting component that accepts two strings, and calls one or more MEF components to actually do the manipulation. Every component has its own library, which may seem a bit overkill, but I wanted to check out the extensibility to the max. So I started out with an empty solution and then used the following track

1. Create a class library "Contracts"
This will contain the interface IMyComponent by which the components communicate:
namespace Contracts
{
  public interface IMyComponent
  {
    string Description { get; }
    string ManipulateString(string a, string b);
  }
}

as you can see, one hell of a complex component we are making here ;-)

2. Create a class library "ImportingLib"
This will contain the host, i.e. the class that actually hosts and calls the components. Add a reference to the "Contracts" projects as well as to "System.ComponentModel.Composition". Then Add a class "Importer", with the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using Contracts;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.IO;

namespace ImportingLib
{
  public class Importer
  {
    [ImportMany(typeof(IMyComponent))]
    private IEnumerable<IMyComponent> operations;

    public void DoImport()
    {
      //An aggregate catalog that combines multiple catalogs
      var catalog = new AggregateCatalog();
      //Adds all the parts found in all assemblies in 
      //the same directory as the executing program
      catalog.Catalogs.Add(
       new DirectoryCatalog(
        Path.GetDirectoryName(
         Assembly.GetExecutingAssembly().Location)));

      //Create the CompositionContainer with the parts in the catalog
      CompositionContainer container = new CompositionContainer(catalog);

      //Fill the imports of this object
      container.ComposeParts(this);
    }

    public int AvailableNumberOfOperations
    {
      get
      {
        return (operations != null ? operations.Count() : 0);
      }
    }

    public List<string> CallAllComponents( string a, string b)
    {
      var result = new List<string>();
      foreach( var op in operations )
      {
        Console.WriteLine(op.Description);
        result.Add( op.ManipulateString(a,b ));
      }
      return result;
    }
  }
}

This deserves some explanation. This host imports 0 or more (ImportMany) components implementing IMyCompoment - and wants them delivered into the private property operations, thank you. The method "DoImport" can be called to initialize this object - Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location) gives the directory in which the executing assembly (i.e. the program or the test) project resides, and by creating a DirectoryCatalog on that directory and then adding that to the main AggregateCatalog you make MEF automatically start searching all the assemblies in the directory where the calling program resides. Property AvailableNumberOfOperations of the Importer returns the number of found operations, and CallAllComponents calls all the IMyComponent exporting components and returns the result in one go.

To prove this actually works, we continue:

3. Create a class library "ExportingLib1"
Add a reference to "Contracts" and "System.ComponentModel.Composition", then add a class "TestComponent1" with the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Contracts;
using System.ComponentModel.Composition;

namespace ExportingLib1
{
  [Export(typeof(IMyComponent))]
  public class TestComponent1 : IMyComponent
  {
    #region IMyComponent Members
    public string Description
    {
      get { return "Concatenates a and b"; }
    }

    public string ManipulateString(string a, string b)
    {
      return string.Concat(a, b);
    }
    #endregion
  }
}

as you can see, this utterly exiting class exports IMyComponent, delivers a description of itself and concatenates the two strings to 1

4. Create a class library "ExportingLib2"
Add a reference to "Contracts" and "System.ComponentModel.Composition", then add a class "TestComponent2" with the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Contracts;
using System.ComponentModel.Composition;

namespace ExportingLib2
{
  [Export(typeof(IMyComponent))]
  public class TestComponent2 : IMyComponent
  {
    #region IMyComponent Members
    public string Description
    {
      get { return "Removes b from a"; }
    }

    public string ManipulateString(string a, string b)
    {      
      return a.Replace(b, string.Empty);
    }
    #endregion
  }
}
Again, a very complex class ;-), this time it removes all occurrences from b in a.

5. Create a test project "ImportingLib.Test"

Add references to ImportingLib, ExportingLib1 and ImportingLib2 and add the following test methods:

[Test]
public void TestCountComponents()
{
  var t = new Importer();
  t.DoImport();
  Assert.AreEqual(2, t.AvailableNumberOfOperations);
}

[Test]
public void TestOperations()
{
  var t = new Importer();
  t.DoImport();
  var result = t.CallAllComponents("all are equal ", "all");
  Assert.IsTrue( result.Contains( "all are equal all"));
  Assert.IsTrue( result.Contains( " are equal "));
}
If you followed my ‘recipe’ correctly, both tests will succeed. In addition, since you have added a Console.WriteLine in the CallAllComponents method, on the standard console output you will see "Concatenates a and b" and "Removes b from a", indicating the components that have been called. As you see, nowhere in code the components are actually instantiated - this is all done by MEF. The fun thing is, just by removing the reference to either ExportingLib1 or ExportingLib2 you can make the test fail. Nowhere are any explicit links between host and components but in the actual calling program itself, and those links are only made by the very presence of an assembly in the directory of the current executing program, or in this case, the test project.

So, you can dump more assemblies exporting IMyComponent - and the host will automatically pick them up. #Thatwaseasy

Parts of this sample are based on this description

Update 06-07-2012: I've added a full demo solution to this post to show how things are put together

01 April 2010

Caveats when migrating existing CLSA.NET objects to Silverlight

So you have been working for a while with CSLA .NET by Rockford Lhotka and now you want – like me – jump on the Silverlight bandwagon. So you want to reuse the business objects in Silverlight. There are some nice samples in the cslalight samples but when I started to try to use my own business objects, things did not run so smoothly as the samples suggest.

The samples by Rockford show the general outline:

  • You make a second assembly into which you add the exisiting business class source files as a link
  • You start adding specific Silverlight functionality surrounded by
    #if SILVERLIGHT (…) #endif preprocessor directives
  • You make sure that the server stuff like data access is not active in the Silverlight configuration (#if !SILVERLIGHT)
  • You add a Silverlight-specific factory method to load an object, that looks a bit like this:
public static void Get(int id, 
  EventHandler<DataPortalResult<MyBusinessClass>> callback)
{
  var dp = new DataPortal<MyBusinessClass>( );
  dp.FetchCompleted += callback;
  dp.BeginFetch( new IdCriteria(id) );
}

If you try to call this from your Silverlight client the result is - unless you are very lucky - most likely that the sky starts caving in. Turns out there are a few 'hidden requirements' –or at least some less apparent ones. Maybe there are more, but this was what I found so far:

  • Both the Silverlight and the full framework assemblies must have the same name, so even if your projects are called MyLib.Server and MyLib.Client, the resulting dll’s must have the same name, for example MyLib.dll.
  • If your full framework assembly is signed, your Silverlight assembly should be signed as well. They then also must have the same version number – all the way to the build number. This is important – and it took me the most time before the penny dropped.
  • All the Silverlight classes must have public constructors. So you add
#if! SILVERLIGHT   
  private MyBusinessClass()
  {
  }
#else
  public MyBusinessClass()
  {
  }
#endif
  • Properties should be defined in the ‘modern’ format. You have still properties in this format?
private string _oldProp = string.Empty;

public string OldProp
{
  get
  {
    return _oldProp;
  }	 
  set
  {
    if (value == null) value = string.Empty;
    if (!_oldProp.Equals(value))
    {
      _oldProp = value;
      PropertyHasChanged("OldProp");
    }
  }
}
Tough luck. Change that into the 'new' form, e.g.
private static PropertyInfo NewPropProperty = 
  RegisterProperty(c => c.NewProp);
public string NewProp
{
	get { return GetProperty(NewPropProperty); }
	set { SetProperty(NewPropProperty, value); }
}
  • Criteria objects should have public constructors as well, and should be public classes – that is, if you have defined them as private classes inside your business object, you should make them public
  • Your Criteria should implement IMobileObject. The easiest way is to let your class descend from CriteriaBase, but then you will find out that although the class is serialized to the server, the properties are not. Turns out that for Criteria objects the property format has changed too. In the past you could just make a simple class with a few getters and setters, now you have to make something along this line:
[Serializable]
public class IdCriteria : CriteriaBase
{
  public static PropertyInfo<int> IdProperty = 
    RegisterProperty(typeof(IdCriteria), new PropertyInfo<int>("Id"));
  public int Id
  {
    get { return ReadProperty(IdProperty); }
    set { LoadProperty(IdProperty, value); }
  }
  public IdCriteria() { }

  public IdCriteria(int id)
  {
    Id = id;
  }
}

So, although CLSA ‘light’ promises a lot of reuse (which is true of course, in the case of business and validation rules) you need a lot of extra plumbing to get going. And mind you, this is a simple single object that I only read – I haven’t covered lists yet, nor updates and deletes. The power of CSLA can come to Silverlight – but certainly for existing libraries it is not quite a free ride. But then again - this is Silverlight, so it should run on Windows Phone 7 series as wel... which will be my next experiment. I will keep you posted!

01 March 2010

Running CSLALight 3.8.2 under .NET 4 and Silverlight 4

Update December 23, 2013: this is article is pretty much outdated. Currently it gets a lot of traffic. I hope some people reading it would like to leave a comment and tell me WHY the are reading it

CSLA .NET by Rockford Lhotka is a business layer framework, but it does not run under .NET4 and Silverlight 4 yet. Fortunately this framework comes with sources, and I set out to get a simple sample application to run under Silverlight 4. As always, it is a lot more work to find out what to do than to actually do it, but eventually I was successful. To make life for those who want to follow me a little harder: I am using Visual Studio 2010RC and the Silverlight 4 tools beta. I know those are not supposed to work together, but if you follow this procedure you actually can run Silverlight 4 tools inside the RC. This procedure, however, included hacking an installer and then editing some registry keys. Follow this procedure at your own risk. It worked for me, but maybe the procedure for getting CSLA to run under .NET 4 and Silverlight 4 may work under VS2010 B2 as well.

1. Download these files
  • cslalightcs-3.8.2-100201.zip
  • lightsamples-3.8.2-100201.zip

Which can all be found on the CSLA.NET site.

2. Unzip the files in working directories

The net result should be something like this
CSLA
  - clsacs
  - clsalightcs
  - Dependencies
  - README.txt
LightSamples
  - cslalight
  - readme.txt

3. Compile clsacs.sln for .NET 4.0
  • Start Visual Studio 2010, and open the solution clsacs.sln in CSLA\cslacs.
  • Let Visual Studio 2010 convert the project
  • right-click the csla project, select properties and change the target framework to .NET 4.0
  • Change the active solution configuration to “Release”
  • Rebuild the solution. This will give some errors. If you check the clsa project’s references, you will see warning signs indicating missing assemblies, which are:
    • PresentationCore
    • PresentationFramework
    • System.Printing
    • System.Runtime.Serialization
    • System.ServiceModel
    • System.Workflow.Runtime
    • WindowsBase
  • Remove these references and replace them by their .NET 4.0 brethren.
  • Add a reference to System.Xaml
  • Rebuild the solution. You will get a whole lot of warnings but CSLA will compile.
4. Compile cslalightcs.sln for Silverlight 4
  • Start Visual Studio 2010, and open the solution clsalightcs.sln in CSLA\cslalightcs.
  • Let VS2010 convert the project
  • right-click the Cslalight project, select properties and change the Target Silverlight Version to 4.0
  • Add a reference to System.Net
  • Change the active solution configuration to “Release”
  • Rebuild the solution. Once again, a whole lot of warnings but CSLAlight will compile

5. Convert and compile the SimpleApp sample

If you browse into LightSamples\cslalight\cs\SimpleApp with the Windows Explorer you will find a simple CSLA/CSLA light solution that demonstrates the basic setup of the CSLA data portal for Silverlight. We will convert this application to work under our freshly created CSLA and CSLALight libraries.

  • Open the SampleApp.sln solution with Visual Studio 2010
  • Let Visual Studio 2010 convert the solution
  • Click “Yes” to upgrade to .NET 4.0 and ignore further errors
  • The solution contains 4 projects.
    • Set the Target Silverlight Version of Library.Client and SimpleApp to Silverlight 4
    • Set the target framework for Library.Server to .NET 4.0. No need to change SimpleApp.Web, Visual Studio has already done that
  • In project Library.Client:
    • Check the references. You will find “Csla” missing.
    • Remove the reference
    • Click Add Reference/Browse
    • Browse to CSLA\cslalightcs\Csla\ClientBin.
    • Add References to Csla.dll and System.Windows.Interactivity.dll
  • Repeat the procedure for SimpleApp
  • In project Library.Server:
    • Check the references. You will find “Csla” missing.
    • Remove the reference
    • Click Add Reference/Browse
    • Browse to CSLA\cslacs\Csla\bin\Release
    • Add a Reference to Csla.dll
  • Repeat the procedure for SimpleApp.Web.

6. Change the ServiceReferences.ClientConfig

This actually took me the longest, because I did not understand the problem. If you run the application (right click SimpleApp.Web/SimpleAppTestPage.aspx and click “View in Browser”), enter some values “for “Name” and “City” and hit “Save” you get an error indicating that there is no endpoint for contract “WcfPortal.IWcfPortal”.

Apparently something has changed in how Service Contracts are referenced in Silverlight 4. The solution turns out to be this:

  • open the ServiceReferences.ClientConfig file in the SimpleApp project
  • Locate the text contract="Csla.WcfPortal.IWcfPortal" 
  • Remove the “Csla.” prefix, including the dot, so that only contract="WcfPortal.IWcfPortal" remains
  • Run SimpleApp.Web/SimpleAppTestPage.aspx again

Hit some values for “Name” and “City” again, hit “Save” and the text “Inserted Client” appears. You can set some breakpoints to see CSLA actually goes back to the server for that. And, of course, you can right-click on the Silverlight application, click “Silverlight” on the ‘context menu’ and see that actually runs under Silverlight 4

This of course guarantees by no means that all the features of Csla will work under Silverlight 4 but at least we can go forward playing around in this new environment.

28 February 2010

Injecting logic in the middle of an algorithm using “Func<T>” function parameters

Sometimes you run into a situation in which you have a very similar complex pieces of logic, that only differ somewhere deep inside. This happens especially when you are dealing with legacy code that requires all kinds of weird initializers. Consider the following example, which is similar to something I ran into deep down in a CSLA library:

private void DataPortal_Fetch(string a, string b, string c)
{
  var helper = new LoaderHelper();
  helper.Init();
  LegacyObjectCollection result = 
OldStaticHelper.GetByThreeStrings( a, b, c); IsReadOnly = false; result.ForEach(p => Add(SomeNewObject.Get(p, helper))); RaiseListChangedEvents = false; IsReadOnly = true; } private void DataPortal_Fetch(string a, int n) { var helper = new LoaderHelper(); helper.Init(); LegacyObjectCollection result = OldStaticHelper.GetByOtherKeys( a, n); IsReadOnly = false; result.ForEach(p => Add(SomeNewObject.Get(p, helper))); RaiseListChangedEvents = false; IsReadOnly = true; }

The idea clearly was to call some legacy code and transform this into a list of “SomeNewObject”. But the annoying thing about the legacy code was that all kinds of helpers needed to be initialized before OldStaticHelper could be called. And then the logic of transforming the data had been duplicated as well. There are a number of ways to refactor this, but because I was fooling around with functional programming concepts at the time, I tried the following, which almost worked:

private void DataPortal_Fetch(string a, string b, string c)
{
  FetchData(OldStaticHelper.GetByThreeStrings( a, b, c)); 
}

private void DataPortal_Fetch(string a, int n)
{
  FetchData(OldStaticHelper.GetByOtherKeys( a, n));
}

private void FetchData(Func<LegacyObjectCollection> loaderMethod)
{
  var helper = new LoaderHelper();
  helper.Init();
  LegacyObjectCollection result = loaderMethod();
  IsReadOnly = false;
  result.ForEach(p => Add(SomeNewObject.Get(p, helper)));
  RaiseListChangedEvents = false;
  IsReadOnly = true;
}

Although this compiled an ran, it did not work as expected. Upon calling “FetchData” the OldStaticHelper.GetBy… method was instantly executed, in stead of of when “result = loaderMethod()” was called. And I just stated that it would not work unless the “helper” code was initialized. Thus, I needed to use delegates:

private void DataPortal_Fetch(string a, string b, string c)
{
  FetchData(() => OldStaticHelper.GetByThreeStrings( a, b, c)); 
}

private void DataPortal_Fetch(string a, int n)
{
  FetchData(() => OldStaticHelper.GetByOtherKeys( a, n));
}
Or, for those not familiar with the lambda syntax:
private void DataPortal_Fetch(string a, string b, string c)
{
  FetchData(delegate { return OldStaticHelper.GetByThreeStrings( a, b, c)}); 
}

private void DataPortal_Fetch(string a, int n)
{
  FetchData(delegate { return OldStaticHelper.GetByOtherKeys( a, n)});
}
Using this technique you can 'inject' a piece of logic into a larger algorithm, eliminating the need to duplicate code or making all kinds of in-between data sets