一、SignalR 概述
          https://docs.microsoft.com/en-us/aspnet/signalr/index
          SignalR是微軟為實現實時通信的一個類庫。一般情況下,signalR會使用JavaScript的長輪詢(long polling)的方式來實現客戶端和服務器通信,隨著Html5中WebSockets出現,SignalR也支持WebSockets通信。另外SignalR開發的程序不僅僅限制于宿主在IIS中,也可以宿主在任何應用程序,包括控制臺,客戶端程序和Windows服務等,另外還支持Mono,這意味著它可以實現跨平臺部署在Linux環境下。

              signalR內部有兩類對象:
          1. 持久連接
            一個持久連接代表了一個端點,它可以發送單一接收者,Group接受者或者廣播信息。持久連接的api是SignalR提供給開發者進入低級別協議的api。連接模型使用起來和WCF比較類似。
          2. Hubs(集線器)
            Hubs是SignalR提供的高級別的api,它允許客戶端和服務端,在自己這邊相互調用對方的方法。Hubs模型類似于.Net Remoting。使用Hubs也可以讓你傳遞強類型參數,進行模型綁定。
          SignalR將整個信息的交換封裝起來,客戶端和服務器都是使用JSON來溝通的,在服務端聲明的所有Hub信息,都會生成JavaScript輸出到客戶端,.NET則依賴Proxy來生成代理對象,而Proxy的內部則是將JSON轉換成對象。



          SignalR 和 WebSocket
          如果客戶端和服務器都支持WebSocket,那么SignalR會通過WebSocket來傳輸數據。當然你也可以自己使用WebSocket來實現SignalR的功能,不過使用SignalR你就不用考慮如果客戶端或者服務器不支持WebSocket的問題了。

          二、SignalR的協議選擇
          SignalR是可以在客戶端和服務器端進行即時通訊的幾種協議的抽象和實現。一個SignalR連接是通過http請求發起的,然后上升為WebSocket(如果客戶端和服務端都支持)。WebSocket是SignalR最理想的協議,它可以有效地利用服務器端的內存,有著最低的延遲,最多的基礎特性(比如客戶端和服務端的全雙工連接),不過它也有著嚴格的要求,需要服務器端使用Windows Server 2012或者Windows 8以上的系統,也需要.NET Framework 4.5.。如果不符合這些要求,那么SignalR會使用其他的協議來建立連接。

          HTML 5協議
          ?WebSocket。如果服務器和客戶端都支持,那么就使用WebSocket協議來進行通訊。
          ?服務器推送事件(Server-sent Events)。除了IE,其他的瀏覽器基本都支持。
          Comet協議
          ?Forever Frame (只支持IE)。
          ?Ajax長輪詢(Ajax long polling)。
          SignalR協議選擇過程
          1.如果瀏覽器是IE8或者更早的版本,使用長輪詢。
          2.如果配置了Jsonp(如果連接開始的時候jsonp的參數設置為true), 使用長輪詢。
          3.如果是跨域連接, 如果下面的條件符合就會使用WebSocket,如果有條件不符合,那就是用長輪詢。
              ?客戶端支持跨域連接
              ?客戶端支持WebSocket
              ?服務器端支持WebSocket
          4.如果沒有配置jsonp,而且不是跨域連接,如果客戶端和服務端都支持WebSocket,那么就使用WebSocket。
          5.如果客戶端或者服務端不支持WebSocket,使用服務器推送事件。
          6.如果不支持服務器推送事件,使用Forever Frame。
          7.如果不支持Forever Frame,使用長輪詢。

          監控協議
          可以通過在你的Hub上開啟logging來監控你的SignalR使用了什么協議。
          $.connection.hub.logging = true;

          指定協議
          SignalR判斷協議也需要消耗一定的客戶端、服務端資源,如果你清楚客戶端、服務端支持的協議,那么你可以指定使用某種協議來建立連接。
          比如,你知道客戶端只支持長輪詢,那么你可以指定使用長輪詢來進行通訊。
          connection.start({ transport: 'longPolling' });

          你也可以指定一個序列,客戶端會按照序列里的順序來進行通訊。下面的代碼的作用是,先使用WebSocket,如果失敗了,就使用長輪詢。
          connection.start({ transport: ['webSockets','longPolling'] });

          SignalR包含下面四種指定的協議常量
              ?webSockets
              ?foreverFrame
              ?serverSentEvents
              ?longPolling
          三、SignalR的三種實現方式
          1. 集線器類(Hub) + 非自動生成代理模式
          服務端與客戶端分別定義的相對應的方法,客戶端通過代理對象調用服務端的方法,服務端通過IHubConnectionContext回調客戶端的方法,客戶端通過回調方法接收結果。
          JS端調用服務端方法采用:chat.invoke,而被服務端回調的方法則采用:chat.on (這里的chat是createHubProxy創建得來的)
                      var conn = $.hubConnection();
                      conn.qs = { "clientName": clientName };
                      conn.start().done(function () {
                          $("#btnSend").click(function () {
                              var toUserId = eUsers.val();
                              if (toUserId != "") {
                                  chat.invoke("sendOne", toUserId, $("#message").val())
                                  .done(function () {
                                      //alert("發送成功!");
                                      $("#message").val("").focus();
                                  })
                                  .fail(function (e) {
                                      alert(e);
                                      $("#message").focus();
                                  });
                              }
                              else {
                                  chat.invoke("send", $("#message").val())
                                  .done(function () {
                                      //alert("發送成功!");
                                      $("#message").val("").focus();
                                  })
                                  .fail(function (e) {
                                      alert(e);
                                      $("#message").focus();
                                  });
                              }
                          });
                      });
           
                      var chat = conn.createHubProxy("chat");
                      chat.on("receiveMessage", function (dt, cn, msg) {
                          var clsName = "linfo";
                          if (cn == clientName || cn.indexOf("您對") >= 0) clsName = "rinfo";
                          eChatBox.append("<p class='" + clsName + "'>" + dt + " <strong>" + cn + "</strong> 說:<br/>" + msg + "</p>");
                          eChatBox.scrollTop(eChatBox[0].scrollHeight);
                      });
           
                      chat.on("userChange", function (dt, msg, users) {
                          eChatBox.append("<p>" + dt + " " + msg + "</p>");
                          eUsers.find("option[value!='']").remove();
                          for (var i = 0; i < users.length; i++) {
                              if (users[i].Value == clientName) continue;
                              eUsers.append("<option value='" + users[i].Key + "'>" + users[i].Value + "</option>")
                          }
                      });

          2. 集線器類(Hub)+ 自動生成代理模式
          需要js引用
          <script src="~/signalr/hubs" type="text/javascript"></script>
          然而,我們在寫代碼的時候上面的引用并不存在,而當運行后就會自動生成上述signalr的代理腳本
          這就是與非自動生成代理腳本最根本的區別,也正是因為這個自動生成的腳本,我們可以在JS中更加方便的調用服務端方法及定義回調方法,調用服務端方法采用:chat.server.XXX,而被服務端回調的客戶端方法則采用:chat.client.XXX

          3.持久化連接類(PersistentConnection)
          ?Startup.Configuration中是需要指定app.MapSignalR<MyConnection>("/MyConnection")
          ?需實現繼承自PersistentConnection類的自定義的持久化連接類,在這個連接中可以重寫:OnConnected、OnDisconnected、OnReceived、OnReconnected、ProcessRequest方法,同時有幾個重要的屬性成員Connection、Groups,服務端發消息給客戶端采用:Connection.Broadcast(廣播,所有客戶端都可以收到消息),Connection.Send(發送給指定的客戶端)

          具體實現參考
          https://www.cnblogs.com/zuowj/p/5674615.html

          四、使用RignalR實現新消息推送(集線器類(Hub)+ 自動生成代理模式
          1.app.MapSignalR();
          using System.Data.Entity;
          using Microsoft.Owin;
          using Owin;
          using RCRS.WebApp.Town.Migrations;
          using RCRS.WebApp.Town.Models.DomainEntity;

          [assembly: OwinStartupAttribute(typeof(RCRS.WebApp.Town.Startup))]
          namespace RCRS.WebApp.Town
          {
              public partial class Startup
              {
                  public void Configuration(IAppBuilder app)
                  {
                      ConfigureAuth(app);
                      app.MapSignalR();

                      Database.SetInitializer(new MigrateDatabaseToLatestVersion<TownContext, TownConfiguration>());
                  }
              }
          }

          2. NotificationHub
          using System.Linq;
          using Microsoft.AspNet.SignalR;
          using Microsoft.AspNet.SignalR.Hubs;
          using RCRS.WebApp.Town.Models.Town;

          namespace RCRS.WebApp.Town.Hubs
          {
              [HubName("NotificationHub")] 
              public class NotificationHub : Hub
              {
                  public void Connect(string userId)
                  {
                      var id = Context.ConnectionId;

                      if (BizHub.ConnectedUsers.Count(x => x.ConnectionId == id) == 0)
                      {
                          BizHub.ConnectedUsers.Add(new HubUser { ConnectionId = id, UserId = userId });
                          // send to caller
                          Clients.Caller.onConnected(id, userId, BizHub.ConnectedUsers);

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

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

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

                      }
                      return base.OnDisconnected(stopCalled);
                  }

              }
          }

          3.BizHub
                  /// <summary>  </summary>
                  public static List<HubUser> ConnectedUsers = new List<HubUser>();

                  public void NotifyAll(string msg)
                  {
                      var hub = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
                      hub.Clients.All.broadcaastNotif(msg);
                  }

                  public void NotifyPrivate(string toUserId, string msg)
                  {
                      var toUser = ConnectedUsers.FirstOrDefault(x => x.UserId == toUserId);
                      var hub    = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();

                      if (toUser != null)
                      {
                          // send to 
                          hub.Clients.Client(toUser.ConnectionId).broadcaastNotif(msg);
                      }
                  }

                  public void NotifyRole(List<string> roleLs, string msg)
                  {
                      List<string> lsUserIds = new List<string>();

                      using (ApplicationDbContext context = new ApplicationDbContext())
                      {
                          string cmd = getUsersByRoleLs(roleLs);
                          lsUserIds = context.Database.SqlQuery<string>(cmd).ToListAsync().Result;
                      }

                      foreach (string toUserId in lsUserIds)
                          NotifyPrivate(toUserId, msg);
                  }

          4.引用js
          bundles.Add(new ScriptBundle("~/bundles/signalR").Include(
                          "~/Scripts/jquery.signalR-2.2.3.js"));

          5.
          <script src="~/signalr/hubs"></script>
              <script type="text/javascript">
                  $(function () {
                      var id = '@ViewBag.UserId';
                      var notifyHub = $.connection.NotificationHub;
                      notifyHub.client.broadcaastNotif = function (message) {
                          $("#assist-top-new-msg").text(message);
                          $("#assist-msg-list-new-flg").text(message);
                      };

                      $.connection.hub.start()
                          .done(function () {
                              console.log("Notification Hub Connected!");
                              //Server Call
                              notifyHub.server.connect(id);
                          })
                          .fail(function () {
                              console.log("Could not Connect Notification Hub!");
                          });

                  });
              </script>



          posted on 2018-05-23 15:02 Ying-er 閱讀(1394) 評論(0)  編輯  收藏 所屬分類: .Net
          主站蜘蛛池模板: 得荣县| 泰和县| 闸北区| 肇庆市| 和静县| 信丰县| 兴安盟| 吴川市| 门源| 天门市| 蓬安县| 巨鹿县| 鹤壁市| 深泽县| 涟水县| 绥中县| 明光市| 溧阳市| 启东市| 手机| 大埔区| 晴隆县| 甘肃省| 田东县| 齐河县| 永安市| 乐都县| 贵阳市| 嘉祥县| 四平市| 衡阳市| 房产| 邵阳市| 榆中县| 延吉市| 武平县| 思茅市| 偏关县| 安平县| 普陀区| 都昌县|