c# WCF getting list of elements values - c#

I have a piece of XML example below
<job>
<refno>XXX</refno>
<specialisms>
<specialism>1</specialism>
<specialism>2</specialism>
</specialisms>
</job>
How using WCF c# do I serialise these values into a list?
I currently have...
[DataMember]
public SpecialismList specialisms { get; set; }
[CollectionDataContract(Name = "specialisms", ItemName = "specialism")]
public class SpecialismList : List<int> { }
But it isn't currently working... any tips?

This data contract should work out just fine to serialize to the XML you posted (see code below). What is the problem you're having?
public class StackOverflow_7386673
{
[DataContract(Name = "job", Namespace = "")]
public class Job
{
[DataMember(Order = 0)]
public string refno { get; set; }
[DataMember(Order = 1)]
public SpecialismList specialisms { get; set; }
}
[CollectionDataContract(Name = "specialisms", ItemName = "specialism", Namespace = "")]
public class SpecialismList : List<int> { }
public static void Test()
{
MemoryStream ms = new MemoryStream();
DataContractSerializer dcs = new DataContractSerializer(typeof(Job));
Job job = new Job
{
refno = "XXX",
specialisms = new SpecialismList { 1, 2 }
};
XmlWriterSettings ws = new XmlWriterSettings
{
OmitXmlDeclaration = true,
Indent = true,
IndentChars = " ",
Encoding = new UTF8Encoding(false),
};
XmlWriter w = XmlWriter.Create(ms, ws);
dcs.WriteObject(w, job);
w.Flush();
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
}
}

Related

How can I return xml without <string> element?

I am using XML serialization in my project. It's working good but I am facing two issues.
Formatting of nodes
Remove <string></string> from response
Sample object which I am trying to serialize is :
[XmlRoot("result")]
public class SwRequestListModel
{
public SwRequestListModel()
{
SwRequest = new List<SwRequestShortInfo>();
}
[XmlElement("api_version")]
public string ApiVersion { get; set; }
[XmlElement("sw_request")]
public List<SwRequestShortInfo> SwRequest { get; set; }
}
[XmlRoot(ElementName = "sw_request_short_info")]
public class SwRequestShortInfo
{
[XmlElement(ElementName = "sw_ref_number")]
public string SwRefNumber { get; set; }
[XmlElement(ElementName = "db_no")]
public string DbNo { get; set; }
[XmlElement(ElementName = "engine_manufacturing_no")]
public string EngineManufacturingNo { get; set; }
[XmlElement(ElementName = "engine_ref_type")]
public string EngineRefType { get; set; }
[XmlElement(ElementName = "raised_date")]
public string RaisedDate { get; set; }
[XmlElement(ElementName = "raised_by")]
public string RaisedBy { get; set; }
[XmlElement(ElementName = "status")]
public string Status { get; set; }
[XmlElement(ElementName = "approved_by")]
public string ApprovedBy { get; set; }
[XmlElement(ElementName = "system_type")]
public string SystemType { get; set; }
}
The code which I am using to serialize is :
public static string ToXml(SwRequestListModel obj)
{
XmlSerializer s = new XmlSerializer(obj.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true,
OmitXmlDeclaration = true,
Encoding = Encoding.UTF8,
NewLineOnAttributes = true,
NamespaceHandling = NamespaceHandling.OmitDuplicates,
IndentChars = Environment.NewLine
};
using (var sww = new StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sww, settings))
{
s.Serialize(writer, obj, ns);
return sww.ToString();
}
}
}
Response is display like :
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"><result> <api_version>1.0</api_version> <sw_request> <sw_ref_number>588</sw_ref_number> <db_no>99899</db_no> <engine_manufacturing_no>MF99899</engine_manufacturing_no> <engine_ref_type>X40B</engine_ref_type> <raised_date>22/06/2021</raised_date> <raised_by>Srusti.Thakkar#test.com</raised_by> <status>Requested</status> <approved_by /> <system_type>test</system_type> </sw_request> <sw_request> <sw_ref_number>589</sw_ref_number> <db_no>88552</db_no> <engine_manufacturing_no>MF99899</engine_manufacturing_no> <engine_ref_type>X40B</engine_ref_type> <raised_date>22/06/2021</raised_date> <raised_by>Srusti.Thakkar#test.com</raised_by> <status>Requested</status> <approved_by /> <system_type>UNIC</system_type> </sw_request> <sw_request> <sw_ref_number>590</sw_ref_number> <db_no>33899</db_no> <engine_manufacturing_no>MF99899</engine_manufacturing_no> <engine_ref_type>X40B</engine_ref_type> <raised_date>22/06/2021</raised_date> <raised_by>Srusti.Thakkar#test.com</raised_by> <status>Requested</status> <approved_by /> <system_type>UNIC</system_type> </sw_request> </result></string>
Actual API Method is :
[HttpGet]
public string GetRequestList(string date, string status, string systemType)
{
SwRequestListModel result = new SwRequestListModel();
result.ApiVersion = "1.0";
//Here get data
return result.ToXml();
}
Browser result is :
Update :
I guess API method GetRequestList serialize string object. Try to return raw string.
[HttpGet]
public HttpResponseMessage GetRequestList(string date, string status, string systemType)
{
SwRequestListModel result = new SwRequestListModel();
result.ApiVersion = "1.0";
//Here get data
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(result.ToXml());
return response;
}

