【问题标题】:C# Deserialization failure on enabling schema validation启用架构验证时 C# 反序列化失败
【发布时间】:2018-10-17 03:55:37
【问题描述】:

我将一个类序列化为 XML。但是启用模式验证后,反序列化到相同的类类型会失败。

这是我正在做的事情:

  1. 从可序列化类创建对象
  2. 将该对象序列化为 XML
  3. 从该对象获取架构
  4. 将该架构添加到验证中
  5. 不经验证反序列化
  6. 使用 XMLschema 验证反序列化

在第六步,它失败了……

在此代码示例中,验证方法失败:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Deserialize
{
    public class Program
    {
        static string filepath = "TestSerilize.xml";
        private static object oSchema;
        private static XmlReaderSettings oXmlReaderSettings;

        static void Main(string[] args)
        {
            MyObject oMyobject = new MyObject();
            oMyobject.MyObjectType = "MyCustomType";
            List<Items> olistItems = new List<Items>();
            Items oItems = new Items();
            oItems.key = "test123";
            oItems.value = "testvalue";
            olistItems.Add(oItems);
            oMyobject.Items = olistItems;
            Saveobjecttofile(oMyobject, filepath);
            dynamic objDeserialized = null;
            objDeserialized = GetObjFormfileWithoutValidation(filepath, oMyobject.GetType());
            objDeserialized = GetObjFormfileWithValidation(filepath, oMyobject.GetType());

        }

        private static dynamic GetObjFormfileWithValidation(string filepath, Type type)
        {
            XmlReaderSettings oXmlReaderSettings = new XmlReaderSettings();
            oXmlReaderSettings.ValidationType = ValidationType.Schema;
            dynamic oSchema = GetSchemaFromType(type);
            oXmlReaderSettings.Schemas.Add(oSchema);
            XmlReader oXmlReader = null;
            if (oSchema != null)
            {
                oXmlReader = XmlReader.Create(filepath, oXmlReaderSettings);
            }
            else
            {
                oXmlReader = XmlReader.Create(filepath);
            }
            object obj = null;
            try
            {
                XmlSerializer oXmlSerializer = new XmlSerializer(type);
                obj = oXmlSerializer.Deserialize(oXmlReader);
            }
            finally
            {
                oXmlReader.Close();
            }
            return obj;
        }

        private static XmlSchema GetSchemaFromType(Type type)
        {
            var oSoapReflectionImporter = new SoapReflectionImporter();
            var oXmlTypeMapping = oSoapReflectionImporter.ImportTypeMapping(type);
            var oXmlSchemas = new XmlSchemas();
            var oXmlSchema = new XmlSchema();
            oXmlSchemas.Add(oXmlSchema);
            var oXMLSchemaExporter = new XmlSchemaExporter(oXmlSchemas);
            oXMLSchemaExporter.ExportTypeMapping(oXmlTypeMapping);
            return oXmlSchema;
        }

        private static dynamic GetObjFormfileWithoutValidation(string filepath, Type type)
        {
            XmlReader oXmlReader = null;
            oXmlReader = XmlReader.Create(filepath);
            object obj = null;
            try
            {
                XmlSerializer oXmlSerializer = new XmlSerializer(type);
                obj = oXmlSerializer.Deserialize(oXmlReader);
            }
            finally
            {
                oXmlReader.Close();
            }
            return obj;

        }

        private static void Saveobjecttofile(object objectToSave, string filepath)
        {
            try
            {
                System.Xml.Serialization.XmlSerializer oXmlSerializer = new System.Xml.Serialization.XmlSerializer(objectToSave.GetType());
                using (System.Xml.XmlTextWriter oXmlTextWriter = new System.Xml.XmlTextWriter(filepath, System.Text.Encoding.UTF8))
                {
                    oXmlTextWriter.Indentation = 2;
                    oXmlTextWriter.Formatting = System.Xml.Formatting.Indented;
                    oXmlSerializer.Serialize(oXmlTextWriter, objectToSave);
                    oXmlTextWriter.Flush();
                    oXmlTextWriter.Close();
                }
            }
            catch (Exception)
            { throw; }
        }
    }
    [XmlType("Items")]
    public class Items
    {
        [XmlAttribute("key")]
        public string key { get; set; }
        [XmlText()]
        public string value { get; set; }
    }

    [Serializable, XmlRoot("MyObject")]
    public class MyObject
    {
        [XmlElement("MyObjectType", IsNullable = true)]
        public string MyObjectType { get; set; }
        [XmlElement("Items")]
        public List<Items> Items;
        public string this[string key]
        {
            get
            {
                return null != Items.Find(x => x.key == key) ? Items.Find(x => x.key == key).value : null;
            }
            set
            {
                if (Items == null) Items = new List<Items>();
                if (null != Items.Find(x => x.key == key))
                {
                    Items.Find(x => x.key == key).value = value;
                }
                else
                {
                    Items.Add(new Items { key = key, value = value });
                }
            }
        }
    }
}

