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?
-
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?
Neil Barnwell : I'm using asmx on the server and client, yes. I'm sort've implementing a kind of half-baked WCF-like fault system because on the client I'm using an interface to the asmx service and I don't want users of that interface to get SoapExceptions, so they get something I've called a ServiceException instead, with a Fault property. That fault property is returned to the asmx client in the SoapException.Detail property, hence the XmlDocument/XmlNode serialisation. I don't have many fault types at the moment, but I want flexibility to add more to the server without breaking deployed clients.John Saunders : So, you're not reinventing the wheel; you're reinventing WCF. -
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; }
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.