javascript 何时从浏览器关闭与 SignalR 的连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21031160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When is the connection closed with SignalR from browser
提问by brouckaertd
I'm making a little chat application with SignalR 2.0 (just like everyone).
我正在用 SignalR 2.0 制作一个小聊天应用程序(就像每个人一样)。
I have a win8.1 application and when the application is closed, the hub receives the OnDisconnected event and removes the user from the list on the hub. The hub sends to every client that the user has left the chat, so we can visualize that the user has left.
我有一个 win8.1 应用程序,当应用程序关闭时,集线器接收 OnDisconnected 事件并从集线器上的列表中删除用户。集线器向每个客户端发送用户离开聊天的消息,因此我们可以想象用户已经离开。
But when I'm using SignalR and Javascript in a webpage and the page gets closed, the hub doesn't get notified that the tab/browser is closed...
但是,当我在网页中使用 SignalR 和 Javascript 并且页面关闭时,集线器不会收到选项卡/浏览器已关闭的通知...
Anyone any idea how the connection can be closed?
任何人都知道如何关闭连接?
What i've coded:
我编码的内容:
Startup Hub
启动中心
[assembly: OwinStartup(typeof(ChatServer.Startup))]
namespace ChatServer
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Map all hubs to "/signalr"
app.MapSignalR();
}
}
}
Hub
中心
[HubName("ChatHub")]
public class ChatHub : Hub
{
private static List<User> Users = new List<User>();
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message, DateTime.Now);
}
public void UserConnected(string name)
{
Clients.Caller.connected(JsonConvert.SerializeObject(Users));
User user = new User() { Name = name, ConnectionID = Context.ConnectionId };
Clients.Others.userConnected(JsonConvert.SerializeObject(user));
Users.Add(user);
}
public void UserLeft()
{
if(Users.Any(x=>x.ConnectionID == Context.ConnectionId))
{
User user = Users.First(x => x.ConnectionID == Context.ConnectionId);
Users.Remove(user);
Clients.Others.userLeft(JsonConvert.SerializeObject(user), Context.ConnectionId);
}
}
public override System.Threading.Tasks.Task OnDisconnected()
{
// Only called when win8.1 app closes
// Not called when browsers closes page
UserLeft();
return base.OnDisconnected();
}
}
HTML - Javascript:
HTML - Javascript:
Javascript:
Javascript:
chat = new function () {
var ChatHub;
// Connecting to the hub
this.attachEvents = function () {
if ($.connection != null) {
ChatHub = $.connection.ChatHub;
$.connection.hub.start({ transport: 'auto' }, function () {
// Register client on hub
ChatHub.server.userConnected("web name");
});
}
this.send = function (name,message) {
if ($.connection != null) {
//Send chat message
ChatHub.server.send(name, message).fail(function (e) {
alert(e);
});
}
}
}
};
window.onbeforeunload = function (e) {
//This is called when we close the page
$.connection.hub.stop();
return "You killed me! :'(";
};
Win8.1 client
Win8.1客户端
internal async void ConnectToHub(string userName)
{
try
{
HubConnection hubConnection = new HubConnection(SERVER_PROXY);
chat = hubConnection.CreateHubProxy("ChatHub");
Context = SynchronizationContext.Current;
MakeHubFunctionsAvailableOnClient();
await hubConnection.Start();
// Register client on hub
await chat.Invoke("UserConnected", userName);
}
catch (Exception)
{
throw;
}
}
private void MakeHubFunctionsAvailableOnClient()
{
//Receive chat messages
chat.On<string, string, DateTime>("broadcastMessage",
(name, message, date) => Context.Post(
delegate {
Messages.Add(new UserMessage() { Message = message, User = name, Date = date });
}, null
)
);
//Receive all online users
chat.On<string>("connected",
(users) => Context.Post(
delegate
{
List<User> userList = JsonConvert.DeserializeObject<List<User>>(users);
foreach (User user in userList)
{
Users.Add(user);
}
Messages.Add(new UserMessage() { Message = "CONNECTED", User = "System", Date = DateTime.Now });
}, null
)
);
//New user connected
chat.On<string>("userConnected",
(user) => Context.Post(
delegate
{
User newUser = JsonConvert.DeserializeObject<User>(user);
Users.Add(newUser);
Messages.Add(new UserMessage() { Message = newUser.Name + " CONNECTED", User = "System", Date = DateTime.Now });
}, null
)
);
//User left, remove user from list on client
chat.On<string>("userLeft",
(user) => Context.Post(
delegate
{
User newUser = JsonConvert.DeserializeObject<User>(user);
User y = Users.First(x=>x.ConnectionID == newUser.ConnectionID);
bool ux = Users.Remove(y);
Messages.Add(new UserMessage() { Message = newUser.Name + " left the conversation", User = "System", Date = DateTime.Now });
}, null
)
);
}
My hub doesn't trigger OnDisconnected, when i close tab / browser / navigating to other site The site is a singe page website (for the moment)
当我关闭选项卡/浏览器/导航到其他站点时,我的集线器不会触发 OnDisconnected 该站点是一个单页网站(目前)
What browser am i using?
Chrome: Version 32.0.1700.68 beta-m
Internet Explorer 11
我使用的是什么浏览器?
Chrome:版本 32.0.1700.68 beta-m
Internet Explorer 11
回答by Lin
I guess your question is how to detect whether a specific user left or closed the browser. When a user comes in or leaves, send a notification to other users.
我想您的问题是如何检测特定用户是离开还是关闭了浏览器。当用户进入或离开时,向其他用户发送通知。
I think the problem is you didn't handle OnConnected
and OnDisconnected
properly.
To make it work, first you need to know each client connecting to a hub passes a unique connection id. You can retrieve this value in the Context.ConnectionId property of the hub context. When each client comes in, they go through OnConnected
, when they leave, they go through OnDisconnected
. Below is a working example:
我认为这个问题是你没有处理好OnConnected
和OnDisconnected
正确。要使其工作,首先您需要知道连接到集线器的每个客户端都传递一个唯一的连接 ID。您可以在中心上下文的 Context.ConnectionId 属性中检索此值。每个客户进来时,他们通过OnConnected
,当他们离开时,他们通过OnDisconnected
。下面是一个工作示例:
Hub Class
集线器类
[HubName("ChatHub")]
public class ChatHub : Hub
{
private static List<User> Users = new List<User>();
public void Send(string message)
{
var name = Context.User.Identity.Name;
Clients.All.broadcastMessage(name, message, DateTime.Now.ToShortDateString());
}
public override Task OnConnected()
{
User user = new User() { Name = Context.User.Identity.Name, ConnectionID = Context.ConnectionId };
Users.Add(user);
Clients.Others.userConnected(user.Name);
return base.OnConnected();
}
public override Task OnDisconnected()
{
if (Users.Any(x => x.ConnectionID == Context.ConnectionId))
{
User user = Users.First(x => x.ConnectionID == Context.ConnectionId);
Clients.Others.userLeft(user.Name);
Users.Remove(user);
}
return base.OnDisconnected();
}
}
View
看法
<input type="text" id="message" />
<button class="btn">Send</button>
<ul id="contents"></ul>
@section scripts
{
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.signalR-2.0.1.js"></script>
<script src="/signalr/hubs"></script>
<script>
var chatHub = $.connection.ChatHub;
chatHub.client.broadcastMessage = function (name, message, time) {
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
var encodedTime = $('<div />').text(time).html();
$('#contents').append('<li><strong>' + encodedName + '</strong>: ' + encodedMsg + '</strong>: ' + encodedTime + '</li>');
};
chatHub.client.userConnected = function (data) {
$('#contents').append('<li>Wellcome<strong>' + '</strong>:' + data + '</li>');
};
chatHub.client.userLeft = function (data) {
$('#contents').append('<li>Bye<strong>' + '</strong>:' + data + '</li>');
};
$(".btn").on("click", function() {
chatHub.server.send($("#message").val());
});
$.connection.hub.start().done(function() {
console.log("connected...");
});
</script>
}
回答by halter73
You might be running into the issue described here: https://github.com/SignalR/SignalR/issues/2719
您可能会遇到此处描述的问题:https: //github.com/SignalR/SignalR/issues/2719
tl;dr: There is a bug introduced in Chrome 31 that is already fixed in Chrome Canary, that prevents SignalR from immediately trigger OnDisconnected.
tl; dr:Chrome 31 中引入了一个已在 Chrome Canary 中修复的错误,该错误阻止 SignalR 立即触发 OnDisconnected。
If you are, you can use the workaround I suggested in the issue which is to add the following to your JS code.
如果是,您可以使用我在问题中建议的解决方法,即将以下内容添加到您的 JS 代码中。
window.onbeforeunload = function (e) {
$.connection.hub.stop();
};
Even with this bug and without the workaround I would expect SignalR to raise OnDisconnected approximately 35s after the browser exits the page hosting SignalR.
即使有这个错误并且没有解决方法,我也希望 SignalR 在浏览器退出托管 SignalR 的页面后大约 35 秒引发 OnDisconnected。
Can you provide more details about which browsers you are experiencing this issue with and in what situations? (e.g. closing the tab, closing the window, refreshing, navigating to another page on the same site, navigating to a different site, etc.)
您能否提供有关您在哪些浏览器以及在什么情况下遇到此问题的更多详细信息?(例如关闭选项卡、关闭窗口、刷新、导航到同一站点上的另一个页面、导航到不同站点等)