I couldn't create subnodes with different prefix in same parent node

I'm trying to create a XML something like this :
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
- <inventory_report:inventoryReportMessage xmlns:inventory_report="urn:gs1:ecom:inventory_report:xsd:3" xmlns:sh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader" xmlns:ecom_common="urn:gs1:ecom:ecom_common:xsd:3" xmlns:shared_common="urn:gs1:shared:shared_common:xsd:3">
- <sh:StandardBusinessDocumentHeader>
<sh:HeaderVersion>Standard Business Header version 1.3</sh:HeaderVersion>
- <sh:Sender>
<sh:Identifier Authority="GS1">0000</sh:Identifier>
- <sh:ContactInformation>
<sh:Contact>some one</sh:Contact>
<sh:EmailAddress>someone#example.com</sh:EmailAddress>
<sh:TelephoneNumber>00357</sh:TelephoneNumber>
<sh:ContactTypeIdentifier>IT Support</sh:ContactTypeIdentifier>
</sh:ContactInformation>
</sh:Sender>
I'm using the below code for creating the XML -->
var xelementNode = doc.CreateElement("inventory_report", "inventoryReportMessage","urn:gs1:ecom:inventory_report:xsd:3");
doc.AppendChild(xelementNode);
var xelementSubNode = doc.CreateElement("sh", xelementNode, "StandardBusinessDocumentHeades","");
xelementNode.AppendChild(xelementSubNode);
I'm getting this output for the above code -->
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
- <inventory_report:inventoryReportMessage xmlns:inventory_report="urn:gs1:ecom:inventory_report:xsd:3">
- <StandartBusinessDocumentHeader>
<HeaderVersion>Standard Business Header Version 1.3</HeaderVersion>
- <Sender>
<Identifier>GS1</Identifier>
- <ContactInformation>
<Contact>Turkey IT Support</Contact>
<EmailAddress>someone#example.com</EmailAddress>
<TelephoneNumber>00 13</TelephoneNumber>
<ContactTypeIdentifier>IT Support</ContactTypeIdentifier>
</ContactInformation>
</Sender>
</StandartBusinessDocumentHeader>
</inventory_report:inventoryReportMessage>
The second prefix ("sh") doesn't work. Can someone help me???
For serialization approach, you can define classes:
public class ContactInformation
{
[XmlElement(ElementName = "Contact")]
public string Contact { get; set; }
[XmlElement(ElementName = "EmailAddress")]
public string EmailAddress { get; set; }
[XmlElement(ElementName = "TelephoneNumber")]
public string TelephoneNumber { get; set; }
[XmlElement(ElementName = "ContactTypeIdentifier")]
public string ContactTypeIdentifier { get; set; }
}
public class Identifier
{
[XmlAttribute("Authority")]
public string Authority { get; set; }
[XmlText]
public string Value { get; set; }
}
public class Sender
{
[XmlElement(ElementName = "Identifier")]
public Identifier Identifier { get; set; }
[XmlElement(ElementName = "ContactInformation")]
public ContactInformation ContactInformation { get; set; }
}
public class StandartBusinessDocumentHeader
{
[XmlElement(ElementName = "HeaderVersion")]
public string HeaderVersion { get; set; }
[XmlElement(ElementName = "Sender")]
public Sender Sender { get; set; }
}
[XmlRoot(ElementName = "inventoryReportMessage", Namespace = "urn:gs1:ecom:inventory_report:xsd:3")]
public class InventoryReportMessage
{
[XmlElement("StandardBusinessDocumentHeader", Namespace = "http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader")]
public StandartBusinessDocumentHeader Header { get; set; }
}
then serialize those as below:
var report = new InventoryReportMessage
{
Header = new StandartBusinessDocumentHeader {
HeaderVersion = "Standard Business Header version 1.3",
Sender = new Sender
{
Identifier = new Identifier
{
Authority = "GS1",
Value = "0000"
},
ContactInformation = new ContactInformation
{
Contact = "some one",
EmailAddress = "someone#example.com",
TelephoneNumber = "00357",
ContactTypeIdentifier = "IT Support"
}
}
}
};
using (var stream = new MemoryStream())
{
using (var writer = new StreamWriter(stream))
{
var settings = new XmlWriterSettings {
Indent = true
};
using (var xmlWriter = XmlWriter.Create(writer, settings))
{
xmlWriter.WriteStartDocument(false);
var serializer = new XmlSerializer(typeof(InventoryReportMessage));
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("inventory_report", "urn:gs1:ecom:inventory_report:xsd:3");
namespaces.Add("sh", "http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader");
namespaces.Add("ecom_common", "urn:gs1:ecom:ecom_common:xsd:3");
namespaces.Add("shared_common", "urn:gs1:shared:shared_common:xsd:3");
serializer.Serialize(xmlWriter, report, namespaces);
}
stream.Position = 0;
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
}
Console.ReadLine();
Using xml linq. I like to create a string header and then add dynamic values in code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string header =
"<inventory_report:inventoryReportMessage xmlns:inventory_report=\"urn:gs1:ecom:inventory_report:xsd:3\" xmlns:sh=\"http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader\" xmlns:ecom_common=\"urn:gs1:ecom:ecom_common:xsd:3\" xmlns:shared_common=\"urn:gs1:shared:shared_common:xsd:3\">" +
"<sh:StandardBusinessDocumentHeader>" +
"<sh:HeaderVersion>Standard Business Header version 1.3</sh:HeaderVersion>" +
"<sh:Sender>" +
"</sh:Sender>" +
"</sh:StandardBusinessDocumentHeader>" +
"</inventory_report:inventoryReportMessage>";
XDocument doc = XDocument.Parse(header);
XElement sender = doc.Descendants().Where(x => x.Name.LocalName == "Sender").FirstOrDefault();
XNamespace shNs = sender.GetNamespaceOfPrefix("sh");
sender.Add(new XElement(shNs + "Identifier", new object[] {
new XAttribute("Authority", "GS1"),
"0000"
}));
sender.Add( new XElement(shNs + "ContactInformation", new object[] {
new XElement(shNs + "Contact", "some one"),
new XElement(shNs + "EmailAddress", "someone#example.com"),
new XElement(shNs + "TelephoneNumber", "00357"),
new XElement(shNs + "ContactTypeOdemtofier", "IT Support")
}));
}
}
}

