9
votes

XMLSérialiseur avec de nouvelles valeurs d'énum

Nous utilisons de manière approfondie la sérialisation / désérialisation XML dans notre projet pour réussir les données entre plusieurs applications. Nous avons un XSD commun que nous générons des classes C # d'utilisez ensuite XMLSerializer pour aller de XML aux objets et à l'arrière.

Le problème que nous ayons est lorsque une application est mise à jour pour ajouter de nouvelles valeurs Enum, mais l'autre application n'est pas encore mise à jour. Maintenant, l'application qui n'est pas mise à jour tente de désérialiser le XML et échoue car elle ne sait pas sur la nouvelle Enum.

Si nous avons APP1 et APP2, les choses fonctionnent correctement sur le terrain, puis app2 est mise à jour avec une nouvelle valeur Enum dans le XSD et mise à jour au client sur le terrain. Soudainement app1 casse parce qu'il ne sait pas sur l'ENUM, l'APP1 pourrait même pas utiliser ce champ Enum, n'a pas d'effet sur l'APP1, mais il se casse toujours.

Y a-t-il des façons connues autour de cela. Fondamentalement, ce que je veux faire, c'est de définir ce que faire quand une énumération n'est pas trouvée, utilisez une valeur par défaut ou si l'ENUM est un type annulable et définissez-le sur NULL.

Les exceptions XMLSerializer et DatacontractSerializerSérialiseur sont cette situation.

J'ai examiné le projet de sérialisation XML personnalisé YaxLib ( http: // www. CodeProject.com/kb/xml/yaxLib.aspx ) Cela jette également une exception, mais il y a un code source et peut être changé. Ce projet utilise différents attributs de propriété et nécessiterait une très peu de changement mais est probablement faisable.

Toute autre suggestion.


1 commentaires

Cela doit-il être une sérialisation XML? J'ai eu bonne chance avec James.Newtonking.com/projects/json-net.aspx . Je l'utilise dans une application de bureau. Ce qui est bien à propos de JSON, c'est qu'il ne porte pas réellement les informations de type à l'intérieur (ni XMLSerializer). Cette bibliothèque a des rappels et a sérialisé tout ce que j'ai jeté. Il semble avoir l'extensibilité que vous pourriez avoir besoin.


7 Réponses :


0
votes

Utilisez la sérialisation personnalisée C # avec le versement des objets; Cela vous permettrait de gérer les différentes situations qui surviennent lorsqu'une application est mise à jour et que l'autre n'est pas


1 commentaires

Veuillez élaborer ce que vous entendez par «sérialisation personnalisée». Vous pouvez également dire pourquoi c'est "C # Serialization personnalisée", puisque le langage de programmation C # n'a pas de sérialisation.



12
votes

Malheureusement, il n'y a aucun moyen de contrôler comment les valeurs ENUM sont désérialisées ... comme solution de contournement, vous pouvez sérialiser les valeurs ENUM en tant que chaîne:

[XmlIgnore]
public MyEnum MyProperty { get; set; }

[XmlElement("MyProperty")]
public string MyPropertyAsString
{
    get
    {
        return EnumToString(MyProperty);
    }
    set
    {
        MyProperty = StringToEnum<MyEnum>(value);
    }
}

public T StringToEnum<T>(string stringValue)
{
    // Manually convert the string to enum, ignoring unknown values
}

public string EnumToString<T>(T enumValue)
{
    // Convert the enum to a string
}


1 commentaires

@Aitay: Nous ne parlons pas de champs inconnus ici (vous pouvez les gérer avec XmanyElement ou XMLanyAttribute), nous parlons de valeurs énoncées inconnues ...



1
votes

Vous pouvez faire connaître la production des multiples versions des applications consommatrices et utiliser différents espaces de noms différents, XML et C #, pour chacune des versions. Il doit y avoir une certaine coordination entre les applications qui conviendront sur quel schéma ils suiviront et là responsabilités isadditionale sur la demande de production de continuer à être compatible avec toutes les applications de consommation actives possibles.


0 commentaires

4
votes

J'ai également lu avec ce problème et j'ai trouvé une solution partielle à l'aide de XMLattributeOverrides. Par la documentation MS:

Vous pouvez remplacer la valeur de la propriété Nom d'un XMLenumAttribute en créant une instance de la classe XMLenumateTribute et en l'attribuant à la propriété XMLENUM d'un objet XMLATtributes. Pour plus de détails, voir la classe XMLattributeOverrides. P> BlockQuote>

Alors je l'ai fait: P>

XmlEnumAttribute enumAttribute = new XmlEnumAttribute();
enumAttribute.Name = "new value";

XmlAttributes attributes = new XmlAttributes();
attributes.XmlEnum = enumAttribute;

XmlAttributeOverrides attributeOverrides = new XmlAttributeOverrides();
attributeOverrides.Add(typeof(EnumType), "OldValue", attributes);

XmlSerializer serializer = new XmlSerializer(typeof(MyType), attributeOverrides);
FileStream fs = new FileStream(filename, FileMode.Open);
MyType newObj = (MyType)serializer.Deserialize(fs);


0 commentaires


2
votes

J'ai récemment couru dans ce même problème avec le DatacontractSérialiseur. Fondamentalement, le processus de désérialisation de l'énumé est impacciant à cet égard, ce qui rend presque impossible de gérer la compatibilité en arrière.

comme un travail autour, j'ai décidé d'utiliser un champ de support et de gérer la conversion enum moi-même. P>

[DataMember(Name="AddressType")]
private string _addressType { get; set; }

public AddressType AddressType
{
    get
    {
        AddressType result;
        Enum.TryParse(_addressType, out result);
        return result;
    }
}


0 commentaires

0
votes

meilleur moyen est de partager le code de sérialisation / désérialisation entre 2 applications Mais s'il n'est pas possible, vous pouvez utiliser XMLATTRibuteOverrides pour contrôler assez largement la manière dont XML sera désérialisé. Par exemple, au-dessous de la version antérieure de XML, nous voulons désérialiser

    var overrides = new XmlAttributeOverrides();
    overrides.Add(typeof(Style), "Style1", new XmlAttributes { XmlEnum = new 
        XmlEnumAttribute("1" ) } );
    overrides.Add(typeof(Style), "Style2", new XmlAttributes { XmlEnum = new      
        XmlEnumAttribute("2") });
    overrides.Add(typeof(Style), "Style3", new XmlAttributes { XmlEnum = new 
        XmlEnumAttribute("3") });

    var xmlSerializer = new XmlSerializer(typeof(ContentRootType),   
        overrides);
    var content = xmlSerializer.Deserialize(xmlReader) as ContentRootType;


0 commentaires