.NET Core调用带签名消息的SOAP Web服务编译错误问题
解决.NET Core 2.0调用WSS版SOAP服务的代码生成编译问题
我之前也踩过类似的坑,用svcutil处理带WSS的WSDL时,生成的代码总是报操作契约相关的编译错误,折腾了好一阵才理顺思路,给你分享几个实用的解决办法:
1. 换用.NET Core兼容的svcutil工具
你大概率是用了.NET Framework版本的svcutil,它生成的代码里会包含很多.NET Core 2.0不兼容的属性或命名空间。赶紧换成.NET Core专属的dotnet svcutil工具:
首先安装对应版本的工具(因为你用的是.NET Core 2.0,要严格匹配版本):
dotnet tool uninstall --global dotnet-svcutil dotnet tool install --global dotnet-svcutil --version 2.0.*
然后用这个工具重新生成代码,加上命名空间映射避免冲突:
dotnet svcutil path/to/your/wss.wsdl path/to/related.xsd --namespace *,Your.Project.ServiceNamespace
2. 补全必要的NuGet依赖
生成的代码编译报错,很多时候是缺少WCF相关的基础包。给你的.NET Core 2.0项目添加这些NuGet包:
System.ServiceModel.PrimitivesSystem.ServiceModel.SecuritySystem.ServiceModel.XmlSerializer(如果WSDL用XmlSerializer序列化的话)
可以通过NuGet包管理器安装,或者用命令行:
dotnet add package System.ServiceModel.Primitives --version 4.5.3 dotnet add package System.ServiceModel.Security --version 4.5.3
3. 手动修复生成代码中的属性错误
如果还是报错,盯着具体的错误信息调整:
- 检查代码顶部是否有
using System.ServiceModel;,没有的话补上,很多属性的命名空间依赖这个 - 如果是
OperationContract的Action参数报错,对照WSDL里的Action地址手动修正字符串格式 - 有些WSS专属的旧版安全属性(比如.NET Framework特有的安全契约标记)在.NET Core 2.0里不存在,直接删掉这些属性,换成手动处理安全头的方式(下面会讲)
4. 手动注入WSS安全头(终极方案)
如果.NET Core 2.0的WCF确实不支持你这个WSDL里的安全特性,那就别纠结生成代码了,手动给SOAP请求加安全头最靠谱。比如常见的UsernameToken认证:
先写一个自定义的消息检查器,用来注入安全头:
using System; using System.ServiceModel; using System.ServiceModel.Channels; using System.Xml; public class WssMessageInspector : IClientMessageInspector { private readonly string _username; private readonly string _password; public WssMessageInspector(string username, string password) { _username = username; _password = password; } public object BeforeSendRequest(ref Message request, IClientChannel channel) { var securityHeader = new SecurityHeader(_username, _password); request.Headers.Add(securityHeader); return null; } public void AfterReceiveReply(ref Message reply, object correlationState) { // 不需要处理回复的话留空即可 } } public class SecurityHeader : MessageHeader { private readonly string _username; private readonly string _password; public SecurityHeader(string username, string password) { _username = username; _password = password; } public override string Name => "Security"; public override string Namespace => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion) { writer.WriteStartElement("UsernameToken", Namespace); writer.WriteElementString("Username", Namespace, _username); writer.WriteStartElement("Password", Namespace); writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"); writer.WriteString(_password); writer.WriteEndElement(); writer.WriteEndElement(); } }
然后把这个检查器添加到服务客户端的行为里:
var client = new YourGeneratedServiceClient(); // 创建行为并添加检查器 var behavior = new ClientBehavior(); behavior.MessageInspectors.Add(new WssMessageInspector("your-username", "your-password")); client.Endpoint.Behaviors.Add(behavior); // 正常调用服务方法 var result = await client.YourServiceMethodAsync();
5. 额外小贴士
- 如果WSDL里有多余的WS-Addressing扩展,生成代码时加上
/disableAddressing参数可以跳过这些不兼容的部分:
dotnet svcutil path/to/wss.wsdl /disableAddressing
- 尽量避开旧版Visual Studio的“添加服务引用”功能,它可能还是调用Framework版的工具,不如
dotnet svcutil适配性好
内容的提问来源于stack exchange,提问作者audunsol
相关产品推荐
相关产品推荐

