how to get Soap Envelope attribute value in wcf service - c#

How do I get the SOAP xml attribute value in a wcf service?
<ns3:NotifRQ Status="Commit"
xmlns:ns2="http://www.dddd.com/df/dd/"
xmlns:ns3="http://www.dd.org/OTA/">
<ns3:rev>dfdfkkl</ns3:rev>
<ns3:change>dfdfkkl</ns3:change>
</ns3:NotifRQ>
This is the code I have now for the data contract:
[DataContract(Name = "NotifRQ", Namespace = "http://www.dd.org/OTA/")]
public class NotifRQ
{
[DataMember(Name = "Status")]
public string ResStatus;
}

Your Status attribute needs to be a field or property of the NotifRQ class and you need to instruct WCF to use the less optimal XmlSerializer instead of the DatacontractSerializer as explained here. You achieve that by using the XmlSerializerFormat attribute on your class.
You can now apply XmlAttribute to a field or property of your class that gets or sets the value of an attribute on the xml element.
Create and annotate your class as follows:
[DataContract(Namespace="http://www.dd.org/OTA/")]
[XmlSerializerFormat]
public class NotifRQ
{
[DataMember, XmlAttribute]
public string Status="Commit";
[DataMember]
public string rev;
[DataMember]
public string change;
}
Above class will write and read the following wire-format:
<?xml version="1.0" encoding="utf-16"?>
<NotifRQ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Status="Commit">
<rev>foo</rev>
</NotifRQ>

Related

How to deserialize a difficult XML format in C# object and read it in order to use its values?

I have a very difficult formatted XML document , which I want to read it and use its parameters.
This is the XML that I want to deserialize:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<APIResponse xmlns="https://testwebservice.com/">
<Result>Api Result Message</Result>
</APIResponse>
</soap:Body>
</soap:Envelope>
I have tried some code samples that I found in some other question here
APIResponse envelopeClass = new APIResponse();
XmlSerializer serializer = new XmlSerializer(typeof(APIResponse), new XmlRootAttribute("Envelope"));
StringReader stringReader = new StringReader(xmlString);
envelopeClass = (APIResponse)serializer.Deserialize(stringReader);
But nothing has helped me so far , as I get an ERROR like this:
System.InvalidOperationException: 'There is an error in XML document (1, 42).'
Inner Exception
InvalidOperationException: <Envelope xmlns='http://schemas.xmlsoap.org/soap/envelope/'> was not expected.
These are the classes that I have used so far with the Paste Special button in Visual Studio.
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://schemas.xmlsoap.org/soap/envelope/", IsNullable = false)]
public partial class Envelope
{
public EnvelopeBody bodyField { get; set; }
}
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
public partial class EnvelopeBody
{
[System.Xml.Serialization.XmlElementAttribute(Namespace = "https://testwebservice.com/")]
public APIResponse aPIResponseField { get; set; }
}
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="https://testwebservice.com/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="https://testwebservice.com/", IsNullable=false)]
public partial class APIResponse
{
public string resultField { get; set; }
}
Despite all these I have not understand why I get the above ERROR , I want to note that I have not fully understand how all this work.
Anyway , if there is anyone that can help with this I would appreciate it.
Please show me which are the right classes that I should use with this XML format document and how to deserialize it.
The "Difficult XML Format" as you name it is actually a standard SOAP (Simple Object Access Protocol) message. SOAP is used as the communication protocol for XML based web services, which at first brings to mind that you may add a service reference for the web service from where you get this XML content. If you are getting this XML content from a web resource, please try to add it as a service reference.
If not and if you've just ended up with this XML content somehow, although there are examples of how to get the response object from inside the xml by parsing it and serializing only part of it, here is what I assume to be a more elaborate and safe way of achieving it.
Add NuGet Reference: Microsoft.Web.Services3
Change the class ApiResponse as follows (change the name resultField to Result)
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "https://testwebservice.com/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "https://testwebservice.com/", IsNullable = false)]
public partial class APIResponse
{
public string Result { get; set; }
}
And then get the ApiResponse object using the SoapEnvelope class and its methods like:
using Microsoft.Web.Services3;
. . .
. . .
SoapEnvelope envelope = new SoapEnvelope();
envelope.LoadXml(xmlString);
APIResponse apiResponse = (APIResponse)envelope.GetBodyObject(typeof(APIResponse));
. . .
. . .

MVC Web API ignores XmlSerializerFormat and uses DataContractSerliazer instead

I have a DTO and a Domain project in my solution and an MVC front end with web api to expose data.
I have the web api controller set up and the action is getting my DTO object back from the DataService. That's all great, however, I want xml to be returned and I want some of the values to be in xml attributes e.g.
<root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<lookups>
<lookup category="General" field="Alert Type" value="Lack of Transparency" entityid="2273"/>
<lookup category="General" field="Alert Type" value="Unfair Terms " entityid="2274"/>
<lookup category="General" field="Alert Type" value="Operator Concerns" entityid="2275"/>
...
</lookups>
<paymentmethods />
<affiliates />
</root>
The Lookup class is as follows:
[Serializable]
[XmlSerializerFormat]
public class Lookup
{
[XmlAttribute("category")]
public String Category { get; set; }
[XmlAttribute("field")]
public String Field { get; set; }
[XmlAttribute("value")]
public String Value { get; set; }
[XmlAttribute("entityid")]
public String EntityId { get; set; }
public Lookup(String Category, String Field, String Value, int? EntityId = null)
{
this.Category = Category;
this.Field = Field;
this.Value = Value;
this.EntityId = (EntityId != null ? EntityId.ToString() : null);
}
public Lookup() { }
}
initially I had my DTO objects (e.g Lookup, PaymentMethod and Affiliates) with my viewmodels, but moved them into my DTO project.
I have set UseXmlSerializer = true in my global.asax
Before moving the objects from hy viewmodels folder to the DTO project, it was working and I was getting the desired XML. AFTER moving, it appears to be ignoring the XmlSerializerFormat and using DataContractSerliazer.
So using DataMember attributes, I can format the xml, but obviously I can't set some properties to be serialised as xml attributes
Any thoughts on why it seems to be ignoring the [XmlSerializerFormat] and [XmlAttribute("field")] attributes?
I've read a few SO posts like:
XmlSerializer ignores [XmlAttribute] in WebApi and
How can you control .NET DataContract serialization so it uses XML attributes instead of elements?
I found the solution to this here:
http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization#xml_pertype
Setting the xml Serializer in the Global.asax to work on a specific type worked for me :
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
xml.SetSerializer<FullResponseRoot>(new XmlSerializer(typeof(FullResponseRoot)));
where FullResponseRoot is the name of the object that I am serialising (the classes mentioned above are properties of FullResponseRoot)
FullResponseRoot forms the root node of the generated xml

