在ASP.NET MVC中检测异步客户端断开连接

给定一个异步控制器:

public class MyController : AsyncController { [NoAsyncTimeout] public void MyActionAsync() { ... } public void MyActionCompleted() { ... } } 

假设MyActionAsync开始需要几分钟的过程。 如果用户现在转到MyAction操作,浏览器将等待连接打开。 如果用户关闭其浏览器,则关闭连接。 是否有可能检测到服务器上发生的情况(最好是在控制器内)? 如果是这样,怎么样? 我已经尝试重写OnException但在这种情况下永远不会触发。

注意:我非常感谢下面的有用答案,但这个问题的关键方面是我正在使用AsyncController 。 这意味着HTTP请求仍然是打开的 (它们像COMET或BOSH一样长寿),这意味着它是一个实时套接字连接。 为什么在此实时连接终止时(即“通过对等方重置连接”,TCP RST数据包)不能通知服务器?

我意识到这个问题已经过时了,但在我寻找相同的答案时经常出现这个问题。 以下详细信息仅适用于.Net 4.5

HttpContext.Response.ClientDisconnectedToken是你想要的。 这将为您提供CancellationToken您可以传递给您的异步/等待调用。

 public async Task Index() { //The Connected Client 'manages' this token. //HttpContext.Response.ClientDisconnectedToken.IsCancellationRequested will be set to true if the client disconnects try { using (var client = new System.Net.Http.HttpClient()) { var url = "http://google.com"; var html = await client.GetAsync(url, HttpContext.Response.ClientDisconnectedToken); } } catch (TaskCanceledException e) { //The Client has gone //you can handle this and the request will keep on being processed, but no one is there to see the resonse } return View(); } 

您可以通过在函数开头放置断点然后关闭浏览器窗口来测试上面的代码段。


另一个片段,与你的问题没有直接关系,但却有用…

您还可以使用AsyncTimeout属性对操作可以执行的时间量设置硬限制。 要使用此function,请添加CancellationToken类型的其他参数。 如果执行时间过长,此令牌将允许ASP.Net超时请求。

 [AsyncTimeout(500)] //500ms public async Task Index(CancellationToken cancel) { //ASP.Net manages the cancel token. //cancel.IsCancellationRequested will be set to true after 500ms try { using (var client = new System.Net.Http.HttpClient()) { var url = "http://google.com"; var html = await client.GetAsync(url, cancel); } } catch (TaskCanceledException e) { //ASP.Net has killed the request //Yellow Screen Of Death with System.TimeoutException //the return View() below wont render } return View(); } 

您可以通过在函数的开头放置一个断点来测试这个(因此在断点被命中时请求需要超过500毫秒)然后让它耗尽。

是不是Response.IsClientConnected工作得相当好? 我刚刚尝试在我的情况下取消大文件上传。 我的意思是,如果客户端中止他们(在我的情况下是Ajax)请求,我可以在我的Action中看到它。 我并不是说它是100%准确但我的小规模测试显示客户端浏览器中止请求,并且Action从IsClientConnected获得正确的响应。

正如@Darin说的那样。 HTTP是无状态协议,这意味着无法(通过使用HTTP)检测客户端是否仍然存在。 HTTP 1.0在每次请求后关闭套接字,而HTTP / 1.1可以将其保持打开一段时间(保持活动超时可以设置为标头)。 HTTP / 1.1客户端关闭套接字(或服务器)并不意味着客户端已经消失,只是套接字已经使用了一段时间。

有一种称为COMET服务器的东西,用于让客户端/服务器继续通过HTTP“聊天”。 在SO或网上搜索彗星,有几种可用的实现。

出于显而易见的原因,无法通知服务器客户端已关闭其浏览器。 或者他去厕所:-)你可以做的是让客户端定期用AJAX请求轮询服务器( window.setInterval ),如果服务器检测到它不再被轮询,则意味着客户端不是那里更长