.NET 6下XML反序列化为Parameters对象报错,原.NET Core 2.2正常
问题场景
输入XML字符串:
<ActivationRequest xmlns="http://schemas.datacontract.org/2004/07/DataLayer.Models" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Key>key</Key> <Edition i:nil="true"/> <HardwareId>542D</HardwareId> <IntelliLockFlags>BIOS CPU</IntelliLockFlags> <MachineName>nikolas</MachineName> <Product>studio</Product> <UseMacHID>false</UseMacHID> <Version xmlns:a="http://schemas.datacontract.org/2004/07/System"> <a:_Build>88</a:_Build> <a:_Major>6</a:_Major> <a:_Minor>4</a:_Minor> <a:_Revision>0</a:_Revision> </Version> </ActivationRequest>
反序列化方法:
public static Parameters DeserializeFromXml<T>(this string xml) { using (var stream = new MemoryStream()) { byte[] data = Encoding.UTF8.GetBytes(xml); stream.Write(data, 0, data.Length); stream.Position = 0; var deserializer = new DataContractSerializer(typeof(Parameters)); return deserializer.ReadObject(stream) as Parameters; // error } }
模型类定义:
public class Parameters { public string Key { get; set; } public string HardwareId { get; set; } public string Product { get; set; } public Version Version { get; set; } public bool UseMacHID { get; set; } public LockFlags IntelliLockFlags { get; set; } public string MachineName { get; set; } } [Flags] public enum LockFlags { Empty = 0, BIOS = 1, CPU = 2 }
代码在.NET Core 2.2中正常运行,升级到.NET 6后抛出错误:
Error in line 1 position 144. Expecting element 'ActivationParameters' from namespace 'http://schemas.datacontract.org/2004/07/DataLayer.NetStandard.BusinessLayer.Activation'.. Encountered 'Element' with name 'ActivationRequest', namespace 'http://schemas.datacontract.org/2004/07/DataLayer.Models'.
错误原因
.NET Core 2.2到.NET 6的版本迭代中,DataContractSerializer的默认行为发生了变更:
- 旧版本中可能自动兼容了类型名称、命名空间的不匹配,或默认命名空间推断逻辑更宽松
- 新版本中序列化器会严格校验根元素的名称和命名空间,当前代码中序列化器默认推断出的
Parameters类对应元素名和命名空间,与XML中的ActivationRequest及目标命名空间完全不匹配,因此触发错误
解决方案
方案1:给模型类添加显式特性匹配XML结构
通过DataContract和DataMember特性,直接指定模型类对应的XML根元素名称、命名空间,同时给枚举添加EnumMember确保字符串值能被正确解析:
[DataContract(Name = "ActivationRequest", Namespace = "http://schemas.datacontract.org/2004/07/DataLayer.Models")] public class Parameters { [DataMember] public string Key { get; set; } [DataMember] public string HardwareId { get; set; } [DataMember] public string Product { get; set; } [DataMember] public Version Version { get; set; } [DataMember] public bool UseMacHID { get; set; } [DataMember(Name = "IntelliLockFlags")] public LockFlags IntelliLockFlags { get; set; } [DataMember] public string MachineName { get; set; } } [Flags] [DataContract] public enum LockFlags { [EnumMember] Empty = 0, [EnumMember] BIOS = 1, [EnumMember] CPU = 2 }
方案2:修改序列化器初始化参数,指定根元素信息
无需修改模型类,在创建DataContractSerializer时显式传入XML根元素的名称和命名空间:
public static Parameters DeserializeFromXml<T>(this string xml) { using (var stream = new MemoryStream()) { byte[] data = Encoding.UTF8.GetBytes(xml); stream.Write(data, 0, data.Length); stream.Position = 0; // 显式指定根元素名称与命名空间,匹配XML内容 var deserializer = new DataContractSerializer( typeof(Parameters), "ActivationRequest", "http://schemas.datacontract.org/2004/07/DataLayer.Models"); return deserializer.ReadObject(stream) as Parameters; } }
方案3:额外处理枚举的空格分隔值解析
如果XML中IntelliLockFlags的空格分隔枚举值(BIOS CPU)无法被正确解析,可以通过序列化器配置强化枚举支持:
public static Parameters DeserializeFromXml<T>(this string xml) { using (var stream = new MemoryStream()) { byte[] data = Encoding.UTF8.GetBytes(xml); stream.Write(data, 0, data.Length); stream.Position = 0; var settings = new DataContractSerializerSettings { UseEnumMemberNames = true }; var deserializer = new DataContractSerializer( typeof(Parameters), "ActivationRequest", "http://schemas.datacontract.org/2004/07/DataLayer.Models", null, int.MaxValue, false, true, null, settings); return deserializer.ReadObject(stream) as Parameters; } }
内容的提问来源于stack exchange,提问作者lucianobonde
相关产品推荐
相关产品推荐

