Sunday, November 7, 2010

From DataTable to DataContract

For the last four months, I have been very busy porting a large SaaS application from the traditional ASP .NET + Ajax platform to Silverlight 4. This application has a quite standard architecture with a data access layer that talks to the database and exposes a simplified interface to the business level. When a piece of data is required, you just need to call a given method with the appropriate parameters and you usually get back a DataTable object with all the data you need. This is a very flexible scenario because you can directly bind to an ASP .NET control or, if you need to further massage the data, transform the data in memory before binding it.

This architecture became a bit of a problem when I started to port the application to Silverlight because it just does not understand ADO .NET, so it is useless to try to marshal a DataTable object through a WCF web service. Because we needed to keep the "old" ASP .NET application running, there was no point in rewriting the old DAL code so a decision was made to keep it and reuse it as a data source for the new WCF web services. This meant writing a lot of boring code to implement the new DataContract classes. When you create a Silverlight-enabled WCF web service, you must send and receive all your data through strongly-typed classes that are very neatly marshalled over between the two endpoints.

I tackled this issue by starting to write all the new DataContract code by hand... until I got bored. The process is incredibly boring, time-consuming and error-prone. After a few weeks at it, I found out that writing all the WCF plumbing was taking a large portion of every ported feature, so this needed a closer look. What could I do to help me bridge the gap between the existing, tried and true DataTables and the new DataContracts?

A code generator.

The idea is quite simple: plug in a piece of code that takes either the freshly-created DataTable (or DataView) and generates a text file containing C# code that declares two DataContracts: one for each row and another for the whole list of rows. Oddly, this code must run on your web server, so it is best suited for your development environment only. To make my life easy, I created a single extension method to the DataTable and DataView classes that you use like this:

dataTable.WriteListDataContract("SingleRowClassName", @"C:\Path", "ID");

The first parameter is the row class name: the extension will automatically generate the corresponding list class name by appending the "List" string to this class name. The second parameter contains the path of the generated file name (based on the first parameter). The last parameter is an optional string containing a comma seperated list of columns that you want to force as non-nullable (the code will throw an exception when trying to convert a DBNull.Value).

Once you have the generated code files, you can comment out the line.

Using the generated code is very straightforward: just paste it in your WCF source code file. Reuse your old DAL code and, when you have the DataTable or DataView ready, create a list class and call its Load method. The generated code reads in the data and converts it into a generic list that you can immediately return to your Silverlight application.

Here's the source code: DataTableExtensions.cs

2 comments:

  1. Great information and code... would you mind posting a all up sample?

    For example a simple WCF project which get's a datatable (fake data) from a DB which supports both the existing clients and the new SL clients using the generated code?

    ReplyDelete
  2. I'm preparing a post to illustrate this...

    ReplyDelete