为了在下次启动时保留对象并恢复它们,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并在反序列化之前删除有问题的元素,但肯定必须有更多的&#34;正确的&#34;比那样的方式?
序列化对象:
<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
答案 0 :(得分:2)
有时候最简单的解决方案是最好的,但你可以用你想要的属性创建一个DTO,使用AutoMapper从源到目标映射(CreateMap不是线程安全btw)并从那里直接反序列化为源类型:
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; }
}
}
答案 1 :(得分:2)
您可以使用XmlAttributeOverrides
类来指定您不拥有的类的属性:
var overrides = new XmlAttributeOverrides();
overrides.Add(
typeof(ScriptingOptions),
"Encoding",
new XmlAttributes { XmlIgnore = true });
var serializer = new XmlSerializer(typeof(ScriptingOptions), overrides);
但总的来说,使用特定的类来处理序列化通常更方便,如a-h所示,因为它为您提供了更大的灵活性。