我正在使用 Visual Studio 2010 中的 WCF 针对供应商的 Web 服务编写客户端。我无法更改它们的实现或配置。
在他们的测试服务器上运行安装,我没有问题。我从他们的 wsdl 添加了一个服务引用,在代码中设置了 url,然后进行了调用:
var client = new TheirWebservicePortTypeClient();
client.Endpoint.Address = new System.ServiceModel.EndpointAddress(webServiceUrl);
if (webServiceUsername != "")
{
client.ClientCredentials.UserName.UserName = webServiceUsername;
client.ClientCredentials.UserName.Password = webServicePassword;
}
TheirWebserviceResponse response = client.TheirOperation(myRequest);
简单明了。直到他们将其移至生产服务器并将其配置为使用 https。然后我得到了这个错误:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm='.
所以我去寻求帮助。我发现了这个:Can not call web service with basic authentication using wcf。
批准的答案建议这样做:
BasicHttpBinding binding = new BasicHttpBinding();
binding.SendTimeout = TimeSpan.FromSeconds(25);
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Basic;
EndpointAddress address = new EndpointAddress(your-url-here);
ChannelFactory<MyService> factory =
new ChannelFactory<MyService>(binding, address);
MyService proxy = factory.CreateChannel();
proxy.ClientCredentials.UserName.UserName = "username";
proxy.ClientCredentials.UserName.Password = "password";
这似乎也很简单。除了我试图找出从 wsdl 生成的众多类和接口中的哪一个来进行服务引用之外,我应该使用上面的“MyService”来代替。
我的第一次尝试是使用“TheirWebservicePortTypeClient”——我在之前的版本中实例化的类。这给了我一个运行时错误:
The type argument passed to the generic ChannelFactory class must be an interface type.
所以我深入研究了生成的代码。我看到了这个:
public partial class TheirWebservicePortTypeClient
:
System.ServiceModel.ClientBase<TheirWebservicePortType>,
TheirWebservicePortType
{
...
}
所以我尝试用他们的WebservicePortType 实例化ChannelFactory<>。
这给了我编译时错误。生成的代理没有 ClientCredentials 成员或 TheyOperation() 方法。
所以我尝试了“System.ServiceModel.ClientBase”。
实例化 ChannelFactory<> 仍然给我编译时错误。生成的代理确实有一个 ClientCredentials 成员,但它仍然没有 TheyOperation() 方法。
那么,什么给了?如何从 WCF 客户端将用户名/密码传递给 HTTPS Web 服务?
==================== 编辑解释解决方案====================
首先,按照建议,使用TheyWebservicePortType 实例化工厂,将用户名和密码添加到factory.Credentials,而不是proxy.ClientCredentials 工作正常。除了一点混乱。
也许这与编写 wsdl 的奇怪方式有关,但是客户端类TheyWebservicePortTypeClient 将TheyOperation 定义为接受一个请求参数并返回一个响应结果。他们的WebservicePortType 接口将他们的操作定义为接受一个他们的操作输入参数并返回一个他们的操作输出结果,其中他们的操作输入包含一个请求成员,他们的操作输出包含一个响应成员。
在任何情况下,如果我从传递的 Request 构造了TheyOperation_Input 对象,则对代理的调用成功,然后我可以从返回的 TheyOperation_Output 对象中提取包含的 Response 对象:
TheirOperation_Output output = client.TheirOperation(new TheirOperation_Input(request));
TheirWebserviceResponse response = output.TheirWebserviceResponse;