将 WCF 客户端升级到 CoreWCF 会导致身份验证失效。

huangapple go评论90阅读模式
英文:

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;
}

huangapple
  • 本文由 发表于 2023年7月31日 18:17:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76802641.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定