我正在开发基于 MVC3 的 Web 应用程序,该应用程序有时需要缓存来自某个外部数据库的大量数据。过程大约需要 10-30 分钟(取决于流量)所以我把它放在 BackgroundWorker 中。当您单击网页上的特定按钮时,使用 ajax 它只是访问 Controller 中的其他方法,根据返回值在用户界面上显示适当的信息。
Controller :
if (IsDbLocked())
{
return this.Json(new
{
success = false,
message = "There is already an update requested by other user on the way."
});
}
this.model.DataUpdateBegin();
return this.Json(new { success = true });
型号:
public void DataUpdateBegin()
{
var backgroundWorker = new BackgroundWorker
{
WorkerSupportsCancellation = false,
WorkerReportsProgress = true
};
backgroundWorker.DoWork += this.DataUpdateWorkerDoWork;
backgroundWorker.ProgressChanged += this.DataUpdaterWorkerProgressChanged;
backgroundWorker.RunWorkerCompleted += this.DataUpdaterWorkerRunWorkerCompleted;
if (this.DataUpdateLockDb(true))
{
backgroundWorker.RunWorkerAsync();
}
}
现在当我更新时,UI 仍然卡住。在调试 Controller 时我可以看到,它启动了 BackgroundWorker 并立即继续返回语句(成功 = true),但随后它就完成了,没有其他任何事情发生(返回的消息永远不会到达网页)。
我可以看到来自其他浏览器/用户的页面并且一切正常,但是这个特定的线程被锁定了几分钟(不是整个 10-30 分钟,因为它在大约 5 分钟后被解锁 - 超时?)
我的问题是,我做错了什么以及如何解决它。我希望 backgroundWorker 只在后台运行,并且用户可以自由地在页面中随意移动。另外在数据库中创建一个条目并创建一些外部应用程序只是获取它并完成所有工作(在真实后台)对我来说不是一个选择。
最佳答案
不要像这样使用后台 worker 。是的,工作将在另一个线程中完成,但仍在该 Web 请求的范围内。 Web 请求不会存活 30 分钟,有很多事情可能会出错(超时、应用程序池重启、其他 IIS 行为......)
如果你有这种类型的长时间运行的任务,你应该在一些 worker 中完成它 - Windows 服务,也许是控制台应用程序等,你只需从 Web 启动它(控制台)或将其设置为完成(消息队列, 蔚蓝队列)
此外,我希望您没有锁定数据库(您使用 IsDbLocked() 方法)30 分钟?只需在事务中进行导入并使用适当的隔离级别(读取已提交),这样数据库就可以一直正常工作,并且在导入完成后立即进行更改。
关于c# - MVC3 应用程序中的 BackgroundWorker 卡住 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18274786/