Monday, February 15, 2010

Enjoy the WCF Data Services sandwich

For 60 years in IT, there are lot of the ever repeating questions in every project.

Among them:

How do I load/persist my object in my relational database?

Who hopes Microsoft is finally giving the the answer with Entity Framework 4 will be disappointed. EF 4 is nailed on my SQL-Server relational tables. But what's a data-access layer worth that exports relational tables? Well, it's simply not what I call a data-access layer. It is a relational table presentation layer, but nothing more. For me a good data-access layer returns at least data transfer objects, that totally abstract the physical storage. Given that fact that I don't like the idea of stacking up a table presentation layer with my own projection framework, EF4 can't be part of any serious architecture I use.

But what about WCF Data Services?

Among the ever returning questions in IT there is also the following question.
How can I forward the query from my client to my object repository if I want it to?

The problem with DDD repositories, is that you basically need the exact number of functions as the number of query possibilities you want to have.

Following example:

public class A
{
public string PropA { get;set; };
public string PropB { get;set; };
public string PropC { get;set; };
}

How many operations you want to implement until you get the flexibility you need?

Maybe

GetAByPropA(string particle);

GetAByPropB(string particle);
GetAByPropC(string particle);
GetAByPropAorB(string particle,string particleB);
GetAByPropAandB(string particle, string particle);
GetAByPropAorC(string particle, string particleB);

Of course you would not implement

GetAByPropAorB(string particle,string particleB);

but maybe

GetAByQuery(List<string>, List<Operator>)

But what are the Operators....

You have 2 options now.

1.) You accept that you cannot implement all the operations you basically need. That means to accept the gap. That means you need to do client side filtering. That means your data-access layer puts much more load on the whole system than necessary
2.) you find yourself writing your own query language.

So either I take the ugly 90% solution or I waste my project time writing a query language instead of implementing business cases. From my point of view this sounds like the choice between black death and cholera. Basically this is the moment to realize we have just broken through the ceiling of current SOA patterns.

But wait. Microsoft promises me they have the answer. It's called WCF Data Services!

What are WCF Data Services related to classic WCF services?

In classic WCF you expose operations. In WCF Data Services you expose objects. WCF Data Services come with a built in functionality to perform queries on a collection of objects exposed through the service.

In .Net terms this means, I can perform a Linq query on the collection of my client proxy object. The client serializes my query through OData protocol, which is then deserialized on the server to a Linq expression again. And with my Linq expression I can basically forward the query directly to my data store. This means I retrieve only the exact data requested and return just the amount of data necessary.

Awesome! All I do is to expose my object, and this is it! Bye 100 insuffient operations, bye you hateful custom query language.

I watched the videos, everything looks absolutely idiot proof. Lets try it.

I tried it on .Net 3.5 getting the latest update, as well on .Net 4 with Visual Studio 2010 RC.

But as I do not like Entity Framework I used my really simply WCF contract. I exposed it through my Data Service and....

"Request Error. The server encountered an error processing the request. See server logs for more details."

Who knows where there is the log for the ASP.Net development server?

To save you the same amount of frustration I recommend you slap the following attribute on your DataService class.

[ServiceBehavior(IncludeExceptionDetailInFaults = true)]

In .Net 3.5 the error message you now get is even less on the first glance.

"The XML page cannot be displayed"

To save you some more frustration I recommend to use FireFox as your default browser. In case of invalid XML IE simply does let you view the source of the document. Although FireFox comes up with a similar "XML processing error" message, you can at least always show the source of the page and sometimes this will get you to the source of the problem.

If you get meaningful exceptions like

System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke ....

this probably means the same as the the error message:

"MyType is not entity type"

? What does that mean?

With WCF Data Services you just cannot expose WCF data contracts. Basically WCF Data Services are missing WCF compatibility. Well.....

You can only expose objects that have either:

a public set & gettable property: ID (yes, case sensitive)
or
a public set & gettable property: <classname>ID
or are decorated with the
[DataServiceKeyAttribute]

What does that mean?

public class MyClass
{
public string Name { get; set;}
}

Not working. And be careful with just slapping [DataServiceKeyAttribute("Name")] on your class. As Name is not a unique identifier of your class you may see some unexpected results if you query provider return 2 objects with the same name. Make sure you test this choice.

public enum myEnum
{
one,
two
}

public class MyClass
{
public string ID { get; set;}
public myEnum MyEnum { get; set;}
}

not working

public class MyOtherClass
{
public string Name { get; set;}
}


public class MyClass
{
public string ID { get; set;}
public MyOtherClass MyOtherClass { get; set;}
}

not working as B has no unique identifier on its own.

It looks like we have to approach the question from the other side. So what is working?

Well, basically if you want to transport your own classes not much. If you have no access to source of the class basically nothing. But I have my WCF data contracts! What happened?

