Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataContract Serializer array node names 'd3p1'

Could someone tell me what the "d3p1" node name means in this?

    <ActionMessage>
        <Data xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
          <d3p1:anyType i:type="Agreement">
 </d3p1:anyType>
      <d3p1:anyType i:type="Agreement"> shortened

I've received many "that looks ugly" and "what if d3p1 changes" comments on this the default serialization in my asp webapi project. I say it's machine readable just fine. But I am curious why it looks like this.

Here are the details, I have a GET verb on the controller that returns an enumerable of ActionMessage

 public IEnumerable<ActionMessage> Get(Guid)

ActionMessage can't be a generic (if that would even help) as the list would contain action messages of different generic types. "newagreement", "keychange", etc.

It would look like ActionMessage<NewAgreement> or ActionMessage<KeyChange> and many more. There's no way to do this in the get as the get returns many "types" of action messages. Outside of a base class or interface. I.E. ActionMessage<IMessage> but these messages have nothing in common.

Here's what action message looks like now.

 public class ActionMessage
{
    [DataMember]
    public Status Status { get; set; }
    [DataMember]
    [XmlElement(ElementName = "Agreement")]
    [XmlArrayItem(ElementName = "testnode")]
    public List<object> Data { get; set; }
    [DataMember]
    public MessageTypes Type { get; set; }
    [DataMember]
    public Guid Id { get; set; }
}

Note the "troubled" XML comes from the data property.

Thoughts? Should the XML human readability matter? Should I go through the pains of switching from the datacontract serializer to the xml serializer? This would likely enable the element name attributes, but I sort of prefer leaving this all vanilla, and while I could completely control the generated XML, do I really need to, or do I really care?

like image 215
Paul Wade Avatar asked Oct 03 '22 22:10

Paul Wade


1 Answers

Having grappled with this a bunch I've come to the conclusion that it's generally best to be as explicit as possible with data contracts. In this case I would split List<object> Data into multiple explicit lists, i.e. List<Agreement> Agreements; List<KeyChange> KeyChanges; and so on. The resulting XML might look something like this:

<ActionMessage>
    <Status>...</Status>
    <Agreements>
        <Agreement>...</Agreement>
    </Agreements>
    <KeyChanges/>
    ...
</ActionMessage>

Some of the elements will be empty (you can configure the serializer to omit these) but each is explicit and easy to read, parse, and deserialize. More importantly, consumers of the schema know exactly what to expect.

There is another option, and that is to define some kind of interface that Agreement, KeyChange, etc. could all implement (e.g. 'IData') and change List<object> Data to List<IData> Data. It would result in a slightly prettier XML document, but you would have to maintain a list of known types to ensure that all of the implementations can be deserialized. The XML would look something like this:

<ActionMessage>
    <Status>...</Status>
    <Data>
        <IData xsi:type="Agreement">..</IData>
        <IData xsi:type="KeyChange">..</IData>
    </Data>
    <KeyChanges/>
    ...
</ActionMessage>

However, this makes for brittle deserialization and can cause problems with forward/backward compatibility of messages.

like image 92
Jesse Sweetland Avatar answered Oct 12 '22 12:10

Jesse Sweetland