Reputation: 42095
In a previous question about serialising an object to an XmlDocument
in C#, I needed to serialise some fault information to an XmlDocument
that was returned from a asmx-style webservice call. On the client I need to de-serialise the XmlDocument
back to an object.
This is straightforward enough if you know the type, but I realised I wanted a flexible approach where the type to de-serialise to is also encoded in the XmlDocument
. I'm currently doing it manually by adding an XmlNode
to the XmlDocument
that has the type name, calculated as follows:
Type type = fault.GetType();
string assemblyName = type.Assembly.FullName;
// Strip off the version and culture info
assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(",")).Trim();
string typeName = type.FullName + ", " + assemblyName;
Then on the client I first get this type name back from the XmlDocument
, and create the type object that is passed into the XmlSerialiser
thus:
object fault;
XmlNode faultNode = e.Detail.FirstChild;
XmlNode faultTypeNode = faultNode.NextSibling;
// The typename of the fault type is the inner xml of the first node
string typeName = faultTypeNode.InnerXml;
Type faultType = Type.GetType(typeName);
// The serialised data for the fault is the second node
using (var stream = new StringReader(faultNode.OuterXml))
{
var serialiser = new XmlSerializer(faultType);
objectThatWasSerialised = serialiser.Deserialize(stream);
}
return (CastToType)fault;
So this is a brute-force approach, and I was wondering if there's a more elegant solution that somehow includes the typename of the serialised type automatically, rather than manually recording it elsewhere?
Upvotes: 5
Views: 3779
Reputation: 16980
I had faced a similar problem and I came up with the same solution. As far as I am concerned, that is the only way to keep types together with values in XML serialization.
I see you are cutting assembly version out as I did too. But I'd like to mention, that you will have troubles with generic types as theirs signature looks like that:
System.Nullable`1[[System.Int, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
So I made a function to only cut out the assembly version(s), which seems to be enough to get rid of versioning problems:
private static string CutOutVersionNumbers(string fullTypeName)
{
string shortTypeName = fullTypeName;
var versionIndex = shortTypeName.IndexOf("Version");
while (versionIndex != -1)
{
int commaIndex = shortTypeName.IndexOf(",", versionIndex);
shortTypeName = shortTypeName.Remove(versionIndex, commaIndex - versionIndex + 1);
versionIndex = shortTypeName.IndexOf("Version");
}
return shortTypeName;
}
Upvotes: 4
Reputation: 161773
Neil, why do you need it to be the same type on both the client and the server?
Are you still using ASMX on the client? That would be a reason, as ASMX does not properly support faults.
Also, do you have so many different fault types that a simple switch statement can't determine the correct type to use?
Upvotes: 0