我应该总是将CancellationToken添加到我的控制器操作中吗?

时间:2018-05-14 11:51:17

标签: c# asp.net-core asp.net-core-mvc asp.net-core-webapi

这是一个很好的做法,无论操作是否很长,总是在我的操作中添加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)吗?

3 个答案:

答案 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个独立的数据库创建数据,然后中途取消,会导致数据不同步。