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)
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)
The SQL query routine is done in an async
method (from here: 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).
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.
The method was in fact well called, but System.Web.HttpContext.Current
then had a null value, causing a Exception not caught.
By replacing with System.Web.Hosting.HostingEnvironment.MapPath
, the code is working successfully.