Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Union serialization defaults to widest data type, which may or may not be ideal #399

Open
jzabroski opened this issue Jul 17, 2023 · 3 comments

Comments

@jzabroski
Copy link

jzabroski commented Jul 17, 2023

One potential problem - that may or not be a problem in my case. I've asked the vendor. But, for DateTime/Date, you are automatically choosing the widest type, and there is no way to control the exact serialization as Date-only or DateTime. e.g., previously we were sending the vendor 2023-03-15, and now it is sending that same value as 2023-03-15T00:00:00. If the presence of a time component carries some semantic difference, then this would be a breaking change when working with this vendors XSD. My fingers are crossed that in my scenario it doesn't matter, but I could see it mattering for some implementations.

Originally posted by @jzabroski in #397 (comment)

@jzabroski
Copy link
Author

The difference appears to be:

  [System.ComponentModel.DataAnnotations.RequiredAttribute()]
  [System.Xml.Serialization.XmlAttributeAttribute("Date")]
  public DateTime DateObject { get; set; }

vs.

 [System.ComponentModel.DataAnnotations.RequiredAttribute()]
 [System.Xml.Serialization.XmlAttributeAttribute("Date", DataType="date")]
 public System.DateTime Date { get; set; }

Obviously, widening is the only approach where data type unification makes sense. So, it's really just a matter of whether or not that is the right value to send, semantically. - That's not something an XSD Validator can tell us, for example, as it's API behavior-defined by the vendor.

Incidentally, Microsoft defines the list of XSD data types they support, here: https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlattributeattribute.datatype?view=net-7.0#remarks (I did not know this, and was just reading the source to figure it out).

@jzabroski
Copy link
Author

Possible alternatives, which may be pretty complex:

  1. Support OneOf (which does not directly solve any problems, since OneOf is a complex type and cannot be serialized by System.Xml.Serialization approach)
  2. Support Tagged Unions, which is probably the same as OneOf but possibly even more complex?
  3. Some combination of the above two approaches

For Tagged Unions, the approach would be:

  1. Create an enum for the field being serialized, called <ElementName><AttributeName>UnionTag. e.g.:
    public enum SnapshotDateUnionTag
    {
      SnapshotDate = 1,
      SnapshotDateTime = 2,
    }
  2. In each parent object referencing a union property, generate backing fields using XmlIgnore:
    public class Snapshot
    {
      [XmlIgnore]
      public SnapshotDateUnionTag SnapshotDateTag { get; set; }
    
      [XmlIgnore]
      public DateTime Date { get; set; }
    
      // The getter here would need to switch on SnapshotDateUnionTag to determine whether to use xs:Date or xs:DateTime serialization format
     [System.Xml.Serialization.XmlAttributeAttribute("Date")]
      public string DateSerialized {
        get
        {
          switch (SnapshotDateUnionTag)
          {
            case SnapshotDateUnionTag.SnapshotDate:
              return $"{Date:yyyy-MM-dd}";
            case SnapshotDateUnionTag.SnapshotDateTime:
              return $"{Date:yyyy-MM-ddThh:mm:ss}";
          }
        }
        set
        {
        }
      }
    }

@jzabroski
Copy link
Author

Some possible inspiration here: https://github.com/dpraimeyuu/OneOf.Serialization - it does Json, not Xml. Practically speaking, the only way to implement Xml support on a complex type like OneOfBase-derived instances would probably be to implement IXmlSerializable. Unless I am missing something? It's been a decade since I was deep into XML APIs in .NET.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant