启用架构验证时C#反序列化失败

时间:2018-10-17 03:55:38

标签: c# xml deserialization xmlserializer

我将一个类序列化为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

1 个答案:

答案 0 :(得分:0)

您的问题在这里:

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属性。您正在使用常规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