Add schemaLocation to XML serializing List<T> using XmlSerializer

I'm trying to add schemaLocation attribute to XML root element when serializing List<T>. Code works fine if I'm serializing just one object but does not work on lists. My current code:
public class SomeObject
{
public int Id { get; set; }
public string Name { get; set; }
}
public class XmlListContainer<T> : List<T>
{
[XmlAttribute(Namespace = XmlSchema.InstanceNamespace)]
public string schemaLocation = "http :// localhost/someschema";
}
public class BuildXml
{
public static void GetXml()
{
var list = new XmlListContainer<SomeObject>()
{
new SomeObject() { Id = 1, Name = "One" },
new SomeObject() { Id = 2, Name = "Two" },
};
var objectToXml = list;
string output;
using (var writer = new StringWriter())
{
var xs = new XmlSerializer(objectToXml.GetType());
var nameSpaces = new XmlSerializerNamespaces();
nameSpaces.Add("xsi", "http :// www.w3.org/2001/XMLSchema-instance");
xs.Serialize(writer, objectToXml, nameSpaces);
output = writer.GetStringBuilder().ToString();
writer.Close();
}
Console.WriteLine(output);
}
}
XML root element appears without schemaLocation:
<ArrayOfSomeObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
If I'm changing code to
public class SomeObject
{
public int Id { get; set; }
public string Name { get; set; }
[XmlAttribute(Namespace = XmlSchema.InstanceNamespace)]
public string schemaLocation = "http :// localhost/someschema";
}
...
var objectToXml = new SomeObject() { Id = 1, Name = "One" };
...all looks fine but I need list list
<SingleObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost/someschema">
Is it possible to add schemaLocation attribute when serializing List<T>?

