ASP.NET Web API and XML Serialization - c#

I am developing a Web API and I have a model as below:
public class Customer
{
[XmlElement]
public string Name { get; set; }
[XmlElement]
public decimal Age { get; set; }
}
And my controller is:
public class CustomerController : ApiController
{
public Customer Get()
{
return new Customer {Name="Mike",Age=22.0M };
}
}
}
When I set accept:application/xml my result is:
<?xml version="1.0" encoding="utf-8"?>
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Mike</Name>
<Age>22.0</Age>
</Customer>
As I am developing it for a customer, I need my xml to be:
<?xml version="1.0" encoding="utf-8"?>
<cu:Customer xmlns:cu="http://www.mywebsite.com/test">
<Name>Mike</Name>
<Age>22.0</Age>
</cu:Customer>
I can do that if I create an XmlSerializer and manually call Serialize fuction and then return the result as string, but I need the function to return Customer as return value.

Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication128
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("cu", "http://www.mywebsite.com/test");
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(FILENAME, settings);
XmlSerializer serializer = new XmlSerializer(typeof(Customer));
CustomerController controller = new CustomerController();
serializer.Serialize(writer, controller.Get(), namespaces);
}
}
public class ApiController
{
}
public class CustomerController : ApiController
{
public Customer Get()
{
return new Customer { Name = "Mike", Age = 22.0M };
}
}
[XmlRoot(ElementName = "Customer", Namespace = "http://www.mywebsite.com/test")]
public class Customer
{
[XmlElement(Namespace = "")]
public string Name { get; set; }
[XmlElement(Namespace = "")]
public decimal Age { get; set; }
}
}

Related

Trying to deserialize list of ints using DataContractSerializer, received unexpected InvalidOperationException

Expectation: Read the list of ints from the XML-file to the List called itemPool;
Result: "InvalidOperationException: Failed to add type System.Collections.Generic.List`1[System.Int32] to known type collection. There already is a registered type for XML name http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfint"
I have to following code:
using System.Collections.Generic;
using System.Runtime.Serialization;
using Characters;
using Items;
[DataContract(Name ="Savefile", Namespace ="")]
public class Savefile
{
[DataMember(Name ="Characters")]
public List<Character> characters = new List<Character>();
[DataMember(Name = "ItemPool")]
public List<int> itemPool = new List<int>();
public void Initialize()
{
foreach (Character c in characters)
c.Initialize();
ItemPool.Load(itemPool.ToArray());
}
}
And another class with the following method:
public static void LoadFromSavefile()
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Savefile));
FileStream stream = new FileStream(Path.Combine(Application.dataPath, _savefilePath), FileMode.Open);
_currentSave = serializer.ReadObject(stream) as Savefile;
stream.Close();
}
And the following xml-file that the class above reads from.
<?xml version="1.0" encoding="utf-8"?>
<Savefile xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Characters>
<Character>
<... not relevant clutter.../>
</Character>
</Characters>
<ItemPool>
<value>1</value>
</ItemPool>
</Savefile>
Edited using DataContractSerializer.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Runtime.Serialization;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace UnitTestProject1 {
[DataContract(Name = "Savefile", Namespace = "")]
public class Savefile {
[DataMember(Name = "Characters", Order = 0)]
public Characters Characters { get; private set; }
[DataMember(Name = "ItemPool", Order = 1)]
public Items ItemPool { get; private set; }
}
[CollectionDataContract(Name = "Characters", ItemName = "Character", Namespace = "")]
public class Characters : List<Character> {
}
public class Character {
public string Weapon { get; set; }
internal void Initialize() {
throw new NotImplementedException();
}
}
[CollectionDataContract(Name = "ItemPool", ItemName = "Item", Namespace = "")]
public class Items : List<int> {
public int value { get; set; }
}
[TestClass]
public class UnitTestSerialization {
[TestMethod]
public void TestMethod1() {
DataContractSerializer serializer = new DataContractSerializer(typeof(Savefile));
FileStream stream = new FileStream("SaveFile2.xml", FileMode.Open);
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
Savefile _currentSave = (Savefile)serializer.ReadObject(reader);
Assert.IsNotNull(_currentSave);
stream.Close();
}
}
}
xml file
<?xml version="1.0" encoding="utf-8"?>
<Savefile>
<Characters>
<Character>
<Weapon>Axe</Weapon>
</Character>
<Character>
<Weapon>Mace</Weapon>
</Character>
<Character>
</Character>
</Characters>
<ItemPool>
<Item>1</Item>
<Item>2</Item>
</ItemPool>
</Savefile>

