英文:
Upgrading WCF client to CoreWCF breaks authentication
问题
我有一个来自.NET Framework 4.8的WCF客户端,我需要将其移植到.NET Core,因为在升级底层项目后,使用旧的客户端会出现PlatformNotSupportedException
的错误。
该客户端是从WSDL文件生成的,并且在VS中将其添加为连接服务后,Reference.cs
客户端会得到很好的更新,主要更改是将GeneratedCodeAttribute
设置为"Microsoft.Tools.ServiceModel.Svcutil", "2.1.0"
,而不是"System.ServiceModel", "4.0.0.0"
(在项目中安装了dotnet-svcutil之后)。它还安装了这两个包,我相信这些包含了新版本.NET中的CoreWCF客户端功能:
System.ServiceModel.Http
(6.0.0)System.ServiceModel.Security
(6.0.0)
我有一个集成,它创建了一个生成的客户端并在调用端点之后调用它:
public string GetArticle(string articleNumber, string goal)
{
using var client = CreateArtikelClient();
return client.getArticle(articleNumber, goal);
}
private ArtikelPortTypeClient CreateArtikelClient()
{
var client = new ArtikelPortTypeClient(ArtikelPortTypeClient.EndpointConfiguration.ArtikelPort);
client.ClientCredentials.UserName.UserName = _integrationConfiguration.UserName;
client.ClientCredentials.UserName.Password = _integrationConfiguration.Password;
return client;
}
客户端创建成功,但调用getArticle
会导致以下异常:
System.ServiceModel.Security.MessageSecurityException
HResult=0x80131500
Message=HTTP请求未经授权,客户端身份验证方案为'Anonymous'。从服务器接收到的身份验证标头为'Basic realm="Login please"'。
Source=System.ServiceModel.Http
StackTrace:
at System.ServiceModel.Channels.HttpResponseMessageHelper.ValidateAuthentication()
at System.ServiceModel.Channels.HttpResponseMessageHelper.<ParseIncomingResponse>d__7.MoveNext()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.<ReceiveReplyAsync>d__18.MoveNext()
at System.ServiceModel.Channels.RequestChannel.<RequestAsync>d__33.MoveNext()
at System.ServiceModel.Channels.RequestChannel.<RequestAsyncInternal>d__32.MoveNext()
at System.Runtime.TaskHelpers.WaitForCompletionNoSpin[TResult](Task`1 task)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(MethodCall methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(MethodInfo targetMethod, Object[] args)
at generatedProxy_1.getArticle(getArticle3Request )
// my code calling the generated client
所以,以这种方式设置用户名和密码似乎不再足够,尽管在.NET Framework中运行良好。我看到其他关于CoreWCF的帖子中设置凭据的方式,所以我不知道我漏掉了什么?
英文:
I have a WCF client from .NET Framework 4.8 that I need to port to .NET Core, as using the old one is giving a PlatformNotSupportedException
after upgrading the underlying project.
The client is generated from a WSDL file, and adding it as a Connected Service in VS updates the Reference.cs
client just fine, with the main changes being the GeneratedCodeAttribute
being set to "Microsoft.Tools.ServiceModel.Svcutil", "2.1.0"
instead of "System.ServiceModel", "4.0.0.0"
(after having installed dotnet-svcutil to the project). It also installs these two packages, which I believe contains the CoreWCF client functionality in newer .NET versions:
System.ServiceModel.Http
(6.0.0)System.ServiceModel.Security
(6.0.0)
I have an integration that is creating one of the generated clients and calls an endpoint afterwards:
public string GetArticle(string articleNumber, string goal)
{
using var client = CreateArtikelClient();
return client.getArticle(articleNumber, goal);
}
private ArtikelPortTypeClient CreateArtikelClient()
{
var client = new ArtikelPortTypeClient(ArtikelPortTypeClient.EndpointConfiguration.ArtikelPort);
client.ClientCredentials.UserName.UserName = _integrationConfiguration.UserName;
client.ClientCredentials.UserName.Password = _integrationConfiguration.Password;
return client;
}
The client is created fine, but calling getArticle
causes the following exception:
System.ServiceModel.Security.MessageSecurityException
HResult=0x80131500
Message=The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm="Login please"'.
Source=System.ServiceModel.Http
StackTrace:
at System.ServiceModel.Channels.HttpResponseMessageHelper.ValidateAuthentication()
at System.ServiceModel.Channels.HttpResponseMessageHelper.<ParseIncomingResponse>d__7.MoveNext()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.<ReceiveReplyAsync>d__18.MoveNext()
at System.ServiceModel.Channels.RequestChannel.<RequestAsync>d__33.MoveNext()
at System.ServiceModel.Channels.RequestChannel.<RequestAsyncInternal>d__32.MoveNext()
at System.Runtime.TaskHelpers.WaitForCompletionNoSpin[TResult](Task`1 task)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(MethodCall methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(MethodInfo targetMethod, Object[] args)
at generatedProxy_1.getArticle(getArticle3Request )
// my code calling the generated client
So, setting the username and password this way doesn't seem to be sufficent anymore, despite it working fine in .NET Framework. I have seen other posts about CoreWCF where credentials where set this way, so I don't know what I am missing?
答案1
得分: 0
原文翻译如下:
原来客户端需要稍微不同的构建方式,需要直接传入端点URL,并且需要先创建一个绑定。
private ArtikelPortTypeClient CreateArtikelClient()
{
var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var client = new ArtikelPortTypeClient(binding, new EndpointAddress(_integrationConfiguration.EndpointAddress));
client.ClientCredentials.UserName.UserName = _integrationConfiguration.UserName;
client.ClientCredentials.UserName.Password = _integrationConfiguration.Password;
return client;
}
英文:
It turns out that the client needs to be constructed slightly differently, with the endpoint URL being passed in directly, and the need to create a binding first.
private ArtikelPortTypeClient CreateArtikelClient()
{
var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var client = new ArtikelPortTypeClient(binding, new EndpointAddress(_integrationConfiguration.EndpointAddress));
client.ClientCredentials.UserName.UserName = _integrationConfiguration.UserName;
client.ClientCredentials.UserName.Password = _integrationConfiguration.Password;
return client;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论