3 votes

Désérialisation XML - lancer des erreurs personnalisées

J'ai donc la méthode suivante :

private int? myIntField
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public int? IntField{
    get {
        return this.myIntField;
    }
    set {
        this.myIntField= value;
    }
 }

Maintenant, je désérialise le xml d'un message, si pour une raison quelconque je reçois une chaîne de caractères, comme "voici le champ int : 55444" au lieu de 55444, l'erreur que je reçois en réponse est : Input string was not in a correct format. ce qui n'est pas très précis, surtout si l'on considère que j'aurai plus d'un champ int à vérifier.

A l'origine, j'avais prévu quelque chose comme ça :

private string myIntField
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public int? IntField{
    get {
        return this.myIntField.CheckValue();
    }
    set {
        this.myIntField= value;
    }
 }

Où CheckValue effectue un try-parse à un Int32, et si elle échoue elle retourne un null et ajoute une erreur à une liste. Cependant, je ne parviens pas à mettre en place cette configuration pour les classes générées.

Existe-t-il un moyen d'envoyer une erreur spécifique si je reçois des chaînes de caractères à la place d'entrées, de dates, etc.

4voto

graver Points 9920

C'est facile si vous avez un ou plusieurs schémas pour votre XML et que vous le validez par rapport au schéma avant de le désérialiser. Supposons que vous ayez un ou plusieurs schémas pour votre XML, vous pouvez initialiser un XmlSchemaSet, y ajouter votre ou vos schémas et le :

var document = new XmlDocument();
document.LoadXml(xml); // this a string holding the XML
document.Schemas.XmlResolver = null; //if you don't need to resolve every references
document.Schemas.Add(SchemaSet); // System.Xml.Schema.XmlSchemaSet instance filled with schemas
document.Validate((sender, args) => { ... }); //args are of type ValidationEventArgs and hold problem if there is one...            

Personnellement, je pense que c'est une meilleure approche, car vous pouvez valider votre XML avant la désérialisation et être sûr que le XML est correct, sinon le désérialiseur lèvera très probablement une exception si quelque chose ne va pas et vous ne serez presque jamais en mesure de montrer un retour significatif à l'utilisateur...
P.S. Je recommande de créer un ou plusieurs schémas décrivant le XML

3voto

Simon Mourier Points 49585

Le message "Input string was not in a correct format" provient d'un standard System.FormatException soulevée par un appel à int.Parse ajouté à l'assemblage généré automatiquement qui effectue la désérialisation. Je ne pense pas que vous puissiez ajouter une logique personnalisée à cela.

Une solution consiste à faire quelque chose comme ceci :

    [XmlElement("IntField")]
    [Browsable(false)] // not displayed in grids
    [EditorBrowsable(EditorBrowsableState.Never)] // not displayed by intellisense
    public string IntFieldString
    {
        get
        {
            return DoSomeConvert(IntField);
        }
        set
        {
            IntField = DoSomeOtherConvert(value);
        }
    }

    [XmlIgnore]
    public int? IntField { get; set; }

Ce n'est pas parfait, car vous pouvez toujours avoir accès au public. IntFieldString mais au moins, le "vrai" IntField est utilisée uniquement de manière programmatique, mais pas par le XmlSerializer ( XmlIgnore ), tandis que le champ qui retient la valeur dans les deux sens est caché aux programmeurs ( EditorBrowsable ), les grilles ( Browsable ), etc... mais pas des XmlSerializer .

2voto

Phil Points 19299

J'ai trois approches pour vous.

  • En supposant que vos données soient saisies par un utilisateur dans une interface utilisateur, utilisez la validation des entrées pour vous assurer que les données sont valides. Il semble étrange d'autoriser la saisie de chaînes de caractères aléatoires alors qu'il devrait s'agir d'un nombre entier.

  • Utilisez exactement l'approche que vous suggérez ci-dessus. Voici un exemple utilisant LINQ Pad

    void Main()
    {
        using(var stream = new StringReader(
                  "<Items><Item><IntValue>1</IntValue></Item></Items>"))
        {
            var serializer = new XmlSerializer(typeof(Container));
    
            var items = (Container)serializer.Deserialize(stream);
    
            items.Dump();
        }
    }
    
    [XmlRoot("Items")]
    public class Container
    {
        [XmlElement("Item")]
        public List<Item> Items { get; set; }
    }
    
    public class Item
    {
        [XmlElement("IntValue")]
        public string _IntValue{get;set;}
    
        [XmlIgnore]
        public int IntValue
        {
            get
            {
                // TODO: check and throw appropriate exception
                return Int32.Parse(_IntValue);
            }
        }
    }
  • Prenez le contrôle de la sérialisation en utilisant IXmlSerializable, voici un autre exemple

    void Main()
    {
        using(var stream = new StringReader(
                  "<Items><Item><IntValue>1</IntValue></Item></Items>"))
        {
            var serializer = new XmlSerializer(typeof(Container));
    
            var items = (Container)serializer.Deserialize(stream);
    
            items.Dump();
        }
    }
    
    [XmlRoot("Items")]
    public class Container
    {
        [XmlElement("Item")]
        public List<Item> Items { get; set; }
    }
    
    public class Item : IXmlSerializable
    {
        public int IntValue{get;set;}
    
        public void WriteXml (XmlWriter writer)
        {
            writer.WriteElementString("IntValue", IntValue.ToString());
        }
    
        public void ReadXml (XmlReader reader)
        {
            var v = reader.ReadElementString();
            // TODO: check and throw appropriate exception
            IntValue = int.Parse(v);
        }
    
        public XmlSchema GetSchema()
        {
            return(null);
        }
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X