January 2009 - Posts
Error handling code can be a drag but the simple fact is that everyone needs to write it because runtime errors can and do occur. Developing a Silverlight app is no different here, exceptions will occur and you as a developer will need to deal with them.
One of the common things in Silverlight is communicate with a server through WCF and as soon as we start executing code on the server that is just another place where errors can occur. No big deal you might think as that is the same with any other application using WCF. Well the fact that it will also happen in other applications is certainly true but unfortunately the way Silverlight communicates with a WCF service makes live a bit more difficult.
But wait, WCF supports a FaultContract so we can just return exceptions as faults right?
Wrong 
Unfortunately the Silverlight WCF stack doesn’t support a service contract with a fault contact and just adding the FaultContract attribute will make the service unusable for Silverlight clients. Even when no faults are returned 
So the standard WCF faults are out, what else?
Well can’t we just throw an exception and have that resurface in the Silverlight client? Unfortunately we can’t. Even though the server WCF stack returns the exception just fine, see the Fiddler output, the browser will not pass the information on to the client and inside of Silverlight all we see is a CommunicationException with the very helpful message “The remote server retuned an error: NotFound”. Less than useful 
So this code will not work
[OperationContract]
public IList<Customer> GetCustomersWithException()
{
IList<Customer> result = GetCustomers();
throw new FaultException<ArgumentException>(
new ArgumentException("This is my error text."));
return result;
}
So is there no solution?
Well there are a few examples out there that tag an Error property onto the data returned. Guess that works but I kind of don’t like it for a few reasons:
- It means you cannot have a simple return value, it must always be a more complicated custom type.
- You are mixing good and bad data into the same object and presumably only a single set will be filled.
- It therefore breaks the single responsibility rule.
So a better solution would be to return two items instead of one.
Turns out we can use out parameters with WCF and they will be wrapped just fine into the return message. So we can return the error information using an out parameter. Great, feels like a much better design 
So my first thought was to send the exception as the out parameter and the Silverlight client would get all error information that way. Turns out that didn’t work all that well. Even though the error was passed to the client the message shown in the client was always the default message and not the one actually send. And a second problem was that the parameter type had to mach the exact exception passed. using the KnownType attribute didn’t help there.
So instead of sending the original exception I decided to create a small wrapper type, MyFaultContract, that would pass the exception type and message to the Silverlight client. This info should be more than enough in most cases.
The service operation now looks like this.
[OperationContract]
public IList<Customer> GetCustomersWithCustomError(out MyFaultContract myFault)
{
IList<Customer> result = null;
myFault = null;
try
{
result = GetCustomersWithException();
}
catch (FaultException<ArgumentException> ex)
{
myFault = new MyFaultContract()
{
FaultType = ex.Detail.GetType().FullName,
Message = ex.Detail.Message
};
}
return result;
}
With the following custom MyFaultContract
[DataContract]
public class MyFaultContract
{
[DataMember]
public string FaultType { get; set; }
[DataMember]
public string Message { get; set; }
}
So what does our client code look like with this extra fault contract?
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Service1Client proxy = GetService1Client();
proxy.GetCustomersWithCustomErrorCompleted += (s, arg) =>
{
if (arg.Error != null)
ErrorText.Text = arg.Error.GetType().FullName +
"\n" + arg.Error.Message;
else if (arg.myFault != null)
ErrorText.Text = arg.myFault.FaultType +
"\n" + arg.myFault.Message;
else
DataContext = arg.Result[0];
};
proxy.GetCustomersWithCustomErrorAsync();
}
Not bad. It does take an extra check as we have to check both the Error and myFault properties for errors but other than that it is exactly the same.
So not a perfect solution but it works well enough for most purposes!
Enjoy!
Part 1
Part 2
Part 3
Part 4
Using the Silverlight Unit Test Framework it isn’t just possible to unit test regular code we we can also start to unit test user interface controls we create. Doing so is very similar to the asynchronous unit test we created before, just like those test we derive our test class from the SilverlightTest base class and decorate our test both with the Asynchronous and the TestMethod attribute.
First we need a user interface control to test. Just for demonstration purposes I created a very simple control to add URL’s to a collection. The XAML looks like this:
<UserControl x:Class="SilverlightApplication1.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel>
<TextBox x:Name="txtPhotoUrl" TextChanged="txtPhotoUrl_TextChanged" />
<Button x:Name="cmdAdd" Click="cmdAdd_Click" Content="Add" IsEnabled="False" />
</StackPanel>
</UserControl>
And the code behind class like this:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication1
{
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
Photos = new List<string>();
}
public IList<string> Photos { get; set; }
private void cmdAdd_Click(object sender, RoutedEventArgs e)
{
string url = txtPhotoUrl.Text;
Photos.Add(url);
}
private void txtPhotoUrl_TextChanged(object sender, TextChangedEventArgs e)
{
string url = txtPhotoUrl.Text ?? "";
Uri uri = new Uri(url);
if (string.IsNullOrEmpty(url))
cmdAdd.IsEnabled = false;
else if (string.IsNullOrEmpty(uri.Scheme))
cmdAdd.IsEnabled = false;
else if (uri.Scheme != "http")
cmdAdd.IsEnabled = false;
else
cmdAdd.IsEnabled = true;
}
}
}
The code is a bit of an oversimplification but good enough to show how to unit test this control. Basically the textbox lets us add a new photo URL and when a valid photo URL has been entered the command button should be enabled so it can be added to the collection. What is a valid photo URL? Well simply any URL starting with http: 
Our first test
The first test is to create the control and make sure the command button is enabled when a valid photo URL is entered. Like in the previous posts we need to create a Silverlight test project and set it up to use the Silverlight Unit Test Framework. See the previous posts on how to do that.
Next we need to make sure out test class derived from Microsoft.Silverlight.Testing.SilverlightTest. This is the class that will allow us to do asynchronous work and add controls to the test surface.
Adding the control to the test surface is easy. As I am using the control in every test I did so in a setup method decorated with the TestInitialize attribute as follows.
[TestClass]
public class Test1 : Microsoft.Silverlight.Testing.SilverlightTest
{
private MyControl _myControl;
[TestInitialize]
public void TestSetup()
{
_myControl = new MyControl();
TestPanel.Children.Add(_myControl);
}
The test to actually add a photo to the collection looks like this:
[TestMethod]
[Asynchronous]
public void TestWeCanAddAValidUrl()
{
TextBoxAutomationPeer textBoxPeer = new TextBoxAutomationPeer(_myControl.txtPhotoUrl);
IValueProvider valueProvider = (IValueProvider)textBoxPeer;
ButtonAutomationPeer buttonPeer = new ButtonAutomationPeer(_myControl.cmdAdd);
IInvokeProvider buttonInvoker = (IInvokeProvider)buttonPeer;
EnqueueCallback(() => valueProvider.SetValue("http://farm4.static.flickr.com/3085/3092376392_dc1aaf9eb6.jpg"));
EnqueueConditional(() => buttonPeer.IsEnabled());
EnqueueCallback(() => buttonInvoker.Invoke());
EnqueueTestComplete();
}
There are a number of interesting things to note here. First of all I need to get a reference to the textbox and button control. These are declared as internal so by default I cannot get to them. However my adding the [assembly: InternalsVisibleTo("SilverlightTest")] attribute to the original project the test project will be able to see internal memebers as well as public members. Thus we can see the two controls.
Next I use the AutomationPeer objects to interact with the controls instead of doing so directly. These AutomationPeer objects are intended for alternative user interaction, for example a Braille screen reader, and allows us to mimic the UI better than by just calling the same method. For example I could just call the cmdAdd_Click() function if I hade made this public or internal but this doesn’t check if the button is enabled or not. The ButtonAutomationPeer will check and throw a ElementNotEnabledException if the button is not enabled.
Another thing to note is that I am using the asynchronous EnqueueCallback() and EnqueueConditional() methods to do the actual work. Finally I use the EnqueueTestComplete() function to end the test.
Adding a negative test
Just like the previous test produced a positive result we want to check if an invalid URL stops us from clicking the button and adding the URL to the list. This can be done using the following code.
[TestMethod]
[Asynchronous]
[ExpectedException(typeof(ElementNotEnabledException))]
public void TestTheButtinIsDisabledWithALocalUrl()
{
TextBoxAutomationPeer textBoxPeer = new TextBoxAutomationPeer(_myControl.txtPhotoUrl);
IValueProvider valueProvider = (IValueProvider)textBoxPeer;
ButtonAutomationPeer buttonPeer = new ButtonAutomationPeer(_myControl.cmdAdd);
IInvokeProvider buttonInvoker = (IInvokeProvider)buttonPeer;
EnqueueCallback(() => valueProvider.SetValue(@"file:c:\images\3092376392_dc1aaf9eb6.jpg"));
EnqueueCallback(() => buttonInvoker.Invoke());
}
Again like the previous time I am setting the textbox to a photo URL. Only in this case we have entered a local URL with the FILE: scheme instead of the required HTTP: scheme so the add button should remain disabled. We can test this by just invoking the button and specifying in test that it should expect an ElementNotEnabledException during the execution.
Conclusion
Unit testing UI elements is always hard and takes a lot of maintenance so something that is usually not the best way to test your complete application. However using the Silverlight Unit Test Framework it is quite doable for small controls and I guess a unit test should be about testing a small thing anyway 
Enjoy!
Today I installed Windows 7 on one of my laptops. Not my main machine, I am not quite ready to take the leap yet, but on a second smaller and newer tablet I carry around more often. First impressions are good! It seems to be as people are saying the OS Vista should have been.
Installing Windows 7 was done in no time at all. I used this tip to create a bootable partition on my PDC and install it that way, worked like a charm and was done in no time. Next was installing VS2008 with service pack 1. No problems but it did take a long long time
.
If you get started this blog post by Tim Sneath is worth reading. He lists a bunch of useful tips and points to quite a few features that are useful but you might not discover all that quickly. Useful tips include using Win+1/5 to start programs or using shift click (of the middle button) to start a second copy of a program.
I will post more when I have been running Windows 7 for a while.
For some reason we Duchies have a national obsession with ice skating on natural ice. I never go skating in a skating ring on artificial ice but when the lake freezes over I can't really resist and must skate. Guess that is what happens when you live on the waterfront 
Here is me skating out behind the house

Here is another near the lake.

And it was really nice skating weather too! Maybe some more tomorrow before I head out to the airport for a week in London teaching Essential Windows Workflow Foundation.
When developing Silverlight line of business (LOB) applications we often need to get at some data from a database. There are various ways to do so. One option that is easy to get started with with is creating an ADO.NET Entity Data Model (EDM) and exposing that entity model using an ADO.NET Data Service.
Getting started
The first thing we need to create is an ASP.NET Web Application. This is basically going to act as a container for our Data Service and our Silverlight LOB application. As you can see below I named the Web Application SLDataService.
Next we need to add the ADO.NET Entity Data Model. I already have a Northwind SQL Server database on my machine and that is the database I am going to expose to I am naming the EDM Northwind.edmx.
When the popup ask if I want to create a new EDM based on an existing database or start from scratch I selected the existing database option and pointed it at my Northwind database. This lets me select the tables I want to import. In this case I am only interested in the Customers table so that is what I am importing. By default the class name will be the same as the table name, i.e. Customers, but as Customer is a more logical name I removed the training “s”.
Next step is creating the ADO.NET Data Service to publish the entity model. Add another item to the project, this time choosing an ADO.NET Data Service and naming it Northwind.svc.
If we open the Northwind.svc.cs file we need to enter a few details before we can proceed. The first thing we need to enter is EDM class name we are going to expose. In this case that is the NorthwindEntities model. Next we need to allow callers to access the EDM. By default nothing is exposed to this is a crucial step that needs to be done in the InitializeService() function! In this case I am going to allow everything, maybe not the best solution in real live 
public class Northwind : DataService<NorthwindEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
}
}
Testing our data service
Now we should be able to test our ADO.NET Data Service in the browser. Start the project and you should see the following in the browser.
Navigate to the following URL http://localhost:4163/Northwind.svc/CustomerSet by adding CustomerSet and you should see the following customer data.
If you see an RSS feed instead of the XML go into settings and disable the feed reading view. BTW the reason the customers data is showing up as an RSS feed is because the ADO.NET Data Services uses the ATOM feed format to transmit its data using a REST approach.
Creating a Silverlight LOB client
The next step is to create a Silverlight client application to consume and display the data. Add a new project the solution of type Silverlight Application and name it SilverlightClient.
When prompted just accept the defaults and add the Silverlight application to the existing SLDataService app. Next we need to add a service reference to the Northwind ADO.NET Data Service. Call it NorthwindService.
Next we need to set up a bit of a user interface to display the list of customers. I kept this really simple and used a ListBox with a DataTemplate like this:
<UserControl x:Class="SilverlightClient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="500" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<ListBox x:Name="lstCustomers">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding CompanyName}" Width="250" />
<TextBlock Text="{Binding City}" Width="100" />
<TextBlock Text="{Binding Country}" Width="100" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
The final step is to load the data from the service and bind this to the ListBox. To do that we need to create an DataServiceContext object of type NorthwindEntities. Unlike a regular service reference the DataServiceContext does not know its own URL by default and we need to be given the URL where the web service is located. Easy enough using the URL of the current page, loaded using HtmlPage.Document.DocumentUri, and the name of the service, Northwind.svc in this case.
Uri uri = new Uri(HtmlPage.Document.DocumentUri, "Northwind.svc");
NorthwindEntities context = new NorthwindEntities(uri);
Using this context object we can do a LINQ query to load some data. Pretty standard stuff except that the asynchronous nature of Silverlight changes the actual loading of the data a bit. Normally you would expect to do something like:
var query = from cust in context.CustomerSet
select cust;
lstCustomers.ItemsSource = query.ToList();
In this case that won’t work and will only result in an System.NotSupportedException with the following message "Specified method is not supported.".
The correct way of doing this is by using a DataServiceQuery object which can load the data asynchronously as follows:
var query = from cust in context.CustomerSet
select cust;
var dsQuery = (DataServiceQuery<Customer>)query;
dsQuery.BeginExecute(
result => lstCustomers.ItemsSource = dsQuery.EndExecute(result),
null);
And the final result looks like this
Not bad at all 
The complete code behind looks like this:
using System;
using System.Data.Services.Client;
using System.Linq;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using SilverlightClient.NorthwindService;
namespace SilverlightClient
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
Uri uri = new Uri(HtmlPage.Document.DocumentUri, "Northwind.svc");
NorthwindEntities context = new NorthwindEntities(uri);
var query = from cust in context.CustomerSet
select cust;
// This doesn't work and will throw an System.NotSupportedException!
// lstCustomers.ItemsSource = query.ToList();
var dsQuery = (DataServiceQuery<Customer>)query;
dsQuery.BeginExecute(
result => lstCustomers.ItemsSource = dsQuery.EndExecute(result),
null);
}
}
}
Visual Studio project sampe code
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu