这是一个很好的做法,无论操作是否很长,总是在我的操作中添加CancellationToken?
我目前正在将其添加到每个操作中,但我不知道它是对还是错。
[Route("api/[controller]")]
public class DummiesController : Controller
{
private readonly AppDbContext _dbContext;
public DummyController(AppDbContext dbContext)
{
_dbContext = dbContext;
}
[HttpGet("{id}")]
public async Task<ActionResult<Dummy>> GetAsync(int id, CancellationToken ct) // <<----- should I always do this?
{
var dummy = await _dbContext.Dummies.AsNoTracking().SingleOrDefaultAsync(e=>e.Id == id, ct);
if (dummy == null) return NotFound();
return dummy;
}
}
还要添加CancellationToken ct = default(CancellationToken)
吗?
答案 0 :(得分:3)
我应该始终向我的控制器操作中添加CancellationToken吗?
不。您不应该始终如此。
在ASP.NET Core MVC控制器中使用CancellationTokens
https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/
这是否正确,将取决于您的应用。 如果 请求修改状态,那么您可能不想暂停执行 方法中途。另一方面,如果请求没有 副作用,那么您可能想停止 费用),请尽快采取行动。
因此,如果您有如下所示的方法/操作(简化);
await ProcessOrder();
await UpdateInventory();
您不希望在处理订单时取消订单,这样可以完成订单,但是如果用户通过隧道并失去Internet连接,则不会更新库存。
答案 1 :(得分:2)
如果您对外部资源有任何依赖性,则值得添加。
假设您的数据库繁忙,或者您为数据库连接设置了临时错误处理/重试策略。如果最终用户在浏览器中按下Stop键,则取消令牌将帮助(在您的代码中)所有等待操作正常地取消。
少考虑正常情况下的长期运行特性,但考虑不到理想情况下的长期运行特性,例如如果运行在Azure上并且您的SQL数据库正在进行例行维护,并且实体框架配置为重试自身(假定实体框架对取消令牌做出明智的响应)。
作为旁注:Polly弹性框架对外部取消令牌提供了出色的支持,以协调来自外部取消的重试取消。他们的Wiki值得一读,因为它可以很好地协调取消活动:https://github.com/App-vNext/Polly/wiki
关于CancellationToken ct = default(CancellationToken)
,在库代码上可能比在Controller操作上更有价值。但是,如果您要直接对控制器进行单元测试但又不想传递取消令牌,则非常方便。话虽这么说,与现在直接测试控制器操作相比,.net core的WebHostBuilder testframework更易于测试。
答案 2 :(得分:0)
我认为取消令牌应该主要用于查询类型的操作。 以CRUD(Create、Read、Update、Delete)操作为例,基于CQRS(Command Query Responsibility Segregation)进行分解。
可以看到,对于Query操作,随时取消都不是问题。但是对于 Command,您很可能不想取消任何操作。例如Create,假设您正在为2个独立的数据库创建数据,然后中途取消,会导致数据不同步。