上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取)

  上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容了,就是SignalR的Hub类。整个即时通讯机制都是以它为基础的。至于原理我也不再讲解,讲了也不如专业的文章讲得好。所以我们直接看业务,上代码。有一部分原理 在文章 ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(二) 实现聊天室连接 (当时是LayIM1.0版本)。原理是一样的,不过这次我把Server端单独提取出来,为了防止 Server端和UI端过度耦合,拆分不方便。进入正题:

  打开项目 LayIM.ChatServer,新建LayIMHub类继承自Hub。(这里要添加Microsoft.AspNet.SignalR.Core,Microsoft.AspNet.SignalR.SystemWeb的引用)核心方法如下:

  上边三个重写的方法一看就很明白,通过这几个方法,客户端很容易知道自己的连接状态。我们主要看下边四个方法。

  • 单聊连接(ClientToClient):这个方法就是当用户点击某个人的头像打开聊天界面的时候,要调用的方法,目的是让当前聊天的两个人分配到一个组里。(当然:Clients.Client(connectionId)才是真正的给某个Client发送消息的方法),我这里用的原理就是群组,就算是两个人聊天,相当于一个群里面只有两个人,所以,两个人和多个人聊天原理是相同的。文字有些抽象,画个图大家应该就明白了

  

  上图就是用户A想和用户B聊天打开聊天窗口时的流程,同理如果B恰好也打开了A的窗口,那么组 FRIEND_10001_10000 里面就是存在A和B两个客户端,那么他们俩发的消息就是他们两个人能够收到了。之所以把自己发送的消息还返回给自己,那是因为,这样客户端能够知道我的消息是否发送成功,因为layim在客户端发送消息时已经做了处理,直接将消息加入到聊天框的,但是服务端可能没有收到。所以可能会出现客户端疯狂发消息,但是服务端(对方)一条也没有接收到的情况。还有另外一种情况,A,B都在线,但是B没有打开A的聊天窗口怎么办呢?这里先卖个关子,涉及到后边的在线人员统计机制了。用这个可以做好多东西,只要是客户端涉及是否在线的都可以用到。

  然后我们在UI端引用ChatServer.dll ,新建Startup(如果没有的话),代码如下:

  

