Wcf 服务在 .NET Core 3.1 控制台应用程序中工作,但在 ASP.NET Core 3.1 Web API 中无法工作

Posted

技术标签:

【中文标题】Wcf 服务在 .NET Core 3.1 控制台应用程序中工作,但在 ASP.NET Core 3.1 Web API 中无法工作【英文标题】:Wcf service works in .NET Core 3.1 console app, but fails to work in ASP.NET Core 3.1 Web API 【发布时间】:2020-07-09 12:04:54 【问题描述】:

在工作中遇到了一个特殊的问题。尝试连接到基于 https、自定义客户端证书的连接服务。我正在使用 BasicHttpsBinding 和 ChannelFactory 类为服务创建客户端。

能够连接到服务并在 3.1 控制台应用程序上获取响应,但是当我将相同的代码放在 3.1 Web API 控制器中时,当我尝试使用客户端调用相同的操作时出现错误 “在 ... 处没有端点监听。这可能是由于不正确的肥皂动作引起的”。内部异常说“winhttp异常。无法解析服务器名称或地址”

我尝试运行 fiddler 以查看有什么不同,对于控制台应用程序,我看到正在建立到外部服务 URL 的隧道,但对于来自 Web API 的调用,我在 Fiddler 上什么也看不到,这意味着它在 Web API 的某个地方出现故障管道本身。

在 Google 上的搜索指向检查代理设置,因为这是在公司网络上,但 netsh winhttp show proxy 显示 direct (no proxy server) 所以我不认为这是与公司代理相关的问题。

3.1 控制台应用程序和 Web API 之间的网络堆栈到底有什么不同,即 WCF 服务调用可能在 Web API 中失败但在控制台应用程序中工作?

有问题的代码

var binding = new BasicHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var endpoint = new EndpointAddress(new Uri("https://service url"));
var channelFactory = new ChannelFactory<ExternalServiceInterface>(binding, endpoint);
channelFactory.Credentials.ClientCertificate.Certificate = new X509Certificate2(certificatepath, password);

_client = channelFactory.CreateChannel();

var sbmtGtDtResp = _client.ExternalServiceOperation(data);

已删除服务 url 等敏感信息,并将在将 Connected Service 添加到项目时生成的接口名称替换为 ExternalServiceInterface。 在 .NET Core 3.1 Web API 中的 _client.ExternalServiceOperation() 处获得异常,但在 .NET Core 3.1 控制台应用程序中有效

异常转储

