Using Converters Instead of Custom Client Properties with Silverlight and ADO.NET Data Services

by brad 23. September 2009 11:37

One challenge with ADO.NET Data Services is that it has trouble understanding what’s going on if you add custom properties to your entities on the client side.  This post will explain using converters to overcome that challenge when using Silverlight.  Or WPF, I suppose.

Background

When you add a reference to an ADO.NET Data Service, Visual Studio generates a set of client classes that represent the entities on the server.  These classes are tantalizing marked as partial, which could lead you to believe that you are welcome to add additional client-only properties to these classes.

   1: [global::System.Data.Services.Common.DataServiceKeyAttribute("Id")]
   2: public partial class Employee
   3: {
   4: }
 
However, if you extend the partial class to add a property, ADO.NET Data Services will be grumpy when you try to save your object since it won’t know what to do with the extra property.

Let’s say that we want to add an extra property to our Employee class called “HasCornerOffice” that returns “true” if the employee has “VP” in their title.  Something like this.

   1: public partial class Employee 
   2: {
   3:     public bool HasCornerOffice 
   4:     {
   5:         get { return this.Title.StartsWith("VP");  }
   6:     }
   7: }

When you try to save an instance of an employee back to the database, you’ll get an error along the lines of “Error processing request stream. The property name ‘HasCornerOffice’ specified for type ‘Employee’ is not valid.”  ADO.NET Data Services has no idea what the property is all about and is letting us know.

Some Solutions

There are a few ways around this. 

You could use a brand-new client-only class that can be mapped to and from Employee.  Adding this layer of abstraction could make a lot of sense and add some insulation between your client and server that could come in handy later.  Not a bad way to go for the trade-off of writing and maintaining the mapping code to back and forth between the client and server objects.

You could also customize the way that objects are serialized by digging into the bowels of the data context and intercepting the ATOM request before it is send to the server.  Not sure what this would do if you were using JSON, but this blog post has the details for wiring it up with an ATOM request.

Using Convertors

An alternate quick and easy solution is to leave the client-side entities as-is and use a converter to transform our Employee data into the data that we want to display.  This has the advantage of being straightforward and low-impact, but is maybe not as flexible or extensible long-term as the two solutions above.

Using the same Employee example as above, our Converter would look like this.

   1: public class CornerOfficeConverter : IValueConverter
   2:  {
   3:      public object Convert(
   4:          object value, 
   5:          Type targetType, 
   6:          object parameter, 
   7:          CultureInfo culture)
   8:      {
   9:          if (string.IsNullOrEmpty(value as string))
  10:          {
  11:             return false;
  12:          }
  13:  
  14:          return value.ToString().StartsWith("VP");
  15:      }
  16: }

And we could bind to it like this.

   1: <TextBlock 
   2:     Text="{Binding Title, 
   3:            Converter={StaticResource TitleConverter}}" />

Conclusion

Hopefully, this shortcoming in ADO.NET Data Services will be resolved in the framework itself in the next version or so, but in the meantime, those are some ideas of how to work around the problem.

Tags:

Comments are closed

About Brad

Brad Tutterow lives in Illinois and works in Missouri. He has 12 years of experience developing web sites and Windows applications using a variety of technologies and is most excited currently about Silverlight, Windows Phone 7, Halo Reach, and Visual Studio 2010.