Geeks With Blogs
Clara's Notes on Technology Notes to me and the world

Suppose you have three tables in your database where one of them specifies a many-to-many relationship between the other two (example from AdventureWorks):                                                                       

 Suppose also that you have a method such as GetVendors(int productID) that will retrieve all the vendors for a given product through the ProductVendors table (that is , the many-to-many table).

Now, if this method is exposed via a WCF service, when your client calls it you will see an exception like this one:

  • "System.ServiceModel.CommunicationException was unhandled. An error occurred while receiving the HTTP response to http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/. 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." 

And the subsequent inner exception messages:

  • "The underlying connection was closed: An unexpected error occurred on a receive."
  • "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host."
  • "An existing connection was forcibly closed by the remote host"

What the ... is going on? This is a seralization problem (yes, the exception message is not that clear). To test the serialization of your data I recommend the following test (from here):

Service1 svc = new Service1(); List<Vendor> lv = svc.GetVendors(319); object dto = lv[0]; DataContractSerializer ser = new DataContractSerializer(typeof(Vendor)); FileStream writer = new FileStream(@"C:\Temp\" + dto.GetType().Name + ".xml", FileMode.Create); ser.WriteObject(writer, dto); writer.Close();

When running the code above, I get a clearer exception mentioning serialization:

  • "System.Runtime.Serialization.SerializationException: Object graph for type 'WcfServiceLibrary1.ProductVendor' contains cycles and cannot be serialized if reference tracking is disabled."

If you then check the XML file that this test created for the Vendor object you will see it is huge and broken. The problem is that the Vendor object contains a reference to the one or more Product objects (linked through the ProductVendor table) which contain a reference to one or more Vendors which contain references to Prodcuts and so on ... An infinite cycle of references is being created. WCF does not realize that these references point to the same object and it serializes each reference (eventually throwing an exception).

There is a great post (http://blogs.msdn.com/sowmy/archive/2006/03/26/561188.aspx) about how to preserve object references in WCF. But if you are looking for a less complicated solution you can just open the *.dbml file, right click, select 'Properties' and choose 'Seralization Mode' = 'Unidirectional'. As the name indicates, serialization only goes in one direction: from a product to a vendor but not back to products (or from a vendor to a product but not back to products).

Without unidirectional serialization you could do this:

Vendor[] vendors = svc.GetVendors(319); foreach (Vendor v in vendors) { Console.WriteLine(v.Name); foreach (ProductVendor pv in v.ProductVendors) { Product p = pv.Product; foreach (ProductVendor pv2 in p.ProductVendors) { Vendor v2 = pv2.Vendor; // and so on } } }

  With unidirectional serialization you can only get as far as this:

Vendor[] vendors = svc.GetVendors(319); foreach (Vendor v in vendors) { Console.WriteLine(v.Name); foreach (ProductVendor pv in v.ProductVendors) { int prodID = pv.ProductID; } }

  

 

 

Posted on Friday, October 10, 2008 7:52 AM WCF , LINQ | Back to top


Comments on this post: Many-to-many relationships & Object graph cycles

# re: Many-to-many relationships & Object graph cycles
Requesting Gravatar...
LINQ to SQL's DataContractSerializer can’t handle serializing LINQ to SQL entities with circular references unless you apply Damien Guard’s T4 template, as described in my Bidirectional Serialization of LINQ to SQL Object Graphs with Damien Guard’s T4 Template in VS 2008 SP1 post of 9/25/2008. See http://oakleafblog.blogspot.com/2008/07/bidirectional-serialization-of-linq-to.html.

For more details on bidirectional serialization, see http://oakleafblog.blogspot.com/2007/11/serializing-object-graphs-with-and.html.

--rj
Left by Roger Jennings on Oct 10, 2008 5:33 PM

# re: Many-to-many relationships & Object graph cycles
Requesting Gravatar...
Thanks for this post, saved my day :D
Left by David on Mar 16, 2012 1:57 PM

Your comment:
 (will show your gravatar)


Copyright © Clara Oscura | Powered by: GeeksWithBlogs.net