不确定这是否可行,但当用户离开页面转到另一个页面时,我希望当前页面上的所有服务器逻辑都能结束执行。我不希望用户看到来自他们之前所在页面的错误(例如,长时间运行的SQL查询超时)。我该怎么做?
答案 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();
}
}
到目前为止似乎工作......