使用 cancellationtoken 取消异步任务
cancel async task using cancellationtoken
我希望 Web 应用程序的用户能够在服务器端取消长 运行 SQL 查询(通过使用 xhr.abort()
方法)
我正在使用 Response.ClientDisconnectedToken
在服务器端捕获用户取消请求的事件(来自此处:)
SQL 查询例程在 async
方法中完成(来自此处:)
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
将被成功引发并捕获。
该方法实际上调用得很好,但是System.Web.HttpContext.Current
然后有一个空值,导致未捕获异常。
通过替换为 System.Web.Hosting.HostingEnvironment.MapPath
,代码运行成功。
Task.Run
安排在不受 AS.NET 的同步上下文控制的线程池线程上执行该代码。这就是 HttpContext.Current
为空的原因。
除此之外,在这个上下文中,Task.Run
导致请求的执行被转移到另一个线程池线程,请求处理线程(另一个线程池线程)被返回到池中并且当Task.Run
完成执行,线程返回到线程池线程,另一个线程被检索并填充请求处理数据。你只是毫无意义地使用了更多的资源。恰恰相反。
转义 ASP.NET 上下文的代码不应依赖它。
Oracle 提供程序不支持异步操作吗?
我希望 Web 应用程序的用户能够在服务器端取消长 运行 SQL 查询(通过使用 xhr.abort()
方法)
我正在使用 Response.ClientDisconnectedToken
在服务器端捕获用户取消请求的事件(来自此处:)
SQL 查询例程在 async
方法中完成(来自此处:)
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
将被成功引发并捕获。
该方法实际上调用得很好,但是System.Web.HttpContext.Current
然后有一个空值,导致未捕获异常。
通过替换为 System.Web.Hosting.HostingEnvironment.MapPath
,代码运行成功。
Task.Run
安排在不受 AS.NET 的同步上下文控制的线程池线程上执行该代码。这就是 HttpContext.Current
为空的原因。
除此之外,在这个上下文中,Task.Run
导致请求的执行被转移到另一个线程池线程,请求处理线程(另一个线程池线程)被返回到池中并且当Task.Run
完成执行,线程返回到线程池线程,另一个线程被检索并填充请求处理数据。你只是毫无意义地使用了更多的资源。恰恰相反。
转义 ASP.NET 上下文的代码不应依赖它。
Oracle 提供程序不支持异步操作吗?