[ad_1]
次の実験コードを使用すると:
var client = new HttpClient(); Task<HttpResponseMessage> response = client.GetAsync(url); response.WaitAsync(TimeSpan.FromMilliseconds(500)); Console.WriteLine("Done async action. response.IsCompleted: {0}, and status code is {1}, task status: {2}", response.IsCompleted, response.Result.StatusCode, response.Status);
結果のログ行は私に与えます:
Done async action. response.IsCompleted: False, and status code is OK, task status: RanToCompletion
そのため、タスクのステータスが RanToCompletion
、 IsCompleted
プロパティは False
.
私が試したこと:
シンプルに使うと Wait
、したがって、タイムアウトがなければ、期待される結果が得られます IsCompleted
に設定されています True
:
var client = new HttpClient(); Task<HttpResponseMessage> response = client.GetAsync(url); response.Wait();
結果のログ行:
Done async action. response.IsCompleted: True, and status code is OK, task status: RanToCompletion
私は私が使用できることを知っています await
上のキーワード GetAsync
メソッドですが、前述のように、これは実験的なコードです。
期待される結果が得られるもう 1 つのことは、セマフォを導入する場合です。
Semaphore sem = new Semaphore(0, 1); var client = new HttpClient(); Task<HttpResponseMessage> response = client.GetAsync(url); response.GetAwaiter().OnCompleted(() => { sem.Release(); }); response.WaitAsync(TimeSpan.FromMilliseconds(500)); sem.WaitOne(1000);
ログ行を複製すると、2 番目のログ行が する 見せる True
. このような:
Done async action. response.IsCompleted: False, and status code is OK, task status: RanToCompletion Done async action. response.IsCompleted: True, and status code is OK, task status: RanToCompletion
これは単なる実験的なコードなので、まったく重要ではありません。 しかし、何が起こっているのか、何が間違っているのかを知っている人がいるのだろうかと思っていました.
解決策 1
ここにはいくつかの問題があります。
初期化中 HttpClient
この方法は遅く、リソースをすぐに使い果たしてしまいます。
あなたは IHttpClentFactory
. Factory はインスタンスを保持してリサイクルするため、実体化が迅速になり、リソースの使用量が少なくなります。 ここでもっと読むことができます: IHttpClientFactory を使用して回復力のある HTTP 要求を実装する | マイクロソフト ラーン[^]
IOC (制御の反転) コンテナーを介して DI (依存性注入) を使用せずにそれを行う方法を示します。
private readonly IHttpClientFactory _httpClientFactory;
の設定 IHttpClientFactory
:
ServiceCollection builder = new ServiceCollection();
builder.AddHttpClient(HttpClientKey);
ServiceProvider serviceProvider = builder.BuildServiceProvider();
_httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
これは、アプリケーション全体で共有するための静的クラス (シングルトン デザイン パターン) にある必要があります。
次に、 HttpClient
実例:
private HttpClient HttpClientFactory(Uri? uri = null) { HttpClient client = _httpClientFactory.CreateClient(HttpClientKey); if (uri is not null) client.BaseAddress = uri; return client; }
次に使用します:
public async Task MyMethod() { using HttpClient client = HttpClientFactory(); { var response = await client.GetAsync(uri).ConfigureAwait(false); // do stuff here... } }
私がラップしたことに注意してください HttpClient
で Using
声明。 これはそうです HttpClient
正しく廃棄されます。
.ConfigureAwait(false)
オプションですが、 MyMethod
呼び出しスレッド (ほとんどの場合 UI スレッド) から離れたスレッドプールからスレッドにマーシャリングされ、アプリケーションをロックしません。
解決策 2
必要がある await
の response.WaitAsync(TimeSpan.FromMilliseconds(500))
内のメソッド try
ブロックして、メソッドがスローする可能性のある例外をキャッチできるようにします。 私の推測では、 response.IsCompleted
は偽であるため、 WaitAsync
タイムアウトしました。 しない限り、例外をキャッチしません。 await
それ。 これらの行に沿って何かを試してください:
private static async Task Main(string[] args) { using var client = new HttpClient(); string url = $"https://www.codeproject.com/"; Task<HttpResponseMessage> response =client.GetAsync(url); try { await response.WaitAsync(TimeSpan.FromMilliseconds(500)); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.WriteLine("Done async action. response.IsCompleted: {0}, and status code is {1}, task status: {2}", response.IsCompleted, response.Result.StatusCode, response.Status);
[ad_2]
コメント