.NET 6 REST API接收SOAP XML POST请求反序列化失败排查
.NET 6 REST API 接收SOAP XML请求反序列化失败问题
外部用户通过SOAP(XML格式)向我的.NET 6 REST API端点POST数据,已将XML负载转换为对应实体类,但用PostMan发送请求时返回404错误,提示输入数据反序列化失败且mymodel字段必填。已在Program.cs中启用XmlSerializerFormatters和XmlDataContractSerializerFormatters,相关代码如下:
XML请求示例
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header/> <soapenv:Body> <PaymentNotificationRequest> <User>USER</User> <Password>pass</Password> <HashVal>NzIwNGE3MzI5YmU5MTg3ZTUwZTQ1YmRjMjA0NDc2MjUyODQ2MmQ1ODIwZTIyYzNkNDk0NTBjNjUwZTgwYmM2Yw==</HashVal> <TransType>999</TransType> <TransID>FTC221024YAWQ</TransID> <TransTime>2210241702</TransTime> <TransAmount>1.00</TransAmount> <AccountNr>6592460859</AccountNr> <Narrative>Test</Narrative> <PhoneNr>66666</PhoneNr> <CustomerName>Customer 1</CustomerName> <Status>SUCCESS</Status> </PaymentNotificationRequest> </soapenv:Body> </soapenv:Envelope>
控制器代码
[HttpPost] [Consumes("application/xml")] [Produces("application/xml")] public dynamic Post([FromBody] MYDATA mymodel) { int createdId = mpesaRepository.Add(mymodel); if (createdId > 0) { mymodel.TransType = createdId; } dynamic result = new { data = new { ID = createdId, mymodel.User, mymodel.Password, mymodel.HashVal, mymodel.TransType, mymodel.TransID, mymodel.TransTime, mymodel.TransAmount, mymodel.AccountNr, mymodel.Narrative, mymodel.PhoneNr, mymodel.CustomerName, mymodel.Status }, }; return result; }
错误信息
<MVC-Errors> <MVC-Empty>An error occurred while deserializing input data.</MVC-Empty> <mymodel>The mymodel field is required.</mymodel> </MVC-Errors>
Program.cs配置
services.AddControllers(options => { options.RespectBrowserAcceptHeader = true; }).AddXmlSerializerFormatters() .AddXmlDataContractSerializerFormatters();
实体类代码
[XmlRoot(ElementName = "PaymentNotificationRequest")] public class PaymentNotificationRequest { [XmlElement(ElementName = "ID")] public int ID { get; set; } [XmlElement(ElementName = "User")] public string User { get; set; } [XmlElement(ElementName = "Password")] public string Password { get; set; } [XmlElement(ElementName = "HashVal")] public string HashVal { get; set; } [XmlElement(ElementName = "TransType")] public long TransType { get; set; } [XmlElement(ElementName = "TransID")] public string TransID { get; set; } [XmlElement(ElementName = "TransTime")] public string TransTime { get; set; } [XmlElement(ElementName = "TransAmount")] public string TransAmount { get; set; } [XmlElement(ElementName = "AccountNr")] public long AccountNr { get; set; } [XmlElement(ElementName = "Narrative")] public string Narrative { get; set; } [XmlElement(ElementName = "PhoneNr")] public string PhoneNr { get; set; } [XmlElement(ElementName = "CustomerName")] public string CustomerName { get; set; } [XmlElement(ElementName = "Status")] public string Status { get; set; } } [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public class Envelope { [XmlElement(ElementName = "PaymentNotificationRequest")] public PaymentNotificationRequest NCBAPaymentNotificationRequest { get; set; } [XmlAttribute(AttributeName = "soapenv", Namespace = "http://www.w3.org/2000/xmlns/")] public string Soapenv { get; set; } }
修复方案
问题核心
- 请求是完整的SOAP信封结构(包含
Envelope、Body层级),但控制器直接期望接收PaymentNotificationRequest对象,反序列化器无法从嵌套结构中提取目标模型。 Envelope实体类未正确映射SOAP的Body节点,且属性名与XML元素不匹配。
具体修复步骤
1. 修正Envelope实体类结构
补充Body节点的映射,确保与SOAP请求结构一致:
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public class Envelope { [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public Body Body { get; set; } } public class Body { [XmlElement(ElementName = "PaymentNotificationRequest")] public PaymentNotificationRequest PaymentNotificationRequest { get; set; } }
2. 修改控制器接收参数
改为接收Envelope类型,从中提取实际业务数据:
[HttpPost] [Consumes("application/xml")] [Produces("application/xml")] public dynamic Post([FromBody] Envelope envelope) { if (envelope?.Body?.PaymentNotificationRequest == null) { return BadRequest(new { error = "请求结构无效" }); } var mymodel = envelope.Body.PaymentNotificationRequest; int createdId = mpesaRepository.Add(mymodel); if (createdId > 0) { mymodel.TransType = createdId; } dynamic result = new { data = new { ID = createdId, mymodel.User, mymodel.Password, mymodel.HashVal, mymodel.TransType, mymodel.TransID, mymodel.TransTime, mymodel.TransAmount, mymodel.AccountNr, mymodel.Narrative, mymodel.PhoneNr, mymodel.CustomerName, mymodel.Status }, }; return result; }
3. 验证请求头
确保PostMan中设置Content-Type为application/xml,与控制器Consumes属性匹配。
内容的提问来源于stack exchange,提问作者Nickson
相关产品推荐
相关产品推荐

