本demo是通過mvc 實現
(1)首先在App_Start下添加Startup.cs文件定義管線的啟動:
using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(SignalRTest.App_Start.Startup))] namespace SignalRTest.App_Start { public class Startup { public void Configuration(IAppBuilder app) { // 有關如何配置應用程序的詳細信息,請訪問 https://go.microsoft.com/fwlink/?LinkID=316888 //app.MapSignalR<MyConnection>("echo/{*operation}"); app.MapSignalR(); } } }
(2)定義Hub的客戶端中包括的方法
public interface IPlatHubClient { void ReceiveMsg(string message);//定義前台客戶端上注冊的方法 }
(3)實現Hub服務器端
首先定義Hub的注冊綁定類,該類可以實現hub的clientid與sessionID、userid的綁定(按需修改使用)
public class PlatHubRegisteInfo { public string Id { get; set; } public string SessionId { get; set; } public string UserId { get; set; } }
PlatHub實現接口如下:(這是真正的通信管線,直接放到項目中即可,無需其他地方注冊)
[HubName("PlatHub")] public class PlatHub : Hub<IPlatHubClient> { private static readonly object ClientMapLock = new object(); public static readonly Dictionary<PlatHubRegisteInfo, string> ClientMap = new Dictionary<PlatHubRegisteInfo, string>(); /// <summary> /// 客戶端注冊連接信息 /// </summary> /// <param name="id"></param> [HubMethodName("Registe")] public void Registe(string id) { lock (ClientMapLock) { ClientMap.Add(new PlatHubRegisteInfo { Id = id }, this.Context.ConnectionId); } Log.Write("", "Registe:ConnectionId=" + Context.ConnectionId + Environment.NewLine +"id="+ id); } public void BroadcastToAll(string message) { Clients.All.ReceiveMsg(Newtonsoft.Json.JsonConvert.SerializeObject(new { id = Context.ConnectionId, msg = message })); } public void BroadcastToSome(string[] ids, string message) { Clients.Clients(ids.ToList()).ReceiveMsg(Newtonsoft.Json.JsonConvert.SerializeObject(new { id = Context.ConnectionId, msg = message })); } // // 摘要: // Called when the connection connects to this hub instance. // // 返回結果: // A System.Threading.Tasks.Task public override async Task OnConnected() { var t = this; base.OnConnected(); return; } // // 摘要: // Called when a connection disconnects from this hub gracefully or due to a timeout. // // 參數: // stopCalled: // true, if stop was called on the client closing the connection gracefully; false, // if the connection has been lost for longer than the Microsoft.AspNet.SignalR.Configuration.IConfigurationManager.DisconnectTimeout. // Timeouts can be caused by clients reconnecting to another SignalR server in scaleout. // // 返回結果: // A System.Threading.Tasks.Task public override async Task OnDisconnected(bool stopCalled) { var t = this; var infos = ClientMap.Where(a => a.Value == this.Context.ConnectionId); if (infos.Any()) { var info = infos.First(); lock (ClientMapLock) { ClientMap.Remove(info.Key); } Log.Write("", "Disconnected:ConnectionId=" + Context.ConnectionId + Environment.NewLine + "id=" + info.Key.Id); } base.OnDisconnected(stopCalled); return; } // // 摘要: // Called when the connection reconnects to this hub instance. // // 返回結果: // A System.Threading.Tasks.Task public override async Task OnReconnected() { var t = this; base.OnReconnected(); return; } protected override async void Dispose(bool disposing) { var t = this; base.Dispose(disposing); return; } }
(3)添加控制器HomeController,並添加試圖方法:
public ActionResult Index() { Guid id = Guid.NewGuid(); Response.Cookies.Add(new HttpCookie("id", id.ToString()));//cookie將通過客戶端的Registe實現與服務器的關聯 return View(); }
(4)前台Index試圖如下:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Home Page - 我的 ASP.NET 應用程序</title> </head> <body> <div>home</div> <div><input type="text" id="msg" /><input type="button" id="sendmsg" value="廣播" /></div> <div id="divStatus"></div> <div>msgs:</div> <div id="msgContainer"></div> <script src="/Scripts/jquery-1.10.2.js"></script> <script src="/Scripts/jquery.cookie-1.4.1.min.js"></script> <script src="/Scripts/bootstrap.js"></script> <script src="/Scripts/respond.js"></script> <!--Script references. --> <!--The jQuery library is required and is referenced by default in _Layout.cshtml. --> <!--Reference the SignalR library. --> <script src="/Scripts/jquery.signalR-2.2.2.min.js"></script> <!--Reference the autogenerated SignalR hub script. --> <script src="/signalr/hubs"></script> <!--SignalR script to update the chat page and send messages.--> <script> $(function () { // hub名稱(如若類名用特性重命名了,則是特性重命名的名稱,否則就是類名的首字母小寫;). var chat = $.connection.PlatHub; //啟用瀏覽器端輸出日志 $.connection.hub.logging = true; // 客戶端定義一個函數,服務器上可以調用. chat.client.ReceiveMsg = function (message) { //var ob = $.parseJSON(message); // $("#msgContainer").append("<div>id:" + ob.code + " msg:" + ob.content + "</div>"); $("#msgContainer").append("<div>" + message+"</div>"); }; // Start the connection. $.connection.hub.starting(function () { console.log('starting.') }); $.connection.hub.received(function (e) { console.log('received.'+e) }); $.connection.hub.connectionSlow(function () { console.log('connectionSlow.') }); $.connection.hub.reconnecting(function () { console.log('reconnecting.') }); $.connection.hub.reconnected(function () { console.log('reconnected.') }); $.connection.hub.stateChanged(function (o, n) { console.log('stateChanged.' + o + "," + n) }); $.connection.hub.disconnected(function () { console.log('disconnected.'); setTimeout(function () { $.connection.hub.start(); }, 1000); // Restart connection after 1 seconds. }); $.connection.hub.error(function (error) { console.log('SignalR error: ' + error) }); $.connection.hub.start().done(function () { chat.server.Registe($.cookie('id'));//定義id,與管線clientid關聯 $("#sendmsg").click(function () { $.ajax({ url: 'GuangBo', type: 'POST', //GET async: true, //或false,是否異步 data: { msg: $("#msg").val() }, timeout: 5000, //超時時間 dataType: 'json', //返回的數據格式:json/xml/html/script/jsonp/text beforeSend: function (xhr) { console.log(xhr) console.log('發送前') }, success: function (data, textStatus, jqXHR) { if (data.code == 1) { $("#divStatus").val(new Date().toString() + ":成功"); } else $("#divStatus").val(new Date().toString() + ":失敗"); }, error: function (xhr, textStatus) { console.log('錯誤') console.log(xhr) console.log(textStatus) }, complete: function () { console.log('結束') } }); }); }).fail(function (error) { console.log('fail Error: ' + error); }); }); // This optional function html-encodes messages for display in the page. function htmlEncode(value) { var encodedValue = $('<div />').text(value).html(); return encodedValue; } </script> </body> </html>
在前端代碼中,如下代碼是定義客戶端的方法:
chat.client.ReceiveMsg = function (message) { //var ob = $.parseJSON(message); // $("#msgContainer").append("<div>id:" + ob.code + " msg:" + ob.content + "</div>"); $("#msgContainer").append("<div>" + message+"</div>"); };
前端如下代碼是訪問服務器:
chat.server.Registe($.cookie('id'));//Registe是PlatHub上通過特性HubMethodName定義的
前端代碼調用的后端控制器GuangBo實現如下:
[HttpPost] public JsonResult GuangBo(string msg) { var chatHub = GlobalHost.ConnectionManager.GetHubContext<PlatHub>(); chatHub.Clients.All.ReceiveMsg(msg);//給所有人 return Json(new { code = 1 }); }
若希望給單獨一個ID發送,可以采用如下:
[HttpPost] public JsonResult ToSingle(string client,string msg) { var chatHub = GlobalHost.ConnectionManager.GetHubContext<PlatHub>(); chatHub.Clients.Client(client).ReceiveMsg(msg); return Json(new { code = 1 }); }
可以通過
HubName、HubMethodName
兩個特性重命名管線名稱、服務器端注冊的管線實現名稱