客户想要一个 asp.net 页面,该页面有一个按钮,可以从具有数百条记录的外部源触发数据库更新。这个过程需要很长时间。他还希望在流程运行时更新状态,例如“处理 1000 条记录中的 10 条”。在阅读各种文章时,我正在考虑将数据库更新代码放在 Windows 服务中。我以前从未使用过 Windows 服务,也找不到很多关于如何启动 Windows 服务并从 asp.net 页面轮询它的教程。我的问题是这是处理此过程的最佳方式吗?而且,有没有人有任何例子说明他们是如何做到这一点的?
2 回答
有几种方法可以解决这个问题。
你是对的,在 Web 的工作进程中执行一个长时间运行的任务通常不会很好地结束:它会占用资源,应用程序池可以被回收等等。在我的大多数复杂项目中,我通常会结束最多有 4 个部分:数据库、包含我的模型的 DLL、作为 Windows 服务的“Worker”和 ASP.NET 网站。
“Worker”是一个始终运行的 Windows 服务,它使用Quartz.net执行计划任务,使用的模型与网站使用的模型相同。这些可以是在维护任何复杂的网站时似乎突然出现的各种周期性任务:VacuumExpiredPickTicketsJob
、、、BackupAndFtpDatabaseJob
等等SendBackorderReminderEmailsJob
。
在 C# 中编写 Windows 服务并不困难(Visual Studio 中有一个内置模板,但您几乎可以继承ServiceBase
并参加比赛),并且TopShelf等库使部署它们变得更加容易。
剩下的就是从网站触发更新并将结果传回给用户。这可以像您希望的那样简单或复杂。如果这需要扩展到大量用户,您可能会使用MSMQ之类的东西将更新命令排队到 Windows 服务,然后 Windows 服务会响应该队列。我的印象是,这可能是矫枉过正。
对于少数用户,您可以覆盖服务的OnCustomCommand(int command)
方法作为触发器。ExecuteCommand()
然后,您的网站将使用ServiceController类来启动该过程。您的网站和服务会同意参数值,即“进行更新” 142
(因为历史原因,它必须是 128 到 255 之间的数字)。
至于将进度反馈给客户端,最简单的方法可能是让网页使用计时器和 AJAX 调用来轮询更新的进度数据。你可以喜欢新的东西,比如WebSockets(我写这篇文章时最前沿的东西)和长轮询,但常规轮询只适用于不需要扩展的东西。
希望这可以帮助!
除了 Nicholas 的彻底回答之外,另一种选择是将后端进程部署为命令行脚本,并安排它们通过 Window 的内置任务调度程序运行,这在 Windows Server 2008+ 中得到了相当大的改进。或者,您可以使用任何其他主机的任务调度程序应用程序。
我发现与标准 Windows 服务相比,命令行方法更容易让 MIS 员工理解和配置,以及迁移到新服务器。