[英]How to cancel .Net Core Web API request using Angular?
我有以下两个应用程序
我正在使用 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方法中使IsCancellationRequested为true ,因此操作将继续进行。
[注意]:即使我使用邮递员拨打电话,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 客户端方法,它在一定的时间间隔后终止请求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.