前幾篇介紹了整個中間件的構成,路由,基本配置等等.基本上沒有涉及到通信部分。不過已經實現了融雲的通信功能,因爲是第三方的就不在單獨去寫。正好.NET Core SignalR已經出來很久了,因而乎趕忙對接上。能夠先看一下以前的文章:.Net Core SignalR初體驗。javascript
Hub我採用了 Hub<T>
,而後只定義了一個 Receive方法。html
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); }
那麼這裏咱們要作的就是,先鏈接上服務器在實現詳細業務。下面咱們要作兩件事情:java
Javascript
客戶端因爲是將SignalR拆分到LayIM.AspNetCore.IM.SignalR
項目中,因此註冊服務端代碼作了小小封裝。在SignalRServiceExtensions
文件中:git
/// <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 調用的時候就能夠這麼寫了:github
//註冊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)客戶端代碼。app
這裏咱們根據官方文檔裏寫就能夠。鏈接部分核心代碼:socket
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發送消息部分的代碼:ide
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
兩個項目。
給你們大致介紹了一下對接思路,其實有不少細節也沒有展現,畢竟貼的代碼已經夠多了。若是小夥伴們有興趣,能夠移步:源碼地址,今天就到這裏啦,再見,祝你們中秋快樂