API呼び出し用に_FileResult : IHttpActionResult
_ webapi戻り値の型を作成しました。 FileResultは、別のURLからファイルをダウンロードしてから、ストリームをクライアントに返します。
当初、私のコードには次のようなusing
ステートメントがありました。
_public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
try
{
HttpResponseMessage response;
using (var httpClient = new HttpClient())
{
response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new System.Net.Http.StreamContent(
await httpClient.GetStreamAsync(this.filePath))
};
}
return response;
}
catch (WebException exception)
{...}
}
_
ただし、これにより断続的にTaskCanceledException
が発生します。非同期呼び出しが終了する前にHttpClientが破棄されると、タスクの状態がキャンセルに変わることを知っています。ただし、await in:Content = new System.Net.Http.StreamContent(await httpClient.GetStreamAsync(this.filePath))
を使用しているため、タスクの完了中にHttpClientが破棄されるのを防ぐことができます。
そのタスクがキャンセルされるのはなぜですか?これは最小のリクエストで発生し、大きなリクエストで常に発生するとは限らないため、タイムアウトが原因ではありません。
using
ステートメントを削除すると、コードは正しく機能しました。
_public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
try
{
HttpResponseMessage response;
var httpClient = new HttpClient();
response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new System.Net.Http.StreamContent(
await httpClient.GetStreamAsync(this.filePath))
};
return response;
}
catch (WebException exception)
{...}
}
_
使用が問題を引き起こした理由は何ですか?
非同期呼び出しが終了する前にHttpClientが破棄されると、タスクの状態がキャンセルに変わることを知っています。ただし、await in:Content = new System.Net.Http.StreamContent(await httpClient.GetStreamAsync(this.filePath))を使用しているため、タスクの完了中にHttpClientが破棄されるのを防ぐ必要があります。
しかし、そのタスクは何をしますか?ストリームを取得します。したがって、コードはStream
で終わり、HttpClient
を閉じるときに完全に読み取られる場合と読み取られない場合があります。
HttpClient
は再利用(および同時使用)用に特別に設計されているため、using
を完全に削除し、HttpClient
宣言をstatic
クラスメンバーに移動することをお勧めします。ただし、クライアントを閉じて再度開く場合は、HttpClient
。
タスクキャンセルの例外についても同様の問題が発生しました。 AggregateException
をキャッチしようとしたり、Exception
の下にあるWebException
ブロックをすべてキャッチしようとしたりすると、「タスクキャンセルされた"
調査を行ったところ、さまざまなスレッドで説明されているように、AggregateException
は非常に誤解を招くことがわかりました。
HttpClientを短すぎるタイムアウトに設定するとプロセスがクラッシュします
HttpClientがタイムアウトしたことを確認するにはどうすればよいですか?
httpclientgetasyncのバグは、taskcanceledexceptionではなくwebexceptionをスローする必要があります
明示的なタイムアウトを設定するようにコードを変更することになりました(ここで、asyncTimeoutInMins
はapp.configファイルから読み取られます)。
string jsonResponse = string.Empty;
try
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(Properties.Settings.Default.MyWebService);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.Timeout = new TimeSpan(0, asyncTimeoutInMins, 0);
HttpResponseMessage response;
response = await httpClient.GetAsync("/myservice/resource");
// Check the response StatusCode
if (response.IsSuccessStatusCode)
{
// Read the content of the response into a string
jsonResponse = await response.Content.ReadAsStringAsync();
}
else if (response.StatusCode == HttpStatusCode.Forbidden)
{
jsonResponse = await response.Content.ReadAsStringAsync();
Logger.Instance.Warning(new HttpRequestException(string.Format("The response StatusCode was {0} - {1}", response.StatusCode.ToString(), jsonResponse)));
Environment.Exit((int)ExitCodes.Unauthorised);
}
else
{
jsonResponse = await response.Content.ReadAsStringAsync();
Logger.Instance.Warning(new HttpRequestException(string.Format("The response StatusCode was {0} - {1}", response.StatusCode.ToString(), jsonResponse)));
Environment.Exit((int)ExitCodes.ApplicationError);
}
}
}
catch (HttpRequestException reqEx)
{
Logger.Instance.Error(reqEx);
Console.WriteLine("HttpRequestException : {0}", reqEx.InnerException.Message);
Environment.Exit((int)ExitCodes.ApplicationError);
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
throw;
}
return jsonResponse;