前言

  前几篇介绍了整个中间件的构成,路由,基本配置等等.基本上没有涉及到通讯部分。不过已经实现了融云的通讯功能,由于是第三方的就不在单独去写。正好.NET Core SignalR已经出来好久了,于是乎赶紧对接上。可以先看一下之前的文章:.Net Core SignalR初体验

Hub设计

  Hub我采用了 Hub<T>,然后只定义了一个 Receive方法。

namespace LayIM.AspNetCore.IM.SignalR
{
public interface ILayIMClient
{
Task Receive(object message);
}
}
   // Hub端代码
public Task SendMessage(string targetId, string message)
{
//这里就可以调用 Receive方法
return Clients.Caller.Receive(message);
}

  那么这里我们要做的就是,先连接上服务器在实现详细业务。下面我们要做两件事情:

  • 修改Startup,注册SignalR
  • 增加Javascript客户端

由于是将SignalR拆分到LayIM.AspNetCore.IM.SignalR项目中,所以注册服务端代码做了小小封装。在SignalRServiceExtensions文件中:

        /// <summary>
/// 使用SignalR通信
/// </summary>
/// <param name="services"></param>
/// <param name="setConfig"></param>
public static IServiceCollection AddSignalR(this IServiceCollection services, Action<LayIMHubOptions> configure)
{
var options = new LayIMHubOptions();
configure?.Invoke(options);
var signalRServerBuilder = services.AddSignalR(options.HubConfigure);
//增加Redis配置
if (options.UseRedis)
{
signalRServerBuilder.AddRedis(options.RedisConfiguration, options.RedisConfigure);
}
//AddSignalR must be called before registering your custom SignalR services.
services.AddSingleton<ILayIMAppBuilder, SignalRAppBuilder>();
//获取用户ID
services.AddSingleton<IUserIdProvider, LayIMUserIdProvider>(); LayIMServiceLocator.SetServiceProvider(services.BuildServiceProvider());
return services;
}

那么在客户端 Startup 调用的时候就可以这么写了:

 //注册LayIM的默认服务
services.AddLayIM(() =>
{
return new MyUserFactory();
}).AddSignalR(options =>
{
options.HubConfigure = hubOptions =>
{
hubOptions.EnableDetailedErrors = true;
hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(5);
};
//使用Redis
options.RedisConfiguration = "192.168.1.225:6379"
})
.AddSqlServer(connectionString);

然后Configure方法中:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
....其他代码
//使用LayIM,自定义配置
app.UseLayIM(options =>
{
options.ServerType = ServerType.SignalR;
});
....其他代码
}

到这里可能大家有疑问,没有看到添加 AddSignalR方法。由于是封装了很多细节,所以,这一部分已经写到了UselayIM代码中。

 public class SignalRAppBuilder : ILayIMAppBuilder
{
public void Build(IApplicationBuilder builder)
{
builder.UseSignalR(route => {
route.MapHub<LayIMHub>("/layimHub", connectionOptions =>
{ });
});
}
}

其实也就对应了上文中services.AddSingleton<ILayIMAppBuilder, SignalRAppBuilder>();这句代码。那么到这里呢,SignalR的服务该注册的也注册了,该添加的也添加了,下面就编写(JS)客户端代码。

SignalR Javascript客户端

  这里我们根据官方文档里写就可以。连接部分核心代码:

            let hubRoute = "layimHub";
let protocol = new signalR.JsonHubProtocol();
var options = {};
connection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Trace)
.withUrl(hubRoute, options)
.withHubProtocol(protocol)
.build();
//receive message
connection.on('Receive', im.handle);
connection.onclose(function (e) {
if (e) { }
log('连接已关闭' + e ? e : '');
});
connection.start()
.then(function () {
//连接成功
})
.catch(function (err) {
log('服务器连接失败:' + err);
});

  运行一下程序。没问题



  那么到这里,我们就可以对接LayIM的实际业务了.这一段其实和融云思路差不多。首先,我们要确保消息能够发送到后端,那么我们修改一下监听LayIM发送消息部分的代码:

 layim.on('sendMessage', function (data) {
//调用socket方法,发送消息
im.sendMsgWithQueue(data);
});