异常详情:

System.Xml.Schema.XmlSchemaException
Message:There is an error in XML document (3, 10).
Inner Exception message:The 'key' attribute is not declared.
StackTrace:    
at system.Xml.Schema.XmlSchemaValidator.SendValidationEvent(XmlSchemaValidationException e, XmlSeverityType severity)
at System.Xml.Schema.XmlSchemaValidator.SendValidationEvent(String code, String arg)
at System.Xml.Schema.XmlSchemaValidator.ValidateAttribute(String lName, String ns, XmlValueGetter attributeValueGetter, String attributeStringValue, XmlSchemaInfo schemaInfo)
at System.Xml.Schema.XmlSchemaValidator.ValidateAttribute(String localName, String namespaceUri, XmlValueGetter attributeValue, XmlSchemaInfo schemaInfo)
at System.Xml.XsdValidatingReader.ValidateAttributes()
at System.Xml.XsdValidatingReader.ProcessElementEvent()
at System.Xml.XsdValidatingReader.ProcessReaderEvent()
at System.Xml.XsdValidatingReader.Read()
at System.Xml.XmlReader.MoveToContent()
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMyObject.Read3_MyObject(Boolean isNullable, Boolean checkType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMyObject.Read4_MyObject()

演示小提琴here.

【问题讨论】:

标签: c# xml deserialization xmlserializer


【解决方案1】:

你的问题在这里:

private static XmlSchema GetSchemaFromType(Type type)
{
    var oSoapReflectionImporter = new SoapReflectionImporter();

SoapReflectionImporter 旨在为已标记为SOAP attributes 的 c# 类型生成架构。这样的模式可用于生成自定义为使用此类属性的XmlSerializer,如How to: Serialize an Object as a SOAP-Encoded XML Stream所示:

XmlTypeMapping myTypeMapping = new SoapReflectionImporter().ImportTypeMapping(type);
XmlSerializer mySerializer = new XmlSerializer(myTypeMapping);  

但是,您没有使用 SOAP 属性。您正在使用 regular XmlSerializer attributes,例如可以看到在你的Items 班级:

[XmlType("Items")]
public class Items
{
    [XmlAttribute("key")]
    public string key { get; set; }
    [XmlText()]
    public string value { get; set; }
}

因此您应该改用XmlReflectionImporter

private static XmlSchema GetSchemaFromType(Type type)
{
    var oReflectionImporter = new XmlReflectionImporter();
    var oXmlTypeMapping = oReflectionImporter.ImportTypeMapping(type);
    var oXmlSchemas = new XmlSchemas();
    var oXmlSchema = new XmlSchema();
    oXmlSchemas.Add(oXmlSchema);
    var oXMLSchemaExporter = new XmlSchemaExporter(oXmlSchemas);
    oXMLSchemaExporter.ExportTypeMapping(oXmlTypeMapping);
    return oXmlSchema;
}

相关:How do I programmatically generate an xml schema from a type?

修复了示例演示here

【讨论】:

    猜你喜欢
    • 2018-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    • 2018-01-07
    相关资源
    最近更新 更多