我是否应该始终将 CancellationToken 添加到我的控制器操作中?

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

无论操作时间长短,始终在我的操作中添加 CancellationToken 这是一个好习惯吗?

我目前正在将它添加到每个动作中,但我不知道它是对还是错。

[ApiController]
[Route("api/[controller]")]
public class DummiesController : ControllerBase
{
    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)
吗?

c# asp.net-core asp.net-core-mvc asp.net-core-webapi cancellation-token
5个回答
54
投票

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

不。你不应该总是。

在 ASP.NET Core MVC 控制器中使用 CancellationTokens
https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/

这是否是正确的行为将取决于您的应用程序。 如果 请求修改状态,那么你可能不想停止执行 方法的中途。另一方面,如果请求没有 副作用,那么你可能想停止(大概 昂贵)尽快行动。

因此,如果您有如下所示的方法/操作(简化);

await ProcessOrder();
await UpdateInventory();

您不想在处理订单时取消订单,如果是这样,订单可以完成,但如果用户穿过隧道,并失去互联网连接,您将不会更新库存。

当操作无法包含在类似工作单元的模式(例如分布式系统)中时,这一点尤其重要,并且应尽量减少取消。


24
投票

如果您对外部资源有任何依赖,则值得添加。

假设您的数据库很忙,或者您为数据库连接设置了瞬时错误处理/重试策略。如果最终用户在浏览器中按下停止按钮,取消令牌将帮助任何等待操作(在您的代码中)优雅地取消。

少考虑正常情况下的长时间运行性质,而考虑在不太理想的情况下长时间运行的性质,例如如果在 Azure 中运行并且您的 SQL 数据库正在进行日常维护,并且实体框架配置为重试自身(假设实体框架明智地响应取消令牌)。

附带说明:Polly 弹性框架对外部取消令牌具有出色的支持,以协调外部取消的重试取消。他们的 wiki 值得一读,因为它让协调取消大开眼界:https://github.com/App-vNext/Polly/wiki

关于

CancellationToken ct = default(CancellationToken)
,库代码可能比控制器操作更有价值。但如果您直接对控制器进行单元测试但不想传递取消令牌,那么这会很方便。话虽如此,现在 .net core 的 WebHostBuilder testframework 比直接测试控制器操作更容易测试。


11
投票

我认为取消令牌应该主要用于查询类型操作。 以CRUD(创建、读取、更新、删除)操作为例,基于CQRS(命令查询职责分离)进行分解。

  • 命令:创建、更新、删除
  • 查询:阅读

可以看到,对于Query操作,随时取消都不会有问题。但对于 Command,您很可能不想取消任何操作。例如Create,假设你正在为2个独立的数据库创建数据,然后中途被取消,就会导致数据不同步。


0
投票

如果您没有使用它 - 既没有检查它,也没有将它传递给其他东西 - 那么它只是一个未使用的变量。

但是如果您正在向网络拨打电话,(这就是您的示例):

他们通常会支持 CancellationToken,你应该利用 - 通过 ASP.NET Core 可以给你的那个。

假设您正在查询的数据库今天非常超载。呼叫将永远持续 -> 您的用户变得不耐烦 -> 不断重试 -> 所有旧呼叫仍在运行 -> 过载变得越来越严重!

如果您通过CancellationToken,那么当您的用户浏览器关闭其连接时,您对慢速远程系统的相关调用将自动结束。

其次,如果您有多阶段或冗长的操作,

您可以在各个阶段之间或在计算循环每隔几次运行后手动检查 CancellationToken。如果用户已停止等待,您可以中止并停止浪费资源。


-1
投票

另一种方法是取消任何操作,而不仅仅是查询操作。

当您在 Windows 上复制文件并按取消按钮时,操作会立即停止。 Web 应用程序也是如此。如果用户按下保存按钮,然后关闭浏览器而不等待操作完成,则保存操作可以立即停止。

对于长时间运行的操作,UI 可能会显示一个带有“请稍候”文本和取消按钮的对话框。这将使行为更加用户友好。

© www.soinside.com 2019 - 2024. All rights reserved.