If you look the Microsoft Pod casts on the subject you see that most their examples are based on the Entity Framework. And if you look closer you find all the limitations in Entity Framework currently are found in Data Services as well. In other words Entity Framework are perfect partners. But this in fact means that both technologies are quite tightly coupled. This makes sense if you consider that WCF Data Services were called ADO.Net Data Services before. The original design was obviously not for exposing object but database entities. For me it feels the
whole concept was originally intended to give Silverlight developers access to a remote SQL-Server database because Silverlight runs in sand boxed context of the browser behind a firewall.

But in fact this is what you get.

So what basically happened is that they nailed the Data Services on Entity Framework which is nailed on relational SQL Server tables. In short: WCF Data Services are intended to provide a web based access to relational SQL server tables.

Now you tell me something about decoupled architecture..... Basically amazing how you manage to nail not only some software components but 3 complete technology frameworks together.

If you try to expose your object or only your WCF data contract through WCF Data Services, you probably will not recognize your object anymore when your implementation finally suffices WCF Data Services.

At the end the result is more than disappointing. If you do not like the SQL-Server, Entity Framework, Data Services Sandwich you can put this technologies aside and wait for Microsoft to publish something more generally usable. Maybe some when somewhere on CodePlex?

More and more it seems the whole .Net 4 release seems to be full set of half ready technologies. WF4 is missing State Machines, the ORM Entity Framework 4 is missing (o)bjects and (m)appings, WCF Data Services are missing WCF, industry standards like XSLT 2 are completely missing. Maybe it's time for Microsoft to rename .Net 4 to .Net 3.75. For me it looks like it looks like Microsoft lost sight in the Cloud.

Please correct me if I got something completely wrong. I am more than happy to correct my findings. Please use the comment function for this.

Update: With the move from ADO.Net Data Services to WCF Data Services Microsoft obviously realized that the current implementation does currently not fulfill the expectations implied by the term WCF.
That is why they come up with a custom Data Service Provider Interface that allows you to plug in new models into WCF Data Services.

4 comments:

Phani Raj said...

My name is Phani and I am a part of the WCF Data Services team.

It's unfortunate that your first attempt at building a Data Service bombed badly .
There's a couple of issues with your data model which are causing the issue you see with your classes.

In the Data Services runtime , we expose CLR types which we identify as Entity Types based on our convention.
We need every entity type to have a key property defined on it .
In case of CLR based providers , one would need to annotate the type with the DataServiceKey attribute
to identify a property of the type as a key.
If we dont find a DataServiceKeyAttribute on the type , we look for a property named ID on the type
or a property which is named ID and if we find one , make that the key property.


In your cases above , the first scenario failed as we weren't able to find a key property on the type ,

public class MyClass
{
public string Name { get; set;}
}

The second case failed as we dont support enums yet ,

public enum myEnum
{
one,
two
}


public class MyClass
{
public string ID { get; set;}
public myEnum MyEnum { get; set;}
}


The third case failed as you have a relation from MyClass to MyOtherClass and MyOtherClass isnt an entity type,
since we couldnt find a key property on MyOtherClass.

public class MyOtherClass
{
public string Name { get; set;}
}


public class MyClass
{
public string ID { get; set;}
public MyOtherClass MyOtherClass { get; set;}
}

For more details about how we layer the WCF Data Service system to allow for any kind of Data Source , not just the Entity Framework,
please read our blog post here :

http://blogs.msdn.com/astoriateam/archive/2007/09/27/astoria-data-sources-and-system-layering.aspx

Mike from the WCF Data Services team , wrote an excellent primer to WCF Data Services and it can be found here :

http://msdn.microsoft.com/en-us/library/cc907912.aspx

The section "Creating a data service from any data source" describes about how to write a CLR based data provider
to use as an input to a Data Service.
Hope this helps.
If you run into any further issue, please feel free to email me at : PhaniRaj AT Microsoft DOT COM

Anonymous said...

Hey Tech Talk, your just so full of it: "60 years in IT" - that would be 1950. Hmm, google for "first relational database" shows that the first paper about relational databases was published 1970. At least get your facts straight...

elLoco said...

IT did not start with relational databases I guess. Anyway this number was a rough guess and is in its essence irrelevant for content of the article.

Denis said...

Thanks for the great post. What I don't understand (and I agree with all your concerns) is why Microsoft invests into school-oriented Entity Framework so much without providing anything serious for enterprise levels. I have stuck to Untyped Data Provider scenario backed with SQL however it is extremely difficult to find any meaningful information that is not related to EF or Linq to SQL (i thought it is dead already). Good point for .NET 3.75 indeed. Starting from .NET 3.5 we don't have a complete foundation within the framework. WCF, WWF, WPF always seem to be half-baked or experimental.