XML Deserialization with "mixed" type - c#

I am trying to consume XML from a web service. I initially started using LINQ to XML but after learning about serialization/deserialization I decided I would instead just try to deserialize the XML.
Although I haven't yet written the deserialization code, I've realised that due to how the web service works, I can't always know the actual type being returned for certain elements.
For example consider this XML (http://api.wunderground.com/api/d36f54198ebbb48c/conditions/q/England/London.xml)
<dewpoint_string>52 F (11 C)</dewpoint_string>
<dewpoint_f>52</dewpoint_f>
<dewpoint_c>11</dewpoint_c>
<heat_index_string>NA</heat_index_string>
<heat_index_f>NA</heat_index_f>
<heat_index_c>NA</heat_index_c>
Now, normally provided that all the data is available then elements such as "heat_index_f" would be a decimal/double. However when certain parts of the data is not available the service will instead have the string value of "NA" in the element. I am deserializing to an object, that has properties for each element. EG: string HeatIndexString; double HeatIndexF; Obviously, if the service returns with the string NA then I will get a runtime exception of trying to convert "NA" to a double.
How should I tackle this problem? Is there some type of attribute I can tell the deserializer to somehow work with these "mixed" types? How do other developers deal with situations like this?

Related

Dummy Objects Good or Bad

I am working on a project that communicates a lot of data with a server. This data is in a json format. We end up creating a lot of dummy objects to parse the json data. This leads to having a lot of classes that just contain class members. Is there a better way of doing things?
thanks
Assuming that you are using NewtonSoft's JSON parser or something similar, you have a couple of choices here. The usual use case here is to deserialize to a named type, thus:
var parsedMessage = JsonConvert.DeserializeObject<Message>(content.AsString());
If you have many types for each differnet JSON message type you wish to receive and wish to avoid to, you can do the following:
var parsedMessage = JsonConvert.DeserializeObject<dynamic>(content.AsString());
This will give you a dynamic object that you can inspect and should also work given other Json libraries. Alternatively, NetwtonSoft also provides the following method:
public static T DeserializeAnonymousType<T>(string value, T anonymousTypeObject);
This will allow you to deserialize to an anonymously typed object rather than a dynamic object.

How can I extract values as strings from an xml file based on the element/property name in a generated .Net class or the original XSD?

I have a large complex XSD set.
I have C# classes generated from those XSDs using xsd.exe. Naturally, though the majority of properties in the generated classes are strings, many are decimals, DateTimes, enums or bools, just as they should be.
Now, I have some UNVALIDATED data that is structured in the correct XML format, but may well NOT be able to pass XSD validation, let alone be put into an instance of the relevant .Net object. For example, at this stage, for all we know the value for the element that should be a DateTime could be "ABC" - not even parseable as a DateTime - let alone other string elements respecting maxLength or regex pattern restrictions. This data is ready to be passed in to a rules engine that we already have to make everything valid, including defaulting things appropriately depending on other data items, etc.
I know how to use the various types in System.Xml to read the string value of a given element by name. Clearly I could just hand craft code to get out all the elements that exist today by name - but if the XSD changes, the code would need to be reworked. I'd like to be able to either directly read the XSD or use reflection on the generated classes (including attributes like [System.Xml.Serialization.XmlTypeAttribute(TypeName=...] where necessary) to find exactly how to recursively query the XML down to the the raw, unverified string version of any given element to pass through to the ruleset, and then after the rules have made something valid of it, either put it back into the strongly typed object or back into a copy of the XML for serialization into the object.
(It has occurred to me that an alternative approach would be to somehow automatically generate a 'stringly typed' version of the object - where there are not DateTimes etc; nothing but strings - and serialize the xml into that. I have even madly thought of taking the xsd.exe generated .cs file and search/replacing all the enums and base types that aren't strings to strings, but there has to be a better way.)
In other words, is there an existing generic way to pull the XElement or attribute value from some XML that would correspond to a given item in a .Net class if it were serialized, without actually serializing it?
Sorry to self-answer, and sorry for the lack of actual code in my answer, but I don't yet have the permission of my employer to share the actual code on this. Working on it, I'll update here when there is movement.
I was able to implement something I called a Tolerant XML Reader. Unlike most XML deserializing, it starts by using reflection to look at the structure of the required .Net type, and then attempts to find the relevant XElements and interpret them. Any extra elements are ignored (because they are never looked for), any elements not found are defaulted, and any elements found are further interpreted.
The main method signature, in C#, is as follows:
public static T TolerantDeserializeIntoType<T>(
XDocument doc,
out List<string> messagesList,
out bool isFromSuppliedData,
XmlSchemaSet schemas = null,
bool tolerant = true)
A typical call to it might look like this:
List<string> messagesList;
bool defaultOnly;
SomeType result = TolerantDeserializeIntoType<SomeType>(someXDocument, out messagesList, out defaultOnly);
(you may use var; I just explicitly put the type there for clarity in this example).
This will take any XDocument (so the only criteria of the original was that it was well-formed), and make an instance of the specified type (SomeType, in this example) from it.
Note that even if nothing at all in the XML is recognized, it will still not fail. The new instance will simply have all properties / public fields nulled or defaulted, the MessageList would list all the defaulting done, and the boolean out paramater would be FALSE.
The recursive method that does all the work has a similar signature, except it takes an XElement instead of an XDocument, and it does not take a schemaSet. (The present implementation also has an explicit bool to indicate a recursive call defaulting to false. This is a slightly dirty way to allow it to gather all failure messages up to the end before throwing an error if tolerant is false; in a future version I will refactor that to only expose publicly a version without that, if I even want to make the XElement version public at all):
public static T TolerantDeserializeXElementIntoType<T>(
ref XElement element,
ref List<string> messagesList,
out bool isFromSuppliedValue,
bool tolerant = true,
bool recursiveCall = false)
How it works, detail
Starting with the main call, the one with with an XDocument and optional SchemaSet:
If a schema Set that will compile is supplied (actually, it also looks for xsi:noNamespaceSchemaLocation as well) the initial XDocument and schemaSet call runs a standard XDocument.Validate() across the supplied XDocument, but this only collects any issued validation error callbacks. It won't throw an exception, and is done for only two reasons:
it will give some useful messages for the MessageList, and
it will populate the SchemaInfo of all XElements to
possibly use later in the XElement version.
(note, however, that the
schema is entirely optional. It is actually only used to resolve
some ambiguous situations where it can be unclear from the C#
object if a given XElement is mandatory or not.)
From there, the recursive XElement version is called on the root node and the supplied C# type.
I've made the code look for the style of C# objects generated by xsd.exe, though most basic structured objects using Properties and Fields would probably work even without the CustomAttributes that xsd.exe supplies, if the Xml elements are named the same as the properties and fields of the object.
The method looks for:
Arrays
Simple value types, explicitly:
String
Enum
Bool
then anything
else by using the relevant TryParse() method, found by reflection.
(note that nulls/xsi:nill='true' values also have to be specially
handled)
objects, recursively.
It also looks for a boolean 'xxxSpecified' in the object for each field or property 'xxx' that it finds, and sets it appropriately. This is how xsd.exe indicates an element being omitted from the XML in cases where null won't suffice.
That's the outline. As I said, I may be able to put actual code somewhere like GitHub in due course. Hope this is helpful to someone.

send custom type to wcf service

i need to pass an unknown type from my client to a wcf service ,
the type is unknown to the service .
for instance i have a class Customer which i create an instance of serialize and send to the service , the problem arises when i need to deserialize i have to provide the type in order to cast the desrialized object to .
Type can't be serialized , when attempted i get the following error :
{"Type 'System.RuntimeType' with data contract name
'RuntimeType:http://schemas.datacontract.org/2004/07/System' is not expected. Consider
using a DataContractResolver or add any types not known statically to the list of
known types - for example, by using the KnownTypeAttribute attribute or by adding
them to the list of known types passed to DataContractSerializer."}
i need to find a work around for this issue , any ideas ?
just to summarize :
i'm looking for a workaround for sending an unknown Type to a WCF service .
If the other end doesn't know anything about it (comments), then you can't possibly deserialize. You couldn't do that even with Type-based serializers (BinaryFormatter/NetDataContractSerializer).
If you are sending completely foreign data, then you are basically limited to things like XML or JSON, and even then the meaning is slightly ambiguous (is <id>123<id> a string? int? float? long?).
WCF is not well suited to your scenario (nor most other contract-based stacks; most systems expect to be able to understand incoming data).

Is there an XML specific object (like XElement) that is binary serializable?

I have a use case where I am serializing objects over the wire via MSMQ (mostly strings). When I read the object off the queue I want to be able to tell if the user meant for the object to be a XML or a string. I was thinking a good way to do this would just be to check the type. If it's XmlElement than it becomes XML data otherwise it becomes string or CDATA. The reason I don't want to just check to see if the data is valid XML is that sometimes data will be provided that is supposed to be serialized as a string but is in fact valid XML. I want the caller to be able to control the de-serialization into string or XML.
Are there any types that are marked as serializable in the .NET Framework like XElement or XmlElement (both which are not marked serializable)?
Why don't you just add a property to the class of the serialized object that tells you what it is? I'd propose IsXml.

Data Member Order and XML Deserialization

I have a RESTful WCF application that makes use of custom classes as service method parameters. These classes are decorated with the [DataContract] attribute and each of their properties is decorated with the [DataMember] attribute.
The deserializer works consistent with the following "Data Member Order" page at MSDN:
http://msdn.microsoft.com/en-us/library/ms729813.aspx.
That is, it expects the elements in XML formatted input data to follow the order so described. In fact, if one of the elements is out of order, after deserialization it does not have the submitted value but rather is null.
Is there a good way to allow the calling program to order the xml elements freely (i.e., in any order) and to have the deserialization come out right for every ordering of the elements?
Most XML does not permit elements to be entered in arbitrary order. There's no good reason to permit this, as far as I know.
The Data Contract Serializer does not support this at all. It would add overhead, and provide no value.
Why can't your callers just send the correct XML?

Categories