web-dev-qa-db-ja.com

C#HttpClient既存の接続がリモートホストによって強制的に閉じられました

hosted page integration を使用して、Alternative Paymentsとの統合に取り組んでいます。彼らのC#SDKには現時点ではこの統合はありませんが、ご覧のとおり、非常にシンプルであるため、投稿リクエストを送信して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);

}

そして、私がデータを投稿する方法:

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

次に、PostAsync行で次のエラーが表示されます:An existing connection was forcibly closed by the remote Host。これはエラーの詳細です。

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

C#4.5、Asp.Net MVCを使用しています。私は同じエラーの答えを読んでいますが、これまでのところ誰も私の問題を解決していません。このコードには何が欠けていますか?

助けてくれてありがとう

31
André Luiz

_baseUrlの値を設定しているコードサンプルには表示されませんが、それはどこかで行われていると想定しています。また、これは支払いに関連しているため、URLはHTTPSであると想定しています。リモートホストがTLS 1.0を無効にしていて、接続がTLS 1.0として着信している場合、その動作が発生する可能性があります。 C#4.6のTLS 1.0/1.1/1.2サポートはデフォルトで有効になっていますが、TLS 1.1および1.2がサポートされていても、C#4.6のデフォルトはSSL3/TLS 1.0のみです。これが問題の原因である場合、次のコードを使用して、TLS 1.1および1.2を有効な値に手動で追加できます。

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

.Net 4.0を使用している場合、SecurityProtocolType.Tls11とSecurityProtocolType.Tls2は定義されていないため、代わりに以下のハードコードされた値を使用できます。

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

8
Tim Kempster

同様の質問に対する この優れた答え で説明されているように、コードを変更せずに問題を解決することができます。

Webプロジェクトのターゲットを。Net 4.6 +に変更してから、web.configを次のように更新します。

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