WCF MessageHeader attribute does not deserialized - c#

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...

Related

How to remove namespace from WEB API request & response XML?

I want to remove highlighted node from WEB API request and response.
Below are the class Models used in web api
[DataContract(Namespace = "")]
public class ValidateRequest
{
[DataMember]
public string Client_Code { get; set; }
[DataMember]
public string ClientValidateNo { get; set; }
[DataMember]
public string UserID { get; set; }
[DataMember]
public string Password { get; set; }
}
[DataContract(Namespace = "")]
public class ValidateResponse
{
}
I want to remove highlighted node from WEB API request and response.
Below are the class Models used in web api
To achieve this function, first you need to create a class that inherits from XmlSerializerOutputFormatter:
public class XmlSerializerOutputFormatterNamespace : XmlSerializerOutputFormatter
{
protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
{
//applying "empty" namespace will produce no namespaces
var emptyNamespaces = new XmlSerializerNamespaces();
emptyNamespaces.Add("", "any-non-empty-string");
xmlSerializer.Serialize(xmlWriter, value, emptyNamespaces);
}
}
Then, add the following service in ConfigureServices in startup.cs:
services
.AddMvc(options =>
{
options.OutputFormatters.Add(new XmlSerializerOutputFormatterNamespace());
}).AddXmlSerializerFormatters();
In api method:
[Produces("application/xml")]
public IActionResult GetXml(ValidateRequest request)
{
ValidateResponse response = new ValidateResponse()
{
Amount = 100,
ClientValidateNo = request.ClientValidateNo,
Client_Code = request.Client_Code,
DepositorCity = "aaa",
DepositorName = "das",
DepositorState = "sadasd",
Status = "fasfas"
};
return Ok(response);
}
The test result:

C# web service - getting list of equal element names

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>

Building XML request with RestSharp

I am attempting to work with a REST API using RestSharp and C#.
The documentation for the API that I am using gives a sample XML request:
<?xml version='1.0' encoding='UTF-8'?>
<messages>
<accountreference>EX0000000</accountreference>
<from>07700900654</from>
<message>
<to>07700900123</to>
<type>SMS</type>
<body>Hello Mr Sands.</body>
</message>
<message>
<to>07700900124</to>
<type>SMS</type>
<body>Hello Mr Mayo.</body>
</message>
</messages>
I am struggling to understand how to build the request in the format that they want (multiple elements called "message")
I have created these classes for RestSharp to serialize:
public class messages
{
public string accountreference { get; set; }
public string from { get; set; }
public message message { get; set; }
}
public class message
{
public string to { get; set; }
public string body { get; set; }
}
And here is my RestSharp code:
var client = new RestClient("http://api.url.com/v1.0")
{
Authenticator =
new HttpBasicAuthenticator(
UserName,
Password)
};
var request = new RestRequest("theresource", Method.POST) { RequestFormat = DataFormat.Xml };
request.AddBody(
new messages
{
accountreference = Configuration.AccountReference,
from = Configuration.From,
message =
new message { to = Configuration.Message.To, body = Configuration.Message.Body }
});
var response = client.Execute(request);
This works great when I have only 1 message element, but I don't know how to create multiple message elements without having them nested in an array, which doesn't work with the API.
By default RestSharp is using its own serializer but it also packs the DotNetSerializer so you achieve your goal by changing the serializer like this:
var request = new RestRequest("theresource", Method.POST)
{
RequestFormat = DataFormat.Xml,
XmlSerializer = new RestSharp.Serializers.DotNetXmlSerializer()
};
Then you can use a list of message objects and decorate it with XmlElement attribute:
public class messages
{
public string accountreference { get; set; }
public string from { get; set; }
[XmlElement("message")]
public List<message> messageList { get; set; }
}
public class message
{
public string to { get; set; }
public string body { get; set; }
}
Then you can change the last bit to add multiple messages:
request.AddBody(
new messages
{
accountreference = "ref",
from = "from",
messageList = new List<message>() {
new message { to = "to1", body = "body1" },
new message { to = "to2", body = "body2" }
}
});
which would produce (I got the XML by checking request.Parameters[0].Value):
<?xml version="1.0" encoding="utf-8"?>
<messages>
<accountreference>ref</accountreference>
<from>from</from>
<message>
<to>to1</to>
<body>body1</body>
</message>
<message>
<to>to2</to>
<body>body2</body>
</message>
</messages>
I guess this is the XML format you've been looking for.
Having message as list will work -
public class messages
{
public string accountreference { get; set; }
public string from { get; set; }
public List<message> message { get; set; }
}
public class message
{
public string to { get; set; }
public string body { get; set; }
}
Check the very last answer here -
How to post an array of complex objects with JSON, jQuery to ASP.NET MVC Controller?
If you face issues with list, try this -
Can RestSharp send a List<string> in a POST request?

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.

