ASP.NET SignalR 與 LayIM2.0 配合輕松實現Web聊天室(五) 之 加好友,加群流程,消息管理和即時消息提示的實現
前言
前前一篇留了個小問題,在上一篇中忘了寫了,就是關於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源碼改造右鍵菜單--好友、組管理功能的實現。



