我正在将一个.net 4.6.2代码移植到一个调用SOAP服务的.net Core项目中。在新代码中我使用C#(由于一些配置原因,我现在还不记得为什么)。
但我得到以下例外。
接收到https://someurl.com/ws/Thing.pub.ws:Something的HTTP响应时发生错误。这可能是由于服务端点绑定不使用HTTP协议。这也可能是由于服务器中止HTTP请求上下文(可能是由于服务关闭)。请参阅服务器日志以获取更多详
投掷它的代码是
try
{
var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var endpoint = new EndpointAddress(new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService"));
var thing= new TheEndpoint.AService_PortTypeClient(binding, endpoint);
thing.ClientCredentials.UserName.UserName = "usrn";
thing.ClientCredentials.UserName.Password = "passw";
var response = await thing.getSomethingAsync("id").ConfigureAwait(false);
}
finally
{
await thing.CloseAsync().ConfigureAwait(false);
}
基于旧的配置工作调用服务是这样的,我错过了什么?
<bindings>
<basicHttpsBinding>
<binding name="TheEndpoint_pub_ws_AService_Binder" closeTimeout="00:02:00"
openTimeout="00:02:00" receiveTimeout="00:03:00" sendTimeout="00:03:00">
<security mode="Transport">
<transport clientCredentialType="Basic" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpsBinding>
</bindings>
<client>
<endpoint address="https://someurl.com/ws/Thing.pub.ws:AService"
binding="basicHttpsBinding" bindingConfiguration="TheEndpoint_pub_ws_AService_Binder"
contract="TheEndpoint.AService_PortType" name="TheEndpoint_pub_ws_AService_Port" />
</client>
我无法在网上找到很多这方面的信息。希望您能够帮助我。
更新Per Sixto Saez的建议我得到了端点以显示其错误,它是
HTTP请求未经授权使用客户端身份验证方案“Basic”。从服务器接收的认证头是'Basic realm =“Integration Server”,encoding =“UTF-8”'。
如果成功,我会尝试找出要做的事情并将结果发布在此处。
更新2
好的,现在我尝试使用此代码转到新语法
ChannelFactory<IAService> factory = null;
IAService serviceProxy = null;
Binding binding = null;
try
{
binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
factory = new ChannelFactory<IAService>(binding, new EndpointAddress(new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService")));
factory.Credentials.UserName.UserName = "usrn";
factory.Credentials.UserName.Password = "passw";
serviceProxy = factory.CreateChannel();
var result = await serviceProxy.getSomethingAsync("id").ConfigureAwait(false);
factory.Close();
((ICommunicationObject)serviceProxy).Close();
}
catch (MessageSecurityException ex)
{
//error caught here
throw;
}
但我仍然得到相同(略有不同)的错误。它现在有'Anonymous'而不是'Basic',现在最后缺少“,encoding =”UTF-8“。
HTTP请求未经授权,客户端身份验证方案为“匿名”。从服务器收到的身份验证标头是'Basic realm =“Integration Server”'。
问题出在我身边还是服务器上?
显然,我的SOAP“技能”现在非常缺乏,但我只是尝试了每一个我能用这种新方法想到的配置组合而没有运气。希望有人能指出我正确的方向。
好的,这个答案适用于那些试图从.net Core项目连接到WCF服务的人。
这是我的问题的解决方案,使用新的.net核心WCF语法/库。
BasicHttpBinding basicHttpBinding = null;
EndpointAddress endpointAddress = null;
ChannelFactory<IAService> factory = null;
IAService serviceProxy = null;
try
{
basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
endpointAddress = new EndpointAddress(new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService"));
factory = new ChannelFactory<IAService>(basicHttpBinding, endpointAddress);
factory.Credentials.UserName.UserName = "usrn";
factory.Credentials.UserName.Password = "passw";
serviceProxy = factory.CreateChannel();
using (var scope = new OperationContextScope((IContextChannel)serviceProxy))
{
var result = await serviceProxy.getSomethingAsync("id").ConfigureAwait(false);
}
factory.Close();
((ICommunicationObject)serviceProxy).Close();
}
catch (MessageSecurityException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
finally
{
// *** ENSURE CLEANUP (this code is at the WCF GitHub page *** \\
CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
}
UPDATE
我使用上面的代码得到以下异常
此OperationContextScope正在按顺序处理。
WCF团队似乎是something that is broken(或需要解决)。
所以我必须做以下工作才能使它工作(基于这个GitHub issue)
basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
factory = new ChannelFactory<IAService_PortType>(basicHttpBinding, new EndpointAddress(new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService")));
factory.Credentials.UserName.UserName = "usern";
factory.Credentials.UserName.Password = "passw";
serviceProxy = factory.CreateChannel();
((ICommunicationObject)serviceProxy).Open();
var opContext = new OperationContext((IClientChannel)serviceProxy);
var prevOpContext = OperationContext.Current; // Optional if there's no way this might already be set
OperationContext.Current = opContext;
try
{
var result = await serviceProxy.getSomethingAsync("id").ConfigureAwait(false);
// cleanup
factory.Close();
((ICommunicationObject)serviceProxy).Close();
}
finally
{
// *** ENSURE CLEANUP *** \\
CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
OperationContext.Current = prevOpContext; // Or set to null if you didn't capture the previous context
}
但您的要求可能会有所不同。以下是帮助您连接到WCF服务可能需要的资源:
测试对我帮助很大,但是他们有点难以找到(我有帮助,谢谢你真的为answering my wcf github issue)
要从.NET核心使用SOAP服务,从项目UI添加连接的服务不起作用。
选项1:使用dotnet-svcutil CLI。先决条件:VS 2017,版本15.5或以上
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.9" />
<PackageReference Include="System.ServiceModel.Http" Version="4.5.3" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="dotnet-svcutil" Version="1.0.*" />
</ItemGroup>
选项2如果您需要引用多个SOAP服务,
对于那些试图对NTLM和.Net Core做同样事情并且想知道某些变量被定义为什么的人,我澄清了代码如下:
如果您按照IAService_PortType
上的指南,https://joshuachini.com/2017/07/13/calling-a-soap-service-from-asp-net-core-or-net-core/是您创建的服务参考
BasicHttpBinding basicHttpBinding =
new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
// Setting it to Transport will give an exception if the url is not https
basicHttpBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Ntlm;
ChannelFactory<IAService_PortType> factory =
new ChannelFactory<IAService_PortType>(basicHttpBinding,
new EndpointAddress(
new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService")));
factory.Credentials.Windows.ClientCredential.Domain = domain;
factory.Credentials.Windows.ClientCredential.UserName = user;
factory.Credentials.Windows.ClientCredential.Password = pass;
IAService_PortType serviceProxy = factory.CreateChannel();
((ICommunicationObject)serviceProxy).Open();
try
{
var result = serviceProxy.getSomethingAsync("id").Result;
}
finally
{
// cleanup
factory.Close();
((ICommunicationObject)serviceProxy).Close();
}