web-dev-qa-db-fra.com

C # HttpClient Une connexion existante a été fermée de force par l'hôte distant

Je travaille sur une intégration avec Alternative Payments en utilisant leur intégration de page hébergée . Leur intégration dans le SDK C # n’a pas cette intégration disponible pour le moment, mais comme vous pouvez le constater, c’est très simple et j’ai créé une petite classe pour envoyer la demande de publication et obtenir la réponse JSON.

J'ai testé l'objet json que j'envoie sur PostMan et cURL et les deux fonctionnent, ainsi que l'en-tête d'authentification, donc je pense qu'ils ne sont pas le problème. Voici le constructeur de ma classe:

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

}

Et la méthode où je poste les données:

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

Ensuite, je reçois cette erreur: An existing connection was forcibly closed by the remote Host, sur la ligne PostAsync. Voici les détails de l'erreur:

[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.]

J'utilise C # 4.5, Asp.Net MVC. J'ai lu les réponses pour la même erreur et aucune d'elles n'a résolu mon problème jusqu'à présent. Qu'est-ce qui me manque dans ce code?

Merci pour toute aide

31
André Luiz

Je ne vois pas dans votre exemple de code où vous définissez la valeur de _baseUrl, mais je suppose que cela se fait quelque part. Je suppose également que puisque cela concerne les paiements, l'URL est HTTPS. Si l'hôte distant a désactivé TLS 1.0 et que votre connexion arrive en tant que TLS 1.0, cela peut être à l'origine de ce problème. Je sais que la prise en charge de TLS 1.0/1.1/1.2 est activée par défaut dans C # 4.6, mais je pense que C # 4.6 utilise toujours uniquement SSL3/TLS 1.0, même si TLS 1.1 et 1.2 sont pris en charge. Si cela est la cause du problème, vous pouvez ajouter manuellement TLS 1.1 et 1.2 aux valeurs activées à l'aide du code suivant.

System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
89
Paul Pearce

Si vous utilisez .Net 4.0, SecurityProtocolType.Tls11 et SecurityProtocolType.Tls2 ne sont pas définis. Vous pouvez donc utiliser la valeur codée en dur ci-dessous.

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

8
Tim Kempster

Il est possible de résoudre le problème sans modifier le code, comme décrit dans cette excellente réponse à une question similaire:

Reciarez le projet Web sur . Net 4.6 + , puis mettez à jour web.config comme suit:

<system.web>
  <compilation targetFramework="4.6" /> 
  <httpRuntime targetFramework="4.6" /> 
</system.web>
0
d_f