SignalR 消息被发送到每个打开的页面实例。如何只发送给确切的一个?
SignalR message being sent to every opened page instance. How to send to only exact one?
这个问题已经回答了很多次了,但我还是没明白。
我正在使用此页面中的示例:https://www.codeproject.com/Articles/1124691/SignalR-Progress-Bar-Simple-Example-Sending-Live-D
但是,我稍微修改了 SendProgress
方法,只将消息发送到特定连接,而不是所有客户端:
public static void SendProgress(string connectionId, string progressMessage, int progressCount, int totalItems)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<RealTimeProgressBar.ProgressHub>();
var percentage = (progressCount * 100) / totalItems;
hubContext.Clients.Client(connectionId).AddProgress(progressMessage, percentage + "%");
}
我正在从覆盖的 OnConnected 方法中获取连接 ID:
public override Task OnConnected()
{
Environments.ConnectionId = Context.ConnectionId;
return base.OnConnected();
}
我目前将其存储在静态 class Environments
中,我想有更好的方法,但我还不知道 :)
问题是,当我在浏览器中打开我的网页的两个实例时,所有这些实例的进度条仍然显示,尽管这些页面上的 connectionIds 不同(在 SendProgress
函数)。
这里有什么问题?
也许,我应该在 js 代码中更改一些内容?
$(function () {
// Reference the auto-generated proxy for the hub.
var progress = $.connection.progressHub;
console.log(progress);
// Create a function that the hub can call back to display messages.
progress.client.AddProgress = function (message, percentage) {
ProgressBarModal("show", message + " " + percentage);
$('#ProgressMessage').width(percentage);
if (percentage == "100%") {
ProgressBarModal();
}
};
$.connection.hub.start().done(function () {
var connectionId = $.connection.hub.id;
console.log(connectionId);
});
});
因为我不太确定 js funcs 是否真的使用 Environments.ConnectionId
或其他东西..
谢谢!
编辑:我想要实现的是为每个打开的页面发送唯一的进度条。例如当我按下第一页上的按钮时,我开始收集数据,进度条反映了这一点。我还在浏览器中打开另一个页面,并从另一个来源收集数据,因此进度条也应该反映该页面的情况。
我的控制器方法:
public ActionResult Generate(InputDataViewModel viewModel, string connectionId)
{
...
var Tasks = getResultsWithProgressBar(viewModel.jobId, connectionId);
...
return RedirectToAction("Details", new { id = job.JobDataId });
}
在这个 "getResult" 中的某处是一个实际调用进度条的函数 (SendProgress)
您的更改应该可以正常工作。
您使用的是静态 ConnectionId,因此只有您上次使用的浏览器,即您上次打开(或上次连接)的浏览器才能看到进度条和更新。
除了添加静态 Environment.ConnectionId 之外,这是我制作的唯一一个。
//PUSHING DATA TO ALL CLIENTS
// hubContext.Clients.All.AddProgress(progressMessage, percentage + "%");
hubContext.Clients.Client(Environments.ConnectionId).AddProgress(progressMessage, percentage + "%");
因此,如果您打开 10 个浏览器 windows 并单击所有这些浏览器上的按钮,一个接一个,只有您最初最后打开的浏览器会看到进度条和更新,但是 它将看到来自单个进度条上显示的所有 10 个浏览器的更新!
虽然很有趣!
当我尝试您的代码时,我看到了您最初观察到的行为。但是当我打开两个独立的隐身浏览器时,我看到了正确的行为。关闭 IIS Express 站点,重建并重试。
编辑:
如果您需要每个选项卡都有自己的进度条,那么您将需要以下两种方法之一:
一种识别哪个rest请求来自哪个connectionId的方法。如果您想继续使用当前代码。只需将连接 ID 传递给 LongRunningProcess。客户端代码如下:
var progress = $.connection.progressHub;
var connectionId = $.connection.hub.id;
$.getJSON("/Home/LongRunningProcess",
{"connectionId":connectionId},
function (data) {
if (!data) {
alert("Success");
}
else
{
alert(data);
}
});
服务器代码为:
public JsonResult LongRunningProcess(string connectionId)
{
//THIS COULD BE SOME LIST OF DATA
int itemsCount = 100;
for (int i = 0; i <= itemsCount; i++)
{
//SIMULATING SOME TASK
Thread.Sleep(500);
//CALLING A FUNCTION THAT CALCULATES PERCENTAGE AND SENDS THE DATA TO THE CLIENT
Functions.SendProgress(connectionId, "Process in progress...", i , itemsCount);
}
return Json("", JsonRequestBehavior.AllowGet);
}
另一种选择是在服务器上调用 signalr 方法而不是 rest 方法。在 ProgressHub 中创建一个新的 hub 方法,如下所示:
public void LongRunningHubMethod()
{
//THIS COULD BE SOME LIST OF DATA
int itemsCount = 100;
for (int i = 0; i <= itemsCount; i++)
{
//SIMULATING SOME TASK
Thread.Sleep(500);
//CALLING A FUNCTION THAT CALCULATES PERCENTAGE AND SENDS THE DATA TO THE CLIENT
Functions.SendProgress(Context.ConnectionId, "Process in progress...", i, itemsCount);
}
}
然后客户端只需在点击时调用集线器方法,如下所示:
var progress = $.connection.progressHub;
var connectionId = $.connection.hub.id;
progress.invoke('LongRunningHubMethod');
这个问题已经回答了很多次了,但我还是没明白。
我正在使用此页面中的示例:https://www.codeproject.com/Articles/1124691/SignalR-Progress-Bar-Simple-Example-Sending-Live-D
但是,我稍微修改了 SendProgress
方法,只将消息发送到特定连接,而不是所有客户端:
public static void SendProgress(string connectionId, string progressMessage, int progressCount, int totalItems)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<RealTimeProgressBar.ProgressHub>();
var percentage = (progressCount * 100) / totalItems;
hubContext.Clients.Client(connectionId).AddProgress(progressMessage, percentage + "%");
}
我正在从覆盖的 OnConnected 方法中获取连接 ID:
public override Task OnConnected()
{
Environments.ConnectionId = Context.ConnectionId;
return base.OnConnected();
}
我目前将其存储在静态 class Environments
中,我想有更好的方法,但我还不知道 :)
问题是,当我在浏览器中打开我的网页的两个实例时,所有这些实例的进度条仍然显示,尽管这些页面上的 connectionIds 不同(在 SendProgress
函数)。
这里有什么问题?
也许,我应该在 js 代码中更改一些内容?
$(function () {
// Reference the auto-generated proxy for the hub.
var progress = $.connection.progressHub;
console.log(progress);
// Create a function that the hub can call back to display messages.
progress.client.AddProgress = function (message, percentage) {
ProgressBarModal("show", message + " " + percentage);
$('#ProgressMessage').width(percentage);
if (percentage == "100%") {
ProgressBarModal();
}
};
$.connection.hub.start().done(function () {
var connectionId = $.connection.hub.id;
console.log(connectionId);
});
});
因为我不太确定 js funcs 是否真的使用 Environments.ConnectionId
或其他东西..
谢谢!
编辑:我想要实现的是为每个打开的页面发送唯一的进度条。例如当我按下第一页上的按钮时,我开始收集数据,进度条反映了这一点。我还在浏览器中打开另一个页面,并从另一个来源收集数据,因此进度条也应该反映该页面的情况。
我的控制器方法:
public ActionResult Generate(InputDataViewModel viewModel, string connectionId)
{
...
var Tasks = getResultsWithProgressBar(viewModel.jobId, connectionId);
...
return RedirectToAction("Details", new { id = job.JobDataId });
}
在这个 "getResult" 中的某处是一个实际调用进度条的函数 (SendProgress)
您的更改应该可以正常工作。
您使用的是静态 ConnectionId,因此只有您上次使用的浏览器,即您上次打开(或上次连接)的浏览器才能看到进度条和更新。
除了添加静态 Environment.ConnectionId 之外,这是我制作的唯一一个。
//PUSHING DATA TO ALL CLIENTS
// hubContext.Clients.All.AddProgress(progressMessage, percentage + "%");
hubContext.Clients.Client(Environments.ConnectionId).AddProgress(progressMessage, percentage + "%");
因此,如果您打开 10 个浏览器 windows 并单击所有这些浏览器上的按钮,一个接一个,只有您最初最后打开的浏览器会看到进度条和更新,但是 它将看到来自单个进度条上显示的所有 10 个浏览器的更新!
虽然很有趣!
当我尝试您的代码时,我看到了您最初观察到的行为。但是当我打开两个独立的隐身浏览器时,我看到了正确的行为。关闭 IIS Express 站点,重建并重试。
编辑: 如果您需要每个选项卡都有自己的进度条,那么您将需要以下两种方法之一:
一种识别哪个rest请求来自哪个connectionId的方法。如果您想继续使用当前代码。只需将连接 ID 传递给 LongRunningProcess。客户端代码如下:
var progress = $.connection.progressHub; var connectionId = $.connection.hub.id; $.getJSON("/Home/LongRunningProcess", {"connectionId":connectionId}, function (data) { if (!data) { alert("Success"); } else { alert(data); } });
服务器代码为:
public JsonResult LongRunningProcess(string connectionId)
{
//THIS COULD BE SOME LIST OF DATA
int itemsCount = 100;
for (int i = 0; i <= itemsCount; i++)
{
//SIMULATING SOME TASK
Thread.Sleep(500);
//CALLING A FUNCTION THAT CALCULATES PERCENTAGE AND SENDS THE DATA TO THE CLIENT
Functions.SendProgress(connectionId, "Process in progress...", i , itemsCount);
}
return Json("", JsonRequestBehavior.AllowGet);
}
另一种选择是在服务器上调用 signalr 方法而不是 rest 方法。在 ProgressHub 中创建一个新的 hub 方法,如下所示:
public void LongRunningHubMethod() { //THIS COULD BE SOME LIST OF DATA int itemsCount = 100; for (int i = 0; i <= itemsCount; i++) { //SIMULATING SOME TASK Thread.Sleep(500); //CALLING A FUNCTION THAT CALCULATES PERCENTAGE AND SENDS THE DATA TO THE CLIENT Functions.SendProgress(Context.ConnectionId, "Process in progress...", i, itemsCount); } }
然后客户端只需在点击时调用集线器方法,如下所示:
var progress = $.connection.progressHub;
var connectionId = $.connection.hub.id;
progress.invoke('LongRunningHubMethod');