簡體   English   中英

使用canceltoken取消異步任務

[英]cancel async task using cancellationtoken

我希望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()注冊的方法canceltk.Register()未記錄相應的文本“ CANCELLING ...”)。

實際上,根本沒有記錄任何文本。 我不知道為什么。

如果在調用executeSelectQueryAsync之前使用Thread.Sleep(5000)並在這5秒鍾內中止請求,則TaskCanceledException被成功引發並捕獲。

Task.Run計划在不受AS.NET同步上下文控制的線程池線程上執行該代碼。 這就是HttpContext.Current為null的原因。

除此之外,在這種情況下, Task.Run導致將請求的執行轉移到另一個線程池線程,請求處理線程(另一個線程池線程)返回到池中,並且當Task.Run完成執行時,該線程為返回到線程池線程,並檢索另一個線程並填充請求處理數據。 您只是使用了更多資源而沒有收益。 恰恰相反。

轉義ASP.NET上下文的代碼不應依賴它。

Oracle提供程序不支持異步操作嗎?

該方法實際上被很好地調用,但是System.Web.HttpContext.Current然后具有空值,導致未捕獲到異常。

通過替換為System.Web.Hosting.HostingEnvironment.MapPath ,代碼可以成功運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM