你如何在客户端(使用JavaScript)取消一个正在运行的AJAX长时间运行的MVC操作?

8 浏览
0 Comments

你如何在客户端(使用JavaScript)取消一个正在运行的AJAX长时间运行的MVC操作?

我有一个长时间运行的(4-10秒)MVC动作,通过一个AJAX调用来运行一个报告。在它运行的同时,用户可以更改参数并运行其他操作,因此在发起另一个请求之前,我会取消AJAX请求。

所以,例如(使用jQuery的例子,但是无论如何都会发生这个问题):

// 如果我们有一个活动请求,并且它尚未完成
if(dataRequest && dataRequest.readyState != 'complete') 
{
    dataRequest.abort();
}
dataRequest = $.ajax(...);

客户端上看起来这个方法运行良好,但是被取消的请求仍然在服务器上运行。例如,如果报告需要10秒,我取消一个请求并开始另一个请求,那么第二个请求需要20秒。

我认为这是由于会话级别的锁定引起的:

[如果]对同一个会话进行两个并发请求(使用相同的SessionID值),第一个请求将独占会话信息。第二个请求只有在第一个请求完成后才执行。

因此,第二个请求在第一个请求完成之前无法访问会话。使用异步MVC动作似乎无法解决此问题,因为该动作仍然需要能够对会话进行更改。

是否可能在不使用AsyncController[SessionState(SessionStateBehavior.ReadOnly)]的情况下停止一个动作并启动下一个动作?

如果不可能,这两个都是必需的吗?

0
0 Comments

问题的原因是ASP.Net sessions无法处理乐观并发,因此如果一个请求在执行时,其他请求必须等待。解决方法是编写自己的会话处理程序,并定期检查是否仍然连接到客户端。

以下是解决方法的代码示例:

public class CustomSessionHandler : IHttpHandler, IRequiresSessionState

{

public void ProcessRequest(HttpContext context)

{

// 检查是否仍然连接到客户端

if (!context.Response.IsClientConnected)

{

// 取消请求

context.Response.End();

}

else

{

// 继续处理请求

// ...

}

}

public bool IsReusable

{

get { return false; }

}

}

在这个示例中,我们创建了一个名为CustomSessionHandler的自定义会话处理程序。在ProcessRequest方法中,我们检查Response的IsClientConnected属性。如果客户端不再连接,我们结束响应,取消请求。否则,我们继续处理请求。

请注意,检查IsClientConnected属性可能会对性能产生影响。因此,在使用时应谨慎使用。

希望以上代码示例能够帮助你解决问题!

0
0 Comments

问题的原因是,当在客户端取消AJAX长时间运行的MVC操作时,使用.abort()方法只能在客户端取消。如果想要在服务器端监控取消操作,可以通过轮询IsClientConnected属性来获取AJAX通信的状态。

解决方法是,使用.poll()方法来监控IsClientConnected属性,并根据其状态来判断AJAX通信的状态。具体实现可以参考问题的原始提问和已经得到的回答。需要注意的是,使用IsClientConnected属性可能会导致严重的性能问题,因为检查该属性可能需要占用较长的时间。

以下是原始回答中的一段代码示例:

var xhr = $.ajax({
    url: "yourUrl",
    type: "POST",
    data: "yourData",
    success: function(result) {
        // handle success
    },
    error: function(xhr, status, error) {
        if (status === "abort") {
            // handle cancellation
        } else {
            // handle other errors
        }
    }
});
// cancel the AJAX request
xhr.abort();

希望这个解决方法能够帮助到你。

0
0 Comments

问题的出现的原因:需要在客户端(javascript)取消一个长时间运行的MVC操作。

解决方法:在服务器端关联每个任务一个唯一的id,并在启动新任务时将此任务id返回给客户端。然后,当在客户端调用.abort()取消AJAX请求时,可以向其他控制器动作发出另一个AJAX请求,并传递唯一的任务id。这个控制器动作本身将设置一个公共标志,指示第一个操作停止。

TPL具有内置的取消支持,可以简化这一过程,以避免两个任务之间的共享数据结构来进行同步。

已经使用TPL来执行大部分耗时的工作,以并行方式执行大约25秒的长时间运行代码,而在4-10秒内完成。然而,使用它来处理中止似乎是重新发明轮子;为什么新的请求需要告诉旧的(仍在运行)请求中止,当它已经被取消了?

不是新的请求告诉旧的请求中止。你必须发送一个特殊的新的AJAX请求,告诉服务器中止处理特定的任务。当你执行dataRequest.abort()时,只是中止了AJAX请求,但是如果你想中止服务器端的处理,就需要做更多的工作。

IIS知道请求在传输层被取消了吗?当在传输层中断等待的连接时,我希望IIS/ASP级别的页面线程会被中止。

IIS确实知道-我只需要在长时间运行的页面中检查Response.IsClientConnected属性。当该属性变为false时,我取消正在进行的操作。

0