如何在用户离开页面时取消所有逻辑的执行?

时间:2011-07-28 13:03:51

标签: c# asp.net

不确定这是否可行,但当用户离开页面转到另一个页面时,我希望当前页面上的所有服务器逻辑都能结束执行。我不希望用户看到来自他们之前所在页面的错误(例如,长时间运行的SQL查询超时)。我该怎么做?

3 个答案:

答案 0 :(得分:1)

执行长时间运行的查询需要多长时间?我可能会专注于优化该部分和应用程序的整体设计。

如果您正在DataGrid中加载数据,并且您调用调用数据层的业务逻辑来从数据库加载一大块数据,如果查询速度很快并且您的服务器端确实执行了查询,同时用户关闭浏览器或导航,结果将不会被消耗,因为没有页面可以加载并再渲染该数据。

如果你真的有足够的持久性服务器端操作,你想控制和中止,这取决于应用程序导航我认为这些操作不应该同步执行,我会异步监视这些操作,只需在页面中显示结果用户打开这样的页面。

答案 1 :(得分:1)

您可以使用Response.IsClientConnected了解您的客户是否仍在阅读您的信息页。

if (!Response.IsClientConnected)
{
     // Stop
}

我同意您需要专注于避免长时间运行的循环,让您的用户继续前进,但如果您想知道您的用户是否仍在您的页面上,您可以使用上述命令。您可以随时调用它来查看它。

答案 2 :(得分:0)

我的网站http://www.iprotein.info遇到了同样的问题。基本上,它在SQL数据库的大型数据集(300 k)上运行,并进行复杂的计算,如果查询很大,可能需要一些时间。当我把这个网站放在网上时,我发现一些用户发布了任务,但决定不等待计算并离开页面,而服务器一直在计算,直到完成。这导致严重的CPU拥塞,浪费CPU时间放弃任务。

所以我的解决方案是:

控制器为每个新页面分配唯一的ID。

private static ConcurrentDictionary<int, CancellationTokenSource> tasks = new ConcurrentDictionary<int, CancellationTokenSource>();

    private static TaskID taskID = new TaskID();
const int taskCap = 10000;

public IActionResult SearchPage()
        {
            lock (taskID)
            {
                if (taskID.id > taskCap)
                    taskID.id = 0;
                ViewBag.taskID = taskID.id;
                taskID.id++;
            }
            return View();
        }

客户端告诉服务器哪个任务将被ID终止:

$(window).unload(function () {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("GET", '@Url.Action("CancelTask")', true);
    xmlHttp.send(@ViewBag.taskID);
});

型号:

public class TaskID
    {
        public int id;
        public TaskID()
        {
            id = 0;
        }
    }

在搜索调用上,指定CancellationTokenSource以允许取消任务,并将其存储在具有线程ID的静态映射中。 _SearchAction()是真正的事情。

[HttpPost]
        public JsonResult SearchAction(string query, int instanceID)
        {           
            lock (tasks)
            {
                tasks[instanceID] = new CancellationTokenSource();
            }
            CancellationToken ct = tasks[instanceID].Token;
            var searchTask = Task.Factory.StartNew(() => _SearchAction(query, instanceID, ct));
            JsonResult res;
            try
            {
                res = searchTask.Result;
            }
            catch (OperationCanceledException)
            {
                res = null;
            }
            lock (tasks)
            {
                CancellationTokenSource temp;
                tasks.Remove(instanceID, out temp);
                temp.Dispose();
            }
            return res;
        }

收到CancelTask​​调用时,取消任务:

public void CancelTask(int id)
        {
            if (interactionCache.ContainsKey(id))
            {
                List<Tuple<int, int>> list;
                interactionCache.Remove(id, out list);
            }
            if (tasks.ContainsKey(id) && tasks[id] != null)
            {
                tasks[id].Cancel();
            }
        }

到目前为止似乎工作......