c# XML Serializing with derived classes using different namespace

I am trying to read a xml file and deserialize it to my InsertSensorType class and than read VALUE1,VALUE2 .. .I tried to add XmlElement name to my InsertionMetadata attribute in InsertSensorTypeMetadata class, but it doesn't work.I have searched and found solutions but they were not valid for this problem. Can anyone please tell me what i am doing wrong.
Xml File :
<?xml version="1.0" encoding="utf-8" ?>
<swes:InsertSensor
xmlns:swes="http://www.opengis.net/swes/2.0"
xmlns:sos="http://www.opengis.net/sos/2.0" >
<swes:metadata>
<sos:SosInsertionMetadata>
<sos:observationType>VALUE1</sos:observationType>
<sos:observationType>VALUE2</sos:observationType>
<sos:featureOfInterestType>VALUE3</sos:featureOfInterestType>
<sos:featureOfInterestType>VALUE4</sos:featureOfInterestType>
</sos:SosInsertionMetadata>
</swes:metadata>
</swes:InsertSensor>
My Classes :
namespace Problem1.Classes
{
[SerializableAttribute()]
[XmlTypeAttribute(Namespace = "http://www.opengis.net/swes/2.0")]
[XmlRootAttribute("InsertSensor", Namespace = "http://www.opengis.net/swes/2.0", IsNullable = false)]
public class InsertSensorType
{
[System.Xml.Serialization.XmlElementAttribute("metadata")]
public InsertSensorTypeMetadata[] metadata { get; set; }
}
[SerializableAttribute()]
[XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.opengis.net/swes/2.0")]
public class InsertSensorTypeMetadata
{
[XmlElement(ElementName = "SosInsertionMetadata", Type = typeof(SosInsertionMetadataType))]
public InsertionMetadataType InsertionMetadata { get; set; }
}
[XmlIncludeAttribute(typeof(SosInsertionMetadataType))]
[SerializableAttribute()]
[XmlTypeAttribute(Namespace = "http://www.opengis.net/swes/2.0")]
public abstract partial class InsertionMetadataType
{
}
[SerializableAttribute()]
[XmlTypeAttribute(Namespace = "http://www.opengis.net/sos/2.0")]
public partial class SosInsertionMetadataType : InsertionMetadataType
{
[System.Xml.Serialization.XmlElementAttribute("observationType", DataType = "anyURI")]
public string[] observationType { get; set; }
[System.Xml.Serialization.XmlElementAttribute("featureOfInterestType", DataType = "anyURI")]
public string[] featureOfInterestType { get; set; }
}
}
And here is my main code :
static void Main(string[] args)
{
XmlElement xmlRequest = null;
XmlDocument doc = new XmlDocument();
doc.Load("request.xml");
xmlRequest = doc.DocumentElement;
executeRequest(xmlRequest);
}
static void executeRequest(XmlElement xmlRequest)
{
InsertSensorType insertSensorRequest = ValidateRequest<InsertSensorType>(xmlRequest);
InsertSensorTypeMetadata[] _InsertSensorTypeMetadata = insertSensorRequest.metadata;
Console.WriteLine("Length of metadata :" + _InsertSensorTypeMetadata.Length);//1
foreach (InsertSensorTypeMetadata istm in _InsertSensorTypeMetadata)
{
SosInsertionMetadataType sos = istm.InsertionMetadata as SosInsertionMetadataType;
//sos is null
}
Console.Read();
}
static T ValidateRequest<T>(XmlElement xmlRequest) where T : class
{
string xml = xmlRequest.OuterXml;
StringReader reader = new StringReader(xml);
XmlSerializer serializer = new XmlSerializer(typeof(T));
//XmlSerializer serializer = new XmlSerializer(typeof(T), new Type[] { typeof(SosInsertionMetadataType) });
T typeInstance = (T)serializer.Deserialize(reader);
return typeInstance;
}
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
InsertSensorType insertSensorType = new InsertSensorType() {
metadata = new Metadata() {
insertSensorTypeMetadata = new InsertSensorTypeMetadata() {
InsertionMetadata = new List<InsertionMetadataType>() {
new ObservationType() { value = "Value1"},
new ObservationType() { value = "Value2"},
new FeatureOfInterestType() { value = "Value3"},
new FeatureOfInterestType() { value = "Value4"}
}
}
}
};
XmlSerializer serializer = new XmlSerializer(typeof(InsertSensorType));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("swes","http://www.opengis.net/swes/2.0");
ns.Add("sos","http://www.opengis.net/sos/2.0");
StreamWriter writer = new StreamWriter(FILENAME);
serializer.Serialize(writer, insertSensorType, ns);
writer.Flush();
writer.Close();
writer.Dispose();
XmlSerializer xs = new XmlSerializer(typeof(InsertSensorType));
XmlTextReader reader = new XmlTextReader(FILENAME);
InsertSensorType newInsertSensorType = (InsertSensorType)xs.Deserialize(reader);
}
}
[XmlRoot(ElementName = "InsertSensor")]
public class InsertSensorType
{
[XmlElement("metadata")]
public Metadata metadata { get; set; }
}
[XmlRoot("metadata", Namespace = "http://www.opengis.net/swes/2.0")]
public class Metadata
{
[XmlElement("SosInsertionMetadata")]
public InsertSensorTypeMetadata insertSensorTypeMetadata { get; set; }
}
[XmlRoot("SosInsertionMetadata", Namespace = "http://www.opengis.net/sos/2.0")]
public class InsertSensorTypeMetadata
{
[XmlElement()]
public List<InsertionMetadataType> InsertionMetadata { get; set; }
}
[XmlInclude(typeof(ObservationType))]
[XmlInclude(typeof(FeatureOfInterestType))]
[Serializable]
[XmlRoot(Namespace = "http://www.opengis.net/sos/2.0")]
public class InsertionMetadataType
{
public string value { get; set; }
}
[Serializable]
[XmlRoot(ElementName = "observationType", Namespace = "http://www.opengis.net/sos/2.0")]
public class ObservationType : InsertionMetadataType
{
}
[Serializable]
[XmlRoot(ElementName = "featureOfInterestType", Namespace = "http://www.opengis.net/sos/2.0")]
public class FeatureOfInterestType : InsertionMetadataType
{
}
}
​
My solution is that :
added this line to over InsertionMetadata attribute in InsertSensorTypeMetadata class
[System.Xml.Serialization.XmlElement(ElementName = "SosInsertionMetadata", Type = typeof(SosInsertionMetadataType), Namespace = "http://www.opengis.net/sos/2.0")] // added
change my deserialize method
public static T ValidateRequest<T>(XmlElement element) where T : class
{
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(new XmlNodeReader(element));
}
and changed way to print values
static void executeRequest(XmlElement xmlRequest)
{
InsertSensorType insertSensorRequest = ValidateRequest<InsertSensorType>(xmlRequest);
foreach (InsertSensorTypeMetadata istm in insertSensorRequest.metadata)
{
SosInsertionMetadataType sos = (SosInsertionMetadataType)istm.InsertionMetadata;
foreach(string s in sos.featureOfInterestType)
Console.WriteLine(s);
foreach (string s in sos.observationType)
Console.WriteLine(s);
}
}

