C# - 早期に戻りたい場合に非同期メソッドからタスクを正しくキャンセルする

okwaves2024-01-25  9

この質問にはすでに答えがあります: タスクの待機中またはタスクの Exception プロパティへのアクセスによって、タスクの例外が検出されませんでした。その結果、観察されなかった例外は、

(答えは2つ)

3 年前

に閉店しました。

複数の非同期操作を開始する MVC WebApi ApiController がありますが、1 つ目は、ロジックが残りのタスクの結果に関心を持たなくなり、単に戻る可能性があることです。

簡単にするために、次のサンプルを作成しました。

[HttpGet]
public async Task<IHttpActionResult> Test2(CancellationToken cancellationToken)
{
    Task<ProductSearchResult> searchTask = _productService.SearchAsync("searchterm", cancellationToken);

    // Some sort of logic that means I want to return early, and not wait for the searchTask
    int next = new Random().Next(1, 5);
    if(next <3)
        return Ok("Done");

    ProductSearchResult productSearchResult = await searchTask;

    return Ok(productSearchResult.TotalResults);
}

コードが早期に戻ることを決定した場合、ログに次のエントリが表示されます。

タスクの待機中またはその Exception プロパティへのアクセスによって、タスクの例外が検出されませんでした。その結果、監視されていない例外がファイナライザー スレッドによって再スローされました。オブジェクト参照がオブジェクトのインスタンスに設定されていません。

System.AggregateException: System.NullReferenceException: System.Web.ThreadContext.AssociateWithCurrentThread (System.Web、バージョン = 4.0.0.0、Culture = 中立、PublicKeyToken = b03f5f7f11d50a3a) で System.Web.HttpApplication.OnThreadEnterPrivate で (System.Web、バージョン = 4.0.0.0、文化 = 中立、PublicKeyToken=b03f5f7f11d50a3a) System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter で (System.Web、バージョン = 4.0.0.0、文化 = 中立、PublicKeyToken = b03f5f7f11d50a3a) System.Web.Util.SynchronizationHelper.SafeWrapCallback で (System.Web、バージョン = 4.0.0.0、文化 = 中立、PublicKeyToken = b03f5f7f11d50a3a) System.Threading.Tasks.Task.Execute で (mscorlib、Version=4.0.0.0、Culture=neutral、PublicKeyToken=b77a5c561934e089)

そこで私の質問は次のとおりです。例外を避けるために、待機する前に戻ることにした場合、_productService.SearchAsync() 呼び出しを適切にキャンセルするにはどうすればよいですか?

単に例外をキャッチするだけではなく、戻る前にタスクを積極的にキャンセルしたいと考えています。ただし、この場合、私は cancelToken を所有していません。

操作を開始する前ではなく、操作を開始する前に早期に戻るロジックを実行してみてはいかがでしょうか?

– サービス

2020 年 9 月 4 日 18:52

CancelToken をコントローラー エンドポイントに渡すにはどうすればよいですか?

– アンディ

2020 年 9 月 4 日 18:52

@Servy 実際のコードでは、4 つの並列非同期呼び出しがあります。その後、最初の結果を待ちます。その結果によっては、他の結果は必要なくなったので、すぐに戻りたい場合もあります。

– モーテンボック

2020 年 9 月 4 日 18:56

@Andy フレームワークは、CancelToken が署名に含まれている場合、自動的に追加します。

– モーテンボック

2020 年 9 月 4 日 18:56

@mortenbock その場合、解決策は重複でカバーされていますが、それは本当に最初から質問に含まれるべきコンテキストです。

– サービス

2020 年 9 月 4 日 18:58



------------------------

この質問は終了しましたが、これを試してみてください:

[HttpGet]
public async Task<IHttpActionResult> Test2()
{
    using (var tokenSource = new CancellationTokenSource())
    {
        var searchTask = _productService.SearchAsync("searchterm", tokenSource.Token);

        // Some sort of logic that means I want to return early, and not wait for the searchTask
        int next = new Random().Next(1, 5);
        if (next < 3)
        {
            tokenSource.Cancel();
            try
            {
                await searchTask; // let it gracefully exit since it was cancelled.
            }
            catch (OperationCanceledException)
            {
                // swallow this
            }
            catch (Exception ex)
            {
                // log this
            }
            return Ok("Done");
        }

        var productSearchResult = await searchTask;

        return Ok(productSearchResult.TotalResults);
    }
}

0

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。