我们应该将 CancellationToken 与 MVC/Web API 控制器一起使用吗?

Posted

技术标签:

【中文标题】我们应该将 CancellationToken 与 MVC/Web API 控制器一起使用吗?【英文标题】:Should we use CancellationToken with MVC/Web API controllers? 【发布时间】:2013-10-01 09:29:33 【问题描述】:

异步控制器有不同的示例。其中一些在方法定义中使用了 CancellationToken:

public async Task<ActionResult> ShowItem(int id, CancellationToken cancellationToken)

    await Database.GetItem(id, cancellationToken);
    ...

但其他示例甚至 VS2013 的默认 ASP.NET 项目根本不使用 CancellationToken 并且没有它也可以工作:

public async Task<ActionResult> ShowItem(int id)

    await Database.GetItem(id);
    ...

尚不清楚,我们是否应该在控制器中使用 CancellationToken(以及为什么)。

【问题讨论】:

【参考方案1】:

你应该使用它。目前它仅适用于if you have an AsyncTimeout,但未来的 MVC/WebAPI 版本可能会将令牌解释为“超时客户端断开连接”。

【讨论】:

Web API 的情况在取消令牌和断开连接的客户端方面是否发生了变化? @DrewNoakes:AFAIK 它还没有。我相信这将在 ASP.NET vNext 中得到解决。 我刚刚在 VS 2015 下对其进行了测试,在浏览器中点击停止确实触发了取消令牌。 如何将取消令牌从 C# Web 客户端传递到 Get API 方法?如何将取消令牌序列化为 URL 字符串? @eesh:我根本不会尝试。相反,请考虑在触发取消令牌时让客户端关闭其连接;并让服务器将取消令牌作为参数(由 WebAPI 自动提供并在连接断开时取消)。【参考方案2】:

你可以用这个

public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)

    CancellationToken disconnectedToken = Response.ClientDisconnectedToken;
    using (var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken))
    
        IEnumerable<ReportItem> items;
        using (ApplicationDbContext context = new ApplicationDbContext())
        
            items = await context.ReportItems.ToArrayAsync(source.Token);
        
        return View(items);
    

取自here。

【讨论】:

你必须处理 LinkedTokenSource 因为它永远不会被 GC 收集,它会导致内存泄漏。 MSDN:请注意,完成后必须在链接的令牌源上调用 Dispose。 msdn.microsoft.com/en-us/library/dd997364.aspx 根据参考,需要这个过程才能使取消令牌与MVC 5一起工作; “...出于某种原因,MVC 5 仅在您使用 AsyncTimeout 属性时才支持取消。”。文章指出“在 ASP.NET Core MVC 和 Web API 中,一切都按预期工作......”。即,如果您使用的是 .NET Core,那么您只需要照常传递 CancellationToken。【参考方案3】:

用户可以随时取消对您的网络应用程序的请求,方法是点击浏览器上的停止或重新加载按钮。通常,您的应用程序将继续生成响应,即使 Kestrel 不会将其发送给用户。如果您有一个长时间运行的操作方法,那么您可能希望检测何时取消请求并停止执行。

您可以通过将 CancellationToken 注入到您的操作方法中来执行此操作,该操作方法将自动绑定到请求的 HttpContext.RequestAborted 令牌。您可以像往常一样检查此令牌是否取消,并将其传递给任何支持它的异步方法。如果请求被取消,会抛出 OperationCanceledException 或 TaskCanceledException。

下面的链接详细解释了这种情况。

https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/

【讨论】:

和 SPA 中的 ajax 请求?

以上是关于我们应该将 CancellationToken 与 MVC/Web API 控制器一起使用吗?的主要内容,如果未能解决你的问题,请参考以下文章

我应该如何使用 DataflowBlockOptions.CancellationToken?

我应该何时调用 CancellationToken.ThrowIfCancellationRequested?

C# CancellationToken 如何与 SqlConnection.OpenAsync(token) 一起使用?

如何使用 CancellationToken 属性?

如何取消 CancellationToken

CancellationToken 取消机制