WCF: The remote server returned an error: "(417) Expectation Failed"

WCF: The remote server returned an error: "(417) Expectation Failed"

我们正在尝试从使用 NET Core 3.1 制作的后端服务连接到遗留 WCF 服务。为此,我们使用两个 NuGet 包“System.ServiceModel.Http”和“System.ServiceModel.Primitives”(最新版本 4.8.1)。

为了连接到端点,我们创建 binding/serviceclient 手册如下

var binding = new BasicHttpsBinding();

binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.Security.Transport = new HttpTransportSecurity() { ClientCredentialType = HttpClientCredentialType.Certificate, ProxyCredentialType = HttpProxyCredentialType.Basic };
binding.CloseTimeout = new TimeSpan(0, 12, 0, 0, 0);
binding.OpenTimeout = new TimeSpan(0, 12, 0, 0, 0);
binding.SendTimeout = new TimeSpan(0, 12, 0, 0, 0);
binding.MaxReceivedMessageSize = 2147483646;
binding.MaxBufferSize = 2147483646;

var channelfactory = new SearchServiceClient(binding, endpoint);
channelfactory.ClientCredentials.ClientCertificate.SetCertificate(System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser, System.Security.Cryptography.X509Certificates.StoreName.My, System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName, "CERTIFICATENAME");

var response = await channelfactory.existsAsync(...);

为了建立连接,我们需要使用 SSL 客户端证书,而不是 username/password。

对于每个请求,我们都会收到以下错误消息:“远程服务器返回错误:(417) 预期失败”。

我做了一些研究,发现您需要做的就是将“ExpectContinue”标志设置为 false。

不幸的是,这在 ServicePointManager 中不起作用(甚至在 web.config 中也不行)。

ServicePointManager.Expect100Continue = false;

如果我将“System.ServiceModel.Http”和“System.ServiceModel.Primitives”的 nuget 包版本降级到 4.4.4,它会起作用。

有谁知道我如何使用最新版本做到这一点?

经过几周的研究,我现在可以找到解决方案。

  1. 创建自定义 MessageHandlerBehavior 和 DelegatingHandler(请查看 https://justsimplycode.com/2019/11/02/disable-header-100-continue-in-net-core-wcf-client/

  2. 使用自定义 MessageHandlerBehavior 并将 ExpectContinue 设置为 false:

    var handlerFactoryBehavior = new HttpMessageHandlerBehavior();
    handlerFactoryBehavior.OnSending = (message, token) =>
    {
       message.Headers.ExpectContinue = false;
       return null;
    };
    
    var channelfactory = new SearchServiceClient(binding, endpoint);
    channelfactory.ClientCredentials.ClientCertificate.SetCertificate(...);
    channelfactory.Endpoint.EndpointBehaviors.Add(handlerFactoryBehavior);