N-tier Entity Framework and debugging WCF problems
Our latest project involves a number of different app clients, for example Web, Phone, Tablet, Facebook app etc. This calls for an n-tier architecture, where we split the code base into logical modules. We can then swap in a different application client and re-use all of the same business and data access code.
Borrowing on ideas from this post, we want our architecture to resemble something like:
However achieving this is not as straightforward as it sounds. If we want to use the Entity Framework as our ORM, then we have to be aware of what happens when WCF tries to serialize/deserialize this to and from our application layer. The first sign of trouble was when I got this message:
System.Xml.XmlException: The maximum read depth (32) has been exceeded because XML data being read has more levels of nesting than is allowed by the quota. This quota may be increased by changing the MaxDepth property on the XmlDictionaryReaderQuotas object used when creating the XML reader. Line 1, position 5230.
The hack would have been to increase the read depth to a higher level, but that isn’t addressing the real problem, and of course there is no guarantee what might happen later.
The reason this exception is occurring in the first place is due to the entire object graph being deserialized by WCF. There is probably a cyclic navigation path between two objects (e.g. object A has reference to object B, and object B has reference to object A) and so the XML goes on for ever.
Easy fix? Detach the object before sending them back across the wire from the WCF service.
Okay, that will work and give you the top level entity, but what I found was that the children of this entity were all NULL. So that didn’t work for me.
Going back to the architecture above, what we want to do is work with Entity Objects in our DAL, but by the time we get to the service/app level we want to work with POCOs – Plain Old CLR Objects. Problem with this is that WCF cannot directly serialize or deserialize the POCO proxy type.
This is because the proxy types are dynamic types, and the serializer can only, as ever, work with known types. The above workaround, applying ProxyDataContractResolver, did NOT work for me, although that’s perhaps because of my slightly different approach.
Following the steps in the first article, I set up my Entity Data Model as normal, although this time I download the POCO Entity Generator so that I can then create POCO classes from my EDMX.
Move the .tt template into the Model project and change the source to point to the original EDMX in the Data project.
For those classes that need custom business logic, I then create partial classes to correspond with the relevant auto-generated POCO partial data class.
So, to recap, I now have an app layer which calls methods on my WCF service to return a list of POCO data objects. The WCF service in turn calls the data layer, which gets the data but puts this into POCO objects in the Model. The WCF service then returns these POCO Model objects, instead of the Entity Objects.
Everything should have worked…. but it didn’t.
I received a generic error message:
An error occurred while receiving the HTTP response to http://localhost/FtyDataService/MainService.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.
The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
Debugging the WCF service didn’t help at all – it would happily get to the end of the method and it was only on the return (serialization routines) that something was going wrong. But what? I’m sure those of you more adept at WCF than myself will know the answer straight away, but I had to debug the problem using the SvcTraceViewer tool.
The SvcTraceViewer is a great tool to debug inside WCF services. To use it, you need to:
- Set up Trace in the web/app.config
- Install .NET 4.0/Windows 7 SDK
- Run the service; this will generate diagnostic files in the root of the service solution, and open the tracelog.svclog in SvcTraceViewer (probably in C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin)
This will show each activity, and any exceptions will show up inside each activity in red. The inner exceptions are then displayed.
The exception is uncovered:
There was an error while trying to serialize parameter http://tempuri.org/:GetUserDataResult. The InnerException message was ‘Object graph for type ‘FtyModel.Team’ contains cycles and cannot be serialized if reference tracking is disabled.’. Please see InnerException for more details.
To eliminate this error, I had to add
[DataContract(IsReference = true)]
to the top of the .tt file, so that each POCO class had this attribute.
(reason why explained in this SO post)
The next run worked, but didn’t return any data. The obvious reason for this was that no property had [DataMember] marked around them. Once fixed, data was returned.
UPDATE: Marking the POCOs as DataContract, DataMember is unnecessary (and not even correct!). POCOs should be clean, unmarked classes.
The “cyclical references” error can only be sorted out by stopping WCF from getting in a bind (infinite references when it tries to serialize) by using an attribute – http://chabster.blogspot.com/2008/02/wcf-cyclic-references-support.html
However, IMPORTANT – this attribute is NOT respected when using the in-built WCF service client!