我正在编写一个针对供应商Web服务的客户端,在VisualStudio2010中使用WCF。我没有能力更改它们的实现或配置。
在他们的测试服务器上运行时,我没有遇到任何问题。我从他们的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
{
...
}
所以我尝试实例化ChannelFactory<>使用TheirWebservicePortType。
这给了我编译时的错误。生成的代理没有ClientCredentials成员或TheirOperation()方法。
所以我尝试了“System.ServiceModel.ClientBase”。
实例化通道工厂<>它仍然给了我编译时的错误。生成的代理确实有ClientCredentials成员,但它仍然没有TheirOperation()方法。
那么,是什么给出的呢?如何从WCF客户端向HTTPS Web服务传递用户名/密码?
====================编辑以解释解决方案====================
首先,按照建议,使用TheirWebservicePortType实例化工厂,将用户名和密码添加到工厂。Credentials,而不是代理。ClientCredentials工作正常。除了一点困惑。
也许这与wsdl的奇怪编写方式有关,但客户端类TheirWebservicePortTypeClient将TheirOperation定义为接受Request参数并返回Response结果。TheirWebservicePortType接口将TheirOperation定义为接受TheirOperation_Input参数并返回TheirOperation_Output结果,其中TheirOperation_Input包含请求成员,TheirOperation_Output包含响应成员。
在任何情况下,如果我从传递的请求中构造了TheirOperation_Input对象,则对代理的调用成功,然后我可以从返回的TheirOperation_Output对象中提取包含的Response对象:
TheirOperation_Output output = client.TheirOperation(new TheirOperation_Input(request));
TheirWebserviceResponse response = output.TheirWebserviceResponse;