WebSocket In ASP.NET Core(二)
2017-09-22 00:16
393 查看
.NET-Core Series
Server in ASP.NET-CoreDI in ASP.NET-Core
Routing in ASP.NET-Core
Error Handling in ASP.NET-Core
WebSocket in ASP.NET-Core(一)
WebSocket in ASP.NET-Core(二)
To Be Continue...
Introduce
上篇博文中,介绍了WebSocket的基本原理,以及一个简单的
Demo用来对其有一个大致的认识。这篇博文讲的是我们平常在网站上可能会经常遇到的——实时聊天,本文就是来讲在
.NET-Core使用
WebSocket来实现一个“乞丐版”的在线实时聊天Demo。
关键词:Middleware,Real-Time,WebSocket
Before You Read.
这个和我们上一篇博文中Demo有何不同的呢?有何共同之处呢?
相同的点是,都是网页作为客户端,使用
JavaScript来发送和接收请求,
.NET-Core服务端接收到请求,发送该请求给客户端。
不同的地方呢,就像我下面这张图这样:
一次同时有多个客户端在,所以应该很清楚,我们只要在上面例子的基础上,对当前的已存在的Socket进行轮询,发送回应即可达到我们想要的效果。
Create WebSocket Middleware
在上个Demo的例子中,我们直接在
Startup的
Configure中直接写接受
WebSocket请求。这次我们换成Middleware形式来处理。在写Middleware之前,在之前的介绍中,我们知道,需要有多个
WebSocket,那么肯定需要一些对
WebSocket的
Get/Set处理。我简单的写了一个下面
WebScoket Manger Class
//WebSocketManager.cs using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace WebSocketManage { public class WSConnectionManager { private static ConcurrentDictionary<string, WebSocket> _socketConcurrentDictionary = new ConcurrentDictionary<string, WebSocket>(); public void AddSocket(WebSocket socket) { _socketConcurrentDictionary.TryAdd(CreateGuid(), socket); } public async Task RemoveSocket(WebSocket socket) { _socketConcurrentDictionary.TryRemove(GetSocketId(socket), out WebSocket aSocket); await aSocket.CloseAsync( closeStatus: WebSocketCloseStatus.NormalClosure, statusDescription: "Close by User", cancellationToken: CancellationToken.None).ConfigureAwait(false); } public string GetSocketId(WebSocket socket) { return _socketConcurrentDictionary.FirstOrDefault(k => k.Value == socket).Key; } public ConcurrentDictionary<string, WebSocket> GetAll() { return _socketConcurrentDictionary; } public string CreateGuid() { return Guid.NewGuid().ToString(); } } }
上面主要是对
WebSocket进行了简单的存取操作进行了封装。下面也把
WebSocket的
Send和
Recieve操作进行了封装。
using System; using System.Collections.Generic; using System.IO; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace WebSocketManage { public class WSHandler { protected WSConnectionManager _wsConnectionManager; public WSHandler(WSConnectionManager wSConnectionManager) { _wsConnectionManager = wSConnectionManager; } public async Task SendMessageAsync( WebSocket socket, string message, CancellationToken cancellationToken = default(CancellationToken)) { var buffer = Encoding.UTF8.GetBytes(message); var segment = new ArraySegment<byte>(buffer); await socket.SendAsync(segment, WebSocketMessageType.Text, true, cancellationToken); } public async Task<string> RecieveAsync(WebSocket webSocket, CancellationToken cancellationToken) { var buffer = new ArraySegment<byte>(new byte[1024 * 8]); using (var ms = new MemoryStream()) { WebSocketReceiveResult result; do { cancellationToken.ThrowIfCancellationRequested(); result = await webSocket.ReceiveAsync(buffer, cancellationToken); ms.Write(buffer.Array, buffer.Offset, result.Count); } while (!result.EndOfMessage); ms.Seek(0, SeekOrigin.Begin); if (result.MessageType != WebSocketMessageType.Text) { return null; } using (var reader = new StreamReader(ms, Encoding.UTF8)) { return await reader.ReadToEndAsync(); } } } } }
有了上面两个辅助类之后,接下来就可以写我们自己的
RealTimeWebSocketMiddlerware了,
using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.IO; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; using WebSocketManage; namespace Robert.Middleware.WebSockets { public class RealTimeWSMiddleware { private readonly RequestDelegate _next; private WSConnectionManager _wSConnectionManager { get; set; } private WSHandler _wsHanlder { get; set; } public RealTimeWSMiddleware( RequestDelegate next, WSConnectionManager wSConnectionManager, WSHandler wsHandler) { _next = next; _wSConnectionManager = wSConnectionManager; _wsHanlder = wsHandler; } public async Task Invoke(HttpContext httpContext) { if (httpContext.WebSockets.IsWebSocketRequest) { var cancellationToken = httpContext.RequestAborted; var currentWebSocket = await httpContext.WebSockets.AcceptWebSocketAsync(); _wSConnectionManager.AddSocket(currentWebSocket); while (true) { if (cancellationToken.IsCancellationRequested) break; var response = await _wsHanlder.ReceiveAsync(currentWebSocket, cancellationToken); if (string.IsNullOrEmpty(response) && currentWebSocket.State != WebSocketState.Open) break; foreach (var item in _wSConnectionManager.GetAll()) { if (item.Value.State == WebSocketState.Open) { await _wsHanlder.SendMessageAsync(item.Value, response, cancellationToken); } continue; } } await _wSConnectionManager.RemoveSocket(currentWebSocket); } else { await _next(httpContext); } } } }
其实到这里,核心部分已经讲完了,接下来就是页面显示,发现信息,交互的问题了。在客户端还是像上篇文章中的一样,直接使用
JavaScript发送
WebScoket请求。
下面主要演示一下效果,在上篇博文的基础上,加上了用户名。
<script> $(function () { var protocol = location.protocol === "https:" ? "wss:" : "ws:"; var Uri = protocol + "//" + window.location.host + "/ws"; var socket = new WebSocket(Uri); socket.onopen = e => { console.log("socket opened", e); }; socket.onclose = function (e) { console.log("socket closed", e); }; //function to receive from server. socket.onmessage = function (e) { console.log("Message:" + e.data); $('#msgs').append(e.data + '<br />'); }; socket.onerror = function (e) { console.error(e.data); }; }); </script>
当写好了页面文件后,运行站点。最终运行的效果图,界面以实用为主,不求美观。 😄😄
At End
这里演示的其实只是简简单单的信息接受操作,实际环境中肯定不会这样用的,比如对用户的身份验证,可以建一个Auth 站点,还需要对信息传输加密。还会有 1对1 的聊天等等。这里只介绍了乞丐版,在参考链接中,一个GitHub上的大哥封装的很好的一个
WebSocket 中间件,如果感兴趣的可以去
fork下来了解了解。当然等
SingleR 2.0出来后,这些肯定都是可以换掉的。
在上述的中间件辅助的两个类中,还可以对一些内容进行封装,比如开始建立连接和断开连接等,还有群发信息等操作,都是可以封装的。
内容中如果陈述错误处,请多多指正。
Reference
websocket-manager相关文章推荐
- Using Custom Domains With IIS Express In Asp.Net Core
- DI in ASP.NET Core
- Allow Only Ajax Requests For An Action In ASP.NET Core
- ASP.NET Core Logging in Elasticsearch with Kibana
- Error Handling in ASP.NET Core
- WebSocket in ASP.NET Core
- [转]Create Custom Exception Filter in ASP.NET Core
- Bower In ASP.NET Core
- Middleware In ASP.NET Core
- Asp.net Core中如何使用中间件来管理websocket
- asp.net core in centos
- [转]How to override HandleUnauthorizedRequest in ASP.NET Core
- 体验 ASP.NET Core 集成测试三剑客:xUnit.net、TestServer、EF Core InMemory
- Setup Automapper in ASP.NET Core
- Talking appsettings.json in Asp.Net Core
- Asp.Net Core WebSocket绑定
- Create an ASP.NET Core web app in Visual Studio Code
- Asp.net core中的websocket
- Server in ASP.NET-Core