调用服务端发送方法:

     if (im.connected) {
this.invoke(connection, 'SendMessage', targetId, msg);
}

invoke方法

 invoke: function () {
if (!im.connected) {
return;
}
var argsArray = Array.prototype.slice.call(arguments);
connection.invoke.apply(connection, argsArray.slice(1))
.then(function (result) {
if (result) {
log(result);
}
}).catch(function (err) {
log(err);
});
},

可以看到,调用了服务端的 SendMessage方法,那么这里就要回到Hub代码部分了。我们在Hub端新增方法SendMessage,然后定义好接收变量。如下:

 public class LayIMMessage
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("avatar")]
public string Avatar { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("content")]
public string Content { get; set; }
[JsonProperty("username")]
public string UserName { get; set; }
}
 public Task SendMessage(string targetId, LayIMMessage message)
{
if (string.IsNullOrEmpty(targetId) || message == null)
{
return Task.CompletedTask;
}
var toClientMessage = LayIMToClientMessage<LayIMMessage>.Create(message, LayIMMessageType.ClientToClient);
//如果消息类型是群聊,调用OthersInGroup方法
if (message.Type == LayIMConst.TYPE_GROUP)
{
return Clients.OthersInGroup(targetId).Receive(toClientMessage);
}
else
{
//如果消息类型是单聊,直接调用User
//或者 Clients.Client([connectionId])
return Clients.User(targetId).Receive(toClientMessage);
}
}

这里有两个细节要注意,第一:用户连接成功之后需要加入到Group,第二,自定义UserIdProvider。 那么第一个,就是我们要在用户连接成功之后调用一下加入群组的方法,同样,用户下线之后要移除掉。IGroupManager中定义了如下两个方法:

namespace Microsoft.AspNetCore.SignalR
{
//
// 摘要:
// A manager abstraction for adding and removing connections from groups.
public interface IGroupManager
{
Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default(CancellationToken)); Task RemoveFromGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default(CancellationToken));
}
}

至于自定义用户ID,很简单,我们实现接口IUserIdProvider即可。细心的同学可能在前文的代码中看到这一段了。为什么要使用重写呢?因为SignalR默认使用ConnectionId。而且每次刷新页面之后,它都是会变化的,那么如果我们改成使用绑定用户ID的话,对于直接定点推送,刷新页面是没有问题的,直接根据User对象推送即可。下面演示一下:

群聊的图就不贴了,一样的。那么至此SignalR的对接就结束了。是不是比Demo也难不了多少。

推送服务分离

  到这里呢,我们就可以融云,SignalR自由切换了。具体细节可以查看 LayIM.AspNetCore.Demo.RongCloud,LayIM.AspNetCore.Demo.SignalR两个项目。

总结

  给大家大体介绍了一下对接思路,其实有很多细节也没有展示,毕竟贴的代码已经够多了。如果小伙伴们有兴趣,可以移步:源码地址,今天就到这里啦,再见,祝大家中秋快乐