How to exclude a property from DataContractSerialization When It Has No Data?

I'm using DataContractSerializer in my Web API application and in my action I'm returning a Data Type as below:
public class Event
{
public string Name {get; set;}
public IList<Division> Divisions {get;set;}
}
When serialized it's returning the below xml:
<Event xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07
/EventTypeNameSpace">
<Name>some name</Name>
<Divisions i:nil="true" />
</Event>
1) Why is it returning two xmlns:i and xmlns attributes? how can they be excluded?
2) How can I exclude the Divisions from the xml when it's null?
1: the "http://schemas.datacontract.org/2004/07" is the default namespace used by types serialized by data-contract serializer; if you don't like that - change your contract; the "http://www.w3.org/2001/XMLSchema-instance" defines "nil" as a special value
2: by defining the contract properly
[DataContract(Namespace="")]
public class Event
{
[DataMember]
public string Name { get; set; }
[DataMember(EmitDefaultValue=false)]
public IList<Division> Divisions { get; set; }
}
However: I should add - if you want tight control over what the layout looks like, you should probably be using XmlSerializer, not DataContractSerializer

How to specify a name to which object will be serialized by WebApi?

My web api is returning a set of objects which are differ from the Domain object. Forexample, I my domain has an Employee class but I don't want to expose all the members of the Employee class in my api so I created another class called EmployeeApiModel.
Now my WebApi is returning a List of EmployeeApiModel but I want to be able to specify the name to which it should serialize to. That is instead of <EmployeeApiModel> tag in the xml, I want to get <Employee> but without changing the fact that the underlying class which is being serialized is EmployeeApiModel.
How can I achieve this?
Technically, Web Api support both json and xml based on content negotiation mechanism, Json is the default format, if you want to receive xml, just put on header:
Accept: application/xml
To understand more content negotiation, access this
Since you want your api support both json and xml, you should use DataContract and DataMember Attribute for serialization for your model: EmployeeApiModel, something like:
[DataContract(Name = "Employee")]
public class EmployeeApiModel
{
[DataMember(Name = "Name2")]
public string Name { get; set; }
[DataMember]
public string Email { get; set; }
}
See more on this blog-post
You can control the output of your serialized XML by using various Attribute tags.
[XmlRoot("Employee")]
Public class EmployeeApiModel
{
[XmlElement("fname")]
public string FirstName { get; set; }
public string LastName { get; set; }
public int age { get; set; }
}
this will produce XML like:
<Employee>
<fname>John</fname>
<LastName >Smith</LastName >
<age>24</age>
</RootElementsName>
You can read more about the various XML modifiers here: http://msdn.microsoft.com/en-us/library/e123c76w.
If you want to use existing XML modifiers for JSON, check out this post: Serialize .Net object to json, controlled using xml attributes

WCF REST Starter Kit not filling base class members on POST

I have a WCF REST Starter Kit service. The type handled by the service is a subclass of a base class. For POST requests, the base class members are not correctly populated.
The class hierarchy looks like this:
[DataContract]
public class BaseTreeItem
{
[DataMember]
public String Id { get; set; }
[DataMember]
public String Description { get; set; }
}
[DataContract]
public class Discipline : BaseTreeItem
{
...
}
The service definition looks like:
[WebHelp(Comment = "Retrieve a Discipline")]
[WebGet(UriTemplate = "discipline?id={id}")]
[OperationContract]
public Discipline getDiscipline(String id)
{
...
}
[WebHelp(Comment = "Create/Update/Delete a Discipline")]
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "discipline")]
public WCF_Result DisciplineMaintenance(Discipline discipline)
{
...
}
Problem: While the GET works fine (returns the base class Id and Description), the POST does not populate Id and Description even though the XML contains the fields.
Sample XML:
<?xml version="1.0" encoding="utf-8"?>
<Discipline xmlns="http://schemas.datacontract.org/2004/07/xxx.yyy.zzz">
<DeleteFlag>7</DeleteFlag>
<Description>2</Description>
<Id>5</Id>
<DisciplineName>1</DisciplineName>
<DisciplineOwnerId>4</DisciplineOwnerId>
<DisciplineOwnerLoginName>3</DisciplineOwnerLoginName>
</Discipline>
Thanks for any assistance.
I could not solve the problem using a DataContractSerializer. I switched to using the XMLSerializerFormat and everything worked fine. In fact, the capabilities of the XMLSerializer are so much better that for purely XML work, it is probably better to use the XMLSerializer in all cases.

Categories