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

时间:2011-01-23 06:21:25

标签: c# asp.net-mvc asynchronous

给定异步控制器:

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

    public void MyActionCompleted() { ... }
}

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

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

4 个答案:

答案 0 :(得分:25)

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

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

public async Task<ActionResult> 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属性对操作执行的时间进行硬性限制。要使用此用法,请添加类型为CancellationToken的其他参数。如果执行时间过长,此令牌将允许ASP.Net超时请求。

[AsyncTimeout(500)] //500ms
public async Task<ActionResult> 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毫秒)然后让它用完。

答案 1 :(得分:7)

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

答案 2 :(得分:5)

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

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

答案 3 :(得分:0)

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

相关问题