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

问题描述 投票:0回答:6

我有以下两个应用程序

  • 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();

上面的代码将取消请求,我可以在浏览器的网络选项卡中看到它被取消,如下所示

enter image description here

但不会在 API 的 LongRunningProcess 方法中将 IsCancellationRequested 设为 true,因此操作将继续进行。

[注意]: 即使我使用 postman 进行调用,API 方法中的 Option 1Option 2 都不起作用。

问题:有什么办法可以取消那个LongRunningProcess方法的运行吗?

c# angular asp.net-core asp.net-core-2.0 asp.net-core-webapi
6个回答
0
投票

在这种情况下你不需要中断,只需像这样使用

 [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();
 }

您可以在这里阅读更多内容


0
投票
这是因为你的虚拟长操作没有监控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(); }
    

0
投票
当时仍在运行的任何 http observables 将完成并运行它们的逻辑,除非您在 onDestroy() 中取消订阅。后果是否微不足道将取决于您在订阅处理程序中执行的操作。如果您尝试更新不再存在的内容,您可能会收到错误。

提示:订阅包含一个封闭的布尔属性,在高级情况下可能很有用。对于 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 }
    

0
投票
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 客户端方法,它会在一定时间间隔后终止请求。


0
投票
当角度取消请求时,您可以从http上下文获取取消令牌

[HttpGet] [Route("LongRunningProcess")] public async Task<IActionResult> LongRunningProcess(CancellationToken cancellationToken) { // Combine the provided cancellation token with the HttpContext.RequestAborted token CancellationToken combinedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, HttpContext.RequestAborted).Token; try { // Dummy long operation using combined cancellation token await Task.Run(() => { for (int i = 0; i < 10; i++) { // Option 1: Check if cancellation is requested if (combinedToken.IsCancellationRequested) break; // Option 2: Throw an exception if cancellation is requested combinedToken.ThrowIfCancellationRequested(); Thread.Sleep(6000); // Simulating long-running task } }, combinedToken); } catch (OperationCanceledException e) { Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}"); return StatusCode(499); // Custom status code for canceled request } return Ok("Operation completed successfully."); }
    

-1
投票
    • 在角度订阅中。unsubscribe();关闭通道并导致 CORE 取消 API 调用者的线程,这很好。
    • 不要使用await Task.Run(()...这会创建一个应该被处理的结果/任务,如果没有,任务会继续执行,您的模式不允许这样做 - 这就是它继续运行的原因。
    • 简单地 - 'await this.YourLongRunningFunction()',我非常确定当所属线程抛出 OperationCancelled 异常时,您的任务将结束。
  1. 如果“3”不起作用,则将取消令牌传递给长时间运行的任务,并在捕获 OperationCancelled 异常时进行设置。
© www.soinside.com 2019 - 2024. All rights reserved.