C#で HttpClient を使って、とある API からデータを取得していたのですがSystem.Net.Http.HttpRequestException: Error while copying content to a stream.が発生してしまいました。根本的な解決はできなかったのですが、調査した内容や実際にやった対策を書きます。

発生したエラー

Prism(WPF)で HttpClient を使って API を呼び出すところで、エラーが発生したりしなかったりする状況でした。(発生条件は不明)

  • .Net Framework 4.6.1
  • Visual Studio 2017
1
2
3
4
5
6
7
8
9
10
11
12
// コード
// 参照:https://dekirukigasuru.com/blog/2020/04/24/csharp-httpclientfactory/

// Microsoft DependancyInjection
var provider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
// Microsoft Http クライアントファクトリーを得る
var factory = provider.GetRequiredService<IHttpClientFactory>();
// Http クライアントを得る
var client = factory.CreateClient();
// Http リクエストを用意
request = new HttpRequestMessage(HttpMethod.Get, "https://example.com/");
response = await client.SendAsync(request); // <===== エラー発生
1
2
// エラー
System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: 転送接続からデータを読み取れません: 接続は閉じられました。。

調べたこと

TLS1.2 が無効?

API を curl で呼ぶと成功するが System.Net.Http.HttpClient だと例外が発生する。(terarail)では、「TLS1.2 が無効」になっていることが原因の可能性があると書かれていました。

しかし、エラーが発生しない場合があることや、.Net 4.6.1 を使用していたので、これが原因ではありませんでした。

対策

調べても例外発生を防止できなかったので、リトライするように修正しました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int MAX_RETRY_COUNT = 3;
for (int i = 1; i <= MAX_RETRY_COUNT; i++)
{
try
{
// APIからJSONデータ取得
request = new HttpRequestMessage(HttpMethod.Get, "https://example.com/");
response = await client.SendAsync(request);
}
catch (HttpRequestException e)
{
// 異常発生の場合
if (i == MAX_RETRY_COUNT)
{
// 上限までリトライしても取得失敗の場合はエラー
throw e;
}
}
if (response != null && response.IsSuccessStatusCode)
{
// 正常取得の場合
break;
}
}