从服务器端取消Mvc Jquery Ajax请求
从服务器端取消Mvc Jquery Ajax请求
我有一个场景,需要从数据库中执行搜索操作,并在网页上显示结果。用户有一个Web表单,可以在Sql Server
数据库中键入和搜索食物。所以在这里,我想取消之前正在进行的搜索操作,并继续进行新的搜索。
例如,用户首先键入茶,并使用Ajax
将请求发送到Mvc ActionResult
。所以现在请求正在处理中,用户键入加牛奶的茶,所以此时我想取消之前的请求,并继续进行新的请求。
我有以下Jquery
代码来发送请求到Mvc ActionResult
并具有abort()
功能。
var xhr = null; function searchFood(o, q, f) { if(xhr && xhr.readyState != 4){ console.log(xhr); xhr.abort(); } xhr = $.ajax({ type: "GET", url: "/food/foodsearch/", data: { o: o, q: q, filters: f }, beforeSend: function () { showSpinner(); }, success: function (a) { try { xhr = null; } catch (c) { xhr = null; } }, error: function (a, b, c) { xhr = null; }, }); }
当用户完成输入后,我调用这个searchfood
方法。看一下我的服务器端c#
代码
[HttpGet] [AjaxOnly] public async Taskfoodsearch(int o, string q, string filters, CancellationToken cancellationToken) { CancellationToken disconnectedToken = Response.ClientDisconnectedToken; var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken); //some local veriable declared model.foods = filters.ToLower() == FoodFilterTypes.b_food || filters.ToLower() == all_categories ? await SearchFoodAsync(o, maxLimit, FoodModel.b_food, q, null, null, source.Token) : new List (); } /// /// search foods /// /// /// /// /// /// ///[NonAction] protected async Task > SearchFoodAsync(int offset, int limit, string filters, string q, CancellationToken cancellationToken) { DataTable dtblFood = await LSocialBL.SearchFoodAsync(offset, limit, filters, q, cancellationToken); //--- few more code lines if (dtblFood != null) { foods = dtblFood.ToList
(); //dispose object dtblFood.Dispose(); dtblFood = null; Parallel.ForEach(foods, new ParallelOptions { CancellationToken = cancellationToken }, async (f) => { f.images = await GetFoodImagesAsync(f.id, cancellationToken); }); //for (int i = 0; i < foods.Count; i++) //{ // foods[i].images = await GetFoodImagesAsync(foods[i].id); //} } }
这里我的LSocialBL.SearchFoodAsync
方法执行如下的数据库操作。
我正在执行存储过程来获取结果。
using (IDataReader drdFood = await objSqlDatabase.ExecuteReaderAsync(objSqlCommand, cancellationToken)) { dtblFoods.Load(drdFood); } return dtblFoods;
在这里,我发送取消令牌来取消现有的数据库操作。这对我来说是必要的,因为我有大量的食品数据。我调试了客户端请求,显示如下
我认为这是一个非常简单的场景,所以我搜索了很多关于这个问题的有用链接或示例。我找到了这个,但我不知道这个实现如何帮助我取消数据库操作或取消以前的旧请求。有人能帮我解决这个问题吗?
原因:本文中的代码演示了如何在服务器端取消jQuery Ajax请求。在Step 1中,获取了会话ID,然后在Step 2中使用该会话ID杀死了该会话。在Step 3中,通过运行一段代码来证明SQL请求已被取消。
解决方法:在Step 4中给出了完整的代码示例,其中展示了如何在服务器端取消Ajax请求。代码中创建了一个新的控制台应用程序,然后使用ADO.NET连接到数据库,并执行一些长时间运行的SQL查询。在主函数中,创建了一个异步任务task1来执行长时间运行的SQL查询,然后等待10秒钟。如果任务没有在10秒钟内完成,就使用会话ID杀死该任务。最后,使用Task.WaitAll方法等待所有任务完成。
该解决方法可以通过在数据库中执行KILL命令来取消正在运行的SQL查询,从而取消Ajax请求。
文章如下:
在开发中,我们经常使用jQuery的Ajax方法来向服务器发送请求并获取响应。但有时候我们可能需要在服务器端取消Ajax请求。本文将介绍如何在服务器端使用MVC取消jQuery Ajax请求。
首先,我们需要获取Ajax请求的会话ID。以下是获取会话ID的代码:
Select @ ;
接下来,我们可以使用会话ID来取消Ajax请求。以下是取消Ajax请求的代码:
Kill 50 ;
如果我们运行上面的代码,将会得到如下错误信息:
Cannot continue the execution because the session is in the kill state.
severe error occurred on the current command. The results, if any, should be discarded.
上面的代码演示了如何取消Ajax请求,但我们也可以将其封装成一个完整的代码示例。以下是完整的代码示例:
using System; using System.Data.SqlClient; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { SqlConnection connection = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True;;Connection Timeout=0"); connection.Open(); var SPID = GetSPID(connection); var task1 = new Task(() => doLongSql(connection), TaskCreationOptions.LongRunning); task1.Start(); Thread.Sleep(1000 * 10);//wait 10 seconds if (!task1.IsCompleted) { KillSPID( SPID); } Task.WaitAll(task1); } static int GetSPID(SqlConnection connection) { SqlCommand command = new SqlCommand("Select @ ",connection); int SPID = Convert.ToInt32( command.ExecuteScalar()) ; return SPID; } static void KillSPID( int SPID) { SqlConnection connection = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True;"); connection.Open(); SqlCommand command = new SqlCommand($"KILL {SPID}", connection); command.ExecuteNonQuery(); connection.Close(); } static void doLongSql(SqlConnection connection) { using (connection) { SqlCommand command = new SqlCommand( "WAITFOR DELAY '01:00'", //wait 1 minute connection); command.ExecuteNonQuery(); } } } }
上面的代码示例中,我们创建了一个新的控制台应用程序,并使用ADO.NET连接到数据库。然后,我们执行了一些长时间运行的SQL查询。在主函数中,我们创建了一个异步任务task1来执行长时间运行的SQL查询,然后等待10秒钟。如果任务没有在10秒钟内完成,我们就使用会话ID来取消该任务。最后,我们使用Task.WaitAll方法等待所有任务完成。
这样,我们就可以在服务器端取消Ajax请求了。
参考资料:
- [Session ID of ADO.NET connection](https://social.msdn.microsoft.com/Forums/sqlserver/en-US/94692d7b-69c6-4c34-a1dd-495c652e7d9d/session-id-of-adonet-connection?forum=sqldataaccess)
- [KILL (Transact-SQL) - SQL Server | Microsoft Docs](https://learn.microsoft.com/en-us/sql/t-sql/language-elements/kill-transact-sql?view=sql-server-2017#using-with-statusonly)
- [Terminating Long Running SQL Queries](https://forums.ni.com/t5/Example-Program-Drafts/Terminate-Stop-or-Kill-Long-Running-SQL-Server-Query/ta-p/3493642)
- [Options for Killing All Connections for a Database](https://www.itprotoday.com/microsoft-sql-server/theres-more-one-way-kill-database-connection)
- [Attention events can cause open transactions and blocking in SQL Server – Pankaj Mittal [MSFT]](https://blogs.msdn.microsoft.com/pamitt/2010/11/07/attention-events-can-cause-open-transactions-and-blocking-in-sql-server/)
- [How to: Cancel a Task and Its Children | Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-cancel-a-task-and-its-children)
在这段代码中,问题的原因是在服务器端取消了正在进行的JQuery Ajax请求。解决方法是使用CancellationTokenSource和CancellationToken来控制任务的取消。
在代码中,当接收到客户端断开连接的信号时,通过调用tokenSource1.Cancel()和tokenSource2.Cancel()来取消正在进行的任务。这样,在下一次循环迭代时,任务会检查Cancellation Token的状态,并在必要时终止任务。
整个过程可以描述如下:
1. 在foodsearch方法中,根据传入的参数进行一些初始化操作。
2. 创建两个Cancellation Token Source对象,分别用于控制任务的取消。
3. 使用Task.Factory.StartNew方法创建一个新的任务,并在其中调用SearchFoodAsync方法。
4. 在任务中,等待SearchFoodAsync方法完成,并将gotResult标记为true。
5. 在while循环中,检查是否接收到客户端断开连接的信号。
6. 如果接收到断开连接的信号,则调用tokenSource1.Cancel()和tokenSource2.Cancel()取消任务。
7. 在循环中,使用Thread.Sleep方法暂停10秒,然后再次检查是否接收到断开连接的信号。
8. 当SearchFoodAsync方法完成或接收到断开连接的信号时,返回PartialView。
通过上述的解决方法,可以在服务器端取消正在进行的JQuery Ajax请求,以避免浪费资源和提高系统性能。
在这个例子中,我使用了ASP.NET MVC 5,并在SQL Profiler和开发者工具的网络选项卡中进行了检查,确认它能够正常工作,数据库服务器也能接收到取消请求并取消查询执行。
问题的原因:在该例子中,用户在文本框中输入内容时,会等待500毫秒来检测用户是否停止输入。如果检测到用户停止输入,就会发送一个ajax请求进行搜索。然而,如果用户重新开始输入,或者输入间隔超过500毫秒,就会取消之前的请求,并且数据库中的查询也会被取消。
解决方法:在Table1Business类中的Search方法中,使用了异步的方式打开数据库连接、执行查询和读取查询结果。在HomeController类中的Search方法中,通过LinkedTokenSource将用户取消请求的token和Response.ClientDisconnectedToken连接到一起。然后在前端的JavaScript代码中,通过判断xhr变量是否为null来判断是否存在其他ajax请求,并在取消请求时调用xhr.abort()方法。此外,所有的方法都需要传递取消请求的token。
在实际应用中,可以根据需要进行更多的优化和改进。
在ASP.NET MVC中,通过前端的JavaScript代码和后端的异步处理,可以实现取消ajax请求的功能。这对于用户体验和减轻服务器负担都非常有帮助。希望对读者有所帮助。