Xml Data In WCF Not Serializing Correctly

i have been developing a wcf service with rest. Here is my DataContract that i have defined in the service. This is service will be consumed by the android device users and the data will be get passed in the service method in the form of the xml.
[DataContract(Namespace = "")]
public class Employee
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public List<City> city { get; set; }
}
[DataContract]
public class City
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string CityName { get; set; }
}
And the following is the servicecontract that i have defined
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/SaveData/New")]
void SaveData(Employee emp);
}
Now the implementation code for this service is as follows :
public void SaveData(Employee emp)
{
Employee obj = emp;
DataContractSerializer dcs = new DataContractSerializer(typeof(Employee));
using (Stream stream = new FileStream(#"D:\file.xml", FileMode.Create, FileAccess.Write))
{
using (XmlDictionaryWriter writer =
XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8))
{
writer.WriteStartDocument();
dcs.WriteObject(writer, obj);
}
}
When i send the data in xml format using fiddler it is not getting parsed correctly. Here is what i m passing to the method using fiddler :
<Employee>
<ID>1</ID>
<Name>Nitin Singh</Name>
<City>
<Id>1<Id>
<CityName>New Delhi<CityName>
<City>
</Employee>
the output that it is rendering is as follows : -
<?xml version="1.0" encoding="utf-8"?><Employee xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><ID>1</ID><Name>Nitin Singh</Name><city i:nil="true" xmlns:a="http://schemas.datacontract.org/2004/07/SampleService"/></Employee>
I want the city valus should also be present into but it is not happening here. Kindly help me to figure out this. Thanks
XmlSerializer allows you to "flatten" a list into a sequence of identically named elements, like so:
[XmlRoot("Employee", Namespace="")]
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
[XmlElement("City")]
public List<City> City { get; set; }
}
public class City
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string CityName { get; set; }
}
And, to use it:
public static class XmlSerializationHelper
{
public static string GetXml<T>(T obj, XmlSerializer serializer, bool omitStandardNamespaces)
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true; // For cosmetic purposes.
settings.IndentChars = " "; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
if (omitStandardNamespaces)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
serializer.Serialize(xmlWriter, obj, ns);
}
else
{
serializer.Serialize(xmlWriter, obj);
}
}
return textWriter.ToString();
}
}
public static string GetXml<T>(this T obj, bool omitNamespace)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
return GetXml(obj, serializer, omitNamespace);
}
public static string GetXml<T>(this T obj)
{
return GetXml(obj, false);
}
}
Test code:
var employee = new Employee { Name = "Nitin Singh", ID = 1, City = new[] { new City { CityName = "New Delhi", Id = 1 }, new City { CityName = "Bangalore", Id = 2 } }.ToList() };
var xml = employee.GetXml();
Debug.WriteLine(xml);
For your classes this produces the following XML:
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>1</ID>
<Name>Nitin Singh</Name>
<City>
<Id>1</Id>
<CityName>New Delhi</CityName>
</City>
<City>
<Id>2</Id>
<CityName>Bangalore</CityName>
</City>
</Employee>
Is that what you want? This writes the XML to a string for testing purposes. Instructions for writing to a file are here: How to: Write Object Data to an XML File.
(You made a couple minor mistakes with your data contract -- public List<City> city should have been public List<City> City and public class City needed [DataContract(Namespace = "")]. However, the resulting list would have been two levels deep.)

