代码之家  ›  专栏  ›  技术社区  ›  Reg Edit

当元素是MS类时,如何控制.NET XML序列化/反序列化以排除元素,因此我无法编辑源代码以添加XMLIgnore等

  •  1
  • Reg Edit  · 技术社区  · 11 年前

    为了持久化对象并在下次启动时恢复它们,XML序列化迄今为止对我来说做得很好。但我当前在Microsoft.SqlServer.Management.Smo命名空间中的ScriptingOptions类遇到问题。

    序列化对象将生成如下所示的XML片段。但当我尝试反序列化它时,XmlSerializer抛出了一个异常:

        There is an error in XML document (n,n)
    

    内部异常是InvalidOperationException:

        Instance is read-only
    

    堆栈跟踪(下面将进一步介绍)标识它正在尝试设置EncoderFallback属性。如果我编辑XML以删除以下元素,则反序列化成功,这进一步证实了这一点:

      <Encoding xsi:type="UnicodeEncoding">
        <EncoderFallback xsi:type="EncoderReplacementFallback" />
        <DecoderFallback xsi:type="DecoderReplacementFallback" />
      </Encoding>
    

    所以我想排除这个 Encoding 元素,在对象的序列化或反序列化期间。

    我已经搜索了答案,但我发现的所有自定义序列化/反序列化方法似乎都假定可以访问类源代码、添加XMLIgnore或实现ISerializable等。

    我想我可以编写一个预处理器,在反序列化之前解析XML并删除有问题的元素,但肯定有比这更“合适”的方法吗?

    序列化对象:

    <ScriptingOptions>
      <FileName />
      <Encoding xsi:type="UnicodeEncoding">
        <EncoderFallback xsi:type="EncoderReplacementFallback" />
        <DecoderFallback xsi:type="DecoderReplacementFallback" />
      </Encoding>
      <DriWithNoCheck>false</DriWithNoCheck>
      <IncludeFullTextCatalogRootPath>false</IncludeFullTextCatalogRootPath>
      <BatchSize>1</BatchSize>
      <ScriptDrops>false</ScriptDrops>
      <TargetServerVersion>Version120</TargetServerVersion>
      <TargetDatabaseEngineType>Standalone</TargetDatabaseEngineType>
      <AnsiFile>false</AnsiFile>
      <AppendToFile>false</AppendToFile>
      <ToFileOnly>false</ToFileOnly>
      <SchemaQualify>true</SchemaQualify>
      <IncludeHeaders>false</IncludeHeaders>
      <IncludeIfNotExists>true</IncludeIfNotExists>
      <WithDependencies>false</WithDependencies>
      <DriPrimaryKey>false</DriPrimaryKey>
      <DriForeignKeys>false</DriForeignKeys>
      <DriUniqueKeys>false</DriUniqueKeys>
      <DriClustered>false</DriClustered>
      <DriNonClustered>false</DriNonClustered>
      <DriChecks>false</DriChecks>
      <DriDefaults>false</DriDefaults>
      <Triggers>false</Triggers>
      <Statistics>false</Statistics>
      <ClusteredIndexes>false</ClusteredIndexes>
      <NonClusteredIndexes>false</NonClusteredIndexes>
      <NoAssemblies>false</NoAssemblies>
      <PrimaryObject>true</PrimaryObject>
      <Default>true</Default>
      <XmlIndexes>false</XmlIndexes>
      <FullTextCatalogs>false</FullTextCatalogs>
      <FullTextIndexes>false</FullTextIndexes>
      <FullTextStopLists>false</FullTextStopLists>
      <Indexes>false</Indexes>
      <DriIndexes>false</DriIndexes>
      <DriAllKeys>false</DriAllKeys>
      <DriAllConstraints>false</DriAllConstraints>
      <DriAll>false</DriAll>
      <Bindings>false</Bindings>
      <NoFileGroup>false</NoFileGroup>
      <NoFileStream>false</NoFileStream>
      <NoFileStreamColumn>false</NoFileStreamColumn>
      <NoCollation>false</NoCollation>
      <ContinueScriptingOnError>false</ContinueScriptingOnError>
      <IncludeDatabaseRoleMemberships>false</IncludeDatabaseRoleMemberships>
      <Permissions>false</Permissions>
      <AllowSystemObjects>true</AllowSystemObjects>
      <NoIdentities>false</NoIdentities>
      <ConvertUserDefinedDataTypesToBaseType>false</ConvertUserDefinedDataTypesToBaseType>
      <TimestampToBinary>false</TimestampToBinary>
      <AnsiPadding>false</AnsiPadding>
      <ExtendedProperties>false</ExtendedProperties>
      <DdlHeaderOnly>false</DdlHeaderOnly>
      <DdlBodyOnly>false</DdlBodyOnly>
      <NoViewColumns>false</NoViewColumns>
      <SchemaQualifyForeignKeysReferences>false</SchemaQualifyForeignKeysReferences>
      <AgentAlertJob>false</AgentAlertJob>
      <AgentJobId>true</AgentJobId>
      <AgentNotify>false</AgentNotify>
      <LoginSid>false</LoginSid>
      <NoCommandTerminator>false</NoCommandTerminator>
      <NoIndexPartitioningSchemes>false</NoIndexPartitioningSchemes>
      <NoTablePartitioningSchemes>false</NoTablePartitioningSchemes>
      <IncludeDatabaseContext>false</IncludeDatabaseContext>
      <NoXmlNamespaces>false</NoXmlNamespaces>
      <DriIncludeSystemNames>false</DriIncludeSystemNames>
      <OptimizerData>false</OptimizerData>
      <NoExecuteAs>false</NoExecuteAs>
      <EnforceScriptingOptions>false</EnforceScriptingOptions>
      <NoMailProfileAccounts>false</NoMailProfileAccounts>
      <NoMailProfilePrincipals>false</NoMailProfilePrincipals>
      <NoVardecimal>true</NoVardecimal>
      <ChangeTracking>false</ChangeTracking>
      <ScriptDataCompression>true</ScriptDataCompression>
      <ScriptSchema>true</ScriptSchema>
      <ScriptData>false</ScriptData>
      <ScriptBatchTerminator>false</ScriptBatchTerminator>
      <ScriptOwner>false</ScriptOwner>
    </ScriptingOptions>
    

    尝试反序列化上述XML时的堆栈跟踪:

        StackTrace  "   at System.Text.Encoding.set_EncoderFallback(EncoderFallback value)\r\n   
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderUserSettings.Read13_UnicodeEncoding(Boolean isNullable, Boolean checkType)\r\n   
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderUserSettings.Read7_Encoding(Boolean isNullable, Boolean checkType)\r\n
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderUserSettings.Read10_ScriptingOptions(Boolean isNullable, Boolean checkType)\r\n   
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderUserSettings.Read14_TableScriptingOptions(Boolean isNullable, Boolean checkType)\r\n   
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderUserSettings.Read15_UserSettings(Boolean isNullable, Boolean checkType)\r\n   
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderUserSettings.Read16_UserSettings()"  string
    
    2 回复  |  直到 11 年前
        1
  •  2
  •   Thomas Levesque    11 年前

    您可以使用 XmlAttributeOverrides 类来指定您不拥有的类的属性:

    var overrides = new XmlAttributeOverrides();
    overrides.Add(
        typeof(ScriptingOptions),
        "Encoding",
        new XmlAttributes { XmlIgnore = true });
    var serializer = new XmlSerializer(typeof(ScriptingOptions), overrides);
    

    但一般来说,使用特定的类来处理序列化通常更方便,正如a-h所建议的那样,因为它给了您更多的灵活性。

        2
  •  2
  •   a-h    11 年前

    有时最简单的解决方案是最好的,但您可以创建一个DTO,其中只包含您想要的财产,使用AutoMapper从源映射到目标(CreateMap不是线程安全的),并从那里直接反序列化为源类型:

    using AutoMapper;
    using Microsoft.SqlServer.Management.Smo;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml.Serialization;
    namespace SerializationTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                Mapper.CreateMap<ScriptingOptions, ScriptingOptionsDto>();
    
                var so = new ScriptingOptions();
                var soDto = Mapper.Map<ScriptingOptionsDto>(so); 
                string xml = Serialize(soDto);
    
                Console.WriteLine(xml); 
                Console.ReadLine(); 
    
                so = Deserialize(xml);
    
                Console.WriteLine(so.ToString());
                Console.ReadLine();
            }
    
            public static string Serialize(ScriptingOptionsDto dto)
            {
                var serializer = new XmlSerializer(dto.GetType()); 
                var ms = new MemoryStream();
                serializer.Serialize(ms, dto); 
                return Encoding.UTF8.GetString(ms.ToArray());
            }
    
            public static ScriptingOptions Deserialize(string xml)
            {
                var serializer = new XmlSerializer(typeof(ScriptingOptions));
                return serializer.Deserialize(new MemoryStream(UnicodeEncoding.UTF8.GetBytes(xml))) as ScriptingOptions;
            }
        }
    
        [XmlType("ScriptingOptions")]
        public class ScriptingOptionsDto
        {
            public bool AgentAlertJob { get; set; }
            public bool AgentJobId { get; set; }
            public bool AgentNotify { get; set; }
            public bool AllowSystemObjects { get; set; }
            public bool AnsiFile { get; set; }
            public bool AnsiPadding { get; set; }
            public bool AppendToFile { get; set; }
            public int BatchSize { get; set; }
            public bool Bindings { get; set; }
            public bool ChangeTracking { get; set; }
            public bool ClusteredIndexes { get; set; }
            public bool ContinueScriptingOnError { get; set; }
            public bool ConvertUserDefinedDataTypesToBaseType { get; set; }
            public bool DdlBodyOnly { get; set; }
            public bool DdlHeaderOnly { get; set; }
            public bool Default { get; set; }
            public bool DriAll { get; set; }
            public bool DriAllConstraints { get; set; }
            public bool DriAllKeys { get; set; }
            public bool DriChecks { get; set; }
            public bool DriClustered { get; set; }
            public bool DriDefaults { get; set; }
            public bool DriForeignKeys { get; set; }
            public bool DriIncludeSystemNames { get; set; }
            public bool DriIndexes { get; set; }
            public bool DriNonClustered { get; set; }
            public bool DriPrimaryKey { get; set; }
            public bool DriUniqueKeys { get; set; }
            public bool DriWithNoCheck { get; set; }
            public bool EnforceScriptingOptions { get; set; }
            public bool ExtendedProperties { get; set; }
            public string FileName { get; set; }
            public bool FullTextCatalogs { get; set; }
            public bool FullTextIndexes { get; set; }
            public bool FullTextStopLists { get; set; }
            public bool IncludeDatabaseContext { get; set; }
            public bool IncludeDatabaseRoleMemberships { get; set; }
            public bool IncludeFullTextCatalogRootPath { get; set; }
            public bool IncludeHeaders { get; set; }
            public bool IncludeIfNotExists { get; set; }
            public bool Indexes { get; set; }
            public bool LoginSid { get; set; }
            public bool NoAssemblies { get; set; }
            public bool NoCollation { get; set; }
            public bool NoCommandTerminator { get; set; }
            public bool NoExecuteAs { get; set; }
            public bool NoFileGroup { get; set; }
            public bool NoFileStream { get; set; }
            public bool NoFileStreamColumn { get; set; }
            public bool NoIdentities { get; set; }
            public bool NoIndexPartitioningSchemes { get; set; }
            public bool NoMailProfileAccounts { get; set; }
            public bool NoMailProfilePrincipals { get; set; }
            public bool NonClusteredIndexes { get; set; }
            public bool NoTablePartitioningSchemes { get; set; }
            public bool NoVardecimal { get; set; }
            public bool NoViewColumns { get; set; }
            public bool NoXmlNamespaces { get; set; }
            public bool OptimizerData { get; set; }
            public bool Permissions { get; set; }
            public bool PrimaryObject { get; set; }
            public bool SchemaQualify { get; set; }
            public bool SchemaQualifyForeignKeysReferences { get; set; }
            public bool ScriptBatchTerminator { get; set; }
            public bool ScriptData { get; set; }
            public bool ScriptDataCompression { get; set; }
            public bool ScriptDrops { get; set; }
            public bool ScriptOwner { get; set; }
            public bool ScriptSchema { get; set; }
            public bool Statistics { get; set; }
            public Microsoft.SqlServer.Management.Common.DatabaseEngineType TargetDatabaseEngineType { get; set; }
            public SqlServerVersion TargetServerVersion { get; set; }
            public bool TimestampToBinary { get; set; }
            public bool ToFileOnly { get; set; }
            public bool Triggers { get; set; }
            public bool WithDependencies { get; set; }
            public bool XmlIndexes { get; set; }
        }
    }