我有一个长时间运行(4-10秒)的MVC操作,它运行来自AJAX调用的报告。虽然它正在运行的用户可以更改参数并运行其他内容,所以我在再创建一个AJAX请求之前取消它。
因此,例如(jQuery中的示例,但无论如何都会出现问题):
// If we have an active request and it's not complete
if(dataRequest && dataRequest.readyState != 'complete')
{
dataRequest.abort();
}
dataRequest = $.ajax(...);
客户端这似乎工作正常,但取消的请求仍在服务器上运行。例如,如果报告需要10秒,我取消一个并启动另一个,那么第二个请求需要20秒。
我认为这是由于session level locking:
[If]为同一个会话发出两个并发请求(使用 相同的SessionID值),第一个请求获得独占访问权限 会话信息。第二个请求仅在执行后执行 第一个请求已经完成。
因此第二个请求无法访问会话,直到第一个请求完成。使用异步MVC操作似乎并没有解决这个问题,因为操作仍然需要能够对会话进行更改。
是否可以停止一个操作并在不使用AsyncController
或[SessionState(SessionStateBehavior.ReadOnly)]
的情况下开始下一个操作?
如果不是都需要?
答案 0 :(得分:4)
[SessionState(SessionStateBehavior.ReadOnly)]
或完全禁用会话足以允许从同一会话并发访问控制器操作。所以第二个请求(来自同一个会话)不需要在处理之前等待第一个请求完成。至于取消服务器上的第一个操作,那就更难了。您必须将每个任务与唯一ID相关联,并在启动新任务时将此任务ID返回给客户端。然后,当您通过调用.abort()
取消客户端上的AJAX请求时,您可以触发另一个AJAX请求到其他控制器操作并将其传递给唯一的任务ID。此控制器操作本身将设置一些公共标志以指示要停止的第一个操作。
TPL具有内置的取消支持,您可以对其进行简化,以避免在同步它们的2之间存在共享数据结构。
答案 1 :(得分:4)
事实证明,完整的答案需要两件事:
首先(感谢Darin confirming it)会话本质上会锁定要一个接一个地执行的页面。 Further investigation指出这是ASP.Net会话的一个更普遍的问题 - 他们只是无法处理乐观并发。
其次,取消的请求需要检查客户端是否仍然连接。在某些情况下,您可能希望继续(例如火灾并忘记ASP操作)但在这种情况下,如果客户端不再等待报告,那么我们就没有必要继续处理它。
这是以property of the response:this.Response.IsClientConnected
因此,为了在jQuery请求时有效取消我的服务器端操作,我必须编写自己的会话处理程序并对this.Response.IsClientConnected
添加定期检查。
答案 2 :(得分:1)
.abort()只是客户端取消。如果要在服务器端监视它,那么执行此操作的一个好方法是轮询 IsClientConnected 属性,该属性将告诉您ajax通信的状态。