0

for the sake of compatibility I need to deserialize an old DataContract-XML into a new model with abstract Types.

Old model and old XML

[DataContract]
class OldType {
  [DataMember] public string Hello;
}

List<OldType> serializeMe = new List<~>(){ new OldType(); }
serializer.WriteObject(..., serializeMe);
<OldType>
  <Hello></Hello>
</OldType>

New Model & XML

[DataContract]
abstract class AbstractType {
 [DataMember] public string Hello;
}

[DataContract]
class NewType : AbstractType {
  // only non serialized fields
}

List<AbstractType> serializeMe = new List<~>(){ new NewType(); }
serializer.WriteObject(..., serializeMe);
<AbstractType i:type="b:NewType" mlns:b="..Namespace">
  <Hello></Hello>
</AbstractType>

Now this obviously doesn't work like that. I was hoping to map the old types to the new abstract types using the DataContractResolver. However the resolver is only called for nodes declared with xsi:type. The last possibility I can think of is using string.replace, however this is just ugly. Any more suggestions? Or can I change the DataContractResolver to ALWAYS get invoked?

martinyyyy
  • 1,652
  • 3
  • 21
  • 44
  • Type is used when you have inherited classes. So original code just has a base class with no inherited classes. New code has inherited classes. So you just have to add the inherited classes. Make sure you use XmlInclude. See : https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlincludeattribute?force_isolation=true&view=net-5.0 – jdweng Sep 03 '21 at 14:30
  • 1
    Setting aside the `xsi:type` issue for a moment, you are making an even more basic change: you are changing the [data contract name](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-names) from `` to ``. That **is always breaking**, as explained in [the docs](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-versioning#breaking-vs-nonbreaking-changes) and also [How to change the Type of DataContract property without breaking backwards compatibility?](https://stackoverflow.com/q/55566176/3744182). – dbc Sep 03 '21 at 15:33
  • 1
    To quote [this answer](https://stackoverflow.com/a/55566232/3744182) by [TheGeneral](https://stackoverflow.com/users/1612975/thegeneral) to [How to change the Type of DataContract property without breaking backwards compatibility?](https://stackoverflow.com/q/55566176/3744182). *you can't do this, this breaks the contract... You will need to cut and run in some way. You may need to make plumbing to deal with older contracts.* Might you explain why you want to solve this with the serializer level, rather than at a higher level? – dbc Sep 03 '21 at 15:34
  • @jdweng - question is about `DataContractSerializer`, your comment applies to `XmlSerializer`. – dbc Sep 03 '21 at 15:35
  • @dbc : OP says xml!!! – jdweng Sep 03 '21 at 16:15
  • @jdweng - yes, they are attempting to serialize and deserialize XML using [`DataContractSerializer`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.datacontractserializer?view=net-5.0#remarks) which can be used to *serialize and deserialize instances of a type into an XML stream or document*. It is a different serializer than `XmlSerializer`, see [DataContractSerializer vs XmlSerializer: Pros and Cons of each serializer](https://stackoverflow.com/q/2505778/3744182). – dbc Sep 03 '21 at 16:24
  • @dbc : Data Contract will not work with XML attributes which is what the OP is having issues with. – jdweng Sep 03 '21 at 18:50
  • @jdweng - in general that is correct but `DataContractSerializer` supports polymorphic specification of type using [`xsi:type`](https://www.w3.org/TR/xmlschema-1/#xsi_type) (or `i:type` in this case) via [known types](https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-known-types). See: [DataContractSerialization of generic type hierarchies](https://stackoverflow.com/q/37284138/3744182). Upgrading a simple data contract to a polymorphic data contract is the entire point of the question. – dbc Sep 03 '21 at 18:54
  • @martinyyyy - may I assume that the attribute `mlns:b="..Namespace"` should be `xmlns:b="..Namespace"`? – dbc Sep 03 '21 at 18:58
  • 1
    @dbc yes, exactly. I've decided to move away from this approach and instead of changing my model to the data I've just added an additional mapping DTO and mapped the name and namespace to the old one. Much better, I don't understand why I wasn't thinking about that. – martinyyyy Sep 06 '21 at 16:03

1 Answers1

1

Thanks to @dbc I found the right solution. Instead of changing the model to the data I've just added an additional mapping DTO and mapped the name and namespace to the old one. Much better.

[DataContract(Name="OldType")]
class DataContractOldType {
  [DataMember] public string Hello;

  AbstractType MapToCorrectType() { .... }
}
martinyyyy
  • 1,652
  • 3
  • 21
  • 44