【问题标题】:Can't cancel Async Action in MVC无法取消 MVC 中的异步操作
【发布时间】:2017-09-27 21:17:11
【问题描述】:

在我看来,我有两个按钮,一个调用 Start() 操作,一个调用 Stop()。这是控制器的外观:

public class TestController : AsyncController
{
    public static CancellationTokenSource cts = new CancellationTokenSource();

    public void StartAsync()
    {
        cts = new CancellationTokenSource();
        CancellationToken cancellationToken = cts.Token;
        AsyncManager.OutstandingOperations.Increment();

        AsyncManager.Parameters["task"] = Task.Factory.StartNew(() =>
        {
            try
            {
                while() {
                    if (cancellationToken.IsCancellationRequested)
                        break;

                    // Do stuff
                }
            }
            finally
            {
                AsyncManager.OutstandingOperations.Decrement();
            }
        }, cancellationToken);
    }

    public ActionResult StartCompleted(Task task)
    {
        try
        {
            task.Wait();
            return Json(new { success = true }, JsonRequestBehavior.AllowGet);
        }
        catch (Exception e)
        {
            return Json(new { success = false }, JsonRequestBehavior.AllowGet);
        }
    }

    public void StopAsync()
    {
        cts.Cancel();
    }

    public ActionResult StopCompleted()
    {
        return Json(new { success = true }, JsonRequestBehavior.AllowGet);
    }
}

但是当我单击停止按钮时,只有在开始完成后才会调用停止操作。我应该如何停止操作?

【问题讨论】:

    标签: c# asp.net-mvc asynchronous


    【解决方案1】:

    引自 Pro .NET Performance 一书:

    取消已经执行的工作需要执行该工作的代码的合作。但是,尚未开始执行的任务可以完全取消而不会产生任何不良后果。

    这意味着在Task lambda 本身中,您需要检查工作是否已被取消并采取相应措施。例如:

    if (cts.IsCancellationRequested) return;
    

    您是否正在检查取消请求?

    更新

    检查需要在// Do stuff 部分中的某个位置。因此,例如,如果您将复杂的多部分计算作为一项任务运行,您必须遍历数百个项目,进行一些处理并在最后返回一些结果,您可以在循环的每次迭代开始时检查取消.

    或者另一个例子,如果在你的任务中你正在使用一些支持取消的 API(比如 HttpClient.GetAsync),那么你必须将你的 CancellationToken 传递给该 API 的适当重载。

    【讨论】:

    • 值得明确指出此if 语句需要在带有// Do stuff 注释的代码块中。
    • 我正在检查取消请求,更新了代码以反映这一点。但这里的主要问题是 Stop 永远不会被调用。
    【解决方案2】:

    我需要使用

    [SessionState(SessionStateBehavior.ReadOnly)]
    

    允许我的控制器异步处理请求。由于我使用的是 MVC 2 并且该属性不可用,因此我必须创建一个自定义路由处理程序。 Serdar 对这个问题的回答帮助了我:Disable Session state per-request in ASP.Net MVC

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-14
    • 2022-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多