繁体   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