{"<user xmlns=''> was not expected.} Deserializing Twitter XML

I'm pulling in the XML from Twitter via OAuth.
I'm doing a request to http://twitter.com/account/verify_credentials.xml, which returns the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<user>
<id>16434938</id>
<name>Lloyd Sparkes</name>
<screen_name>lloydsparkes</screen_name>
<location>Hockley, Essex, UK</location>
<description>Student</description>
<profile_image_url>http://a3.twimg.com/profile_images/351849613/twitterProfilePhoto_normal.jpg</profile_image_url>
<url>http://www.lloydsparkes.co.uk</url>
<protected>false</protected>
<followers_count>115</followers_count>
<profile_background_color>9fdaf4</profile_background_color>
<profile_text_color>000000</profile_text_color>
<profile_link_color>220f7b</profile_link_color>
<profile_sidebar_fill_color>FFF7CC</profile_sidebar_fill_color>
<profile_sidebar_border_color>F2E195</profile_sidebar_border_color>
<friends_count>87</friends_count>
<created_at>Wed Sep 24 14:26:09 +0000 2008</created_at>
<favourites_count>0</favourites_count>
<utc_offset>0</utc_offset>
<time_zone>London</time_zone>
<profile_background_image_url>http://s.twimg.com/a/1255366924/images/themes/theme12/bg.gif</profile_background_image_url>
<profile_background_tile>false</profile_background_tile>
<statuses_count>1965</statuses_count>
<notifications>false</notifications>
<geo_enabled>false</geo_enabled>
<verified>false</verified>
<following>false</following>
<status>
<created_at>Mon Oct 12 19:23:47 +0000 2009</created_at>
<id>4815268670</id>
<text>ยป #alexmuller your kidding? it should all be "black tie" dress code</text>
<source><a href="http://code.google.com/p/wittytwitter/" rel="nofollow">Witty</a></source>
<truncated>false</truncated>
<in_reply_to_status_id>4815131457</in_reply_to_status_id>
<in_reply_to_user_id>8645442</in_reply_to_user_id>
<favorited>false</favorited>
<in_reply_to_screen_name>alexmuller</in_reply_to_screen_name>
<geo/>
</status>
</user>
I am using the following code to deserialize:
public User VerifyCredentials()
{
string url = "http://twitter.com/account/verify_credentials.xml";
string xml = _oauth.oAuthWebRequestAsString(oAuthTwitter.Method.GET, url, null);
XmlSerializer xs = new XmlSerializer(typeof(User),"");
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml));
return (User)xs.Deserialize(ms);
}
And I have the following for my User class:
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class User
{
[XmlElement(ElementName = "id")]
public long Id { get; set; }
[XmlElement(ElementName = "name")]
public string Name { get; set; }
[XmlElement(ElementName = "screen_name")]
public string ScreenName { get; set; }
[XmlElement(ElementName = "location")]
public string Location { get; set; }
[XmlElement(ElementName = "description")]
public string Description { get; set; }
[XmlElement(ElementName = "profile_image_url")]
public string ProfileImageUrl { get; set; }
[XmlElement(ElementName = "url")]
public string Url { get; set; }
[XmlElement(ElementName = "protected")]
public bool Protected { get; set; }
[XmlElement(ElementName = "followers_count")]
public int FollowerCount { get; set; }
[XmlElement(ElementName = "profile_background_color")]
public string ProfileBackgroundColor { get; set; }
[XmlElement(ElementName = "profile_text_color")]
public string ProfileTextColor { get; set; }
[XmlElement(ElementName = "profile_link_color")]
public string ProfileLinkColor { get; set; }
[XmlElement(ElementName = "profile_sidebar_fill_color")]
public string ProfileSidebarFillColor { get; set; }
[XmlElement(ElementName = "profile_sidebar_border_color")]
public string ProfileSidebarBorderColor { get; set; }
[XmlElement(ElementName = "friends_count")]
public int FriendsCount { get; set; }
[XmlElement(ElementName = "created_at")]
public string CreatedAt { get; set; }
[XmlElement(ElementName = "favourties_count")]
public int FavouritesCount { get; set; }
[XmlElement(ElementName = "utc_offset")]
public int UtcOffset { get; set; }
[XmlElement(ElementName = "time_zone")]
public string Timezone { get; set; }
[XmlElement(ElementName = "profile_background_image_url")]
public string ProfileBackgroundImageUrl { get; set; }
[XmlElement(ElementName = "profile_background_tile")]
public bool ProfileBackgroundTile { get; set; }
[XmlElement(ElementName = "statuese_count")]
public int StatusesCount { get; set; }
[XmlElement(ElementName = "notifications")]
public string Notifications { get; set; }
[XmlElement(ElementName = "geo_enabled")]
public bool GeoEnabled { get; set; }
[XmlElement(ElementName = "Verified")]
public bool Verified { get; set; }
[XmlElement(ElementName = "following")]
public string Following { get; set; }
[XmlElement(ElementName = "status", IsNullable=true)]
public Status CurrentStatus { get; set; }
}
But when it's deserializing the above XML the application throws the following:
$exception {"There is an error in XML document (2, 2)."} System.Exception {System.InvalidOperationException}
InnerException {"<user xmlns=''> was not expected."} System.Exception {System.InvalidOperationException}
Now I have searched around and the best solution I can find is to add blank namespaces to the serializer when you serialize the content, but i'm not serializing it so I can't.
I also have some code for receiving Statuses, which works fine.
So can someone explain to me why the error is happening? As well as a possible solution?
Either decorate your root entity with the XmlRoot attribute which will be used at compile time.
[XmlRoot(Namespace = "www.contoso.com", ElementName = "MyGroupName", DataType = "string", IsNullable=true)]
Or specify the root attribute when de serializing at runtime.
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "user";
// xRoot.Namespace = "http://www.cpandl.com";
xRoot.IsNullable = true;
XmlSerializer xs = new XmlSerializer(typeof(User),xRoot);
Even easier is just to add the following annotations to the top of your class:
[Serializable, XmlRoot("user")]
public partial class User
{
}
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName"));
The error message is so vague, for me I had this code:
var streamReader = new StreamReader(response.GetResponseStream());
var xmlSerializer = new XmlSerializer(typeof(aResponse));
theResponse = (bResponse) xmlSerializer.Deserialize(streamReader);
Notice xmlSerializer is instantiated with aResponse but on deserializing I accidentally casted it to bResonse.
The simplest and best solution is just to use XMLRoot attribute in your class, in which you wish to deserialize.
Like:
[XmlRoot(ElementName = "YourPreferableNameHere")]
public class MyClass{
...
}
Also, use the following Assembly :
using System.Xml.Serialization;
In my case, my xml had multiple namespaces and attributes.
So I used this site to generate the objects - https://xmltocsharp.azurewebsites.net/
And used the below code to deserialize
XmlDocument doc = new XmlDocument();
doc.Load("PathTo.xml");
User obj;
using (TextReader textReader = new StringReader(doc.OuterXml))
{
using (XmlTextReader reader = new XmlTextReader(textReader))
{
XmlSerializer serializer = new XmlSerializer(typeof(User));
obj = (User)serializer.Deserialize(reader);
}
}
As John Saunders says, check if the class/property names matches the capital casing of your XML. If this isn't the case, the problem will also occur.
The only thing that worked in my case was by using david valentine code. Using Root Attr. in the Person class did not help.
I have this simple Xml:
<?xml version="1.0"?>
<personList>
<Person>
<FirstName>AAAA</FirstName>
<LastName>BBB</LastName>
</Person>
<Person>
<FirstName>CCC</FirstName>
<LastName>DDD</LastName>
</Person>
</personList>
C# class:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
De-Serialization C# code from a Main method:
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "personList";
xRoot.IsNullable = true;
using (StreamReader reader = new StreamReader(xmlFilePath))
{
List<Person> result = (List<Person>)(new XmlSerializer(typeof(List<Person>), xRoot)).Deserialize(reader);
int numOfPersons = result.Count;
}
My issue was that the root element actually has a xmlns="abc123"
So had to make XmlRoot("elementname",NameSpace="abc123")
Nothing worked for me for these errors EXCEPT
... was not expected,
... there is an error in XML document (1,2)
... System.FormatException Input String was not in correct format ...
Except this way
1- You need to inspect the xml response as string (the response that you are trying to de-serialize to an object)
2- Use online tools for string unescape and xml prettify/formatter
3- MAKE SURE that the C# Class (main class) you are trying to map/deserialize the xml string to HAS AN XmlRootAttribute that matches the root element of the response.
Exmaple:
My XML Response was staring like :
<ShipmentCreationResponse xmlns="http://ws.aramex.net/ShippingAPI/v1/">
<Transaction i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"/>
....
And the C# class definition + attributes was like :
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="ShipmentCreationResponse", WrapperNamespace="http://ws.aramex.net/ShippingAPI/v1/", IsWrapped=true)]
public partial class ShipmentCreationResponse {
.........
}
Note that the class definition does not have "XmlRootAttribute"
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.aramex.net/ShippingAPI/v1/", IsNullable = false)]
And when i try to de serialize using a generic method :
public static T Deserialize<T>(string input) where T : class
{
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (System.IO.StringReader sr = new System.IO.StringReader(input))
{
return (T)ser.Deserialize(sr);
}
}
var _Response = GeneralHelper.XMLSerializer.Deserialize<ASRv2.ShipmentCreationResponse>(xml);
I was getting the errors above
... was not expected, ... there is an error in XML document (1,2) ...
Now by just adding the "XmlRootAttribute" that fixed the issue for ever and for every other requests/responses i had a similar issue with:
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.aramex.net/ShippingAPI/v1/", IsNullable = false)]
..
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://ws.aramex.net/ShippingAPI/v1/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.aramex.net/ShippingAPI/v1/", IsNullable = false)]
public partial class ShipmentCreationResponse
{
........
}
My problem was one of my elements had the xmlns attribute:
<?xml version="1.0" encoding="utf-8"?>
<RETS ReplyCode="0">
<RETS-RESPONSE xmlns="blahblah">
...
</RETS-RESPONSE>
</RETS>
No matter what I tried the xmlns attribute seemed to be breaking the serializer, so I removed any trace of xmlns="..." from the xml file:
<?xml version="1.0" encoding="utf-8"?>
<RETS ReplyCode="0">
<RETS-RESPONSE>
...
</RETS-RESPONSE>
</RETS>
and voila! Everything worked.
I now parse the xml file to remove this attribute before deserializing.
Not sure why this works, maybe my case is different since the element containing the xmlns attribute is not the root element.
All above not worked for me, but this was:
Check that the name of Root element of class is exactly like the one from XML case sensitive.

Categories