您可以使用 SignalR 将跟踪消息从服务器端直接发送到浏览器中的“进度窗口”。
Dino Esposito 在 msdn 上写了一个 article,用进度条做了类似的事情。
这样您就不需要从进度窗口轮询服务器,也不需要在轮询请求之间使用 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 调用来调用 home 控制器中名为 RunProcess 的方法。它将传递 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");
}