简体   繁体   English

使用canceltoken取消异步任务

[英]cancel async task using cancellationtoken

I would like the users of a web application to be able to cancel long running SQL queries on the server side (by using xhr.abort() method) 我希望Web应用程序的用户能够取消服务器端长期运行的SQL查询(通过使用xhr.abort()方法)

I'm using the Response.ClientDisconnectedToken to catch on the server side the event of the canceling of a request by the user (from here: https://stackoverflow.com/a/17713153/8790102 ) 我正在使用Response.ClientDisconnectedToken在服务器端捕获用户取消请求的事件(来自此处: https : //stackoverflow.com/a/17713153/8790102

The SQL query routine is done in an async method (from here: https://stackoverflow.com/a/24834029/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;
}

My problem is that the method registered in canceltk.Register() is not called when aborting the request (the corresponding text "CANCELLING..." is not logged). 我的问题是中止请求时,不会调用在canceltk.Register()注册的方法canceltk.Register()未记录相应的文本“ CANCELLING ...”)。

In fact, no text is logged at all. 实际上,根本没有记录任何文本。 I have no idea why. 我不知道为什么。

If I use a Thread.Sleep(5000) before calling executeSelectQueryAsync and abort the request during these 5 seconds, then the TaskCanceledException is successfully raised and caught. 如果在调用executeSelectQueryAsync之前使用Thread.Sleep(5000)并在这5秒钟内中止请求,则TaskCanceledException被成功引发并捕获。

Task.Run schedules the execution of that code on a thread pool thread which is not controlled by AS.NET's synchronization context. Task.Run计划在不受AS.NET同步上下文控制的线程池线程上执行该代码。 That's why HttpContext.Current is null. 这就是HttpContext.Current为null的原因。

Besides that, in this context, Task.Run causes the execution of the request to be transferred to another thread pool thread, the request handling thread (another thread pool thread) is returned to the pool and when Task.Run finishes execution that thread is returned to the thread pool thread and another one is retrieved and populated with request handling data. 除此之外,在这种情况下, Task.Run导致将请求的执行转移到另一个线程池线程,请求处理线程(另一个线程池线程)返回到池中,并且当Task.Run完成执行时,该线程为返回到线程池线程,并检索另一个线程并填充请求处理数据。 You just used more resources for no benefit. 您只是使用了更多资源而没有收益。 Quite the contrary. 恰恰相反。

Code that escapes the ASP.NET context should not rely on it. 转义ASP.NET上下文的代码不应依赖它。

Doesn't the Oracle provider support asynchronous operations? Oracle提供程序不支持异步操作吗?

The method was in fact well called, but System.Web.HttpContext.Current then had a null value, causing a Exception not caught. 该方法实际上被很好地调用,但是System.Web.HttpContext.Current然后具有空值,导致未捕获到异常。

By replacing with System.Web.Hosting.HostingEnvironment.MapPath , the code is working successfully. 通过替换为System.Web.Hosting.HostingEnvironment.MapPath ,代码可以成功运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用CancellationToken取消任务? - How to cancel a Task using CancellationToken? 使用CancellationToken取消特定任务 - Cancel Specific Task using CancellationToken 使用CancellationToken取消任务而不显式检查任务? - Using a CancellationToken to cancel a task without explicitly checking within the task? 如何使用CancellationToken安全地取消任务并等待Task.WhenAll - How to safely cancel a task using a CancellationToken and await Task.WhenAll 使用CancellationToken仅取消一项任务 - Cancel ONLY one task with CancellationToken Async Task.Delay CancellationToken - Async Task.Delay CancellationToken 为什么如果我尝试使用CancellationToken.Cancel()停止任务,那么实际任务就会卡在Task.Wait()上? - Why if I try to stop a task using CancellationToken.Cancel() then the actual task get stucked on Task.Wait()? 使用CancellationToken进行异步/等待不会取消操作 - Async/await with CancellationToken doesn't cancel the operation 是否可以在没有CancellationToken的情况下取消C#任务? - Is it possible to cancel a C# Task without a CancellationToken? 使用 ASP.NET Core2.2 中的 CancellationToken 取消内部任务 - Cancel an internal task using CancellationToken in ASP.NET Core2.2
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM