I'm using Silverlight 4, .NET 4.0.
I have an object that's defined in a shared library (shared between my Silverlight project, and the web project hosting the WCF service)
The object is a tree structure which has a list of its children, as well as reference to its parent and to the root.
ie.
class TreeNode
{
public List<TreeNode> Children {get; set;}
public TreeNode Root { get; set; }
public TreeNode Parent { get; set; }
}
The problem is when Silverlight tries to take this object and send it to the server, I get an exception about cyclical references. After some research, I found out I had to enable the attribute IsReference to true like so:
[DataContract(IsReference = true)]
class TreeNode
{
public List<TreeNode> Children {get; set;}
public TreeNode Root { get; set; }
开发者_StackOverflow社区 public TreeNode Parent { get; set; }
}
The problem is when I do this, my WCF service no longer works as it can't load the needed assembly for this:
"Could not load file or assembly 'System.Runtime.Serialization, Version=2.0.5.0"
This is because the project containing the TreeNode class is built against the Silverlight runtime, not the .NET runtime and uses System.Runtime.Serialization v2.0.5.0, while the web project and the WCF service uses v4.0.30319.
So, my question is: Is there a way that I can have this object serialize while preserving references without moving the entire object structure a different project that builds against the standard .NET 4.0 runtime?
Also, it's worth noting that I've tried using conditional compilation such as:
#if SILVERLIGHT
[DataContract(IsReference = true)]
#endif
But that doesn't work, as it's the WCF service that needs to know it must preserve references...
Greatly appreciate any help on this.
There are three options I've used for this scenario:
- Proxies
- Not sharing the assembly, but rather sharing the code.
- Referencing the System.Runtime.Serialization for SL from the full .NET code and setting copy local to true (and optionally using an ILMerge post build step to merge in the System.Runtime.Serialization assembly and internalize it to prevent other assemblies from using it).
2 is the most straightforward. Keep the DataContract with IsReference = true. Create another project targeted to .NET (the other one targeted to SL). In the .NET project add your files as linked files. That way, when it compiles, the SL one will use the System.Runtime.Serialization dll for SL and the .NET project will use the System.Runtime.Serialization dll for .NET.
1 and 3 allow you to keep sharing the actual DLL.
Option 1 works as follows: Remove the DataContract attribute. Before serializing over the wire, create proxy types dynamically that match your classes that you want to serialize (but add the DataContract attribute with IsReference = true). You can create these classes using Reflection.Emit (or some other dynamic type builder like Windsor). Then use something like AutoMapper to copy your data into the proxy types. Serialize/Deserialize the proxied types.
Option 3 works like this: Leave your code like you have it now (with the DataContract and IsReference = true). Set System.Runtime.Serialization to Copy Local. Optionally add an ILMerge post build task with the /internalize option to merge the System.Runtime.Serialization dll into your own.
精彩评论