Introduction
Now if you are like me, you’ve probably had some interest in POCO (plain old CLR objects) objects for at least some time. They are an invaluable tool in the distributed systems and service oriented architecture areas, but up until now they’ve been inaccessible for those designs.
In a nutshell, both LINQ to SQL and Entity Framework (v1) class entities did not support serialization for the purpose of stateless transport(such as web service communication). This stems from the embedded context tracking attributes, and the design which stipulates a fairly poor experience for those daring enough to detach entities and “pass them around”.
Enter the ADO.net Entity Framework v2.. ahem, version 4 which shipped in the early part of this year. Whilst the EFv4 doesn’t support POCO objects out of the box (you have to use an online template), it’s easy enough to accomplish with minimal effort. Plus, they can used (almost) as seamlessly as non-POCO objects.
Before we get into the nitty gritty of this particularly long post, I will direct your attention to the following MSDN article which covers most of the steps for harmonious life with POCO objects and WCF services. What the article does not cover is handling somewhat more complex object graphs. In other words, the MSDN scenario is fine with fairly basic (and bland) objects, but it’s pretty nasty when you have objects containing, well, joins (collections, relationships, yada yada).
Now what follows, is based on a number of other articles floating around the Internet. I’m not trying to take any credit for (the majority), I’m just collating the information into one handy to reach place. I’m also going to supply sample code in case you have any trouble getting it all configured. The parts which are my implementation alone, I’ll highlight.
The Data Model
First, let us take a quick look at the sample data model. Nothing fancy, I’ll admit, but enough for our purposes:
Which we will use with a WCF Service or two. You can use the attached T-SQL script to create and populate a SQL Server database (and later generate your EDMX model from that schema). Next, create a solution containing WCF services, and add a ADO.net Entity Framework (v4) model. You can see from my sample below, the model is admittedly not very complex. Notice the “self join” on the Category table. This is not an uncommon scenario in designing parent/child relationships at the DB level. It also has the (awesome) advantage of generating Parent/Child navigation properties (you may need to do some renaming if you generated the model from my sample schema).
The Object Model
Solutions and Settings
Once you have generated the model, right click anywhere on the blank model surface and select “Add Code Generation Item”. This prompts you with a bulky dialog window – select “Online Templates” from the left hand side tree view.
Select ADO.NET C# POCO Entity Generator and click OK a few times as needed. The template builds up the POCO entities and removes the EDMX/Designer based implementation which the EF designer would have originally generated. This leaves you with a number of new files in your solution, which should look a lot like the following:
Web Services
Now that I’ve got your attention, lets have a think about how we’re going to expose these via WCF. I’ve created two WCF Services, SystemLogService.svc and ProductService.svc.
The interface definition of each is per below:
Don’t worry about those attributes just yet! I’ll explain a little about why they are necessary shortly. If you have reviewed the original MSDN article you’ll recall:
“The POCO proxy type cannot be directly serialized or deserialized by the Windows Communication Foundation (WCF), because the DataContractSerializer serialization engine can only serialize and deserialize known types. The proxy type is not a known type. For more information, see the Serializing POCO Proxies section in the Working with POCO Entities topic. To serialize POCO proxies as POCO entities, use the ProxyDataContractResolver class to map proxy types to POCO types during serialization.”
Which means that the default (runtime) classes generated by LINQ/EF are incompatible with WCF because WCF requires classes defined at compile time.
The Solution
As such, you need to both disable the use of Proxies, and also label your web service methods with the [ApplyDataContractResolver] attribute as seen above. You can obtain the details about this attribute from the MSDN article or from my sample solution. You only need to use it on the service side. This is as simple as creating a new class and pasting the implementation from either source. Then add the attribute to decorate your web service definition (on the interfaces).
Now, for the part not previously covered – we generally encounter a problem with passing entities which are a little more complicated than the example POCO objects encountered in the MSDN article. Take our sample application. The System Log entities define a basic relationship, and the products include a (fairly standard) self join, allowing product categories to have a hierarchy.
If we then create a standard console application, and add a web service reference, we can observe the class definition from the generated WSDL (below).
If you’re unsure about how to view the WSDL code within Visual Studio, simply follow these steps:
- Right Click on the Service Reference
- Select “View in Object Browser”
- From here, expand the namespace of the reference, then right click on one of the interfaces
- Select “Go To Definition”
Now assuming you have done everything correctly, you should be able to consume the web services and the POCO objects in your console application:
Execution
If we execute the code, the first web service call returns fine, with no errors. The second call however, which returns a collection is not as fortunate.
When we step over the following line of code, we receive an exception with the following message:
SystemLog[] logs = logClient.GetLogEntryByCategoryId(1);
“The underlying connection was closed: The connection was closed unexpectedly.”
Looking deeper into the service side of affairs (debugging), we may discover that the exception being thrown is, in fact, the following:
There was an error while trying to serialize parameter http://tempuri.org/:GetLogEntryByCategoryIdResult. The InnerException message was ‘Object graph for type ‘Products.WcfServices.SystemLogCategory’ contains cycles and cannot be serialized if reference tracking is disabled.’. Please see InnerException for more details.
After a fair amount of searching, I found a way to work around this little problem. Implementing the suggested attribute [CyclicReferencesAware(true)] to methods involving collections appears to fix the problem. After applying the attribute and updating the service reference (just to be sure!) you will find the call succeeds, as per below:
But Wait.. There’s More..
Just when you thought it was safe to go back into the ocean.. What happens when we want to send things the other direction?
Let’s look ahead to a web service method which takes one of our POCO objects, and tries to apply an update.
The logic I’ve used here detects a new entity, and also when an existing entity can not be located in the data store.
So nothing terribly complicated, correct? If we implement something on the client side – something very simple, like the following:
When we try to execute this rather simple update scenario, we get the same kind of exception we’ve seen before:
I love it when a plan comes together..
So what is the solution? Well, rather simple, if somewhat complex in the implementation.
The outcome I found which works quite well is to emit the same attribute into the generated WSDL on the client side, when the reference is created.
This turned out to be a pretty straightforward idea, but a terribly intriguing problem to try to solve.
Without delving too much into details (please download and examine the sample solution) the basic premise was two fold:
- Define the required files in a common or shared assembly that both the service and the client project can consume.
- Build a class which implements several WSDL extensions: IWsdlImportExtension, IServiceContractGenerationExtension,IOperationContractGenerationExtension and IOperationBehavior
Basically, the class is triggered when the WSDL is being imported, and it adds the appropriate [CyclicReferencesAware(true)] attribute above the appropriate methods.
To do this, you must modify the client’s App.Config to include the following configuration:
When the WSDL import is called, the referenced extension finds operations decorated with the CyclicReferencesAware attribute (the export decorates them with a documentation text).
When an operation decorated with the attribute is found, the importer adds (writes) a reference to itself to the operations’s behavours collection.
As the WSDL is being generated, it’s a relatively easy step to output the required attribute.
Now, when if you update the service reference the appropriate attribute is applied to the generated WSDL code, as you can see from the screenshot below:
Side Notes
The only thing I didn’t figure out was how to add the required using directive to the generated code, however it is very easy to add the reference yourself – just compile the client project and you’ll get the appropriate errors.
Double click on one, right click on the reference and you can easily add it to the code. I realise it’s a bad practice to modify generated code, but I ran out of patience and figured this wasn’t a terrible oversight. If you find a nice way to fix this, please get in touch.
Running the solution after updating the configuration (and referencing the shared assembly) and now the previous code runs just fine. You can check the database to ensure the update occurred.
Summary and Disclaimer
Thus far, I haven’t had much time to test this any further. I’ve implemented it on a number of web service clients without any problems.
I’ve not tried any further complicated scenarios, but I’d really appreciate any feedback if people find further problems.
To wrap up, I’ve included the sample project and T-SQL to create a database. This is not production code, so please use it as a demo.
There’s no encryption, compression or other types of scenarios we might encounter in a complete system.
It is supplied “As-IS” and no warranty is implied 🙂
As always, if you have any feedback please leave it here or get in touch.
Seriously though, I sincerely hope this might help out some folks who are as intrigued and equally baffled with WCF and the Entity Framework.
Bon Appétit. /R
[ Download Sample Project and Schema ]
Additional Reading
http://blogs.msdn.com/adonet/archive/2009/12/22/poco-proxies-part-1.aspx
http://blogs.msdn.com/adonet/archive/2010/01/05/poco-proxies-part-2-serializing-poco-proxies.aspx
MSDN Walkthrough on POCO Entities
http://msdn.microsoft.com/en-us/library/ee705457.aspx
The source for the cyclic check is courtesy of:
http://chabster.blogspot.com/2008/02/wcf-cyclic-references-support.html
16 thoughts on “The ADO.Net Entity Framework, POCO Objects and You”
Hola,
ЎGracias! Ahora me irй en este blog cada dнa!
Worker
Very good site, a bunch of helpful information
Hello
In case you are interested i found a solution to the namespace problem.
In the CyclicReferencesAwareAttributeImporter, in the GenerateOperation method, replace:
context.SyncMethod.CustomAttributes.Add(new CodeAttributeDeclaration(“CyclicReferencesAware”, new CodeAttributeArgument[] { codeAttr }));
with:
context.SyncMethod.CustomAttributes.Add(new CodeAttributeDeclaration(“global::” + typeof(CyclicReferencesAwareAttribute).FullName, new CodeAttributeArgument[] { codeAttr }));
Global:: was added to avoid any namespace mix-ups.
I realize that the article is a bit old but i thought i would post this anyways.
I hope there is someone who can use this.
Thanks Rob, for the entire solution, and Ken for cleaning things up a bit. I’m surprised there isn’t more info out there about this problem. Seems like it would be a fairly common issue. I guess people are using separate DTOs, STEs, or RESTful models(does this problem exist with STE’s?) in most solutions with EF and WCF. Writing DTOs was out of the question for our solution with nearing 400 entities, STEs are too “heavy” and REST is too simple.
I just hope the performance of this solution is up to snuff in a high volume transactional software system.
Ken or Rob, are you using this code in any high impact high volume scenarios?
Zack
Hi Zack,
It depends on your definition of ‘high volume’ I guess. I was running about 50-100 operations a minute (in production, per remote client) through WCF with the EFv4 POCO entities, but that’s not really high volume IMHO. I’d love to test it at about 5,000-10,000 transactions a minute (as a start), and see how it performs.
I’m a bit limited in resources at the moment, so I couldn’t do much in the way of high volume performance testing, but I’d be incredibly interested to hear stories from the field.
When I get a spare moment, probably next month, I’ll rework the code samples to include Ken’s additional changes and try and run some more aggressive testing. I’m planning on doing some more in-depth articles on EFv4 + WCF “in the Enterprise”.
Cheers.. Rob
100 operations a minute I guess isn’t quite “high” volume but it’s certainly not a drop in the bucket either. Gives me a reasonable level of confidence in the robustness of this approach.
My question to you Rob, is what do we truly gain from this approach vs. using the “(IsReference = true)” parameter to a DataContract attribute in out of the box .NET 3.5+? How dangerous are
My second question (probably due to partial lack of understanding) is whether the “[ApplyDataContractResolver]” is necessary at all if I am not using Visual Studio generated client proxies? My proof of concept currently is using a generic channel factory class instead of any tightly coupled proxy, and then of course requiring me to copy my operation contract interface and POCO classes into a library residing on the client. This seems to work fine without the DataContractResolver solution from the MSDN article. Am I missing something?
Thanks again!
Hi Zack,
Sorry for the late followup, I’ve been transiting Internationally.
In reply to the first question, I haven’t tested this with .Net 3.5, only with 4.0 and the new POCO Template, so I can’t answer without recompiling to the previous version (EF v1) which, in honesty, I wouldn’t recommend (EFv1 has all sorts of performance problems, for one).
As for the second question – a great point actually, and one I was considering originally. As far as I know what we have here (in this article) is designed for VS/Generated Proxy stubs from the WSDL. I haven’t tried it from a generic client implementation.
The cyclic problem would only (seem) to apply when you have a self join on a table, it doesn’t affect navigation properties or collections (aka Foreign Keys/Relationships). So it might not even be a factor if you don’t use self joins – I haven’t looked at this recently though – I plan a review of this whole article next month.
Stay Tuned!
oops, something got screwed up there.
My second paragraph should have ended with “How dangerous are these circular references to EF with WCF?”
You saved me at least 1 week!
So many thanks…
Thanks for sharing.
Awesome! I have been three days looking for a solution and I found in this article: clear, brief, and useful..
Thanks
Really nice article!! The download link to the sample solution is broken however and I would very much like to get my hands on it!
Hi Mikael,
Oops – must have been missed during the site migration. I’ll upload and e-mail you a direct link. Thanks for pointing it out!
Best,
Rob
Amazing article! The ApplyDataContractResolverAttribute really solved my problem. I didn’t think out that!
Greetings,
Todor