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

C#/WCF无法实现SOAP UI同款WSDL请求的问题排查

问题

我有一个WSDL,通过SOAP UI可以成功发送请求,需要启用基于WSSE的UsernameToken预认证,预期的SOAP认证头如下:

<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    <wsse:UsernameToken wsu:Id="test" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:Username>username</wsse:Username> 
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
    </wsse:UsernameToken> 
</wsse:Security>

我尝试了多种WCF绑定配置创建客户端,但调用方法时失败:

// 尝试1
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

// 尝试2
var bindingws = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
var bindinghttps = new BasicHttpsBinding(BasicHttpsSecurityMode.TransportWithMessageCredential);
bindinghttps.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

// 尝试3
var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
basicHttpBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

// 客户端初始化
InboundPortClient client = new InboundPortClient(basicHttpBinding, endpointAddress);
client.ClientCredentials.UserName.UserName = "your_username";
client.ClientCredentials.UserName.Password = "your_password";

client.Open();// 此步骤正常
client.updateCall(null); // 调用时出错

错误信息:

System.ServiceModel.ProtocolException:
'The content type text/html; charset=utf-8 of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly.
The first 1024 bytes of the response were:--access denied page

我认为是绑定配置不正确导致返回访问拒绝页面,请问如何使用WCF/.NET Framework实现与SOAP UI相同的请求?


解决方案

你混淆了HTTP Basic认证和WSSE UsernameToken认证的核心区别:SOAP UI发送的是消息层面的WSSE认证头(用户名密码嵌入SOAP Header的<wsse:Security>节点),而你尝试的部分配置是在设置HTTP传输层面的Basic Auth,这与服务端要求的认证方式不匹配,导致返回403访问拒绝页面(HTML格式),进而触发内容类型不匹配的错误。

以下是匹配SOAP UI请求的正确WCF配置方案:

1. 针对BasicHttpBinding的正确配置

如果服务端使用的是BasicHttpBinding类型的端点,使用以下代码:

// 安全模式:Transport(HTTPS)+ 消息层面的凭证认证
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
// 指定消息凭证类型为UserName,对应WSSE UsernameToken
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

// 初始化客户端端点
var endpointAddress = new EndpointAddress("https://your-service-endpoint-url");
var client = new InboundPortClient(binding, endpointAddress);

// 设置用户名密码
client.ClientCredentials.UserName.UserName = "your_username";
client.ClientCredentials.UserName.Password = "your_password";

// 关键:强制使用明文密码(匹配服务端要求的PasswordText类型)
client.ClientCredentials.UserName.PasswordType = System.ServiceModel.Security.PasswordType.Text;

try
{
    client.Open();
    client.updateCall(null);
}
finally
{
    // 确保客户端正确关闭
    if (client.State != CommunicationState.Closed)
        client.Close();
}

2. 针对WSHttpBinding的正确配置

如果WSDL中定义的是WSHttpBinding端点,改用以下配置:

var binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
// 指定消息凭证类型为UserName
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;

var endpointAddress = new EndpointAddress("https://your-service-endpoint-url");
var client = new InboundPortClient(binding, endpointAddress);

client.ClientCredentials.UserName.UserName = "your_username";
client.ClientCredentials.UserName.Password = "your_password";
// 强制明文密码
client.ClientCredentials.UserName.PasswordType = System.ServiceModel.Security.PasswordType.Text;

try
{
    client.Open();
    client.updateCall(null);
}
finally
{
    if (client.State != CommunicationState.Closed)
        client.Close();
}

3. 验证请求一致性(排查问题用)

如果仍无法解决,开启WCF消息日志对比SOAP UI的请求内容,确认SOAP头是否一致:
在项目的App.config或Web.config中添加以下配置:

<system.diagnostics>
    <sources>
        <source name="System.ServiceModel.MessageLogging">
            <listeners>
                <add name="messages"
                     type="System.Diagnostics.XmlWriterTraceListener"
                     initializeData="c:\logs\wcf_messages.svclog" />
            </listeners>
        </source>
    </sources>
</system.diagnostics>

<system.serviceModel>
    <diagnostics>
        <messageLogging 
             logEntireMessage="true" 
             logMalformedMessages="true"
             logMessagesAtServiceLevel="true" 
             logMessagesAtTransportLevel="true"
             maxMessagesToLog="3000"
             maxSizeOfMessageToLog="2000"/>
    </diagnostics>
</system.serviceModel>

生成日志后,查看WCF发送的SOAP请求头是否包含正确的<wsse:Security>节点,重点检查命名空间、密码类型属性是否与SOAP UI的请求一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 08:01:43