C# web service - getting list of equal element names - c#

I was creating C# SOAP web service and web method from interface specification that should have specific xml structure in request:
<SomeItems>
<Value></Value>
<Value></Value>
...
</SomeItems>
It needs to have list of elements with equal names.
When I put in C# code class like:
public List<int> SomeItems { get; set; }
I get as output (checked in SOAP UI) (epv is xmlns:epv="..."):
<epv:SomeItems>
<!--Zero or more repetitions:-->
<epv:int></epv:int>
</epv:SomeItems>
If I add another class named "Value":
public List<Value> SomeItems { get; set; }
public class Value
{
public int Value1 { get; set; }
}
I get in SOAP UI:
<epv:SomeItems>
<!--Zero or more repetitions:-->
<epv:Value>
<epv:Value1></epv:Value1>
</epv:Value>
</epv:SomeItems>
Is there any way to get:
<epv:SomeItems>
<!--Zero or more repetitions:-->
<epv:Value></epv:Value>
</epv:SomeItems>
Where "Value" is int.

Moved solution from question to answer:
EDIT:
I have found solution:
public SomeItems SomeItems{ get; set; }
[XmlType(AnonymousType = true)]
public class SomeItems
{
[XmlElement(ElementName = "Value")]
public List<int> Value { get; set; }
}
Finally in SOAP UI:
<epv:SomeItems>
<!--Zero or more repetitions:-->
<epv:Value>?</epv:Value>
</epv:SomeItems>

Related

XML API Request returns "d3p1" for arrays or sub-classes

