C# HttpClient Een bestaande verbinding is geforceerd gesloten door de externe host

Ik werk aan een integratie met alternatieve betalingen met behulp van hun gehoste pagina-integratie . Hun C# SDK heeft deze integratie momenteel niet beschikbaar, maar zoals je kunt zien is het vrij eenvoudig en ik heb een kleine klas gemaakt om het postverzoek te verzenden en het JSON-antwoord te krijgen.

Ik heb het json-object dat ik verzend op PostMan en cURL getest en beide werken, ook de authenticatie-header, dus ik denk dat ze niet het probleem zijn. Hier is de constructor van mijn klas:

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

En de methode waarop ik de gegevens plaats:

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

Dan krijg ik deze foutmelding: An existing connection was forcibly closed by the remote host, op de PostSync-lijn. Dit is de foutdetails:

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

Ik gebruik C # 4.5, ASP.NET MVC. Ik heb antwoorden gelezen voor dezelfde fout en geen van hen heeft mijn probleem tot nu toe opgelost. Wat mis ik in deze code?

Bedankt voor alle hulp


Antwoord 1, Autoriteit 100%

Ik zie niet in uw codevoorbeeld waar u de waarde van _baseurl instelt, maar ik neem aan dat er ergens wordt gedaan. Ik neem ook aan dat sinds dit verband met betalingen, de URL HTTPS is. Als de externe host is uitgeschakeld TLS 1.0 en uw verbinding binnenkomt als TLS 1.0, kan dit gedrag veroorzaken. Ik weet dat C # 4.6 TLS 1.0 / 1.1 / 1.2 ondersteuning is ingeschakeld die standaard is ingeschakeld, maar ik denk dat C # 4.6 nog steeds in staat is om alleen SSL3 / TLS 1.0 toe te staan, hoewel TLS 1.1 en 1.2 worden ondersteund. Als dit de oorzaak is van het probleem, kunt u handmatig TLS 1.1 en 1.2 toevoegen aan de ingeschakelde waarden met behulp van de volgende code.

System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

Antwoord 2, Autoriteit 9%

Als u .NET 4.0 gebruikt, worden beveiligingsprotocoltype.tls11 en securityprotocoltype.tls2 niet gedefinieerd, dus in plaats daarvan kunt u de harde gecodeerde waarde hieronder gebruiken.

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;


Antwoord 3, Autoriteit 5%

Het is mogelijk om het probleem op te lossen zonder enige wijzigingen in de code, zoals beschreven in Dit uitstekende antwoord naar een vergelijkbare vraag:

retarget het webproject naar .net 4.6 + , update vervolgens Web.config als volgt:

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

Antwoord 4

Dit werkte voor mij, de eerste regel zorgt voor de protocollen ssl3en TLS1.2, en de tweede regel negeert eventuele potentiële certificaatfouten (negeer en doorgaan – zoals verlopen Certs.):

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback +=  (sender, certificate, chain, sslPolicyErrors) => true;

Antwoord 5

Voor mij is deze fout veroorzaakt door te vergeten om de proxyserver te configureren.
De volgende code gebruiken om de HttpClientte construeren opgelost het voor mijn .NET 4.7.2 Toepassing:

var httpClientHandler = new HttpClientHandler { Proxy = WebRequest.GetSystemWebProxy() };
var httpClient = new HttpClient(httpClientHandler);

Ik hoop dat dit iemand helpt.

Other episodes