web api list serialization - c#

I want to serialize a list to xml (from a web-api method).
public class Result
{
public List<string> Users { get; set; }
}
So I get for example:
<result>
<user>Paul</user>
<user>David</user>
<user>Joan</user>
</result>
So far, I get:
<result>
<users>
<user>Paul</user>
<user>David</user>
<user>Joan</user>
</users>
</result>
How do I tell the serialization not to wrap the user list in a "users" tag?
Thanks.

You could either derive from XmlObjectSerializer and implement your own XML Serializer (see here FMI) or else manipulate your type so it works with the default formatter. Which isn't a great solution, but may work for a simple example, like so:
public class Result : List<User>
{
//Any user added to Result will be nested directly within Result in the XML
}
Further reading:
MSDN: XmlObjectSerializer Class:
"Extend the XmlObjectSerializer to create your own serializer to serialize and deserialize objects."
Insights on WCF: CustomXmlObjectSerializer: Real-world example with source code.

You need to replace default DataContractSerializer with XmlSerializer in Application_Start method.
For whole project:
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
For specific type:
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.SetSerializer<Result>(new XmlSerializer(typeof(Result)));
After this you can use attributes to format your xml output:
public class Result
{
[XmlElement("user")]
public List<string> Users { get; set; }
}

Related

C# XmlSerializer conditionally serialialize List<T> items

i need to serialize and deserialize XML with C# XmlSerializer (or is there something better?).
[XmlElement]
public virtual List<Map> Maps { get; set; }
public class Map
{
[XmlAttribute("item")]
public string Item { get; set; }
[XmlAttribute("uri")]
public string Uri { get; set; }
}
Maps = new List<Map>{
new Map { Item="", Uri="" },
new Map { Item="something", Uri="foo" },
new Map { Item="", Uri="foo" },
}
The serializer should throw out every item with string.IsNullOrEmpty(map.Item) so that the resulting Xml only holds the map with "something".
How can I achieve this without a big hassle?:
<Maps>
<Map item="something" uri="foo" />
</Maps>
As far as I've understood, you want to filter your XML before you serialize it.
I suggest you use LINQ for this:
var filteredMaps = Maps.Where(map => !string.IsNullOrWhiteSpace(map.Item)).ToList();
Notice the .ToList() call at the end of the line. This is important, as your XmlSerializer is of type List<Map> I suppose. Put this line before you serialize your object and the result should look like this:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Map item="something" uri="foo" />
</ArrayOfMap>
Don't forget the using System.Linq;
Well you can try creating an XmlWriter that filters out all elements with an xsi:nil attribute or containing an empty string, and passes all other calls to the underlying standard XmlWriter to "clean up" serialized XML.

How to deserialize XML file with nested elements of same name, with one of elements are root?

I am trying to use the XmlSerializer class in C# to deserialize some XML that I am pulling from someone. Unfortunately, they have their root element named "Employee", and then the inner elements inside that root element are also named "Employee":
<Employee xmlns="http://www.testxmlns.com/employee">
<Employee>
<OtherElement>OE</OtherElement>
...
</Employee>
<Employee>
<OtherElement>OE</OtherElement>
...
</Employee>
</Employee>
I was able to find another question that is very similar, but not exactly. Here is what my current object looks like:
[XmlType("Employee")]
[XmlRootAttribute(Namespace = "http://www.testxmlns.com/employee", IsNullable = true)]
public class Employee
{
[XmlElement("Employee")]
public Employee[] InnerEmployee;
[XmlElement("OtherElement")]
public String OtherElement;
...
}
When I run the following, everything seems to work (no exceptions thrown), but everything in the returned object is null, including the inner list of Employee objects, which should not be null based on the XML I am inputting:
Employee retObj;
XmlSerializer serializer = new XmlSerializer(typeof(Employee));
using (TextReader sr = new StringReader(xmlString))
{
retObj = (Employee)serializer.Deserialize(sr);
}
return retObj;
Any help would be appreciated!
You can see in this fiddle that if I take your code and run it... it works!
What I would suggest, however, is to have two classes: one for the 'root' and one for each child element. This would make it less confusing to work with:
[XmlRoot("Employee", Namespace = "http://www.testxmlns.com/employee")]
public class EmployeeRoot
{
[XmlElement("Employee")]
public Employee[] Employees { get; set; }
}
public class Employee
{
public string OtherElement { get; set; }
}
You can see in this fiddle that this also works.

Restsharp - how to serialize a list of enums to strings

