You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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; }
}

修复方案

问题核心

  1. 请求是完整的SOAP信封结构(包含Envelope、Body层级),但控制器直接期望接收PaymentNotificationRequest对象,反序列化器无法从嵌套结构中提取目标模型。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:01:04