2014-01-09 56 views
3

我正在用SignalR 2.0創建一個小聊天應用程序(就像每個人一樣)。什麼時候關閉了來自瀏覽器的SignalR連接

我有一個win8.1應用程序,當應用程序關閉時,集線器收到OnDisconnected事件並從集線器列表中刪除用戶。 集線器發送給用戶已離開聊天的每個客戶端,以便我們可以看到用戶已離開。

但是當我在網頁中使用SignalR和Javascript以及網頁被關閉,該中心沒有得到通知的標籤/瀏覽器關閉...

任何人任何想法連接如何能被關閉?

我所編碼:

創業中心

[assembly: OwinStartup(typeof(ChatServer.Startup))] 

namespace ChatServer 
{ 
public class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     // Map all hubs to "/signalr" 
     app.MapSignalR(); 
    } 
} 
} 

樞紐

[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:

的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客戶

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 
       ) 
     ); 
    } 

我中心不觸發OnDisconnected,當我關閉標籤/瀏覽器/導航到其他網站 該網站是一個燎頁網站(暫時)

我用什麼瀏覽器?
Chrome:版本32.0.1700.68 beta -m
Internet Explorer 11

回答

11

我想你的問題是如何檢測特定用戶是否離開或關閉瀏覽器。當用戶進入或離開時,向其他用戶發送通知。

我認爲問題在於您沒有正確處理OnConnectedOnDisconnected。 要使其工作,首先需要知道連接到集線器的每個客戶端都會傳遞一個唯一的連接ID。您可以在集線器上下文的Context.ConnectionId屬性中檢索此值。當每個客戶進來時,他們通過OnConnected,當他們離開時,他們通過OnDisconnected。下面是一個工作示例:

集線器類

[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(); 
     } 
    } 

查看

<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>:&nbsp;&nbsp;' + encodedMsg + '</strong>:&nbsp;&nbsp;' + 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> 
} 
+0

問題是當瀏覽器被關閉時集線器不會觸發OnDisconnected /用戶導航到另一個頁面或用戶關閉選項卡。即使我調用$ .connection.hub.stop(); Ps:我用一些代碼更新了我的問題。 – brouckaertd

+0

嗨@林,如果我執行你的代碼,我得到這些錯誤:「Uncaught TypeError:Object#沒有方法'連接'」。當我登錄客戶端對象 - > console.log($。connection.ChatHub.client);結果是:Object {}。如果我使用小寫字母c的ChatHub,chathub是undefined – brouckaertd

+0

hi @brouckaertd,我想問題是你的hub類沒有OnConnected函數。我爲你創建了一個類似的聊天功能,看看。 – Lin

4

您可能會運行到這裏描述的問題:https://github.com/SignalR/SignalR/issues/2719

TL;博士:在Chrome Canar中已經修復了Chrome 31中引入的錯誤y,這可以防止SignalR立即觸發OnDisconnected。

如果你是這樣,你可以使用我在問題中建議的解決方法,即將以下內容添加到您的JS代碼中。

window.onbeforeunload = function (e) { 
    $.connection.hub.stop(); 
}; 

即使有此問題,並沒有我期望SignalR提高OnDisconnected大約35秒的瀏覽器退出託管SignalR頁面後的解決方法。

您能否提供有關哪些瀏覽器遇到此問題以及在何種情況下的更多詳細信息? (例如關閉標籤,關閉窗口,刷新,導航到同一站點上的另一個頁面,導航到不同的站點等)

+0

之間有什麼區別我已經爲我的問題添加了一些代碼和信息。 當我使用$ .connection.hub.stop();集線器不會觸發OnDisconnected。即使當我等待35秒或更長時間。 – brouckaertd