using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin; [assembly: OwinStartupAttribute(typeof(LayIM_SignalR_Chat.V1._0.Startup))]
namespace LayIM_SignalR_Chat.V1._0
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
//ConfigureAuth(app);
app.Map("/layim", map =>
{
var hubConfiguration = new HubConfiguration()
{
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});
}
}
}

  页面上需要引用 jquery.js,signalr.js,/layim/hubs (这个是客户端代理自动生成的),另外,我自己写了个简单的服务调用封装 hub.js,先运行项目,看看自动生成的代码有没有:(http://localhost:8496/layim/hubs)

/*!
* ASP.NET SignalR JavaScript Library v2.1.2
* http://signalr.net/
*
* Copyright Microsoft Open Technologies, Inc. All rights reserved.
* Licensed under the Apache 2.0
* https://github.com/SignalR/SignalR/blob/master/LICENSE.md
*
*/ /// <reference path="..\..\SignalR.Client.JS\Scripts\jquery-1.6.4.js" />
/// <reference path="jquery.signalR.js" />
(function ($, window, undefined) {
/// <param name="$" type="jQuery" />
"use strict"; if (typeof ($.signalR) !== "function") {
throw new Error("SignalR: SignalR is not loaded. Please ensure jquery.signalR-x.js is referenced before ~/signalr/js.");
} var signalR = $.signalR; function makeProxyCallback(hub, callback) {
return function () {
// Call the client hub method
callback.apply(hub, $.makeArray(arguments));
};
} function registerHubProxies(instance, shouldSubscribe) {
var key, hub, memberKey, memberValue, subscriptionMethod; for (key in instance) {
if (instance.hasOwnProperty(key)) {
hub = instance[key]; if (!(hub.hubName)) {
// Not a client hub
continue;
} if (shouldSubscribe) {
// We want to subscribe to the hub events
subscriptionMethod = hub.on;
} else {
// We want to unsubscribe from the hub events
subscriptionMethod = hub.off;
} // Loop through all members on the hub and find client hub functions to subscribe/unsubscribe
for (memberKey in hub.client) {
if (hub.client.hasOwnProperty(memberKey)) {
memberValue = hub.client[memberKey]; if (!$.isFunction(memberValue)) {
// Not a client hub function
continue;
} subscriptionMethod.call(hub, memberKey, makeProxyCallback(hub, memberValue));
}
}
}
}
} $.hubConnection.prototype.createHubProxies = function () {
var proxies = {};
this.starting(function () {
// Register the hub proxies as subscribed
// (instance, shouldSubscribe)
registerHubProxies(proxies, true); this._registerSubscribedHubs();
}).disconnected(function () {
// Unsubscribe all hub proxies when we "disconnect". This is to ensure that we do not re-add functional call backs.
// (instance, shouldSubscribe)
registerHubProxies(proxies, false);
}); proxies['layimHub'] = this.createHubProxy('layimHub');
proxies['layimHub'].client = { };
proxies['layimHub'].server = {
clientSendMsgToClient: function (message) {
return proxies['layimHub'].invoke.apply(proxies['layimHub'], $.merge(["ClientSendMsgToClient"], $.makeArray(arguments)));
}, clientSendMsgToGroup: function (message) {
return proxies['layimHub'].invoke.apply(proxies['layimHub'], $.merge(["ClientSendMsgToGroup"], $.makeArray(arguments)));
}, clientToClient: function (fromUserId, toUserId) {
return proxies['layimHub'].invoke.apply(proxies['layimHub'], $.merge(["ClientToClient"], $.makeArray(arguments)));
}, clientToGroup: function (fromUserId, toGroupId) {
return proxies['layimHub'].invoke.apply(proxies['layimHub'], $.merge(["ClientToGroup"], $.makeArray(arguments)));
}
}; return proxies;
}; signalR.hub = $.hubConnection("/layim", { useDefaultPath: false });
$.extend(signalR, signalR.hub.createHubProxies()); }(window.jQuery, window));

自动生成的hubs代码

  可以看到,上述代码server已经对应了服务端我们自定义的方法。(这里注意,当我们调用server端的方法的时候,首字母都是小写的。)

  

  客户端连接服务器核心代码:

  

//连接服务器
connect: function () {
$.connection.hub.url = _this.option.serverUrl;
_this.proxy.proxyCS = $.connection.layimHub;
$.connection.hub.start({ jsonp: true }).done(function () {
//连接服务器
//TODO处理聊天界面之前的逻辑
//console.log('自定义连接服务器成功方法:' + success);
if (call.ready) {
for (var i = 0; i < call.ready.length; i++) {
call.ready[i]({ connected: true });
}
}
console.log('连接服务器成功');
}).fail(function () {
//console.log('自定义连接服务器成功方法:' + success);
if (call.failed) {
for (var i = 0; i < call.failed.length; i++) {
call.failed[i]({ connected: false });
}
}
});
},

  不知不觉竟然写成了倒叙,给大家解释一下,上文中A和B能够连接的前提条件是 初始化连接服务器能够成功,也就是说客户端调用connect方法然后能够打印 ‘连接服务器成功’。

  最后呢,跟Layim1.0不同的是Layim2.0引用js的方法有所变化,类似seajs的语法。所以,我们的hub代码要改成如下形式:

  autohub.js

  

  signalr.2.1.2.min.js

  

  hub.js

  

  我们都以这种形式定义成模块之后,需要在页面中添加模块:

  

 //自定义模块
layui.extend({
signalr: '/scripts/signalr/signalr',
autohub: '/scripts/signalr/autohub',//自动生成的
hub: '/Scripts/signalr/hub', });

  最后,我们以use的形式开启服务端:

  

  运行项目看一下,打印输出:

  

  到此为止,连接服务器工作已经完成了,总结一下:

  1.创建Hub文件

  2.修改相应config(startup)

  3.修改相应的js代码规范(layui.use)

  4.界面初始化之后调用connect方法。

  本篇就到这里了,由于项目还在进行中,暂时不能提供源代码,不过思路应该没问题吧,如果对博客中有什么疑问或者看法的话,欢迎在底下评论交流。

      下篇预告【初级】ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(三) 之 实现单聊,群聊,发送图片,文件。

   想要学习的小伙伴,可以关注我的博客哦,我的QQ:645857874,Email:fanpan26@126.com

  GitHub:https://github.com/fanpan26/LayIM_NetClient/

ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。的更多相关文章

  1. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室 实战系列

    ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言  http://www.cnblogs.com/panzi/p/5742089.html ASP.NET S ...

  2. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十二) 代码重构使用反射工厂解耦(一)缓存切换

    前言 上一篇中,我们用了反射工厂来解除BLL和UI层耦合的问题.当然那是最简单的解决方法,再复杂一点的程序可能思路相同,但是在编程细节中需要考虑的就更多了,比如今天我在重构过程中遇到的问题.也是接下来 ...

  3. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言

    前端时间听一个技术朋友说 LayIM 2.0 发布了,听到这个消息抓紧去官网看了一下.(http://layim.layui.com/)哎呀呀,还要购买授权[大家支持一下哦],果断买了企业版,喜欢钻研 ...

  4. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取)

    大家好,本篇是接上一篇 ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言  ASP.NET SignalR WebIM系列第二篇.本篇会带领大家将 LayIM ...

  5. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(三) 之 实现单聊,群聊,发送图片,文件。

    上篇讲解了如何搭建聊天服务器,以及客户端js怎么和layui的语法配合.服务器已经连接上了,那么聊天还会远吗? 进入正题,正如上一篇提到的我们用 Client.Group(groupId)的方法向客户 ...

  6. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(四) 之 用户搜索(Elasticsearch),加好友流程(1)。

    前面几篇基本已经实现了大部分即时通讯功能:聊天,群聊,发送文件,图片,消息.不过这些业务都是比较粗犷的.下面我们就把业务细化,之前用的是死数据,那我们就从加好友开始吧.加好友,首先你得知道你要加谁.L ...

  7. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(五) 之 加好友,加群流程,消息管理和即时消息提示的实现

    前言 前前一篇留了个小问题,在上一篇中忘了写了,就是关于LayIM已经封装好的上传文件或者图片的问题.对接好接口之后,如果上传速度慢,界面就会出现假死情况,虽然文件正在上传.于是我就简单做了个图标替代 ...

  8. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(六) 之 Layim源码改造右键菜单--好友、组管理功能的实现。

    前言 上一篇中讲解了加好友的流程,本篇将介绍好友管理,群组管理的右键菜单功能.当然由于菜单项目太多,都实现也得花费时间.只讲解一下我是如何从不知道怎么实现右键菜单到会自定义菜单的一个过程.另外呢,针对 ...

  9. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(七) 之 历史记录查询(时间,关键字,图片,文件),关键字高亮显示。

    前言 上一篇讲解了如何自定义右键菜单,都是前端的内容,本篇内容就一个:查询.聊天历史纪录查询,在之前介绍查找好友的那篇博客里已经提到过 Elasticsearch,今天它又要上场了.对于Elastic ...

