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

.NET中如何将s:Envelope改为soap12:Envelope格式?

解决.NET WCF生成SOAP12信封前缀s:改为soap12:的问题

服务器仅接受前缀为soap12:的SOAP12信封(如Postman发送的<soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">),但你的WCF代码默认生成的是s:前缀的信封,导致请求报错。以下是修改方案:

核心问题

WCF默认会为SOAP12的命名空间http://www.w3.org/2003/05/soap-envelope分配s前缀,而服务器要求必须使用soap12前缀,因此需要覆盖WCF的默认前缀分配逻辑。

解决方案:自定义消息编码器

通过自定义TextMessageEncodingBindingElement和消息编码器,在消息序列化阶段修改XML前缀:

1. 实现自定义编码器相关类

using System.IO;
using System.ServiceModel.Channels;
using System.Xml;
using System.Text;

public class Soap12PrefixTextMessageEncoder : TextMessageEncoder
{
    private readonly TextMessageEncoder _innerEncoder;

    public Soap12PrefixTextMessageEncoder(TextMessageEncoder innerEncoder)
    {
        _innerEncoder = innerEncoder;
    }

    public override string ContentType => _innerEncoder.ContentType;
    public override string MediaType => _innerEncoder.MediaType;
    public override MessageVersion MessageVersion => _innerEncoder.MessageVersion;

    public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
    {
        return _innerEncoder.ReadMessage(stream, maxSizeOfHeaders, contentType);
    }

    public override void WriteMessage(Message message, Stream stream)
    {
        using (var ms = new MemoryStream())
        {
            // 先让默认编码器写入内存流
            _innerEncoder.WriteMessage(message, ms);
            ms.Position = 0;

            var xmlDoc = new XmlDocument();
            xmlDoc.Load(ms);

            // 修改SOAP信封节点的前缀和命名空间声明
            var envelopeNode = xmlDoc.DocumentElement;
            if (envelopeNode != null && envelopeNode.NamespaceURI == "http://www.w3.org/2003/05/soap-envelope")
            {
                envelopeNode.Prefix = "soap12";
                // 添加soap12命名空间声明,移除原有的s前缀声明
                if (envelopeNode.Attributes["xmlns:soap12"] == null)
                {
                    envelopeNode.SetAttribute("xmlns:soap12", envelopeNode.NamespaceURI);
                    var sAttr = envelopeNode.Attributes["xmlns:s"];
                    sAttr?.RemoveAll();
                }
            }

            // 统一修改所有SOAP命名空间下元素的前缀
            foreach (XmlNode node in xmlDoc.SelectNodes("//*[namespace-uri()='http://www.w3.org/2003/05/soap-envelope']"))
            {
                node.Prefix = "soap12";
            }

            // 将修改后的XML写入目标流
            xmlDoc.Save(stream);
        }
    }

    public override Stream CreateMessageBuffer()
    {
        return _innerEncoder.CreateMessageBuffer();
    }
}

public class Soap12PrefixTextMessageEncodingBindingElement : TextMessageEncodingBindingElement
{
    public Soap12PrefixTextMessageEncodingBindingElement() : base() { }
    public Soap12PrefixTextMessageEncodingBindingElement(MessageVersion version, Encoding encoding) : base(version, encoding) { }

    public override MessageEncoderFactory CreateMessageEncoderFactory()
    {
        var innerFactory = base.CreateMessageEncoderFactory();
        return new Soap12PrefixMessageEncoderFactory(innerFactory);
    }

    public override BindingElement Clone()
    {
        return new Soap12PrefixTextMessageEncodingBindingElement(this.MessageVersion, this.WriteEncoding);
    }
}

public class Soap12PrefixMessageEncoderFactory : MessageEncoderFactory
{
    private readonly MessageEncoderFactory _innerFactory;

    public Soap12PrefixMessageEncoderFactory(MessageEncoderFactory innerFactory)
    {
        _innerFactory = innerFactory;
    }

    public override MessageEncoder Encoder => new Soap12PrefixTextMessageEncoder((TextMessageEncoder)_innerFactory.Encoder);
    public override MessageVersion MessageVersion => _innerFactory.MessageVersion;
}

2. 修改绑定代码

将原代码中的TextMessageEncodingBindingElement替换为自定义的Soap12PrefixTextMessageEncodingBindingElement:

System.ServiceModel.Channels.CustomBinding result = new System.ServiceModel.Channels.CustomBinding();
// 使用自定义编码绑定元素
System.ServiceModel.Channels.TextMessageEncodingBindingElement textBindingElement = new Soap12PrefixTextMessageEncodingBindingElement();
textBindingElement.MessageVersion = System.ServiceModel.Channels.MessageVersion.CreateVersion(System.ServiceModel.EnvelopeVersion.Soap12, System.ServiceModel.Channels.AddressingVersion.WSAddressing10);
result.Elements.Add(textBindingElement);

System.ServiceModel.Channels.HttpsTransportBindingElement httpsBindingElement = new System.ServiceModel.Channels.HttpsTransportBindingElement();
httpsBindingElement.AllowCookies = true;
httpsBindingElement.MaxBufferSize = int.MaxValue;
httpsBindingElement.MaxReceivedMessageSize = int.MaxValue;
result.Elements.Add(httpsBindingElement);

return result;

原理说明

自定义编码器会在WCF默认序列化消息后,将消息内容加载到XML文档中,修改SOAP命名空间对应的前缀为soap12,并调整命名空间声明,最终生成符合服务器要求的信封格式,和Postman发送的请求保持一致。

内容的提问来源于stack exchange,提问作者Ainsley Penza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:57:51