Prefixes and Namespaces with C# Objects

I am attempting to create a POST function that serialises C# class objects into XML.
The part I am having great difficulty with is adding namespace prefixes to the sub-root element's children, so in this instance, contact children only.
The only way I seem to be able to get the prefix onto the child elements of contactis to add them through SerializerNamespace class, however I can only get this to attach to the root element, CreateContact.
How can I achieve this?
XML Currently Produced:
<?xml version=\"1.0\"?>
<CreateContact xmlns:a="http://foo.co.uk/Contact" xmlns="http://foo.co.uk">
<a:contact>
<a:Email>stest#gmail.com</a:Email>
<a:FirstName>Simon</a:FirstName>
<a:LastName>Test</a:LastName>
<a:Phone>09088408501</a:Phone>
<a:Title>Mr</a:Title>
</a:contact>
</CreateContact>
Serialisation function:
public static void CreateContact(Contact contact)
{
string tmp = url;
string xml = "";
string result = "";
XmlDocument xd = new XmlDocument();
var cc = new CreateContact();
cc.contact = contact;
var xs = new XmlSerializer(cc.GetType());
XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
xsn.Add("a", "http://foo.co.uk/Contact");
using (MemoryStream ms = new MemoryStream())
{
xs.Serialize(ms, cc, xsn);
ms.Position = 0;
xd.Load(ms);
xml = xd.InnerXml;
}
using (WebClient web = new WebClient())
{
web.Credentials = new NetworkCredential(username, password);
web.Headers.Add("Content-Type", "application/xml");
try
{
result = web.UploadString(tmp, "POST", xml);
}
catch (WebException ex)
{
}
}
}
XML Class Constructs:
[Serializable()]
[XmlRoot(ElementName = "CreateContact", Namespace = "http://foo.co.uk")]
public class CreateContact
{
[XmlElement(ElementName = "contact", Namespace = "http://foo.co.uk/Contact")]
public Contact contact { get; set; }
}
[DataContract(Name = "Contact", Namespace = "http://foo.co.uk/Contact")]
[XmlType("a")]
public class Contact
{
[XmlElement(ElementName = "Email", Namespace = "http://foo.co.uk/Contact")]
[DataMember(Name = "Email")]
public string Email { get; set; }
[XmlElement(ElementName = "FirstName", Namespace = "http://foo.co.uk/Contact")]
[DataMember(Name = "FirstName")]
public string Firstname { get; set; }
[XmlElement(ElementName = "LastName", Namespace = "http://foo.co.uk/Contact")]
[DataMember(Name = "LastName")]
public string Lastname { get; set; }
[XmlElement(ElementName = "Phone", Namespace = "http://foo.co.uk/Contact")]
[DataMember(Name = "Phone")]
public string Phone { get; set; }
[XmlElement(ElementName = "Title", Namespace = "http://foo.co.uk/Contact")]
[DataMember(Name = "Title")]
public string Title { get; set; }
}
XML Desired:
<?xml version=\"1.0\"?>
<CreateContact xmlns="http://foo.co.uk">
<contact xmlns:a="http://foo.co.uk/Contact">
<a:Email>stest#gmail.com</a:Email>
<a:FirstName>Simon</a:FirstName>
<a:LastName>Test</a:LastName>
<a:Phone>09088408501</a:Phone>
<a:Title>Mr</a:Title>
</contact>
</CreateContact>
As alluded in the comments, the reason for the difference is that contact should be in the namespace http://foo.co.uk, not http://foo.co.uk/Contact.
As an aside, a couple of further comments:
You probably don't need the DataMember attributes, unless you're using DataContractSerializer somewhere else.
Most of the Xml* attributes are superfluous here, and could be removed or consolidated by inheriting from XmlRoot.
If all you need is the XML string, you'd be better off serialising to something like a StringWriter rather than to a stream and then loading into the DOM just to get the text (see this question if you need the XML declaration to specify utf-8)
So, you'd get the XML as below:
var xsn = new XmlSerializerNamespaces();
xsn.Add("a", "http://foo.co.uk/Contact");
var xs = new XmlSerializer(typeof(CreateContact));
using (var stringWriter = new StringWriter())
{
xs.Serialize(stringWriter, cc, xsn);
xml = stringWriter.ToString();
}
With your classes defined as:
[XmlRoot(ElementName = "CreateContact", Namespace = "http://foo.co.uk")]
public class CreateContact
{
[XmlElement(ElementName = "contact")]
public Contact Contact { get; set; }
}
[XmlRoot("contact", Namespace = "http://foo.co.uk/Contact")]
public class Contact
{
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Title { get; set; }
}
See this fiddle for the complete example.

