C#HttpClient远程主机强制关闭现有连接

And*_*uiz 34 c# asp.net json dotnet-httpclient

我正在使用其托管页面集成与Alternative Payments进行集成.他们的C#SDK暂时没有这种集成,但正如你所看到的那样非常简单,我发了一个小类来发送post请求并获得JSON响应.

我测试了我在PostMan和cURL上发送的json对象,两者都工作,也是认证头,所以我认为它们不是问题.这是我班级的构造函数:

public AlternativePaymentsCli(string apiSecretKey)
{
    this._apiSecretKey = apiSecretKey;

    _httpClient = new HttpClient();
    _httpClient.DefaultRequestHeaders.Accept
        .Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var authInfo = _apiSecretKey;
    authInfo = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:", _apiSecretKey)));

    // The two line below because I saw in an answer on stackoverflow.
    _httpClient.DefaultRequestHeaders.Add("Connection", "Keep-Alive"); 
    _httpClient.DefaultRequestHeaders.Add("Keep-Alive", "3600");

    _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Anything.com custom client v1.0");
    _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authInfo);

}
Run Code Online (Sandbox Code Playgroud)

以及我发布数据的方法:

public string CreateHostedPageTransaction(HostedPageRequest req) 
{
    var settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };

    // I send this same json content on PostMan and it works. The json is not the problem
    var content = new StringContent(JsonConvert.SerializeObject(req, settings), Encoding.UTF8, "application/json");
    var response = _httpClient.PostAsync(this._baseUrl + "/transactions/hosted", content).Result;
    var responseText = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

    if (response.IsSuccessStatusCode)
        return responseText;

    return "";
}
Run Code Online (Sandbox Code Playgroud)

然后我得到这个错误:An existing connection was forcibly closed by the remote host,在PostAsync行.这是错误细节:

[SocketException (0x2746): An existing connection was forcibly closed by the remote host]
   System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult) +8192811
   System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult) +47

[IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.]
   System.Net.TlsStream.EndWrite(IAsyncResult asyncResult) +294
   System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar) +149

[WebException: The underlying connection was closed: An unexpected error occurred on a send.]
   System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context) +324
   System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar) +137

[HttpRequestException: An error occurred while sending the request.]
Run Code Online (Sandbox Code Playgroud)

我正在使用C#4.5,Asp.Net MVC.我一直在阅读相同错误的答案,到目前为止,他们都没有解决我的问题.我在这段代码中缺少什么?

谢谢你的帮助

Pau*_*rce 99

我没有在你的代码示例中看到你在哪里设置_baseUrl的值,但我假设在某处做了.我还假设由于这与付款有关,因此URL是HTTPS.如果远程主机已禁用TLS 1.0并且您的连接以TLS 1.0的形式进入,则可能会导致该行为.我知道C#4.6默认启用了TLS 1.0/1.1/1.2支持,但我认为C#4.6仍然默认只支持SSL3/TLS 1.0,即使支持TLS 1.1和1.2.如果这是问题的原因,您可以使用以下代码手动将TLS 1.1和1.2添加到启用的值.

System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
Run Code Online (Sandbox Code Playgroud)

  • 您不必更改代码即可为当前在产品中运行的应用程序启用此功能:https://learn.microsoft.com/en-us/officeonlineserver/enable-tls-1-1-and-tls-1-2 -办公室在线服务器支持 (2认同)
  • @Ruchira 和 NathanTregillus 您可以按请求设置它(在发送请求之前添加代码),或者您可以通过在 Global.asax.cs 中设置 Application_Start() 为整个应用程序设置一次 (2认同)
  • 谢谢@PaulPearce。我最终将其添加到 Global.asax 中。使用“使用 System.Net;” 添加顶部支持ServicePointManager和SecurityProtocolType。 (2认同)

小智 9

如果您使用.Net 4.0,则未定义SecurityProtocolType.Tls11和SecurityProtocolType.Tls2,因此您可以使用下面的硬编码值.

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;


d_f*_*d_f 8

可以在不更改代码的情况下解决该问题,如对类似问题的出色回答中所述:

将 web 项目重定向到.Net 4.6+,然后更新 web.config 如下:

<system.web>
  <compilation targetFramework="4.6" /> 
  <httpRuntime targetFramework="4.6" /> 
</system.web>
Run Code Online (Sandbox Code Playgroud)