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

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

能够连接到服务并在 3.1 控制台应用程序上获得响应,但是当我将相同的代码放入 3.1 Web API 控制器时,当我尝试使用客户端出现错误 "There was no endpoint listening at .... This may be caused due to incorrect soap action"。内部异常说 "winhttp exception. The server name or address could not be resolved".

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

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

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,并替换了通过 ExternalServiceInterface 将连接服务添加到项目时生成的接口名称。 在 .NET Core 3.1 Web API 中的 _client.ExternalServiceOperation() 处出现异常 API 但在 .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()}

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

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

读到较新版本的 .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

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