Data Transfer using WCF
February 19, 2013 Leave a comment
So forgetting OData for a minute (not hard to do), I was thinking about how to transfer SDO classes to and from a WCF service. All of the WCF projects I have worked on have been POCOs with the appropriate WCF attributes from System.ServiceModel and System.Runtime.Serialization. I never thought about putting an ADO.NET recordset as a return value from a WCF method. I also wondered about putting the recordset as a parameter to a WCF method. I assume it is possible, I was curious about how much effort it would take. I Binged on Google (or was it Googled on Bing) and these was nothing that jumped out.
I fired up a typical WCF project and then added a consuming console app to the solution. I then wrote an interface that returns a dataTable like so:
[ServiceContract] public interface IDataFactory { [OperationContract] DataTable GetDataTable(); }
public class DataFactory : IDataFactory { public DataTable GetDataTable() { throw new NotImplementedException(); } }
I then hit F6 and sure enough it compiled. I then changed the implementation to this
public DataTable GetDataTable() { DataTable dataTable = new DataTable(); dataTable.TableName = "Customers"; dataTable.Columns.Add("CustomerId"); dataTable.Columns.Add("CustomerName"); DataRow row1 = dataTable.NewRow(); row1[0] = 1; row1[1] = "Customer #1"; dataTable.Rows.Add(row1); DataRow row2 = dataTable.NewRow(); row2[0] = 2; row2[1] = "Customer #2"; dataTable.Rows.Add(row2); return dataTable; }
and I am still compiling. So then I went to the client and added a reference and it worked:
I then fired up the client like so:
static void Main(string[] args) { Console.WriteLine("Starting"); DataFactoryClient client = new DataFactoryClient(); DataTable table = client.GetDataTable(); foreach (DataRow row in table.Rows) { Console.WriteLine(String.Format("Customer {0} named {1}.",row[0],row[1])); } Console.WriteLine("Ending"); Console.ReadKey(); }
And I hit F5:
Wow. Microsoft made this stupid simple.
I then though about how to pass in an individual data row.
[OperationContract] String InsertDataRow(DataRow row);
public String InsertDataRow(DataRow row) { return String.Format("You entered {0}.", row[0].ToString()); }
And when I hit update reference from my consuming app, I got this:
Crud! I then thought I could just add a serializable data row like so:
[Serializable] public class SerializableDataRow: DataRow { }
And this:
[OperationContract] String InsertDataRow(SerializableDataRow row);
But no, I get this:
So now I have to jump down a rabbit hole and possible violate the Liskov Substitution Principle. Since I want things to be stupid simple, I gave up with inheritance. I then found this post. So either use a datatable (and suffer the overhead) or convert the DataRow into something that can be seialized (like XML, custom classes, etc..)
So I give Microsoft a C on this – somewhat stupid simple, but not entirely…