SignalR 聊天室實例詳解(服務器端推送版)

翻譯自:http://www.codeproject.com/Articles/562023/Asp-Net-SignalR-Chat-Room  (在這裏能夠下載到實例的源碼)
javascript

Asp.Net SignalR 聊天室html

 

簡單介紹:
        最近微軟向ASP.NET Web Application Framework中添加了不少的新特性,SignalR是其中比較顯著的特性之一,它是用來建立實時的應用程序的,例如:社交應用(social application)、多人遊戲、新聞天氣等,在實時的應用程序中,一旦內容能夠產生立刻就會被推送給用戶,它爲遠程呼叫(remote procedure calls)提供一個asp.net API,用來在服務器端經過.net代碼調用一個客戶端瀏覽器中的js方法。java

       web應用程序經過請求處理模型來工做,瀏覽器或者其餘的代理髮送一個請求,而後服務器端爲請求提供相應在這個模型當中,服務器在沒有被請去I的時候不能作出響應,然而在實時的應用程序服務器上,最新的可用內容會被推送到客戶端你能夠經過使用ASP.NET SignalR API 來達到這一特性jquery


        爲了解釋 SignalR Web API ,在這篇文章中,我會建立一個能夠羣組聊天也能夠私聊的聊天程序,你須要用VS2012 來建立這個項目
你在這個網站能夠獲取更多的信息http://www.asp.net/signalrweb

 

 

讓咱們開始吧:
        在VS中建立一個新的應用程序項目(web application project ),建立好了之後,右鍵——添加新項——選擇SignalR Hub Class ,命名以後點擊添加按鈕,它會自動添加 Hub 類,須要的引用,還有腳本。瀏覽器

 

 

 

 


註冊Hub URL
爲了使用SignalR API,咱們須要註冊 ~/signalr/hubs URL,在你的解決方案中添加global.asax文件,在Application_Start方法中用RouteTable.Routes.MapHubs()來註冊 Hub URL緩存

 public class Global : System.Web.HttpApplication
 {
    protected void Application_Start(object sender, EventArgs e)
    {
        // Register the default hubs route: ~/signalr/hubs
        RouteTable.Routes.MapHubs();
    }服務器

 }    app

 

 

Hub 類
ChatHub 類必須繼承自Microsoft.AspNet.SignalR.Hub 類,Hub 類暴露出一些屬性和方法,你能夠經過Clients屬性與保持連接的客戶端交流
你能夠獲得正在調用方法使用Contextde 客戶端的信息,你也能夠經過Groups屬性來管理組。asp.net

public abstract class Hub : IHub, IDisposable
{
  public HubConnectionContext Clients { get; set; }
  public HubCallerContext Context { get; set; }
  public IGroupManager Groups { get; set; }

  public virtual Task OnConnected();       
  public virtual Task OnDisconnected();      
  public virtual Task OnReconnected();

}

 

 

子類能夠重寫Onconnected,OnDisconnected方法,這個對事件觸發一些動做是很是有用的,ChatHub 類是Hub類的子類,在接下來的部分咱們來討論它們的方法
 public class ChatHub : Hub
 {
    public void Connect(string userName);

    public void SendMessageToAll(string userName, string message);

    public void SendPrivateMessage(string toUserId, string message);

    public override System.Threading.Tasks.Task OnDisconnected();

    .
    .
    .

 }   
客戶端在他想進入聊天室的時候會調用Connect方法,調用SendMessageToAll方法,他能夠向聊天室中保持鏈接的全部人
經過調用 SendPrivateMessage 方法,key與單獨的一個客戶端聊天

 

 


客戶端的代理(Proxy)

在項目中添加index.html 頁面,引用JQuery,SignalR、還有自動生成的hubs(?不知道這個指什麼)

 <script src="http://www.codeproject.com/Scripts/jquery-1.8.2.min.js%22%3E%3C/script>

 <!--Reference the SignalR library. -->
 <script src="http://www.codeproject.com/Scripts/jquery.signalR-1.0.0.js%22%3E%3C/script>

 <!--Reference the autogenerated SignalR hub script. -->
 <script src="http://www.codeproject.com/signalr/hubs%22%3E%3C/script>

 

 

 


在客戶端,你須要建立一個hub 代理(hub proxy)並啓動它,一能夠經過$.connection.yourHubClass來建立它$.connection.hub.start() 來啓動它
 <script type="text/javascript">

  $(function () {

     // Declare a proxy to reference the hub.
     var chatHub = $.connection.chatHub;

     registerClientMethods(chatHub);

     // Start Hub
     $.connection.hub.start().done(function () {

        registerEvents(chatHub)

     });

  });

 </script>   
在這裏咱們須要注意的是自動生成的Hub proxy的命名方法,咱們在服務器端用Camel命名法給ChatHub類命名,可是在客戶端咱們獲得的是用little camel 方式命名的,就像$.connection.chatHub

 

 


鏈接到聊天室


