我有一个 MVC4 应用程序,它有一个或两个长时间运行的请求。为此,首先,迭代我将把这些作为同步任务。但是,我希望将这些任务的跟踪输出显示在我的 Web 应用程序的可选“进度”窗口上。
我看到了两个候选解决方案,涉及数据库跟踪侦听器或对会话中存储的“跟踪集合”对象具有权限的跟踪侦听器。然后“进度”窗口可以使用setInterval
Ajax 调用定期轮询这些跟踪存储。
这听起来太简单了,这就是为什么我要问我应该怎么做。有没有更好的方法、既定的模式和技术,还是没有什么价值的练习?
我有一个 MVC4 应用程序,它有一个或两个长时间运行的请求。为此,首先,迭代我将把这些作为同步任务。但是,我希望将这些任务的跟踪输出显示在我的 Web 应用程序的可选“进度”窗口上。
我看到了两个候选解决方案,涉及数据库跟踪侦听器或对会话中存储的“跟踪集合”对象具有权限的跟踪侦听器。然后“进度”窗口可以使用setInterval
Ajax 调用定期轮询这些跟踪存储。
这听起来太简单了,这就是为什么我要问我应该怎么做。有没有更好的方法、既定的模式和技术,还是没有什么价值的练习?
您可以使用SignalR将跟踪消息从服务器端直接发送到浏览器中的“进度窗口”。
Dino Esposito 在 msdn 上写了一篇文章,用进度条做了类似的事情。
这样您就不需要从进度窗口轮询服务器,也不需要使用 Session 来存储轮询请求之间的消息。
已编辑:添加示例
自从那篇文章写完之后,SignalR 发生了一些变化。除了在 global.asax 中注册路由并在视图中包含脚本之外,您还需要以下一段 javascript 来初始化客户端 signalR 代理并添加一个函数来显示进度信息:
<script type="text/javascript">
$(document).ready(function () {
// Create a proxy for the server endpoint
var progressHub = $.connection.progressHub;
$.connection.hub.start();
// Add a client-side callback to process any data
// received from the server
progressHub.client.addProgress = function (message) {
$('#progress').append('<li>' + message + '</li>');
};
});
</script>
假设您在该页面上有一个按钮,可以触发服务器中的长时间运行的进程。为简单起见,我将使用以下 jquery 调用来调用RunProcess
home 控制器中命名的方法。它将传递 SignalR 客户端的 id,以便服务器知道谁需要接收进度数据:
$("#runProcess").click(function () {
var id = $.connection.hub.id;
$.get("/Home/RunProcess/" + id);
});
在服务器端,HomeController 的以下方法将模拟长时间运行的过程。为了使用 SignalR 通知客户端,您需要使用GlobalHost.ConnectionManager.GetHubContext<T>()
. 然后它将需要调用addProgress(message)
已在客户端代理上定义的方法,但仅针对具有接收到的 Id 的客户端:
public void RunProcess(string id)
{
var progressHub = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
progressHub.Clients.Client(id).addProgress("25% completed");
Thread.Sleep(2000);
progressHub.Clients.Client(id).addProgress("50% completed");
Thread.Sleep(3000);
progressHub.Clients.Client(id).addProgress("75% completed");
Thread.Sleep(2000);
progressHub.Clients.Client(id).addProgress("Process Finished");
}