前言
前前一篇留了個小問題,在上一篇中忘了寫了,就是關於LayIM已經封裝好的上傳檔案或者圖片的問題。對接好介面之後,如果上傳速度慢,介面就會出現假死情況,雖然檔案正在上傳。於是我就簡單做了個圖示替代來增強使用者體驗。
上傳中。。。
上傳完成後
是不是很簡單啊,接下來進入正題。
業務介紹
LayIM中的加好友可以說是不太必要的邏輯,而且其實大部分在模仿QQ,當然業務複雜度肯定沒法和QQ比。主線,就是使用者A請求新增使用者B為好友,使用者B收到訊息提示之後點選同意或者拒絕或者直接忽略,然後在將訊息反饋到使用者A。就是這麼一個比較簡單的流程,不過細節還是比較多的。
實戰演示
第一步,傳送好友申請。
第二步,接收好友申請(小氣球為訊息提示)
第三步:訊息處理(這裡拒絕會輸入拒絕理由,忽略不做訊息提示)
第四步:同意(拒絕)之後訊息回傳。
第五步:流程結束
講解
資料庫上的業務邏輯不多贅述,一般的設計只要包含請求表和處理結果表就可以了,然後根據使用者id去查詢他自己未處理的訊息。可能看上面的圖看不出哪裡即時來,其實我在截圖過程中,全程兩個瀏覽器並沒有重新整理頁面,完全是依靠後臺的Hub訊息推送來實現。在這之前呢,我們要做好準備工作,就是使用自定義使用者Id,也就是我們資料庫中的userId,而不是Hub中給我們的Guid。我們重寫 介面 IUserIdProvider的GetUserId的方法就可以了。
namespace Microsoft.AspNet.SignalR { public interface IUserIdProvider { string GetUserId(IRequest request); } }
新增自定義類繼承自介面 IUserIdProvider
public class LayIMUserFactory : IUserIdProvider { /// <summary> /// 自定義獲取使用者ID方法 /// </summary> /// <param name="request"></param> /// <returns></returns> public string GetUserId(IRequest request) { //直接讀取Cookie中的userid,然後將userid返回,否則返回空,未登入 if (request.GetHttpContext().Request.Cookies[LayIMConst.LayIM_SignalR_UserId] != null) { return request.GetHttpContext().Request.Cookies[LayIMConst.LayIM_SignalR_UserId].Value; } return ""; } }
然後在startup檔案中,我們註冊一下這個類
public void Configuration(IAppBuilder app) { ///註冊自定義使用者ID方法 var userIdProvider = new LayIMUserFactory(); GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => userIdProvider); //ConfigureAuth(app); //其他程式碼 }
同理呢,在ChatServer.LayIMHub 中,我們也是讀取cookie中的使用者Id
public string CurrentUserId { get { var cookie = Context.Request.GetHttpContext().Request.Cookies[LayIMConst.LayIM_SignalR_UserId]; if (cookie != null) { return cookie.Value; } return ""; } }
然後針對某一個使用者傳送訊息的時候呼叫
Clients.User(CurrentUserId).receiveMessage("你好,我給你傳送了一個訊息,用Client.User發給你的");
這樣做有什麼好處呢,因為如果使用者連線Hub伺服器後,重新整理頁面的話,使用者的ConnectionId是會變的,但是如果用我們自定義的userId來傳送訊息,只要是同一個使用者,都能夠使用UserId來進行傳送訊息的操作,省去了對ConnectionId的處理。所以這個場景很適合用在新增好友過程中的訊息提醒上。比如,我們申請已經提交,那麼後臺就需要給被申請人傳送一個提示訊息:
public static void SendMessage(object message, string userId, ChatToClientType type, bool moreUser = false) { //構造訊息體 ToClientMessageResult result = new ToClientMessageResult { msg = message, msgtype = type, other = null }; //獲取當前的Hub物件 IHubContext hub = GlobalHost.ConnectionManager.GetHubContext<LayIMHub>(); // 給多個使用者傳送訊息 if (moreUser) { hub.Clients.Users(userId.Split(',').ToList()).receiveMessage(result); } else { //給單個使用者傳送訊息 hub.Clients.User(userId).receiveMessage(result); } }
只要實現了以上這個方法,不管我們是傳送申請資訊,訊息處理資訊還是其他資訊,都可以在後臺呼叫。只要該使用者線上,就能夠實現實時推送,如果不線上,即使推送了,也是收不到的。那就是歷史訊息的功能了。這裡不再贅述。
所以,當請求傳送出去的時候,另外一個客戶端就會看到這麼一條訊息:
對應介面上呢,就是那個右下角的小氣球閃爍,因為是截圖,所以閃爍效果看不出,雖然很low。。實現方法 是用setInterval 然後控制文字實現的。
var i = 0; var blings = function () {
//html交替變換,一會是圖示一會是空,就會有圖示閃動的效果,不過如果有一個漂亮的gif就更好了。 $('.layim-tool-apply').attr('title', msg).html(i % 2 ? '' : ''); i++; } other.msgTipInterval = setInterval(blings, 500);
至於使用者開啟訊息介面,因為是另外一個介面,所以直接讀取該使用者需要處理的訊息即可,當使用者同意或者拒絕該請求時,後臺同樣呼叫:
public static void SendMessage(ApplyHandledMessgae message) { short agreeFlag = 1; short refuseFlag = 2; //只有有訊息,並且同意 if (message.id > 0) { var userid = message.applyuid.ToString(); if (message.result == refuseFlag) { //如果是被拒絕,只需要傳送一條提示訊息即可 var msg = new ApplySendedMessage { msg = "您的" + (message.applytype == 0 ? "好友" : "加群") + "請求已經被處理,請點選檢視詳情" }; SendMessage(msg, userid, ChatToClientType.ApplyHandledToClient); } else if (message.result == agreeFlag) { //如果同意了,判斷如果是加群,需要給群傳送訊息:某某某已經加入群,如果是加好友,傳送一條訊息,我們已經成為好友了,開始聊天吧。 var msg = "您的" + (message.applytype == 0 ? "好友" : "加群") + "請求已經被處理,請點選檢視詳情"; if (message.applytype == ApplyType.Friend.GetHashCode()) { //這裡的friend是為了配合 LayIM的 addList介面 SendMessage(new { friend = message.friend, msg =msg }, userid, ChatToClientType.ApplyHandledToClient); } else { //傳送群資訊 group也是為了配合Layim的addList介面 SendMessage(new { group = message.group, msg = msg }, userid, ChatToClientType.ApplyHandledToClient); } } } }
所以,當處理完申請訊息時候,申請方使用者就會收到如下的訊息:
客戶端訊息處理:
console.log("收到申請被處理的訊息"); //開始閃爍右下角訊息圖示 global.other.startTips(result.msg.msg); if (result.msg.friend) { result.msg.friend.remark = result.msg.friend.sign; //呼叫layim介面,將好友直接新增到相應的好友組裡面 global.layim.addList(result.msg.friend); } if (result.msg.group) { //呼叫layim介面,將群組直接新增到相應的好友組裡面 global.layim.addList(result.msg.group); }
到這裡,基本上加好友流程就完成了,加群同理,不過加群不同的是,群主和管理員都可以審批,所以會出現給多個使用者傳送即時訊息的情況。處理的時候也得注意重複操作的問題。
所以,本篇的核心內容就是Hub在後臺的呼叫,以及自定義UserId的使用方法。不過好像我們還少些東西,比如說,提示群裡的其他成員:xxx已經加入群。或者自動給申請成功的好友傳送一條:“我們已經是好友了,開始聊天吧。”的訊息。
總結
萬變不離其宗,其實只要掌握了,訊息推送機制,能夠實現客戶端與伺服器端的聯通。訊息推送做任何業務都可以遊刃有餘。今天的加好友流程就到這裡了。你會了嗎?
下篇預告:【中級】ASP.NET SignalR 與 LayIM2.0 配合輕鬆實現Web聊天室(六) 之 Layim原始碼改造右鍵選單--好友、組管理功能的實現。
想要學習的小夥伴,可以關注我的部落格哦,我的QQ:645857874,Email:fanpan26@126.com