老規矩,前言~,在此先道個歉,之前的1-5對很多細節問題都講的不是很詳細,也有很多人在QQ或者博客問我一些問題
所以,特開了這個續集.. - -, 講一些大家在開發中遇到的問題和一些解決方案,今天就來說說經常被問到的,如何使用自己定義的連接ID.
之前我們說過,Signalr提供了唯一的連接ID 獲取方法:Context.ConnectionId,
那麼怎麼自己定義這個東西呢? (廢話一堆 - - ,),進入主題:
首先,其實在Signalr的前期版本是可以直接自定義Context.ConnectionId,
使用老版本的可以自行查看IConnectionIdGenerator,
IConnectionIdFactory 這兩個接口.
所以特意說明一下,本博客這裏的代碼,只適用於Signalr2.0以上版本
開發工具:VS2013 數據庫:SQL2008 R2 SignalR版本:2.2
其實在2.0的版本中,SignalR團隊爲了安全性,已經完全去除了自定義Context.ConnectionId的接口,但是相應的開放了相對安全的IUserIdProvider
廢話不多說,直接上代碼:
首先帳戶登陸的代碼:
其實就是很傳統的登陸代碼..把一些用戶信息寫入到Cookie中而已.黃色爲重點
public class UserController : ApiController { [HttpGet] public object Login(string name,string pwd) { UserInfoBLL bll = new UserInfoBLL(); if (CacheHelper.Get(name) == null) { var userinfo = bll.LoginUser(name, pwd); if (userinfo != null) { var context = HttpContext.Current; //帳戶信息寫入Cookie,自行加密 context.Response.Cookies.Add(new HttpCookie(UserEnum.INFO) { Value = JsonConvert.SerializeObject(userinfo) });
//唯一的登陸ID,作爲連接ID context.Response.Cookies.Add(new HttpCookie(UserEnum.SignalRID) { Value = userinfo.LoginName });
return new { State=true,Message="登陸成功!"}; } else { return new { State=false,Message="帳戶或密碼輸入錯誤!"}; } } else { return new { State=false,Message="該帳戶已經登陸!"}; } } }
接下來實現IUserIdProvider:
public class MyUserFactory : IUserIdProvider { public string GetUserId(IRequest request) { if (request.GetHttpContext().Request.Cookies[UserEnum.SignalRID] != null) { return request.GetHttpContext().Request.Cookies[UserEnum.SignalRID].Value; } return ""; // return Guid.NewGuid().ToString(); } }
以上代碼是創建一個MyUserFactory類,繼承自IUserIdProvider,實現IUserIdProvider的抽象方法GetUserId
這裏的ID我們從Cookies中獲取,細心的人應該已經發現了,有個IRequest的參數,所以原則上你可以使用IRequest的各種屬性比如QS..你隨意..(注:Session暫時無法使用,原因未知)
接下來,重點來了..
在Starup中,把我們自定義的MyUserFactory注入到回話設置中..
代碼如下(黃色爲重點):
public class Startup { public void Configuration(IAppBuilder app) { // 有關如何配置應用程序的詳細信息,請訪問 http://go.microsoft.com/fwlink/?LinkID=316888 //重點,將MyUserFactory注入 var userIdProvider = new MyUserFactory(); GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => userIdProvider);
//設置Webapi var config = new HttpConfiguration(); config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional }); System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); app.UseWebApi(config); app.MapSignalR(); } }
接下來在Hub中添加代碼如下:
/// <summary> /// 獲取連接ID,你可以寫成自己的擴展方法,或設置成屬性,自行定義 /// </summary> /// <returns></returns> public string GetSignalrID() { if (Context.Request.GetHttpContext().Request.Cookies[UserEnum.SignalRID] != null) { return Context.Request.GetHttpContext().Request.Cookies[UserEnum.SignalRID].Value; } return ""; } //編寫發送信息的方法 public void SendMessage(string message) { string id = Context.ConnectionId; string username = Context.User.Identity.Name; var userinfo = JsonConvert.DeserializeObject<UserInfo>(Context.Request.GetHttpContext().Request.Cookies[UserEnum.INFO].Value); var Message = new { name = userinfo.UserName, loadname = userinfo.LoginName, picurl = userinfo.UserPicUrl, time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), message = message }; Clients.User(GetSignalrID()).broadcastMessage(Message); }
說明:重點是標黃色的地方,看過我之前文章的都知道,之前我們的對指定連接對象發送數據,寫法爲: Clients.Client("連接ID").客戶端方法,
這裏我們換成了Clients.User("自定義ID"),這樣就完成了整個使用自己的連接ID的替換工作.