Friday, February 4, 2011

Dynamic WCF Services & Silverlight

Sample: Get Sample

Problem
Everybody knows that you need to some kind of communication layer to access your database these days. In the past you would use Web Services, and now WCF services are popular. The problem for a lot of teams is that out of the box these services remain static while a customer's database is constantly changing.

There are basically two kinds of apps. Apps where the database structure will be determined before the application is written and will not change in future. These apps have the same structure no matter which customer they go out to. Generally these apps are not enterprise level apps and they generally do a simple task in a well defined way which is not customisable.

However, in modern enterprise architecture apps, it's a given that the database will change from customer to customer. This is not really a problem for WCF or Silverlight. However, if you follow the out of the box Microsoft solution, it seems very difficult. Generally, people tend to use SlSvcUtil, or Visual Studio's build Service Reference tools to achieve the client side of the equation. These tools may sound like a good solution but they cut you off at the knees in a very subtle way which I will explain in the solution.

Before I go any further, you could pursue Microsoft RIA Services. These services are definitely along the lines of what I am suggesting. RIA Services . Although I personally find them a bit clunky and intrusive upon my programming style. I'm not sure but they may actually solve the problem that I am talking about here.

Solution
We must take control of the service side, model objects (Person, Car, whatever houses the data), and the client side. The model objects will share code across the service side (.Net) and the client side (Silverlight). The model objects will be based on the tables in the database. The end goal is that the only assembly that will need to be redeployed is the model assemblies on the client and server side. This is a necessity because the models must match the database.

There is an assumption though. This solution will assume that you have some kind of generic data layer. If a table is added to the client's system, the data layer should not have ot be rebuilt in order to deal with the situation. But, if your data layer is not this flexible, it's OK. You may have to redeploy the data layer as well.

The service itself should have the standard CRUD operations (Create, Read, Update, Delete). But I like to cut the CRUD thing down to Get, Save and Delete. You could create an operation for each database table in the customer's system, however, this defeats the purpose of this exercise. You could make a service that looks like this:

using System;


using System.ServiceModel;





namespace DynamicWCFService


{


public interface IService


{


[OperationContract(AsyncPattern = true)]


[ServiceKnownType("GetKnownServiceTypes", typeof(ServiceKnownTypeGetter))]


IAsyncResult BeginGetEntity(string entityTypeName, object entityKey, AsyncCallback callback, object state);


IEntity EndGetEntity(IAsyncResult result);





[OperationContract(AsyncPattern = true)]


[ServiceKnownType("GetKnownServiceTypes", typeof(ServiceKnownTypeGetter))]


IAsyncResult BeginSaveEntity(IEntity entity, AsyncCallback callback, object state);


IEntity EndSaveEntity(IAsyncResult result);





[OperationContract(AsyncPattern = true)]


[ServiceKnownType("GetKnownServiceTypes", typeof(ServiceKnownTypeGetter))]


IAsyncResult BeginDeleteEntity(IEntity entity, AsyncCallback callback, object state);


bool EndDeleteEntity(IAsyncResult result);


}


}




This service will allow you to create, read, update or delete records in any database table in the system as long as a the corresponding model class exists.

Service Contract
This must use a method (I have used GetKnownServiceTypes) to determine which models can be passed across the wire. This is crucial and must exist on both the client and server side. This is the reason that SlSvcUtil does not provide an adequate solution. When you pump out a client proxy using SlSvcUtil it hard codes the list of classes that are allowed to be passed across WCF in to the CS file. That means that if you wanted to add a class to the list, you would have to re-run SlSvcUtil, recompile and redeploy our reference dll. This is not good for maintaining your software.

Client Side Service Contract
The client side service contract must match the server side one. However, we can't just use the existing one because Silverlight requires us to use async methods. Keep an eye out for the async framework though because with any luck, we might be able to just leverage the interface from the actual service itself (we can do that in .Net but not Silverlight).

Client Side Proxy
The proxy I have created is very similar to the one generated by SlSvcUtil. I wish SlSvcUtil did what we needed it to do here (allow for a dynamic method for the KnownTypes) but it doesn't. Meantime, please use my snippet to create the bits and pieces you need for the client. Just clicks Tools->Code Snippet Manager in VS to import the snippet. Put it in the My Code Snippets section.

Model Library
This should be separate from the rest of your app. This is theoretically, the only thing in your app that should change and it should change in concert with changes to your database. Bare in mind that you need a smart data layer to use the model to figure out how to persist data to the database.

Data Access Layer
I'm deliberately leaving this open. You might be able to use something like Entity Framework. Or, you can create your own. The main thing is that you will need to separate it from your model objects but the DAL itself should load and save data based on the structure of the model objects. It should not explicitly need a function like GetPerson. Instead it should have something like GetEntity. I might talk about this in another post.

Running the Sample
I recommend deploying the WCF service to IIS and ensuring that there is a valid clientaccesspolicy.xml setup (please google this). Then you can run the Silverlight app from VS and point the servicereferences.clientconfig at your deployed WCF app. I have never been successful in getting a Silverlight app to talk to a WCF service running inside WcfSvcHost (VS's native WCF host).

Conclusion
Anyway, some example source is provided. It should give you some ideas about how to achieve what I have talked about. This is quite simple but as I mentioned, most people get lead astray by using the standard toolset. But, I think in future Microsoft will be improving the SlSvcUtil tool so that it creates better proxies. If you are really smart, you could investigate hooking in to SlSvcUtil to change the code that is outputted. I have done small things with this but it is possible to write an app which catches events that SlSvcUtil goes through and then change the output of the code but this is beyond the scope of this post.

Notes
Thanks to To Html.com for the syntax highlighting.

Sample: Get Sample

Create Proxy Code Snippet: Get Snippet

6 comments:

  1. I'm trying to develop an application structure totally dynamic. Would be nice if I can integrate this idea of dynamic wcf service with Webmatrix.Data assembly, getting dynamic entities and returning to a silverlight application.

    ReplyDelete
  2. Yes. A dynamic software framework is the aim of most developers. I haven't really looked at Webmatrix. Could you explain more about your idea? Also, check out the soft coding logic post with WF I just did.

    ReplyDelete
  3. checkout this: "massive" project from rob conery.

    http://datachomp.com/archives/getting-started-with-massive-in-mvc3/


    http://blog.wekeroad.com

    I'll try to find a way to use a dynamic wcf ria services to send data to a silverlight application.

    ReplyDelete
  4. It seems that WCF RIA Services cannot serialize a dynamic/expando object types. I'm trying to find an alternative way... maybe only pure WCF can do this.

    ReplyDelete
  5. Standard WCF deals with Dynamic just fine : http://www.basarat.com/2011/04/how-wcf-will-deal-will-dynamic.html

    ReplyDelete
  6. Thanks for your post,Christian.As for our team, we use The DatumNode Data Services Platform. I think it will be interesting to you an others to look at http://datumnode.com

    ReplyDelete