Using Postman, C#, .NET Framework 4.7
I make a GET request from Postman with content-accept set to "application/xml" and my .NET Framework Web API will respond with XML (brilliant!). I have not needed to serialize anything manually as .NET Framework serializes my response object with when I return Request.CreateResponse(HttpStatusCode.OK, myResponse).
However, it seems to include extra things which I am not familiar with and I am wondering if they can be removed via Global.asax settings or similar?
xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels" is something I would like to remove!
"d3p1" is not something I have come across when creating XML. Can I remove it somehow?
<error i:nil="true" /> pops up when something is null. Is it possible to just be or just not appear when it is null?
So, The XML response looks like this:
<SimpleResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels">
<error i:nil="true" />
<result>
<bookList xmlns:d3p1="http://schemas.datacontract.org/2004/07/dto.MyModels.Shared">
<d3p1:Book>
<d3p1:bookname>Book 1 Name</d3p1:bookname>
<d3p1:serial>ZMeTaQ1kejh0mJYGHE4+1a4Y2juU6tMDd5zYDqN4tqI=</d3p1:serial>
<d3p1:id>4</d3p1:id>
</d3p1:Book>
<d3p1:Book>
<d3p1:bookname>Hello World</d3p1:bookname>
<d3p1:serial>9lM16kho3bgsrG+wRh4ejtZjwrYJwp6FbRqnnZ4CJPA=</d3p1:serial>
<d3p1:id>5</d3p1:id>
</d3p1:Book>
<d3p1:Book>
<d3p1:bookname>Ding</d3p1:bookname>
<d3p1:serial>XCqqKB+Wi3i4z6nN1Ry8IHtar6ogojjiqxMfvfgC0qc=</d3p1:serial>
<d3p1:id>6</d3p1:id>
</d3p1:Book>
</bookList>
<author xmlns:d3p1="http://schemas.datacontract.org/2004/07/dto.Models.Android.Shared">
<d3p1:pictureId>0</d3p1:pictureId>
<d3p1:websiteurl i:nil="true" />
<d3p1:email i:nil="true" />
<d3p1:name>Jo Blogs</d3p1:size>
<d3p1:age>0</d3p1:size>
</author>
</result>
</SimpleResponse>
My classes look something like this:
public string error { get; set;}
public class SimpleResponse
{
public List<Book> bookList { get; set; }
public Author author { get; set; }
}
public class Book
{
public string bookname { get; set; }
public string serial { get; set; }
public int id { get; set; }
}
public class Author
{
public string pictureId{ get; set; }
public string websiteurl { get; set; }
public string email { get; set; }
public string name { get; set; }
public int age { get; set; }
}
xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels" is something I would like to remove!
"d3p1" is not something I have come across when creating XML. Can I remove it somehow?
The attributes:
xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels"
xmlns:d3p1="http://schemas.datacontract.org/2004/07/dto.MyModels.Shared"
are both XML namespace declarations. The first establishes a default XML namespace for your XML document; the second declares a namespace to which all child elements prefaced with d3p1: belong.
From the specific namespace chosen, it's apparent you are using DataContractSerializer for XML serialization. This serializer assigns XML namespaces according to rules documented in Data Contract Names: Data Contract Namespaces
By default, any given CLR namespace (in the format Clr.Namespace) is mapped to the namespace http://schemas.datacontract.org/2004/07/Clr.Namespace. To override this default, apply the ContractNamespaceAttribute attribute to the entire module or assembly. Alternatively, to control the data contract namespace for each type, set the Namespace property of the DataContractAttribute.
Since you don't want an XML namespace for any of your types, the first option would appear to be the easiest: apply the following attributes to your assembly:
[assembly: ContractNamespaceAttribute("", ClrNamespace = "dto.MyModels")]
[assembly: ContractNamespaceAttribute("", ClrNamespace = "dto.MyModels.Shared")]
[assembly: ContractNamespaceAttribute("", ClrNamespace = "dto.Models.Android.Shared")]
Alternatively, you could apply data contract attributes to your types:
[DataContract(Name = "Book", Namespace = "")]
public class Book
{
[DataMember]
public string bookname { get; set; }
[DataMember]
public string serial { get; set; }
[DataMember]
public int id { get; set; }
}
Note that data contract serialization is opt-in so you will need to apply [DataMember] to each member to be serialized.
As a final alternative, you could switch to using XmlSerializer which has no default XML namespace. To do that you will need to apply [XmlSerializerFormat] to your service contract as shown in Manually Switching to the XmlSerializer.
<error i:nil="true" /> pops up when something is null. Is it possible to just be or just not appear when it is null?
These null elements can be removed by setting DataMemberAttribute.EmitDefaultValue on reference type data members as shown in this answer to Can I configure the DataContractSerializer to not create optional (i.e. Nullable<> and List<>) elements in output XML? by Darren Clark:
[DataContract(Name = "Book", Namespace = "")]
public class Book
{
[DataMember(EmitDefaultValue = false)]
public string bookname { get; set; }
[DataMember(EmitDefaultValue = false)]
public string serial { get; set; }
[DataMember]
public int id { get; set; }
}
Alternatively you could switch to XmlSerializer which does not output null reference values by default.

c# serialize object without root element

