【问题标题】:cancel async task using cancellationtoken使用 canceltoken 取消异步任务
【发布时间】:2018-08-21 13:26:21
【问题描述】:

我希望 Web 应用程序的用户能够取消服务器端长时间运行的 SQL 查询(通过使用 xhr.abort() 方法)

我正在使用Response.ClientDisconnectedToken 在服务器端捕获用户取消请求的事件(来自这里:https://stackoverflow.com/a/17713153/8790102)

SQL 查询例程在 async 方法中完成(来自这里:https://stackoverflow.com/a/24834029/8790102)

private async Task<DataTable> executeSelectQueryAsync(string SQL, Dictionary<string, object> BindObject = null)
{
    // This cancellationToken is tripped when the client abort the request
    CancellationToken canceltk = HttpContext.Current.Response.ClientDisconnectedToken; // Require IIS 7.5

    DataTable dt = new DataTable();

    // Only line to be logged in the server
    File.AppendAllText(System.Web.HttpContext.Current.Server.MapPath("~/data/logCanceledRequest.txt"), "CANCELING ENABLED" + Environment.NewLine);

    try
    {
        dt = await Task.Run(() =>
        {
            // If token is canceled, cancel SQL query
            canceltk.Register(() =>
            {
                File.AppendAllText(System.Web.HttpContext.Current.Server.MapPath("~/data/logCanceledRequest.txt"), "CANCELLING..." + Environment.NewLine);
                // scmd is of type OracleCommand
                if (scmd.Connection.State == ConnectionState.Open)
                    scmd.Cancel();
            });

            // Open the connection, execute the SQL command using OracleDataAdapter.Fill method and return a DataTable
            return executeSelectQuery_inner(SQL, BindObject);
        }, canceltk);
    }
    catch (TaskCanceledException ex)
    {
        try
        {
            File.AppendAllText(System.Web.HttpContext.Current.Server.MapPath("~/data/logCanceledRequest.txt"), "Cancelling query..." + Environment.NewLine);
            if(scmd.Connection.State == ConnectionState.Open)
                scmd.Cancel();
        }
        catch (Exception ex1)
        {
            File.AppendAllText(System.Web.HttpContext.Current.Server.MapPath("~/data/logCanceledRequest.txt"), "Cancel_ERROR:" + ex1.ToString() + Environment.NewLine);
        }
    }
    catch (Exception ex)
    {
        File.AppendAllText(System.Web.HttpContext.Current.Server.MapPath("~/data/logCanceledRequest.txt"), "OTHER EXCEPTION:" + ex.ToString() + Environment.NewLine);
    }

    return dt;
}

我的问题是在中止请求时没有调用canceltk.Register()中注册的方法(没有记录相应的文本“CANCELLING...”)。

事实上,根本没有记录任何文本。我不知道为什么。

如果我在调用executeSelectQueryAsync 之前使用Thread.Sleep(5000) 并在这5 秒内中止请求,那么TaskCanceledException 会成功引发并捕获。

【问题讨论】:

  • 非本地数据库命令对象总是让我紧张。我们可以看看executeSelectQuery_inner 的样子吗?
  • 与手动记录而不是使用编写良好的记录库一样(即紧张)。由于不保持日志文件打开并准备好写入,您会产生相当大的开销。
  • 同意,特别是因为手动记录是问题的原因 - 请参阅下面的答案!
  • 是的,是时候选择一个合适的日志库了(这样您就可以在需要时使用它,并且如果您做对了,即使工作正常,也可以保留日志代码,准备好下次有问题要调查)

标签: c# asp.net async-await cancellationtokensource cancellation-token


【解决方案1】:

Task.Run 安排在不受 AS.NET 同步上下文控制的线程池线程上执行该代码。这就是HttpContext.Current 为空的原因。

此外,在这种情况下,Task.Run 导致请求的执行被转移到另一个线程池线程,请求处理线程(另一个线程池线程)被返回到池中,当Task.Run 完成执行该线程返回到线程池线程,并检索另一个线程并填充请求处理数据。您只是使用了更多资源而没有任何好处。恰恰相反。

转义 ASP.NET 上下文的代码不应依赖它。

Oracle 提供程序不支持异步操作吗?

【讨论】:

  • ODP.NET 确实提供了这样的异步方法,尽管它们 are not async。我真正需要的是并行,而不是异步,以便能够取消SQL 查询。在性能方面使用 Oracle 的异步操作会更好吗?是否仍然可以取消查询?如何进行?感谢您的帮助!
  • 如果您需要并行性,Task.Run 是一个不错的选择,但您不应依赖其中的任何 ASP.NET。只需检索数据。你有很多关于甲骨文的问题。我不知道如何回答他们。
【解决方案2】:

该方法实际上调用得很好,但是 System.Web.HttpContext.Current 然后有一个空值,导致未捕获异常。

通过替换为System.Web.Hosting.HostingEnvironment.MapPath,代码运行成功。

【讨论】:

    猜你喜欢
    • 2017-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多