最稳方案是用 dotnet-svcutil 从 WSDL 自动生成客户端代码,它能正确处理命名空间、xs:choice、复杂类型嵌套和 SOAP Action 头;手写易错难维护,版本变更易崩。

用 dotnet-svcutil 生成客户端类最稳
直接手写 SOAP 调用在 C# 里几乎没人干,容易错、难维护、版本一变就崩。.NET Core / .NET 5+ 官方推荐用 dotnet-svcutil 工具从 WSDL 自动生成客户端代码——它能正确处理命名空间、xs:choice、复杂类型嵌套和 SOAP Action 头。
常见错误现象:InvalidOperationException: There was an error reflecting type,基本是因为手写引用类没对齐 WSDL 的 schema;或者调用时抛 System.ServiceModel.CommunicationException,十有八九是生成的 endpoint 地址或 binding 配置漏了。
- 先确保 WSDL 地址可访问(浏览器能打开,且不含重定向)
- 运行命令:
dotnet-svcutil https://example.com/service.asmx?wsdl --outputDir ./Generated --namespace MyCompany.SoapClients - 生成后只引用
System.ServiceModel.Http和System.ServiceModel.Primitives两个 NuGet 包(.NET Core 默认不带 WCF) - 别把生成的
Reference.cs手动改名或拆分——类型名、[XmlRoot]、[DataContract]全是跟 WSDL 严格绑定的
BasicHttpBinding 和 CustomBinding 怎么选
绝大多数老系统用的是 BasicHttpBinding,它模拟 .NET Framework 2.0 的默认行为,兼容性最好;但如果你遇到“HTTP 415 不支持的媒体类型”或“SOAP Action 不匹配”,大概率得切到 CustomBinding 手动配消息编码和传输协议。
性能影响很小,但配置错会导致请求根本发不出去。比如某些 WebService 要求 text/xml 而不是默认的 application/soap+xml,这时 BasicHttpBinding 就无能为力。
-
BasicHttpBinding:适合标准 ASMX 或简单 WCF 服务,开箱即用,设MaxReceivedMessageSize和ReaderQuotas防大响应体炸掉 -
CustomBinding:必须显式指定TextMessageEncodingBindingElement(设MessageVersion.Soap11) +HttpTransportBindingElement,否则默认走 SOAP 1.2 - 注意:
https场景下,CustomBinding必须设HttpsTransportBindingElement.AuthenticationScheme = AuthenticationSchemes.Anonymous,否则 Windows 凭据干扰
调用时传参失败?重点查 XmlElement 和 XmlAttribute 标记
WSDL 里定义的字段是元素()还是属性(),生成的类里必须完全一致。手动生成或旧工具(如 svcutil.exe)常把属性错标成元素,导致服务端收不到值。
典型表现:参数对象传进去了,但服务端日志显示某字段为空,而其他字段正常;或者反序列化时报 There is an error in XML document。
- 打开生成的
Reference.cs,搜你要传的字段名,看它上面是[XmlElement]还是[XmlAttribute] - 对比 WSDL 的
和定义——如果 WSDL 写的是,但生成类里是[XmlElement],就得手动改成[XmlAttribute] - 数组字段要留意
[XmlArray]+[XmlArrayItem]组合,不能只加一个
超时、证书、代理这些非功能问题最容易卡住上线
开发环境跑得通,一上生产就挂,90% 是网络层配置没对齐。SOAP 不像 REST 那样靠 Fiddler 一眼看出问题,错误信息往往很模糊。
比如 The HTTP request was forbidden with client authentication scheme 'Anonymous',其实是服务端开了 Windows 身份验证,但客户端没配凭据;又比如 The underlying connection was closed,大概率是 TLS 版本不匹配(老服务只认 TLS 1.0/1.1)。
- 超时:必须同时设
binding.OpenTimeout、SendTimeout、ReceiveTimeout,缺一个都可能卡死 - 证书:若服务端用自签名证书,需在
HttpClientHandler(用于CustomBinding)或ClientCredentials.ServiceCertificate.SslCertificateAuthentication中忽略验证(仅测试环境) - 代理:企业内网常见,
binding.ProxyAddress和UseDefaultWebProxy得配合着开,否则请求根本不出内网
SOAP 的麻烦不在协议本身,而在每个环节都依赖外部定义(WSDL、服务端实现、网络策略)。少看一个 header、漏配一个 binding 属性、忽略一个 xsd:attribute,都会让调用无声失败。动手前,先 curl -v 看真实请求长什么样,比猜强得多。