用戶成功的連接以後發送他的名稱就能夠鏈接到聊天室,咱們會給他發送一個列表,和一些存在咱們程序中的最近的聊天記錄在ChatHub類中的第一個方法就是Connect

public void Connect(string userName)
 {
    var id = Context.ConnectionId;

    if (ConnectedUsers.Count(x => x.ConnectionId == id) == 0)
    {

        ConnectedUsers.Add(new UserDetail { ConnectionId = id, UserName = userName });

        // send to caller
        Clients.Caller.onConnected(id, userName, ConnectedUsers, CurrentMessage);

        // send to all except caller client
        Clients.AllExcept(id).onNewUserConnected(id, userName);
    }
 }   

 


經過Context.ConnectionId屬性拿到調用Connect方法的用戶的鏈接Id,在已有的連接列表彙總覈對是否已經存在該用戶的連接,如今咱們還要作兩件事,首先,咱們要將已鏈接的客戶端的列表和最近的聊天記錄發送給想要連接的客戶端,而後咱們要同通知其餘的用戶有新人加進來了,咱們能夠經過Clients.Caller屬性來很方便的調用想要鏈接到聊天室的客戶端的方法:

 // send to caller
  Clients.Caller.onConnected(id, userName, ConnectedUsers, CurrentMessage);

 

 


要通知其餘的連接在聊天室的人,可是咱們又不想調用新加入的人的方法,能夠用Clients的AllExcept屬性,它能夠按照你的意願來排除一些客戶端
// send to all except caller client
 Clients.AllExcept(id).onNewUserConnected(id, userName);    

 

定義/發佈 你在服務器端調用的客戶端的方法,作法是聲明Clients.Caller.onConnected(...) 和 Clients.AllExcept(id).onNewUserConnected(...)
???You can define your methods using chatHub.client.yourMethodName at client side.

 

// Calls when user successfully logged in
 chatHub.client.onConnected = function (id, userName, allUsers, messages) {

    .
    .
    .

 }

 // On New User Connected
 chatHub.client.onNewUserConnected = function (id, name) {

    AddUser(chatHub, id, name);
 }    

 


用chatHub.server.yourMethod聲明, 在客戶端,你能夠調用服務器端的方法。
chatHub.server.connect(name); 

 

 

在聊天室中發送消息:
在出聊天室中,用戶輸入的消息會廣播給全部正在鏈接中的用戶,在服務器端的ChatHub類中,寫用Clients.All.messageReceived來寫 SendMessageToAll方法,
messageReceived是一個客戶端的方法。

 public void SendMessageToAll(string userName, string message)
 {
    // store last 100 messages in cache
    AddMessageinCache(userName, message);

    // Broad cast message
    Clients.All.messageReceived(userName, message);
 }   

 


在客戶端引起messageReceived 方法,這個方式只是簡單的用JQuery將消息加入到聊天區域

chatHub.client.messageReceived = function (userName, message) {

    AddMessage(userName, message);
 }   

 

 

在寫好了客戶端和服務器端的方法之後,如今咱們要在客戶端來註冊按鈕的點擊事件,在用戶點擊按鈕的時候,就會調用服務器端的sendMessageToAll方法,它會廣播消息給全部處於鏈接狀態的客戶端

 $('#btnSendMsg').click(function () {

     var msg = $("#txtMessage").val();
     if (msg.length > 0) {

         var userName = $('#hdUserName').val();

         chatHub.server.sendMessageToAll(userName, msg);
       
         $("#txtMessage").val('');
     }
 });   

 


私聊模式
你也能夠經過雙擊客戶端的名稱實現私聊,私聊的時候咱們不用發信息給全部正在鏈接的客戶端,在私聊的時候,只有兩個客戶端之間進行通話,因此在發送私人信息的時候,
發送人要調用sendPrivateMessage 方法

public void SendPrivateMessage(string toUserId, string message)
 {

    string fromUserId = Context.ConnectionId;

    var toUser = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == toUserId) ;
    var fromUser = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == fromUserId);

    if (toUser != null && fromUser!=null)
    {
        // send to
        Clients.Client(toUserId).sendPrivateMessage(fromUserId, fromUser.UserName, message);

        // send to caller user
        Clients.Caller.sendPrivateMessage(toUserId, fromUser.UserName, message);
    }

 }   

 


斷開鏈接:
在瀏覽器關閉的時候,SignalR API 調用 OnDisconnected 方法,在你的ChatHub類中重寫這個方法,
在這個方法中將斷開鏈接的客戶端從緩存結合中刪除而且向其餘的用戶發送一個提示。

 public override System.Threading.Tasks.Task OnDisconnected()
 {
     var item = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
     if (item != null)
     {
         ConnectedUsers.Remove(item);

         var id = Context.ConnectionId;
         Clients.All.onUserDisconnected(id, item.UserName);

     }

     return base.OnDisconnected();
 }   

相關文章
相關標籤/搜索