C# deserialization element mapping

I would like to deserialize the following XML into the following type. How do I map the status correctly? (it is currently not mapped and remains null after the deserialization process)
<?xml version="1.0" encoding="UTF-8"?>
<job:job-status xsi:schemaLocation="http://marklogic.com/xdmp/job-status job-status.xsd" xmlns:job="http://marklogic.com/xdmp/job-status" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<job:forest>
<job:forest-name>FOREST2</job:forest-name>
<job:forest-id>1168048654236455340</job:forest-id>
<job:status>completed</job:status>
<job:journal-archiving>false</job:journal-archiving>
</job:forest>
</job:job-status>
[XmlRoot("job-status", Namespace = "http://marklogic.com/xdmp/job-status")]
public class DatabaseRestoreStatus
{
[XmlElement("status")]
public string Status { get; set; }
}
Using DataContract Serializer worked for me. I also had to create one more class.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
namespace SandboxConoleApp
{
internal class Program
{
private static void Main(string[] args)
{
DatabaseRestoreStatus data = null;
using (var stream = File.Open("test.xml",FileMode.Open))
{
var formatter = new DataContractSerializer(typeof(DatabaseRestoreStatus));
data = (DatabaseRestoreStatus)formatter.ReadObject(stream);
}
}
}
[DataContract(Name = "job-status", Namespace = "http://marklogic.com/xdmp/job-status")]
public class DatabaseRestoreStatus
{
[DataMember(Name = "forest")]
public Forest Forest { get; set; }
}
[DataContract(Name = "forest", Namespace = "http://marklogic.com/xdmp/job-status")]
public class Forest
{
[DataMember(Name = "status")]
public string Status { get; set; }
}
}

how to remove namespace from XML root element?

is there a simple way to remove the namespace from the XML root element. I have tried with
[XmlRootAttribute("MCP", Namespace = "", IsNullable = false)]
on the serializable class. But no use. still getting the same result.
sample class
[Serializable]
[XmlRootAttribute("MCP", Namespace = "", IsNullable = false)]
public class BINDRequest
{
public BINDRequest()
{
}
[XmlAttribute]
public string CLIENT_REQUEST_ID { get; set; }
public BINDRequestBody BIND { get; set; }
}
result xml
<?xml version="1.0" encoding="utf-8"?>
<MCP xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CLIENT_REQUEST_ID="1">
<BIND CLIENT_ID="test" PASSWORD="test" />
</MCP>
i don't understand then whats the use of specifying namsespace in XmlRootAttribute??
Try this:
public class BINDRequest
{
[XmlAttribute]
public string CLIENT_REQUEST_ID { get; set; }
}
class Program
{
static void Main()
{
var request = new BINDRequest
{
CLIENT_REQUEST_ID = "123"
};
var serializer = new XmlSerializer(request.GetType());
var xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
using (var writer = XmlWriter.Create("result.xml"))
{
serializer.Serialize(writer, request, xmlnsEmpty);
}
}
}

Categories