I am working with a 3rd party who has an xml structure for multiple different requests.
Each request has a common header structure and then some specific footer data.
Unfortunately, the header and footer sections are not wrapped within their own element tags and this is something that I can't change.
Some sample contrived requests are shown below:
Sample Request 1
<?xml version="1.0" encoding="UTF - 8" standalone="yes"?>
<Request>
<RequestType>1</RequestType>
<User>User01</User>
<id>1234</id>
<Name>John</Name>
<Age>20</Age>
</Request>
Sample Request 2
<?xml version="1.0" encoding="UTF - 8" standalone="yes"?>
<Request>
<RequestType>2</RequestType>
<User>User02</User>
<id>1235</id>
<School>The School</School>
<Teacher>Mrs Smith</Teacher>
</Request>
Sample Request 3
<?xml version="1.0" encoding="UTF - 8" standalone="yes"?>
<Request>
<RequestType>3</RequestType>
<User>User01</User>
<id>223</id>
<Work>The Office</Word>
<Boss>Mr White</Boss>
<Phone>1234567</Phone>
<Payday>Friday</Payday>
</Request>
You can see that each request has a RequestType, User and id.
My question relates to writing C# code that will encapsulate this Xml for serialization.
To me, it seems wrong to have each of my C# classes having the repeated header (RequestType, User and id) data.
I have tried using generics (see sample code below) but that leads to my question.
Question: How can I serialize my generic object Footer so that it is not wrapped within "root" Footer element?
[System.Xml.Serialization.XmlRoot("Request")]
public class GenericRequest<typeT>
{
public GenericRequest()
{
}
public int RequestType { get; set; }
public string User { get; set; }
public int id { get; set; }
public typeT Footer { get; set; }
}
You can create a class with interface IFooter, which can have different implementor as per requirement (e.g.
interface IFooter : ISerializable
{
//Define common member.
}
public class Footer1: IFooter
{
// define members (e.g. work)
}
public class Footer2: IFooter
{
// define members
}
public class Footer3: IFooter
{
// define members
}
Now serialize main class
[System.Xml.Serialization.XmlRoot("Request")]
public class GenericRequest
{
public GenericRequest()
{
}
public int RequestType { get; set; }
public string User { get; set; }
public int id { get; set; }
public IFooter Footer { get; set; }
}
Visit How can I serialize an object that has an interface as a property? for reference.

WCF MessageHeader attribute does not deserialized

I am developing the the SOAP based web services in the WCF.
My client sending the request to the WCF services with the following SOAP request xml:
<e:Envelope xmlns:e="http://schemas.xmlsoap.org/soap/envelope/" e:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<e:Header>
<me:RequestHead xmlns:me="http://www.my-namespace.org/header/abc" >
<ID>0</ID>
<Green>
<a>101</a>
<b>0</b>
</Green>
<Time>1</Tim>
</me:RequestHead>
</e:Header>
<e:Body>
<m:RequestBody xmlns:m="http://www.my-namespace.org/service/abc">
<Time>
<hh>23</hh>
<mm>59</mm>
<ss>59</ss>
</Time>
</m:RequestBody>
</e:Body>
</e:Envelope>
I created the MessageContract class to pass the value to client or get the value from the client.
In MessageContract class there is multiple MessageHeader attribute property, but when request send to the server the property with MessageHeader attribute is not deserialize and it is always null.
In RequestHead tag there is prefix me, I think its create the problem to deserialize the XML request to the object at the WCF services
But in RequestBody tag there is also prefix m but it deserialize successfully.
When I remove the prefix me from the RequestHead tag than it worked successfully. and I got the value of the MessageHeader attribute property.
<e:Envelope xmlns:e="http://schemas.xmlsoap.org/soap/envelope/" e:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<e:Header>
<RequestHead xmlns="http://www.my-namespace.org/header/abc" >
<ID>0</ID>
<Green>
<a>101</a>
<b>0</b>
</Green>
<Time>1</Tim>
</RequestHead>
</e:Header>
<e:Body>
<m:RequestBody xmlns:m="http://www.my-namespace.org/service/abc">
<hh>23</hh>
<mm>59</mm>
<ss>59</ss>
</m:RequestBody>
</e:Body>
</e:Envelope>
My Classes:
[MessageContract]
class Green
{
[MessageHeader(Namespace = "")]
public string a { get; set; }
[MessageHeader(Namespace = "")]
public string b { get; set; }
}
[MessageContract]
class RequestHead
{
[MessageHeader(Namespace = "")]
public int id { get; set; }
[MessageHeader(Namespace = "")]
public Green green { get; set; }
[MessageHeader(Namespace = "")]
public int Time { get; set; }
}
[MessageContract]
class Head
{
[MessageHeader(Namespace = "http://www.my-namespace.org/header/abc")]
public RequestHead RequestHead { get; set; }
}
[MessageContract(Namespace = "http://www.my-namespace.org/service/abc")]
class RequestBody : Head
{
[MessageBodyMember(Order = 1)]
public int hh { get; set; }
[MessageBodyMember(Order = 1)]
public int mm { get; set; }
[MessageBodyMember(Order = 1)]
public int ss { get; set; }
}
And my action method in the WCF services is look like this:
public RequestBody CheckTime(RequestBody objBody)
{
}
When I checked the request SOAP XML using the following code:
OperationContext.Current.RequestContext.RequestMessage.ToString();
It give me the full request SOAP XML with the header value also but does not deserialize it to the object.
I does not understand where I am going wrong or I am missing something.
Here is the same question asked but till now it is does not get any answered: How can I deserialize a custom SOAP header in WCF?
Thanks for help...

Message contract wrappername and message body name attribute does not work

I have couple of classes which define as message contract and properties define as message body. I specified wrappername and name attribute respectively. It works for parent class but does not work for child class.
Classes:
[MessageContract(WrapperName = "ticketstatus",IsWrapped = true)]
public class TicketStatusResponse
{
[MessageBodyMember(Name="status")]
public string Status { get; set; }
[MessageBodyMember(Name="errorcode")]
public string ErrorCode { get; set; }
[MessageBodyMember(Name="errormessage")]
public string ErrorMessage { get; set; }
[MessageBodyMember(Name="tasks")]
public List<Task> Tasks { get; set; }
}
[MessageContract(WrapperName="task")]
public class Task
{
[MessageBodyMember(Name="taskname")]
public string TaskName { get; set; }
[MessageBodyMember(Name="complete")]
public string Complete { get; set; }
}
Response info:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ticketstatus xmlns="http://tempuri.org/">
<errorcode>0</errorcode>
<errormessage/>
<status>Pending</status>
<tasks xmlns:a="http://schemas.datacontract.org/2004/07/MessageContractExample.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Task>
<a:Complete>1</a:Complete>
<a:TaskName>task1</a:TaskName>
</a:Task>
<a:Task>
<a:Complete>2</a:Complete>
<a:TaskName>task2</a:TaskName>
</a:Task>
</tasks>
<ticketno>567890</ticketno>
<waittime>4</waittime>
</ticketstatus>
</s:Body>
</s:Envelope>
My expected xml tag name of "Task" should be as follows because I change name using wrappername and name attribute:
<a:task>
<a:complete>2</a:complete>
<a:taskname>task2</a:taskName>
</a:task>
But i am getting
<a:Task>
<a:Complete>1</a:Complete>
<a:TaskName>task1</a:TaskName>
</a:Task>
Why wrapper name and name attribute do not work for child node. How can I fix node name?
Any idea or hints?
Have you considered IsWrapped = true as that is the difference between the classes.

Recursive XML Deserialization

I have some XML that I am trying to deserialize the xml below.
<?xml version="1.0" encoding="UTF-8"?>
<disproot version="1.0">
<header>
<msg-type> init_req </msg-type>
<txn-id> 0090 </txn-id>
</header>
<body />
</disproot>
My object is something like this.
[XmlRoot("disproot")]
public class Request
{
[XmlAttribute("version")]
public string Version
{ get; set; }
[XmlElement("header", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
Header header = new Header();
}
public class Header
{
public Header()
{
}
[XmlElement("txn-id")]
public string TransactionId
{
get;
set;
}
[XmlElement("msg-type")]
public string MessageType
{
get;
set;
}
}
My Header's object is not populated. The members are displaying as Null values. See below.
Request.Header.TasnsactionId's value is Null
Request.Header.MessageType's value is also Null
Anything wrong I am doing here?
Any help would be appreciable.
XML serialization works only on public members. So, you can change the field to
public Header header = new Header();
and it should work fine. Although I would advise you against using public fields, you should probably make it into a property:
public Header Header { get; set; }

Categories