I have an List<AnimalsEnum> Foo property in a class that I'm serializing to XML with RestSharp for the body of a request. I'd like the output to be:
<rootNode>
... existing content...
<Foo>Elephant</Foo>
<Foo>Tiger</Foo>
.... more content
Instead, for the relevant serialisation part, I have
<Foo>
<AnimalsEnum />
<AnimalsEnum />
</Foo>
I'd like to convert the enum values to strings and remove the container element that is automatically added. Is this possible with RestSharp? I thought it may be possible with attributes, but apparently not. Am I going to have to wrangle this output myself with a custom serialiser?
Code is difficult to post, but keeping with the example:
class Bar
{
public string Name{get;set;}
public List<AnimalsEnum> Foo{get;set;}
public enum AnimalsEnum {Tiger,Elephant,Monkey}
}
and to serialize into a request
var req = new RestSharp.RestRequest(RestSharp.Method.POST);
req.RequestFormat = RestSharp.DataFormat.Xml;
req.AddQueryParameter("REST-PAYLOAD", "");
req.AddXmlBody(myBar);
You can use the built-in DotNetXmlSerializer of RestSharp to make Microsoft's XmlSerializer do the actual serialization. Then you can use XML serialization attributes to specify that the List<AnimalsEnum> of Bar should be serialized without an outer container element by applying [XmlElement]:
public class Bar
{
public string Name { get; set; }
[System.Xml.Serialization.XmlElement]
public List<AnimalsEnum> Foo { get; set; }
public enum AnimalsEnum { Tiger, Elephant, Monkey }
}
Then, when making the request, do:
var req = new RestSharp.RestRequest(RestSharp.Method.POST);
// Use XmlSerializer to serialize Bar
req.XmlSerializer = new RestSharp.Serializers.DotNetXmlSerializer();
req.RequestFormat = RestSharp.DataFormat.Xml;
req.AddQueryParameter("REST-PAYLOAD", "");
req.AddXmlBody(myBar);
Note that Bar must be public because XmlSerializer can only serialize public types.

Property will not serialize as XML attribute

I am attempting to serialize a class as XML and to have the properties be serialized as attributes of the class, rather than a nested node. I am using WebApi to automatically handle the serialization of the XML.
This is my class:
[DataContract (Namespace="", Name="AttributeTest")]
[Serializable]
public class AttributeTestClass
{
[XmlAttribute("Property")]
[DataMember]
public int Property1 { get; set; }
}
Here is the output I am receiving (note that Property1 is not an attribute in spite of it being decorated with [XmlAttribute]):
<AttributeTest xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Property1>123</Property1>
</AttributeTest>
This is the output I want to receive:
<AttributeTest Property1="123" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
</AttributeTest>
What am I missing?
I'm not familiar with WebApi but the output you receive looks like it's serialized using DataContractSerializer, not XmlSerializer which you would need. Check if adding the following to Application_Start in Global.asax helps:
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(
new System.Net.Http.Formatting.XmlMediaTypeFormatter());
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
(From http://serena-yeoh.blogspot.de/2013/02/xml-serialization-in-aspnet-web-api.html)

Deserialize XML Array Where Root is Array and Elements Dont Follow Conventions

The XML I am getting is provided by an outside source so I don't have the ability to easily reformat it. I would like to use xml attributes on my entities instead of having to write a linq query that knows how the XML and entity is formatted. Here is an example:
<?xml version="1.0"?>
<TERMS>
<TERM>
<ID>2013-2</ID>
<DESC>Spring 2013</DESC>
</TERM>
<TERM>
<ID>2013-3</ID>
<DESC>Summer 2013 Jun&Jul</DESC>
</TERM>
</TERMS>
I know the the XMLSerializer expects ArrayOfTerm instead of TERMS for example, but that I can tweak my entity to use a different element name with the xml attributes such as this:
public class TermData
{
[XmlArray("TERMS")]
[XmlArrayItem("TERM")]
public List<Term> terms;
}
public class Term
{
[XmlElement("ID")]
public string id;
[XmlElement("DESC")]
public string desc;
}
and I am deserializing the data like so:
TermData data;
XmlSerializer serializer = new XmlSerializer(typeof(TermData));
using (StringReader reader = new StringReader(xml))
{
data = (TermData)serializer.Deserialize(reader);
}
return View(data.terms);
The problem I am facing is that TERMS is the root and the array itself. If the XML were to have a root element that was not the array, I could edit my TermData class like so and it would deserialize correctly (already tested).
[XmlRoot("ROOT")]
public class TermData
{
[XmlArray("TERMS")]
[XmlArrayItem("TERM")]
public List<Term> terms;
}
Note that using TERMS as the XMLRoot does not work. Right now, my code is throwing
InvalidOperationException: There is an error in XML document (2,2).
InnerException: "<TERMS xmlns=" was not expected.
This would lead me to believe that the XML is not formatted correctly, but from my understanding the example I gave is perfectly valid XML.
This would all be trivial if I could edit the source xml, but there could be tons of other responses like this and I need to be able to flex for whatever I might get. What I'm trying to confirm is whether or not the XMLSerializer can support this type of XML structure. I've tested just about everything and can't get it deserialize without editing the XML. It would also be convenient if I didn't have to define a wrapper class (TermData) to hold the list, but this seems to only work if the xml follows the naming conventions for the serializer (ArrayOfTerm, etc).
Maybe you can try :
[XmlRoot("TERMS")]
public class TermData
{
public TermData()
{
terms = new List<Term>();
}
[XmlElement("TERM")]
public List<Term> terms{get;set;}
}
public class Term
{
[XmlElement("ID")]
public string id{get;set;}
[XmlElement("DESC")]
public string desc{get;set;}
}
Hope this will help,

Categories

Resources