如何使用 Angular 取消 .Net Core Web API 请求?
Posted
技术标签:
【中文标题】如何使用 Angular 取消 .Net Core Web API 请求?【英文标题】:How to cancel .Net Core Web API request using Angular? 【发布时间】:2020-01-04 20:42:03 【问题描述】:我有以下两个应用程序
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();
上面的代码将cancel请求,我可以在浏览器的Network标签中看到它被取消了,如下所示
但它不会在API的LongRunningProcess方法中使IsCancellationRequested变为true,所以操作会继续进行。
[注意]: API 方法中的 Option 1 和 Option 2 都不起作用,即使我使用 postman 拨打电话。
问题:有没有办法取消那个LongRunningProcess方法的操作?
【问题讨论】:
在同时使用 Kestrel 和 IIS Express 时可能会出现问题。我尝试不使用 IIS Express(请参阅 ***.com/questions/39574061/… 和 ***.com/questions/47153525/…),它按预期完美运行。我得到 IsCancellationRequested = true。 这个问题有答案吗?我有同样的问题。 我稍后没有检查,但如果您阅读我之前的评论可能会有所帮助 【参考方案1】:当角度取消请求时,您可以从 http 上下文中获取取消令牌
CancellationToken cancellationToken = HttpContext.RequestAborted;
if (cancellationToken.IsCancellationRequested)
// The client has aborted the request
【讨论】:
【参考方案2】:在这种情况下你不需要休息,只需要这样使用
[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();
您可以阅读更多here
【讨论】:
感谢您的回复。我已经浏览了上面的博客,它还指出“当检测到 CancellationToken.IsCancellationRequested 属性为 true 时,Task.Delay 调用会引发 TaskCancelledException,立即停止执行。”甚至微软文档都说“ThrowIfCancellationRequested”方法提供了等效于 if (token.IsCancellationRequested)throw new OperationCanceledException(token); 的功能。但问题是取消令牌无法检测到请求被取消。 我会再试一次,并会就此与您联系。【参考方案3】:这是因为您的 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();
【讨论】:
感谢您的回复。在这个问题中,我没有编写代码来在任何任务中传递取消令牌。但在实际代码中,我在循环中放置了一个断点,然后取消了来自客户端的请求并进行了检查。它没有使“IsCancellationRequested”变为“真”。不过,我会再试一次并回复你。 我明白了,那么问题一定出在您调用this.subscription.unsubscribe()
的 Angular 代码中。将围绕它的代码附加到您的问题中怎么样?
我已经在问题中写了一段代码。据我所知,取消任何请求只需要那么多代码。
因为我在您提供的客户端代码中没有发现任何错误,所以我只是怀疑您在其余客户端代码中做了什么。会有问题的。不过也有可能
顺便说一下,Task.Run 就相当于 Task.Factory.StartNew。。 almost【参考方案4】:
除非您在 onDestroy() 中取消订阅,否则当时仍在运行的任何 http observable 都将完成并运行它们的逻辑。结果是否微不足道取决于您在订阅处理程序中所做的事情。如果您尝试更新不再存在的内容,您可能会收到错误消息。
提示:订阅包含一个封闭的布尔属性,在高级情况下可能很有用。对于 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
【讨论】:
通常我用下面的方式(和你说的一样) import Subject from 'rxjs';从 'rxjs/operators' 导入 takeUntil ;私人退订者 = 新主题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 客户端方法。
【讨论】:
以上是关于如何使用 Angular 取消 .Net Core Web API 请求?的主要内容,如果未能解决你的问题,请参考以下文章
Angular + core 如何将文件数组从 Angular 上传到 Dot Net Core
如何使用 .NET Core 2 配置 Angular 6 以允许来自任何主机的 CORS?
asp.net core + angular2 JWT 承载
如何从.net core 2.1 Angular 6模板中的非相对路径导入ts和scss文件