簡體   English   中英

如何使用 Angular 取消 .Net Core Web API 請求?

[英]How to cancel .Net Core Web API request using Angular?

我有以下兩個應用程序

  • Angular 6/7 應用程序
  • .Net Core Web API

我正在使用 Angular 的HttpClient向 API 發出GET請求,如下所示

this.subscription = this.httpClient.get('api/Controller/LongRunningProcess')
                                   .subscribe((response) => 
                                   {
                                      // Handling response
                                   });

API 控制器的LongRunningProcess方法有以下代碼

    [HttpGet]
    [Route("LongRunningProcess")]
    public async Task<IActionResult> LongRunningProcess(CancellationToken cancellationToken)
    {
        try
        {
            // Dummy long operation
            await Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    // Option 1 (Not working)
                    if (cancellationToken.IsCancellationRequested)
                        break;

                    // Option 2 (Not working)
                    cancellationToken.ThrowIfCancellationRequested();

                    Thread.Sleep(6000);
                }

            }, cancellationToken);
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
        }

        return Ok();
    }

現在我想取消這個長時間運行的過程,所以我從客戶端取消訂閱,如下所示

// On cancel button's click
this.subscription.unsubscribe();

上面的代碼將取消請求,我可以在瀏覽器的“網絡”選項卡中看到它被取消,如下所示

在此處輸入圖像描述

但它不會在 API 的LongRunningProcess方法中使IsCancellationRequestedtrue ,因此操作將繼續進行。

[注意]:即使我使用郵遞員撥打電話,API 方法中的選項 1選項 2都不起作用。

問題:有什么方法可以取消LongRunningProcess方法的操作?

當角度取消請求時,您可以從 http 上下文中獲取取消令牌

   CancellationToken cancellationToken = HttpContext.RequestAborted;
    if (cancellationToken.IsCancellationRequested)
    {
        // The client has aborted the request
    }

在這種情況下你不需要休息只使用這樣

 [HttpGet]
 [Route("LongRunningProcess")]
 public async Task<IActionResult> LongRunningProcess(CancellationToken cancellationToken)
 {
   for (int i = 0; i < 10; i++)
   {
      cancellationToken.ThrowIfCancellationRequested();
       // Dummy long operation
       await Task.Factory.StartNew(() => Thread.Sleep(60000));
   }

    return Ok();
 }

你可以在這里閱讀更多

這是因為您的 dummy long 操作不監視 canncellationToken。 我不確定您是否真的打算毫無延遲地並行啟動 10 個一分鍾的任務,這就是您的代碼所做的。

為了進行虛擬長操作,代碼如下

[HttpGet]
[Route("LongRunningProcess")]
public async Task<IActionResult> LongRunningProcess(CancellationToken cancellationToken)
{
    // Dummy long operation
    await Task.Run(() =>
        {
            for (var i = 0; i < 60; i++)
            {
                if (cancel.IsCancellationRequested)
                    break;
                Task.Delay(1000).Wait();
            }
        });

    return Ok();
}

順便說一下, Task.Run就相當於Task.Factory.StartNew

但是,如果您只需要在 Web API 中進行一個虛擬的長期運行操作,那么您也可以簡單地使用支持取消令牌的Task.Delay Task.Delay在請求被取消的時候會拋出異常,所以在請求取消后需要做一些事情的時候添加異常處理代碼。

[HttpGet]
[Route("LongRunningProcess")]
public async Task<IActionResult> LongRunningProcess(CancellationToken cancellationToken)
{
    // Dummy long operation
    await Task.Delay(60000, cancel);

    return Ok();
}

除非您在 onDestroy() 中取消訂閱,否則當時仍在運行的任何 http observables 都將完成並運行它們的邏輯。 結果是否微不足道取決於您在訂閱處理程序中所做的事情。 如果您嘗試更新不再存在的內容,您可能會收到錯誤消息。

提示:訂閱包含一個封閉的布爾屬性,在高級情況下可能很有用。 對於 HTTP,這將在完成時設置。 在 Angular 中,在某些情況下,在 ngDestroy 中設置 _isDestroyed 屬性可能很有用,您的訂閱處理程序可以檢查該屬性。

提示 2:如果處理多個訂閱,您可以創建一個臨時的 new Subscription() 對象並向其添加(...)任何其他訂閱 - 因此,當您取消訂閱主要訂閱時,它也會取消訂閱所有添加的訂閱。

因此,最佳實踐是使用 takeUntil() 並在組件被銷毀時取消訂閱 http 調用。

   import { takeUntil } from 'rxjs/operators';
   .....
   ngOnDestroy(): void {
     this.destroy$.next();  // trigger the unsubscribe
     this.destroy$.complete(); // finalize & clean up the subject stream
   }
var cancellationToken = new CanellationToken();
    cancellationToken.CancelAfter(2000);
    using (var response = await _httpClient.GetAsync("emp", 
        HttpCompletionOption.ResponseHeadersRead, cancellationTokenSource.Token))
    {
        response.EnsureSuccessStatusCode();
        var stream = await response.Content.ReadAsStreamAsync();
        var emp = await JsonSerializer.DeserializeAsync<List<empDto>>(stream, _options);
    }

此外,我們還可以擁有這個“CancellationToken”類,它只是 Http 客戶端方法,它在一定的時間間隔后終止請求。

    • 在角度訂閱.unsubscribe(); 關閉通道並導致 CORE 取消 API 調用者的線程,這很好。
    • 不要使用 await Task.Run(()... 這會創建一個應該被處理的結果/任務,如果沒有,任務會繼續進行,您的模式不允許這樣做 - 這就是它繼續運行的原因。
    • 簡單地說-'await this.YourLongRunningFunction()',我很確定當擁有線程拋出 OperationCancelled 異常時,您的任務將結束。
  1. 如果“3”不起作用,則將取消令牌傳遞給您長時間運行的任務,並在您捕獲 OperationCancelled 異常時設置它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM