I need to make a api where in the request body there needs to be a CData object. All works exept that I cant figure out how to make my object serialze into a CData object. The project is written in the .net-framework.
I currently have the following code.
C#:
[XmlRoot(ElementName = "DATA")]
public class DATA
{
[XmlElement(ElementName = "ID")]
public int ID { get; set; }
[XmlElement(ElementName = "NAME")]
public string NAME{ get; set; }
}
[XmlRoot(ElementName = "NewDataSet")]
public class CDataSet
{
[XmlElement(ElementName = "DATA")]
public DATA data{ get; set; }
}
How the xml needs to look after:
<![CDATA[
<NewDataSet>
<DATA>
<ID>007</ID>
<NAME>John</NAME>
</DATA>
</NewDataSet>
]]>
I can make it working by serializing normally by making a request to this function:
public static string SerializeObject<T>(this T toSerialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
using (StringWriter textWriter = new StringWriter())
{
xmlSerializer.Serialize(textWriter, toSerialize);
return textWriter.ToString();
}
}
Than manual adding the CData parts around it.
However my boss wants it make it work without manually adding the parts.
Please note I'm very new to C#.
Any step in the right direction will help. Thanks!
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication8
{
class Program
{
static void Main(string[] args)
{
CDataSet data = new CDataSet()
{
data = new DATA() { ID = "007", NAME = "John" }
};
MemoryStream stream = new MemoryStream();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(stream, settings);
XmlSerializer serializer = new XmlSerializer(typeof(CDataSet));
serializer.Serialize(writer, data);
writer.Flush();
writer.Close();
stream.Position = 0;
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, (int)stream.Length);
string xml = Encoding.UTF8.GetString(buffer);
string output = string.Format("<![CDATA[\n{0}\n]]>", xml);
}
}
[XmlRoot(ElementName = "DATA", Namespace = "")]
public class DATA
{
private int _ID { get; set; }
[XmlElement(ElementName = "ID")]
public string ID {
get { return _ID.ToString("D3");}
set{ _ID = int.Parse(value);}
}
[XmlElement(ElementName = "NAME")]
public string NAME { get; set; }
}
[XmlRoot(ElementName = "NewDataSet")]
public class CDataSet
{
[XmlElement(ElementName = "DATA")]
public DATA data { get; set; }
}
}
Related
I get from a webservice a XML like this:
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<Get_PersonResponse
xmlns="http://tempuri.org/">
<Get_PersonResult
xmlns:a="http://schemas.datacontract.org/example"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:LASTNAME>DOE</a:LASTNAME>
<a:EMAIL/>
<a:FIRSTNAME>JONH</a:FIRSTNAME>
<a:NUM_CARD/>
<a:ID_PERSON>12345456</a:ID_PERSON>
<a:PHONE/>
</Get_PersonResult>
<RESP_COMMENT>"Person found"</RESP_COMMENT>
</Get_PersonResponse>
</s:Body>
</s:Envelope>
I want to check if RESP_COMMENT is empty. Then if is not empty get all the values (a:FIRSTNAME, a:LASTNAME, etc)
I got the a:FIRSTNAME on the fiddle but I am not sure if I have to do a bucle for every single value or is a better way to do it:
https://dotnetfiddle.net/cOsX6s
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(output);
XmlNodeList nodeList = xmldoc.GetElementsByTagName("a:FIRSTNAME");
string lastname = string.Empty;
foreach (XmlNode node in nodeList)
{
firstname = node.InnerText;
Console.Write(firstname);
}
Try xml serialization :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication177
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
StringReader sReader = new StringReader(xml);
XmlReader xReader = XmlReader.Create(sReader);
XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
Envelope envelope = (Envelope)serializer.Deserialize(xReader);
}
}
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement(Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
}
public class Body
{
[XmlElement(ElementName = "Get_PersonResponse", Namespace = "http://tempuri.org/")]
public Get_PersonResponse Get_PersonResponse { get; set; }
}
public class Get_PersonResponse
{
[XmlElement(Namespace = "http://tempuri.org/")]
public string RESP_COMMENT { get; set; }
[XmlElement(ElementName = "Get_PersonResult", Namespace = "http://tempuri.org/")]
public Get_PersonResult Get_PersonResult { get; set; }
}
public class Get_PersonResult
{
[XmlElement(Namespace = "http://schemas.datacontract.org/example")]
public string LASTNAME { get;set;}
[XmlElement(Namespace = "http://schemas.datacontract.org/example")]
public string EMAIL { get; set; }
[XmlElement(Namespace = "http://schemas.datacontract.org/example")]
public string FIRSTNAME { get; set; }
[XmlElement(Namespace = "http://schemas.datacontract.org/example")]
public string NUM_CARD { get; set; }
[XmlElement(Namespace = "http://schemas.datacontract.org/example")]
public string ID_PERSON { get; set; }
[XmlElement(Namespace = "http://schemas.datacontract.org/example")]
public string PHONE { get; set; }
}
}
There should be a way to get this values using xpath. I have tried a few different things and it seems that the empty prefix on namespace xmlns="http://tempuri.org/" is causing problems, see the element Get_PersonResponse namespace attribute.
<Get_PersonResponse xmlns="http://tempuri.org/">
To overcome this problem we need to remove the namespace that is causing the problem before loading the xml.
using System;
using System.Xml;
public class Program
{
public static void Main()
{
string output = #"<s:Envelope
xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
<s:Body>
<Get_PersonResponse
xmlns=""http://tempuri.org/"">
<Get_PersonResult
xmlns:a=""http://schemas.datacontract.org/example""
xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<a:LASTNAME>DOE</a:LASTNAME>
<a:EMAIL/>
<a:FIRSTNAME>JONH</a:FIRSTNAME>
<a:NUM_CARD/>
<a:ID_PERSON>12345456</a:ID_PERSON>
<a:PHONE/>
</Get_PersonResult>
<RESP_COMMENT>""Person found!""</RESP_COMMENT>
</Get_PersonResponse>
</s:Body>
</s:Envelope>";
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(output.Replace(#"xmlns=""http://tempuri.org/""", ""));
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmldoc.NameTable);
nsmgr.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("a", "http://schemas.datacontract.org/example");
var personResultNode = xmldoc.SelectSingleNode("//s:Envelope/s:Body/Get_PersonResponse/Get_PersonResult", nsmgr);
foreach (var nodes in personResultNode.ChildNodes)
{
var personAttribute = (XmlNode)nodes;
Console.WriteLine($"{personAttribute.LocalName}: {personAttribute.InnerText}");
}
Console.Read();
}
}
BTW: I have also tried to add an empty prefix for namespace xmlns="http://tempuri.org/" to the XmlNamespaceManager but that didn't help.
I am trying to post an object in my controller but it is coming in null. The object is a complex type and suspect it is the reason why Im getting an exception.
public class CertificateRequest
{
public string Name {get;set;}
public string RequestNumber {get;set;}
public List<TradeUnit> TradeUnits {get;set;}
}
public class TradeUnit
{
public string TradeUnitNumber {get;set;}
}
Controller:
[HttpPost]
public IHttpActionResult Post(CertificateRequest req)
{
........
}
When I check Swagger, it appears the object its expecting is silently different.
<CertificateRequest>
<Name>Some Name</Name>
<RequestNumber>Req001</RequestNumber>
<TradeUnits>
<TradeUnitNumber>TUN0005</TradeUnitNumber>
</TradeUnits>
</CertificateRequest>
The problem happens when I have multiple TradeUnits I would like to post and would have my structure to be in the following format, how do I achieve this.
<CertificateRequest>
<Name>Some Name</Name>
<RequestNumber>Req001</RequestNumber>
<TradeUnits>
<TradeUnit>
<TradeUnitNumber>TUN0001</TradeUnitNumber>
</TradeUnit>
<TradeUnit>
<TradeUnitNumber>TUN0002</TradeUnitNumber>
</TradeUnit>
<TradeUnit>
<TradeUnitNumber>TUN0003</TradeUnitNumber>
</TradeUnit>
</TradeUnits>
</CertificateRequest>
How can I achieve this?
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication135
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(FILENAME, settings);
CertificateRequest request = new CertificateRequest();
XmlSerializer serializer = new XmlSerializer(typeof(CertificateRequest));
serializer.Serialize(writer, request);
}
}
public class CertificateRequest
{
public string Name { get; set; }
public string RequestNumber { get; set; }
[XmlArray("TradeUnits")]
[XmlArrayItem("TradeUnit")]
public List<TradeUnit> tradeUnits { get; set; }
public CertificateRequest()
{
Name = "Some Name";
RequestNumber = "Req001";
tradeUnits = new List<TradeUnit>() {
new TradeUnit() { TradeUnitNumber = "TUN0001"},
new TradeUnit() { TradeUnitNumber = "TUN0002"},
new TradeUnit() { TradeUnitNumber = "TUN0003"}
};
}
}
public class TradeUnit
{
public string TradeUnitNumber { get; set; }
}
}
Using following will eliminate a tag
[XmlElement("TradeUnit")]
public List<TradeUnit> tradeUnits { get; set; }
I have two class : Osoba, test
public class test
{
public string raz { get; set; }
public string dwa { get; set; }
}
public class Osoba
{
public test tehe { get; set; }
}
I also add namespaces to main root and seralize
Osoba ne = new Osoba();
test t1 = new praca2.test();
t1.dwa = "fgfg";
t1.raz = "dfdfdfdf";
ne.tehe = t1;
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("dfs", "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution");
ns.Add("d", "http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields");
ns.Add("pc", "http://schemas.microsoft.com/office/infopath/2007/PartnerControls");
XmlSerializer xsSubmit = new XmlSerializer(typeof(Osoba));
var xml = #"D:\dupa1.xml";
using (var stream = new FileStream(xml, FileMode.Create))
{
using (XmlWriter writer = XmlWriter.Create(stream))
{
xsSubmit.Serialize(writer, ne,ns);
xml = stream.ToString(); // Your XML
}
}
I get
<?xml version="1.0" encoding="utf-8"?>
<Osoba xmlns:dfs="http://schemas.microsoft.com/office/infopath/2003/dataFormSolution"xmlns:pc="http://schemas.microsoft.com/office/infopath/2007/PartnerControls"xmlns:d="http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields">
<tehe>
<raz>dfdfdfdf</raz>
<dwa>fgfg</dwa>
</tehe>
</Osoba>
I want add to node namespaces examle:
...
<pc:tehe>
<dfs:raz>dfdfdfdf</dfs:raz>
<dfs:dwa>fgfg</dfs:dwa>
</pc:tehe>
How I can do it?
I try add class atribute which set namespace
[XmlRoot("Node", Namespace="http://flibble")]
but it bad idea
You're almost there you just need to modify your classes slightly:
public class test
{
[XmlElement(Namespace = "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution")]
public string raz { get; set; }
[XmlElement(Namespace = "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution")]
public string dwa { get; set; }
}
public class Osoba
{
[XmlElement(Namespace = "http://schemas.microsoft.com/office/infopath/2007/PartnerControls")]
public test tehe { get; set; }
}
Sample implementation copied mostly from yours:
class Program
{
static void Main(string[] args)
{
Osoba ne = new Osoba();
test t1 = new test();
t1.dwa = "fgfg";
t1.raz = "dfdfdfdf";
ne.tehe = t1;
XmlSerializer xsSubmit = new XmlSerializer(typeof(Osoba));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("dfs", "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution");
ns.Add("pc", "http://schemas.microsoft.com/office/infopath/2007/PartnerControls");
var xml = #"D:\dupa1.xml";
using (var stream = new FileStream(xml, FileMode.Create))
{
using (XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8))
{
xsSubmit.Serialize(writer, ne, ns);
}
}
}
}
You will get this XML:
<?xml version="1.0" encoding="utf-8"?>
<Osoba xmlns:dfs="http://schemas.microsoft.com/office/infopath/2003/dataFormSolution" xmlns:pc="http://schemas.microsoft.com/office/infopath/2007/PartnerControls">
<pc:tehe>
<dfs:raz>dfdfdfdf</dfs:raz>
<dfs:dwa>fgfg</dfs:dwa>
</pc:tehe>
</Osoba>
Hth...
Uisng xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication42
{
class Program
{
static void Main(string[] args)
{
string xmlHeader =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<Osoba xmlns:dfs=\"http://schemas.microsoft.com/office/infopath/2003/dataFormSolution\"" +
" xmlns:pc=\"http://schemas.microsoft.com/office/infopath/2007/PartnerControls\"" +
" xmlns:d=\"http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields\">" +
"</Osoba>";
XDocument doc = XDocument.Parse(xmlHeader);
XElement osoba = doc.Root;
XNamespace dfsNs = osoba.GetNamespaceOfPrefix("dfs");
XNamespace pcNs = osoba.GetNamespaceOfPrefix("pc");
osoba.Add(new XElement(pcNs + "tehe", new object[] {
new XElement(dfsNs + "raz", "dfdfdfdf"),
new XElement(dfsNs + "dwa", "fgfg")
}));
}
}
}
I think you are new at C#.I suggest you to study C# basics, design patterns and repository pattern.For your requirement you can use below codes
public class Tehe
{
public string Raz { get; set; }
public string Dwa { get; set; }
}
public class TeheRepository
{
private System.Xml.Linq.XDocument xmlDatas;
public TeheRepository(string filePath)
{
xmlDatas = XDocument.Load(filePath);
}
public IEnumerable<Tehe> FindAll()
{
return xmlDatas.Elements().Elements().Select(tehe =>
{
Tehe t = new Tehe();
t.Dwa = tehe.Elements().ElementAt(1).Value;
t.Raz = tehe.Elements().ElementAt(0).Value;
return t;
});
}
}
I'm trying to deserialize an xml document:
<?xml version="1.0"?>
<games xmlns = "http://serialize">
<game>
<name>TEST1</name>
<code>TESTGAME1</code>
<ugn>1111111</ugn>
<bets>
<bet>5,00</bet>
</bets>
</game>
<game>
<name>TEST2</name>
<code>TESTGAME2</code>
<ugn>222222</ugn>
<bets>
<bet>0,30</bet>
<bet>0,90</bet>
</bets>
</game>
</games>
.cs class:
namespace XmlParse
{
using System.Collections.Generic;
using System.Runtime.Serialization;
[DataContract(Namespace = "http://serialize")]
public class game
{
#region Public Properties
[DataMember]
public string name { get; set; }
[DataMember]
public string code { get; set; }
[DataMember]
public long ugn { get; set; }
[DataMember]
public List<decimal> bets { get; set; }
#endregion
}
[KnownType(typeof(game))]
[DataContract(Namespace = "http://serialize")]
public class games
{
#region Public Properties
[DataMember]
public List<game> game { get; set; }
#endregion
}
}
Main:
FileStream fs = new FileStream(Path.Combine(this.path, xmlDocumentName), FileMode.Open);
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
DataContractSerializer ser = new DataContractSerializer(typeof(games));
// Deserialize the data and read it from the instance.
games deserializedPerson = (games)ser.ReadObject(reader, true);
reader.Close();
fs.Close();
deserializedPerson shows count = 0
what gives?
I figured it out. Maybe there are other implementations but this works. For the life of me I couldn't find any examples that use List inside an object. Here is a working example:
XML document to parse:
<?xml version="1.0"?>
<games xmlns = "http://serialize">
<game>
<name>TEST1</name>
<code>TESTGAME1</code>
<ugn>1111111</ugn>
<bets>
<bet>5,00</bet>
</bets>
</game>
<game>
<name>TEST2</name>
<code>TESTGAME2</code>
<ugn>222222</ugn>
<bets>
<bet>0,30</bet>
<bet>0,90</bet>
</bets>
</game>
</games>
.cs class:
namespace XmlParse
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization;
[DataContract(Name = "game", Namespace = "")]
public class Game
{
[DataMember(Name = "name", Order = 0)]
public string Name { get; private set; }
[DataMember(Name = "code", Order = 1)]
public string Code { get; private set; }
[DataMember(Name = "ugn", Order = 2)]
public string Ugn { get; private set; }
[DataMember(Name = "bets", Order = 3)]
public Bets Bets { get; private set; }
}
[CollectionDataContract(Name = "bets", ItemName = "bet", Namespace = "")]
public class Bets : List<string>
{
public List<decimal> BetList
{
get
{
return ConvertAll(y => decimal.Parse(y, NumberStyles.Currency));
}
}
}
[CollectionDataContract(Name = "games", Namespace = "")]
public class Games : List<Game>
{
}
}
Read and parse xml document:
string fileName = Path.Combine(this.path, "Document.xml");
DataContractSerializer dcs = new DataContractSerializer(typeof(Games));
FileStream fs = new FileStream(fileName, FileMode.Open);
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
Games games = (Games)dcs.ReadObject(reader);
reader.Close();
fs.Close();
I am using a DataContractSerializer to serialize an object to XML. The main object is SecurityHolding with the namespace "http://personaltrading.test.com/" and contains a property called Amount that's a class with the namespace "http://core.test.com". When I serialize this to XML I get the following:
<ArrayOfSecurityHolding xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://personaltrading.test.com/">
<SecurityHolding>
<Amount xmlns:d3p1="http://core.test.com/">
<d3p1:Amount>1.05</d3p1:Amount>
<d3p1:CurrencyCode>USD</d3p1:CurrencyCode>
</Amount>
<BrokerageID>0</BrokerageID>
<BrokerageName i:nil="true" />
<RecordID>3681</RecordID>
</SecurityHolding></ArrayOfSecurityHolding>
Is there anyway I can control the d3p1 prefix? Am I doing something wrong or should I be doing something else?
Firstly, the choice of namespace alias should make no difference to a well-formed parser.
But; does it have to be DataContractSerializer? With XmlSerializer, you can use the overload of Serialize that accepts a XmlSerializerNamespaces. This allows you to pick and choose the namespaces and aliases that you use.
Ultimately; DataContractSerializer is not intended to give full xml control; that isn't its aim. If you want strict xml control, XmlSerializer is a better choice, even if it is older (and has some nuances/foibles of its own).
Full example:
using System;
using System.Xml.Serialization;
public class Amount
{
public const string CoreNamespace = "http://core.test.com/";
[XmlElement("Amount", Namespace=CoreNamespace)]
public decimal Value { get; set; }
[XmlElement("CurrencyCode", Namespace = CoreNamespace)]
public string Currency { get; set; }
}
[XmlType("SecurityHolding", Namespace = SecurityHolding.TradingNamespace)]
public class SecurityHolding
{
public const string TradingNamespace = "http://personaltrading.test.com/";
[XmlElement("Amount", Namespace = Amount.CoreNamespace)]
public Amount Amount { get; set; }
public int BrokerageId { get; set; }
public string BrokerageName { get; set; }
public int RecordId { get; set; }
}
static class Program
{
static void Main()
{
var data = new[] {
new SecurityHolding {
Amount = new Amount {
Value = 1.05M,
Currency = "USD"
},
BrokerageId = 0,
BrokerageName = null,
RecordId = 3681
}
};
var ser = new XmlSerializer(data.GetType(),
new XmlRootAttribute("ArrayOfSecurityHolding") { Namespace = SecurityHolding.TradingNamespace});
var ns = new XmlSerializerNamespaces();
ns.Add("foo", Amount.CoreNamespace);
ser.Serialize(Console.Out, data, ns);
}
}
Output:
<ArrayOfSecurityHolding xmlns:foo="http://core.test.com/" xmlns="http://personaltrading.test.com/">
<SecurityHolding>
<foo:Amount>
<foo:Amount>1.05</foo:Amount>
<foo:CurrencyCode>USD</foo:CurrencyCode>
</foo:Amount>
<BrokerageId>0</BrokerageId>
<RecordId>3681</RecordId>
</SecurityHolding>
</ArrayOfSecurityHolding>
I have solved this problem slightly differently to Marc that can be implemented in a base class.
Create a new attribute to define the additional XML namespaces that you will use in your data contract.
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public sealed class NamespaceAttribute : Attribute
{
public NamespaceAttribute()
{
}
public NamespaceAttribute(string prefix, string uri)
{
Prefix = prefix;
Uri = uri;
}
public string Prefix { get; set; }
public string Uri { get; set; }
}
Add the attribute to your data contracts.
[DataContract(Name = "SomeObject", Namespace = "http://schemas.domain.com/namespace/")]
[Namespace(Prefix = "a", Uri = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
[Namespace(Prefix = "wm", Uri = "http://schemas.datacontract.org/2004/07/System.Windows.Media")]
public class SomeObject : SerializableObject
{
private IList<Color> colors;
[DataMember]
[DisplayName("Colors")]
public IList<Colors> Colors
{
get { return colors; }
set { colours = value; }
}
}
Then in your Save method, use reflection to get the attributes and then write them to the file.
public static void Save(SerializableObject o, string filename)
{
using (Stream outputStream = new FileStream(filename, FileMode.Create, FileAccess.Write))
{
if (outputStream == null)
throw new ArgumentNullException("Must have valid output stream");
if (outputStream.CanWrite == false)
throw new ArgumentException("Cannot write to output stream");
object[] attributes;
attributes = o.GetType().GetCustomAttributes(typeof(NamespaceAttribute), true);
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.Indent = true;
writerSettings.NewLineOnAttributes = true;
using (XmlWriter w = XmlWriter.Create(outputStream, writerSettings))
{
DataContractSerializer s = new DataContractSerializer(o.GetType());
s.WriteStartObject(w, o);
foreach (NamespaceAttribute ns in attributes)
w.WriteAttributeString("xmlns", ns.Prefix, null, ns.Uri);
// content
s.WriteObjectContent(w, o);
s.WriteEndObject(w);
}
}
}
I have struggled with this problem also. The solution I present below is not optimal IMHO but it works. Like Marc Gravell above, I suggest using XmlSerializer.
The trick is to add a field to your class that returns a XmlSerializerNamespaces object. This field must be decorated with a XmlNamespaceDeclarations attribute. In the constructor of your class, add namespaces as shown in the example below. In the xml below note that the root element is prefixed correctly as well as the someString element.
More info on XmlSerializerNamespaces
Schemas reference
[XmlRoot(Namespace="http://STPMonitor.myDomain.com")]
public class CFMessage : IQueueMessage<CFQueueItem>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces xmlns;
[XmlAttribute("schemaLocation", Namespace=System.Xml.Schema.XmlSchema.InstanceNamespace)]
public string schemaLocation = "http://STPMonitor.myDomain.com/schemas/CFMessage.xsd";
[XmlAttribute("type")]
public string Type { get; set; }
[XmlAttribute("username")]
public string UserName { get; set; }
[XmlAttribute("somestring", Namespace = "http://someURI.com")]
public string SomeString = "Hello World";
public List<CFQueueItem> QueueItems { get; set; }
public CFMessage()
{
xmlns = new XmlSerializerNamespaces();
xmlns.Add("myDomain", "http://STPMonitor.myDomain.com");
xmlns.Add("xyz", "http://someURI.com");
}
}
<?xml version="1.0" encoding="utf-16"?>
<myDomain:CFMessage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xyz="http://someURI.com"
xsi:schemaLocation="http://STPMonitor.myDomain.com/schemas/CFMessage.xsd"
xyz:somestring="Hello World" type="JOIN" username="SJ-3-3008-1"
xmlns:myDomain="http://STPMonitor.myDomain.com" />
Add "http://www.w3.org/2001/XMLSchema" namespace by:
private static string DataContractSerialize(object obj)
{
StringWriter sw = new StringWriter();
DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
using (XmlTextWriter xw = new XmlTextWriter(sw))
{
//serializer.WriteObject(xw, obj);
//
// Insert namespace for C# types
serializer.WriteStartObject(xw, obj);
xw.WriteAttributeString("xmlns", "x", null, "http://www.w3.org/2001/XMLSchema");
serializer.WriteObjectContent(xw, obj);
serializer.WriteEndObject(xw);
}
StringBuilder buffer = sw.GetStringBuilder();
return buffer.ToString();
}