I am creating a service using Microsoft ASP.NET Web API with the following requirements:
- Input must be in XML (no json)
- XML will follow a standard (cannot add custom element names/attributes to the input xml)
- When encountering exceptions in deserialization (i.e. data values in bad format) they must be logged as warnings and parsing of the input xml must continue
- The XML will contain collections of elements in which the elements need to be
deserialized into types derived from a base type
Requirements 1 and 2 simply define my input. I started developing my solution by using the built-in System.Xml.Serialization.XmlSerializer class, but had to abandon it because it could not handle requirement #3.
Alternately, I found YAXLib which provided a very useful way to handle requirement #3.
YAXLib also handles requirement #4, but only by utilizing custom attributes in the XML:
<ListOfObjects>
<Object yaxlib:realtype="System.Int32">7</Object>
<Object yaxlib:realtype="System.Double">3.14</Object>
<Object yaxlib:realtype="System.String">Congrats</Object>
<Object yaxlib:realtype="System.StringSplitOptions">RemoveEmptyEntries</Object>
</ListOfObjects>
Because of requirement #2, I cannot use this approach. I need something like the System.Xml.Serialization.XmlElementAttribute so I can instruct the serializer in code, not in the data. Is there an existing solution out there that will handle all of these requirements?
Example:
Input
<DEALS>
<DEAL>
<COLLATERALS>
<COLLATERAL>xyz</COLLATERAL>
<COLLATERAL>1.2</COLLATERAL>
<COLLATERAL>4.5</COLLATERAL>
</COLLATERALS>
<LOANS>
<LOAN>
<CLOSING_INFORMATION />
</LOAN>
</LOANS>
</DEAL>
</DEALS>
C# Classes
public class DEAL
{
[System.Xml.Serialization.XmlElementAttribute("COLLATERALS", typeof(COLLATERALS))]
[System.Xml.Serialization.XmlElementAttribute("LOANS", typeof(LOANS))]
[YAXCollection(YAXCollectionSerializationTypes.RecursiveWithNoContainingElement)]
public object[] Items
{
get
{
return this.itemsField;
}
set
{
this.itemsField = value;
}
}
// Remaining implementation details omitted..
}
public class COLLATERALS { /* details omitted.. */ }
public class LOANS { /* details omitted.. */ }
public class COLLATERAL
{
[System.Xml.Serialization.XmlTextAttribute()]
public decimal Value { get; set; }
}
Expected Output
Objects in the Items collection of the DEALS class should be deserialized into their respective types: COLLATERALS and LOANS. Also, the first collateral with the value ‘xyz’ will not get deserialized (since the type is decimal) but the remaining valid COLLATERAL items would get deserialized. The error parsing ‘xyz’ to decimal should be logged somehow.
You can use an XML Schema (an XSD file) to define what the valid format of an XML file is. There are existing tools which will validate whether or not a particular file complies with a schema or not.
By providing this schema publicly you will be able to allow your clients to validate their own requests without needing to actually interact with your web service. It will allow them to see if their inputs are valid, and if they need to perform complex analysis on what specifically needs to be changed to comply they would be capable of doing that on their own.