30

Problem:

I have a WCF service setup to be an endpoint for a call from an external system. The call is sending plain xml. I am testing the system by sending calls into the service from Fiddler using the RequestBuilder.

The issue is that all of my fields are being deserialized with the exception of two fields. price_retail and price_wholesale.

What am I missing? All of the other fields deserialize without an issue - the service responds. It is just these fields.

XML Message:

<widget_conclusion>
    <list_criteria_id>123</list_criteria_id>
    <list_type>consumer</list_type>
    <qty>500</qty>
    <price_retail>50.00</price_retail>
    <price_wholesale>40.00</price_wholesale>
    <session_id>123456789</session_id>
</widget_conclusion>

Service Method:

public string WidgetConclusion(ConclusionMessage message)
{
    var priceRetail = message.PriceRetail;
}

Message class:

[DataContract(Name = "widget_conclusion", Namespace = "")]
public class ConclusionMessage  
{
    [DataMember(Name = "list_criteria_id")]
    public int CriteriaId  { get; set;}
    [DataMember(Name = "list_type")]
    public string ListType { get; set; }
    [DataMember(Name = "qty")]
    public int ListQuantity { get; set; }
    [DataMember(Name = "price_retail")]
    public decimal PriceRetail { get; set; }
    [DataMember(Name = "price_wholesale")]
    public decimal PriceWholesale { get; set; }
    [DataMember(Name = "session_id")]
    public string SessionId { get; set; }
}
Justin Hersh
  • 337
  • 1
  • 3
  • 7

2 Answers2

57

Fields are in the wrong order for your message. DataContracts default to Alphabetical ordering and not order of declaration; and expects XML elements to arrive in that order; Out of order elements are discarded usually.

Either fix your contract to specify the right order explicitly (using the Order property of the DataMemberAttribute) or make sure your client sends them in the right one.

tomasr
  • 13,683
  • 3
  • 38
  • 30
  • 1
    Good answer. I tried both ways and the behavior is exactly how you describe. It is always a humbling experience to miss the simple things. I am interested in why DataContracts default to alphabetical order. It seems that it would be more declarative to maintain order of declaration...but I suppose supplying the Order attribute is the most declarative. – Justin Hersh Mar 26 '10 at 01:22
  • 1
    Yep. I've made it a practice of always declaring the order explicitly, makes things a lot easier later. – tomasr Mar 26 '10 at 02:41
  • 9
    Is there another serializer (other than the antedeluvian XmlSerializer) that doesn't have this bone-headed behavior? Because if I wanted that kind of rigid hyper-strict deserialization, I'd just use binary. – Pxtl Feb 13 '15 at 15:58
  • 2
    What about the use of optional fields? (minOccurs="0") in wsdl? This can be a part of the response or not. So it can completely mess up the order. – cmart Aug 27 '15 at 14:24
  • I was in a similar situation seemingly doing everything right, i.e.: setting [DataMember(Order=...)], but deserialization still DIDN'T work. It turned out [DataContract] is required, lest empty, for [DataMember] to be considered by DCS. – esteewhy May 06 '20 at 17:37
0

You can try to use XmlSerializer instead of DataContractSerializer. In my case, I need to change default engine in global.asax file:

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;

Do this carefully because some XML can become not valid, for example - namespaces, with XmlSerializer should be determined like:

[XmlNamespaceDeclarations] 
private XmlSerializerNamespaces xmlns 
{  
  get {
    var xns = new XmlSerializerNamespaces();
    xns.Add("i", "http://www.w3.org/2001/XMLSchema-instance");
    return xns;
  }    
  set { } 
}

Or u can set XmlSerializerFormatAtrribute to You class (not work for me). Look in url head "Manually Switching to the XmlSerializer"

Vlad
  • 1,017
  • 1
  • 15
  • 18