System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at "https://service url" that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
 ---> System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.Net.Http.WinHttpException (80072EE7, 12007): The server name or address could not be resolved
   at System.Threading.Tasks.RendezvousAwaitable`1.GetResult()
   at System.Net.Http.WinHttpHandler.StartRequest(WinHttpRequestState state)
   --- End of inner exception stack trace ---
   at System.ServiceModel.Channels.ServiceModelHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
   --- End of inner exception stack trace ---
   at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(HttpRequestException requestException, HttpRequestMessage request, HttpAbortReason abortReason)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
   at System.ServiceModel.Channels.RequestChannel.RequestAsync(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.RequestAsyncInternal(Message message, TimeSpan timeout)
   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)
--- End of stack trace from previous location where exception was thrown ---
   at System.Reflection.DispatchProxyGenerator.Invoke(Object[] args)
   at generatedProxy_1.submitGetDataRequest(submitGetDataRequestRequest )
   at WebAPIPOC.Controllers.ServiceController.Process() in "Code filepath.cs":line 50
   at lambda_method(Closure , Object , Object[] )
   at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()

【问题讨论】:

这是如何工作的。您需要发布相关代码,以便我们可以复制它并尝试解决问题。否则我们如何确定解决方案是什么? @JonathanAlfaro 知道了,过段时间会更新 @JonathanAlfaro 更新了从 .NET Core 3.1 Web API 运行时引发异常的代码位 看起来像 WCF 客户端? ....无论如何,错误的关键是:“无法解析服务器名称或地址” ....这意味着它找不到服务器,所以很肯定它正在尝试连接到错误的 IP 或 DNS 名称...该错误不是来自服务器,而是来自无法解析域的 DNS。仔细检查它是否正在尝试访问正确的域,并且该服务实际上正在侦听该地址 @JonathanAlfaro 是的,我会调查一下,但是当我在控制台应用程序中编写相同的代码时,我能够连接到相同的服务,Web api 和控制台应用程序都在我的工作机器。这表明 Web api 和控制台应用程序之间的网络堆栈处理存在差异,并且想了解更多相关信息以便我可以解决该问题。如果是 IP 或 DNS 问题,在连接到相同外部服务的同一台机器上运行的控制台应用程序应该也失败了,对吧?甚至 web api 和控制台应用程序的目标框架也是 3.1 【参考方案1】:

所以,像往常一样,我真的很愚蠢。但万一其他人犯了和我一样的错误,我会列出来。

System.ServiceModel.* Nuget 包更新到最新版本(从 4.4.0 -> 4.7.0)为我解决了这个问题,不知道为什么在添加 WCF/连接服务时会自动安装旧版本。

已经阅读了较新版本的 .NET Core 不再使用 WinHttp 而是使用 SocketsHttpHandler,这应该提醒我在看到 WinHttpException 时正在使用旧库

以及为什么它在我的控制台应用程序中工作。我在那里也有 4.4.0 版本的库,但显然是为了修复一些参考错误,我手动安装了 System.Private.ServiceModel,它是 System.ServiceModel 的依赖项,通常不需要手动安装。并且我安装了System.Private.ServiceModel的4.7.0版本。这以某种方式使 WCF 服务调用在控制台应用程序中工作,即使 System.Private.ServiceModelSystem.ServiceModel 包之间的版本不匹配

让我检查库版本的 Github 问题线程,详细说明了为什么旧版本的库会导致错误 - https://github.com/dotnet/wcf/issues/3311

【讨论】:

@Pani 很高兴这对您有所帮助! 谢谢你。我遇到了一些问题,不同的错误消息,但控制台工作正常并且 net core 3.1 web api 失败。我检查了参考资料,在更新所有参考资料后,它可以工作了。 谢谢!这解决了我的问题。我在 IIS 代理后面运行 WCF 客户端。我收到错误消息:WinHttpHandler 仅在 System.ServiceModel 上的 .NET Framework 和 .NET Core 上受支持。* 4.4.0。升级到 4.8.0 解决了我的问题。 更新后我需要刷新/更新参考来解决问题【参考方案2】:

我浪费了 6 个小时试图解决这个问题。就我而言,我试图在控制台中使用肥皂并得到“在https://swea.riksbank.se/sweaWS/services/SweaWebServiceHttpSoap12Endpoint 处没有可以接受消息肥皂的端点监听”错误。访问此答案后,我将所有 ServiceModel 包:System.ServiceModel.DuplexSystem.ServiceModel.HttpSystem.ServiceModel.NetTcpSystem.ServiceModel.Security 更新为 v4.7.0,现在它可以正确获得响应。尽管当前的问题和接受的答案是针对 netcore3.1,但我的控制台应用程序在 dotnetcore 2.1 中,所以我假设它与整个 wsdl 导入过程有关,因为包是通过脚手架过程安装的。

【讨论】:

以上是关于Wcf 服务在 .NET Core 3.1 控制台应用程序中工作,但在 ASP.NET Core 3.1 Web API 中无法工作的主要内容,如果未能解决你的问题,请参考以下文章

如何在 .NET Core 3.1 应用程序中添加 WCF 服务引用?

如何从 .NET Core 3.1 中的 F# 访问 WCF 服务?

连接的服务 WCF 不起作用 NET core 3.1

忽略 ASP.NET Core 3.1 中的 WCF 证书错误

尝试使用 .Net Core 3.1 连接 mySAP WCF 时出现问题

使用 .NET Core 3.1 生成 WCF wsdl 客户端的问题