LayIM.AspNetCore Middleware 开发日记(七)Asp.Net.Core.SignalR闪亮登场的更多相关文章

  1. LayIM.AspNetCore Middleware 开发日记(六)嵌入资源的使用,layim.config的封装

    前言 距离上一篇博客竟然已经10多天了...工作上的事,个人原因,种种吧.不多说废话,本文将会重点介绍layim的入口配置. LayIM配置 其实在开发者文档里面已经描述的很清楚了.除了几个重要的接口 ...

  2. LayIM.AspNetCore Middleware 开发日记(一)闲言碎语

    前言 前几天写博客的时候突然看见了历史上的今天.不禁感慨时光如梭,这系列博客后来被我标注了已经过时,但是还有很多小伙伴咨询我.既然过时就要更新,正好 .NET Core 也出来很久了,于是乎想到把La ...

  3. LayIM.AspNetCore Middleware 开发日记(三)基础框架搭建

    前言 在上一篇中简单讲了一些基础知识,例如Asp.Net Core Middleware 的使用,DI的简单使用以及嵌入式资源的使用方法等.本篇就是结合基础知识来构建一个基础框架出来. 那么框架有什么 ...

  4. LayIM.AspNetCore Middleware 开发日记(四)主角登场(LayIM介绍)

    前言 在前几篇中已经初步介绍了开发AspNetCore中间件的一些基础知识,不过都没有很深入的去研究,后续还是需要去看看源码.本篇呢,终于有点开头的味道了,就是要介绍LayIM了,其实标题写的是主角, ...

  5. LayIM.AspNetCore Middleware 开发日记(二)预备知识介绍

    前言 开发一个AspNetCore的中间件需要理解RequestDelegate.另外,还需要理解.NET Core中的依赖注入.还有一个就是内嵌资源的访问.例如:EmbeddedFileProvid ...

  6. LayIM.AspNetCore Middleware 开发日记(五)Init接口实现细节

    前言 “一旦开始了就要坚持下去“.为什么本文的第一句话是这么一句话呢,因为我经常就是开头轰轰烈烈,结果越来越枯燥,就不想做下去了.但是版图就放弃又那么不甘心,继续加油吧. 吐槽完毕,进入正题.在上一篇 ...

  7. 在CentOS7 开发与部署 asp.net core app笔记

    原文:在CentOS7 开发与部署 asp.net core app笔记 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/lihongzhai/art ...

  8. 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(1)

    最近使用vscode比较多. 学习了一下如何在mac上使用vscode开发asp.netcore项目. 这里是我写的关于vscode的一篇文章: https://www.cnblogs.com/cgz ...

  9. Asp.Net Core SignalR 与微信小程序交互笔记

    什么是Asp.Net Core SignalR Asp.Net Core SignalR 是微软开发的一套基于Asp.Net Core的与Web进行实时交互的类库,它使我们的应用能够实时的把数据推送给 ...

随机推荐

  1. 撩课-Java每天10道面试题第6天

    51.HashMap的实现原理 HashMap的主干是一个Entry数组. Entry是HashMap的基本组成单元, 每一个Entry包含一个key-value键值对. HashMap基于hashi ...

  2. [LeetCode] Three Sum题解

    Three Sum: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? ...

  3. nginx 安装配置和常用命令

    基本环境:CentOS 1. 下载 nginx [root@localhost ~]# cd Downloads/ [root@localhost Downloads]# wget http://ng ...

  4. 基于.Net下整合FastReport,实现条码标签批量打印

    一. 准备工作 1. 点击此下载支持.Net4.0的 FastReport ,安装后并破解 2. VS2012 工具箱中,新建选项卡,添加 %安装目录%\Framework 4.0\FastRepor ...

  5. HDU 2639(01背包第K大)

    http://acm.hdu.edu.cn/showproblem.php?pid=2639 http://blog.csdn.net/lulipeng_cpp/article/details/758 ...

  6. lumen配置日志daily模式

    默认的日志保存模式是single 也就是单文件模式 要想改成每日的daily模式可以在bootstrap/app.php下添加: /* * 配置日志文件为每日 */ $app->configur ...

  7. MyBatis学习(二)---数据表之间关联

    想要了解MyBatis基础的朋友可以通过传送门: MyBatis学习(一)---配置文件,Mapper接口和动态SQL http://www.cnblogs.com/ghq120/p/8322302. ...

  8. CF891E Lust

    传送门 题目大意 你有 \(n\) 个数 \(a_1,a_2...a_n\) 要进行 \(k\) 次操作 每次随机选择一个数 \(x\),使得答案加上 \(\prod_{i \neq x}a_i\) ...

  9. js获取昨天/上周/上个月开始和结束的时间戳,可以设置时分秒 js obtain start and end timestamp of yesterday/last week/last month, with set of hour/minute/second

    //obtain timestamp of last week var now=new Date() var nowDayOfWeek = now.getDay(); //今天本周的第几天 var n ...

  10. html开发那些不好的习惯,和问题。

    最近网上看了好多html开发中那些问题和不好的习惯,顺手总结一下. 一.上下间距 在开发中你会发现你明明设置的两个p标签上下间距为20px但你实际测量中会发现他会多4~8px,这是为什么呢!如果你是老 ...