ASP.NET Core城市API XML响应反序列化失败问题排查
问题:SOAP XML反序列化时NewDataSet为null,无法获取RetailCities数据
调用城市API返回XML格式响应,反序列化时可获取到diffgram对象,但其中的NewDataSet属性为null,无法获取RetailCities列表。已创建带有XmlElement注解的模型类,相关内容如下:
API响应
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soap:Body> <getRTLCitiesResponse xmlns="http://track.smsaexpress.com/secom/"> <getRTLCitiesResult> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="NewDataSet"> <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="RetailCities"> <xs:complexType> <xs:sequence> <xs:element name="routCode" type="xs:string" minOccurs="0" /> <xs:element name="rCity" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> <diffgr:diffgram xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <NewDataSet xmlns=""> <RetailCities diffgr:id="RetailCities1" msdata:rowOrder="0"> <routCode>ABT</routCode> <rCity>Aqiq</rCity> </RetailCities> <RetailCities diffgr:id="RetailCities2" msdata:rowOrder="1"> <routCode>ABT</routCode> <rCity>Atawlah</rCity> </RetailCities> <RetailCities diffgr:id="RetailCities3" msdata:rowOrder="2"> <routCode>ABT</routCode> <rCity>Baha</rCity> </RetailCities> </NewDataSet> </diffgr:diffgram> </getRTLCitiesResult> </getRTLCitiesResponse> </soap:Body> </soap:Envelope>
模型类与反序列化代码
[XmlRoot(ElementName = "RetailCities")] public class RetailCity { [XmlElement(ElementName = "routCode")] public string RoutCode { get; set; } [XmlElement(ElementName = "rCity")] public string RCity { get; set; } } [XmlRoot(ElementName = "NewDataSet")] public class NewDataSet { [XmlElement(ElementName = "RetailCities")] public List<RetailCity> RetailCities { get; set; } = new List<RetailCity>(); } [XmlRoot(ElementName = "diffgram", Namespace = "urn:schemas-microsoft-com:xml-diffgram-v1")] public class Diffgram { [XmlElement(ElementName = "NewDataSet")] public NewDataSet NewDataSet { get; set; } } [XmlRoot(ElementName = "getRTLCitiesResult", Namespace = "http://track.smsaexpress.com/secom/")] public class GetRTLCitiesResult { [XmlElement(ElementName = "diffgram", Namespace = "urn:schemas-microsoft-com:xml-diffgram-v1")] public Diffgram Diffgram { get; set; } } [XmlRoot(ElementName = "getRTLCitiesResponse", Namespace = "http://track.smsaexpress.com/secom/")] public class GetRTLCitiesResponse { [XmlElement(ElementName = "getRTLCitiesResult")] public GetRTLCitiesResult GetRTLCitiesResult { get; set; } } [XmlRoot(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public class SoapBody { [XmlElement(ElementName = "getRTLCitiesResponse", Namespace = "http://track.smsaexpress.com/secom/")] public GetRTLCitiesResponse GetRTLCitiesResponse { get; set; } } [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public class SoapEnvelope { [XmlElement(ElementName = "Body")] public SoapBody Body { get; set; } [XmlNamespaceDeclarations] public XmlSerializerNamespaces Xmlns { get; set; } = new XmlSerializerNamespaces(); public SoapEnvelope() { Xmlns.Add("soap", "http://schemas.xmlsoap.org/soap/envelope/"); Xmlns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance"); Xmlns.Add("xsd", "http://www.w3.org/2001/XMLSchema"); } } private static T DeserializeXml<T>(string xml) { XmlSerializer serializer = new XmlSerializer(typeof(T)); using (StringReader reader = new StringReader(xml)) { return (T)serializer.Deserialize(reader)!; } }
API调用代码
using (var client = new HttpClient()) { var content = new StringContent(AramexCitiesSoapEnvelope(), Encoding.UTF8, "text/xml"); try { var response = await client.PostAsync(endPoint, content); if (response.IsSuccessStatusCode) { // Read and return the response content var resultContent = await response.Content.ReadAsStringAsync(); var envelope = DeserializeXml<SoapEnvelope>(resultContent); return envelope; } else { // Return the failed response content var errorContent = await response.Content.ReadAsStringAsync(); return new SoapEnvelope() { ErrorMessage = errorContent }; } } catch (HttpRequestException e) { return new SoapEnvelope() { ErrorMessage = e.Message }; } }
问题原因
XML中的NewDataSet元素明确声明了xmlns=""(空默认命名空间),但当前Diffgram类中NewDataSet属性的XmlElement注解未指定对应的空命名空间,导致XmlSerializer无法匹配该元素,最终赋值为null。
修复方案
修改Diffgram类的NewDataSet属性注解,添加空命名空间声明:
[XmlRoot(ElementName = "diffgram", Namespace = "urn:schemas-microsoft-com:xml-diffgram-v1")] public class Diffgram { [XmlElement(ElementName = "NewDataSet", Namespace = "")] // 新增空命名空间匹配 public NewDataSet NewDataSet { get; set; } }
额外补充:GetRTLCitiesResult中包含未处理的<xs:schema>元素,虽然不影响数据获取,但会触发XmlSerializer警告,可添加属性忽略或处理:
[XmlRoot(ElementName = "getRTLCitiesResult", Namespace = "http://track.smsaexpress.com/secom/")] public class GetRTLCitiesResult { [XmlElement(ElementName = "diffgram", Namespace = "urn:schemas-microsoft-com:xml-diffgram-v1")] public Diffgram Diffgram { get; set; } // 忽略schema元素,避免警告 [XmlElement(ElementName = "schema", Namespace = "http://www.w3.org/2001/XMLSchema")] public XmlNode Schema { get; set; } }
修改完成后,反序列化即可正确获取NewDataSet及下属的RetailCities列表数据。
内容的提问来源于stack exchange,提问作者Faisal Shahab
相关产品推荐
相关产品推荐