随机推荐

  1. CentOS6.3编译安装Memcached集群分布式缓存代理Magent-0.6出错汇总

    参考文章:Memcached集群/分布式/高可用 及 Magent缓存代理搭建过程 详解,搭建Magent,在编译的过程中会出现很多错误: #编译安装安装magent到 /usr/local/mage ...

  2. JS中的prototype(原文地址:http://www.cnblogs.com/yjf512/archive/2011/06/03/2071914.html)

    JS中的phototype是JS中比较难理解的一个部分 本文基于下面几个知识点: 1 原型法设计模式 在.Net中可以使用clone()来实现原型法 原型法的主要思想是,现在有1个类A,我想要创建一个 ...

  3. Javascript高级程序设计——函数声明与函数表达式的区别

    在Javascript中,函数是Functioin类型的实例,所以函数也具备属性和方法,因为函数是对象,所以函数名自然就是指向对象的指针啦. 函数可以通过声明语法和表达式来定义: 声明:functio ...

  4. 纯CSS多级菜单

    主要代码部分: /*新增的二级菜单部分*/ .menu ul ul { visibility:hidden;/*开始时是隐藏的*/ position:absolute; left:0px; top:3 ...

  5. C#GDI+编程基础(二)

    pen类:绘制指定宽度和样式的直线.使用DashStyle属性绘制几种虚线,可以使用各种填充样式(包括纯色和纹理)来填充Pen绘制的直线,填充模式取决于画笔或用作填充对象的纹理. 创建画笔: //用指 ...

  6. 用jQuery实现的一种网页内容呈现方式

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. mongodb的sql例子(简单版)

    插入数据 db.person.insert({"name":"zfx","age":21}) 查找所有数据 db.person.find() ...

  8. HTTP及状态码汇总

    什么是HTTP: HTTP(HyperText Transfer Protocol超文本传输协议)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这个标准,为了提供一种发布和接收HTM ...

  9. android中paint的setXfermode属性

    本文前半部分来自于:http://www.cnblogs.com/rayray/p/3670120.html 1.下面的Xfermode子类可以改变这种行为: AvoidXfermode  指定了一个 ...

  10. TIMIT语音库

    TIMIT语音库有着准确的音素标注,因此可以应用于语音分割性能评价,同时该数据库又含有几百个说话人语音,所以也是评价说话人识别常用的权威语音库,但该语音库的商业用途是要花钱买的.下面的资源来自与MIT ...