XML反序列化 - 抛出自定义错误。

3

我有以下方法:

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

现在,我正在从post请求中反序列化xml,如果由于某种原因我收到了一个字符串,例如“这里是int字段:55444”,而不是55444,则我得到的响应错误是:输入字符串格式不正确。这并不是非常具体的错误提示,特别是考虑到我需要验证多个int字段。

最初,我的计划是这样的:

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;
    }
 }

在这里,CheckValue执行了一个try-parse操作,尝试把值转换成Int32类型。如果转换失败,则返回null并将错误添加到列表中。但是,我似乎无法为生成的类设置好这个问题。

是否有一种方法可以在获取字符串而不是int、DateTime等时抛出特定的错误呢?


1
你应该只在已经通过序列化创建的数据上使用反序列化。在其他情况下,特别是当你需要处理可能出现的错误时,你应该正常解析输入(例如使用LINQ to XML、XPath等)。 - eflorico
@Tonnie:您提出的方法似乎是有效的。 “我似乎无法掌握生成类的设置”是什么意思? - Phil
@Tonnie:你说的“post”是指什么?是HTTP POST请求还是博客文章? - Phil
3个回答

4

如果您有XML的模式(schema),在反序列化之前对其进行验证是很容易的。假设您有XML的模式(schema),您可以初始化一个XmlSchemaSet,将您的模式(schema)添加到其中,然后:

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...            

个人认为这是一种更好的方法,因为在反序列化之前可以验证 XML 并确保 XML 正确无误,否则如果出现错误,反序列化器很可能会抛出异常,你几乎永远不可能向用户显示有意义的反馈...
附注:我建议创建描述 XML 的模式(schema)。


3
“输入字符串的格式不正确”消息来自于对int.Parse进行调用时引发的标准System.FormatException,该调用是添加到执行反序列化的自动生成程序集中的。我认为您无法向其中添加一些自定义逻辑。
一种解决方法是像这样做:
    [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; }

这并不完美,因为你仍然可以访问公共的IntFieldString,但至少,“真正的”IntField属性只在程序中使用,而不是由XmlSerializer(XmlIgnore)使用,同时用于保存值的字段被隐藏在程序员(EditorBrowsable)、网格(Browsable)等地方...但不是在XmlSerializer中。


2

我为您提供三种方法。

  • Assuming your data is being entered by a user in a user interface, use input validation to ensure the data is valid. It seems odd to allow random strings to be entered when it should be an integer.

  • Use exactly the approach you suggest above. Here's an example using 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);
            }
        }
    }
    
  • Take control of serialization using IXmlSerializable, here's another example

    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);
        }
    }
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接