C#调用XML服务反序列化返回内容报根级数据无效错误
问题原因
反序列化报错的核心原因有两个:
- 该接口是传统ASMX服务,返回的XML根节点是带默认命名空间的
<string>包装节点,你定义的实体类没有匹配这个外层结构,序列化器找不到预期根节点就会抛出根级别数据无效的错误。 - 你定义的业务实体没有配置XML序列化相关特性,即使手动剥掉外层包装,默认命名空间的匹配规则也可能导致属性值读取失败。
解决方案
方法1:剥离外层包装后反序列化(逻辑简单,推荐使用)
<string>是ASMX框架自动追加的通用返回包装,节点内部的XML才是你需要的业务数据,提取内部内容再反序列化即可。
首先给实体类补全XML序列化特性,指定节点匹配规则:
using System.Xml.Serialization; [XmlRoot(ElementName = "Datos_de_INGC011_CAT_INDICADORECONOMIC", Namespace = "")] public class Datos_de_INGC011_CAT_INDICADORECONOMIC { [XmlElement(ElementName = "INGC011_CAT_INDICADORECONOMIC")] public INGC011_CAT_INDICADORECONOMIC IndicadorEconomico { get; set; } } public class INGC011_CAT_INDICADORECONOMIC { [XmlElement(ElementName = "COD_INDICADORINTERNO")] public int CodigoIndicador { get; set; } [XmlElement(ElementName = "DES_FECHA")] public DateTime Fecha { get; set; } [XmlElement(ElementName = "NUM_VALOR")] public double Valor { get; set; } }
拿到接口返回字符串后,先提取内层业务XML再执行反序列化:
using System.Xml; using System.Xml.Serialization; // 沿用你原有请求逻辑拿到returnedXml后,执行以下处理 var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(returnedXml); // 提取<string>节点包裹的真实业务XML内容 var negocioXml = xmlDoc.DocumentElement!.InnerXml; var serializer = new XmlSerializer(typeof(Datos_de_INGC011_CAT_INDICADORECONOMIC)); using var lector = new StringReader(negocioXml); var resultado = (Datos_de_INGC011_CAT_INDICADORECONOMIC)serializer.Deserialize(lector); // 正常读取数据即可,比如resultado.IndicadorEconomico.Valor就是接口返回的650.1
方法2:补全外层包装实体,直接反序列化完整返回
如果你不想手动剥离节点,可以定义匹配外层<string>节点的实体,一次性完成反序列化:
[XmlRoot(ElementName = "string", Namespace = "http://ws.sdde.bccr.fi.cr")] public class EnvoltorioRespuestaBccr { [XmlElement(ElementName = "Datos_de_INGC011_CAT_INDICADORECONOMIC", Namespace = "")] public Datos_de_INGC011_CAT_INDICADORECONOMIC DatosIndicador { get; set; } } // Datos_de_INGC011_CAT_INDICADORECONOMIC、INGC011_CAT_INDICADORECONOMIC两个类的定义和方法1完全一致
反序列化时直接传入完整返回字符串即可:
var serializer = new XmlSerializer(typeof(EnvoltorioRespuestaBccr)); using var lector = new StringReader(returnedXml); var resultado = (EnvoltorioRespuestaBccr)serializer.Deserialize(lector); // 业务数据从resultado.DatosIndicador.IndicadorEconomico中获取
注意事项
- 不要用
.Result同步调用HttpClient,高并发场景下容易触发线程池死锁,建议把请求逻辑改成async/await异步写法。 - 日期字段
DES_FECHA带-06:00时区偏移,反序列化后会自动转换为程序运行环境的本地时间,如果你需要保留原始时区时间,可以把实体里的对应属性类型改成DateTimeOffset。
内容的提问来源于stack exchange,提问作者jtorrescr
相关产品推荐
相关产品推荐