How to use protobuf-net for xml-serialization?

Maybe i misunderstood something for serialization. i wanna serialize my .net object fastest way. i made some googling i found protobuf. Myfirstquestion is ProtoBuf.Net has avility for xml serailization.if it has, can i use it for xml serialization.
My model:
[XmlType]
public class CT {
[XmlElement(Order = 1)]
public int Foo { get; set; }
}
[XmlType]
public class TE {
[XmlElement(Order = 1)]
public int Bar { get; set; }
}
[XmlType]
public class TD {
[XmlElement(Order = 1)]
public List CTs { get; set; }
[XmlElement(Order = 2)]
public List TEs { get; set; }
[XmlElement(Order = 3)]
public string Code { get; set; }
[XmlElement(Order = 4)]
public string Message { get; set; }
[XmlElement(Order = 5)]
public DateTime StartDate { get; set; }
[XmlElement(Order = 6)]
public DateTime EndDate { get; set; }
}
my serializer :
CT ct = new CT() { Foo = 1 };
List<CT> list = new List<CT>();
list.Add(ct);
TE te = new TE() { Bar = 2 };
List<TE> list2 = new List<TE>();
list2.Add(te);
TD td = new TD() { Code = "Test",Message = "Yusuf",StartDate = DateTime.Now,EndDate = DateTime.Now,CTs = list,TEs = list2 };
List<TD> list3 = new List<TD>();
list3.Add(td);
Stopwatch stopwatch5 = new Stopwatch();
stopwatch5.Start();
string str = String.Empty;
using (MemoryStream stream = new MemoryStream())
{
byte[] data = Serialize(list3);
XmlDocument doc = new XmlDocument();
string xml = Encoding.UTF8.GetString(data); <--SHOULD CREATE XML
doc.LoadXml(xml);
// str = Convert.ToBase64String(stream.GetBuffer(),0,(int)stream.Length);
}
stopwatch5.Stop();
Console.WriteLine(((double)(stopwatch5.Elapsed.TotalMilliseconds * 1000000) / 1000000).ToString("0.00 ns"));
Console.Read();
}
public static byte[] Serialize(List<TD> tData) {
using(var ms = new MemoryStream()) {
ProtoBuf.Serializer.Serialize(ms,tData);
return ms.ToArray();
}
}
public static List<TD> Deserialize(byte[] tData) {
using(var ms = new MemoryStream(tData)) {
return ProtoBuf.Serializer.Deserialize<List<TD>>(ms);
}
}
it should create xml as a result of " string xml = Encoding.UTF8.GetString(data);". But doesn't. How can i produxe xml result?
Protocol buffers doesn't serialize objects to XML.
It produces binary data. And it has its own set of attributes.
Check this answer
Is Protobuf-net's serialization/deserialization faster than XML ? Yes, by far.
However XmlSerializer is fast enough for most of the tasks.
What you should remind when using it though, is:
XmlSerializer instance is generating code on the fly and compile this code into an assembly.
This generated assembly is then used to serialize and deserialize your objects really fast.
So you should cache instances of XmlSerializer (and avoid recreating them)
you could add a warm up by calling Serialize and Deserialize in order to initialize inner objects and jit them.
You could even go further by generating the auto-generated assembly by yourself, but then you should remember to regenerate each time you change the objects (It can be automated with a MsBuild Task).
You can also look further optimizations:
On Stack Overflow
With Sgen
You can only have one tag at the root level of your xml. So either TD cannot be a list, or you must have an outer tag around the List. This code works
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
{
static void Main(string[] args)
{
TD td = new TD()
{
Code = "Test",
Message = "Yusuf",
StartDate = DateTime.Now,
EndDate = DateTime.Now,
CTs = new List<CT>() {
new CT() { Foo = 1},
new CT() { Foo = 2},
new CT() { Foo = 3},
},
TEs = new List<TE>() {
new TE() { Bar = 1},
new TE() { Bar = 2},
new TE() { Bar = 3},
}
};
using (MemoryStream stream = new MemoryStream())
{
byte[] data = Serialize(td);
XmlDocument doc = new XmlDocument();
string xml = Encoding.UTF8.GetString(data);
doc.LoadXml(xml);
// str = Convert.ToBase64String(stream.GetBuffer(),0,(int)stream.Length);
}
}
public static byte[] Serialize(TD tData)
{
using (var ms = new MemoryStream())
{
XmlSerializer serializer = new XmlSerializer(typeof(TD));
serializer.Serialize(ms, tData);
return ms.ToArray();
}
}
public static TD Deserialize(byte[] tData)
{
using (var ms = new MemoryStream(tData))
{
XmlSerializer xs = new XmlSerializer(typeof(TD));
return (TD)xs.Deserialize(ms);
}
}
}
[XmlRoot("CT")]
public class CT
{
[XmlElement(ElementName = "Foo", Order = 1)]
public int Foo { get; set; }
}
[XmlRoot("TE")]
public class TE
{
[XmlElement(ElementName = "Bar", Order = 1)]
public int Bar { get; set; }
}
[XmlRoot("TD")]
public class TD
{
[XmlElement(ElementName = "CTs", Order = 1)]
public List<CT> CTs { get; set; }
[XmlElement(ElementName = "TEs", Order = 2)]
public List<TE> TEs { get; set; }
[XmlElement(ElementName = "Code", Order = 3)]
public string Code { get; set; }
[XmlElement(ElementName = "Message", Order = 4)]
public string Message { get; set; }
[XmlElement(ElementName = "StartDate", Order = 5)]
public DateTime StartDate { get; set; }
[XmlElement(ElementName = "EndDate", Order = 6)]
public DateTime EndDate { get; set; }
}
}
​

Categories