Introduced
ASP. NET Core signalr is a useful library that simplifies the management of real-time communication in Web applications. However, I prefer to use websockets because I want to be more flexible and compatible with any WebSocket client.
In the Microsoft documentation, I found a good example of websockets work. It is still a management connection so that it can broadcast messages from one connection to another, which is signalr out-of-the-box functionality. Expect this logic to be very complex and I want to remove it from the startup class.
Background
To read websockets support in ASP. NET core, you can view it here. Read this link if you want to learn about middleware and how to write it in ASP.
Code use
First, you must add the Microsoft.AspNetCore.WebSockets
package to your project.
Now you can create an extension method and a class to manage websockets:
Public Static classwebsocketextensions{ Public StaticIapplicationbuilder Usecustomwebsocketmanager ( ThisIapplicationbuilder app) { returnApp. Usemiddleware<customwebsocketmanager>(); }} Public classcustomwebsocketmanager{Private ReadOnlyrequestdelegate _next; PublicCustomwebsocketmanager (requestdelegate next) {_next=Next; } Public AsyncTask Invoke (HttpContext context, Icustomwebsocketfactory wsfactory, Icustomwebsocketmessagehandler wsmhandler) { if(Context. Request.path = ="/ws") { if(context. Websockets.iswebsocketrequest) {stringUsername = context. request.query["u"]; if(!string. IsNullOrEmpty (username)) {WebSocket WebSocket=awaitcontext. Websockets.acceptwebsocketasync (); Customwebsocket Userwebsocket=NewCustomwebsocket () {WebSocket=WebSocket, Username=username}; Wsfactory.add (Userwebsocket); awaitwsmhandler.sendinitialmessages (Userwebsocket); awaitListen (context, Userwebsocket, wsfactory, Wsmhandler); } } Else{context. Response.statuscode= -; } } await_next (context); } Private AsyncTask Listen (HttpContext context, Customwebsocket Userwebsocket, Icustomwebsocketfactory wsfactory, Icustomwebsocketmessagehandler wsmhandler) {WebSocket WebSocket=Userwebsocket.websocket; varBuffer =New byte[1024x768*4]; Websocketreceiveresult result=awaitWebsocket.receiveasync (Newarraysegment<byte>(buffer), cancellationtoken.none); while(!result. Closestatus.hasvalue) {awaitwsmhandler.handlemessage (result, buffer, userwebsocket, wsfactory); Buffer=New byte[1024x768*4]; Result=awaitWebsocket.receiveasync (Newarraysegment<byte>(buffer), cancellationtoken.none); } wsfactory.remove (Userwebsocket.username); awaitWebsocket.closeasync (result. Closestatus.value, result. Closestatusdescription, Cancellationtoken.none); }}
In this case, the WebSockets request always contains "/ws" in the URL. The query string contains the parameter u for the user name that is used to associate WebSocket with the logged-on user.
Customwebsocket is a class that contains websocket and user names:
Public class customwebsocket{ publicgetset;} Public string Get Set ; }}
I also created a custom WebSocket message:
class customwebsocketmessage{ publicstringgetset;} Public Get Set ; } Public string Get Set ; } Public Get Set ; }}
Where type is an enumeration of the different types of messages you might have.
In the startup class, you must register the following services:
Services. Addsingleton<icustomwebsocketfactory, customwebsocketfactory>(); services. Addsingleton<icustomwebsocketmessagehandler, customwebsocketmessagehandler> ();
Customwebsocketfactory is responsible for collecting the WebSockets list of connections:
Public Interfaceicustomwebsocketfactory{voidAdd (Customwebsocket UWS); voidRemove (stringusername); List<CustomWebSocket>All (); List<CustomWebSocket>Others (Customwebsocket client); Customwebsocket Client (stringusername);} Public classcustomwebsocketfactory:icustomwebsocketfactory{List<CustomWebSocket>List; Publiccustomwebsocketfactory () {List=NewList<customwebsocket>(); } Public voidAdd (Customwebsocket UWS) {list.add (UWS); } //When disconnect Public voidRemove (stringusername) {List.remove (Client (username)); } PublicList<customwebsocket>All () {returnList; } PublicList<customwebsocket>Others (Customwebsocket client) {returnList.where (c = c.username! =client. Username). ToList (); } PublicCustomwebsocket Client (stringusername) { returnList.first (C=>c.username = =username); }}
Customwebsocketmessagehandler contains logic about the message (that is, any message needs to be sent at the time of the connection and how to react to the incoming message)
Public Interfaceicustomwebsocketmessagehandler{Task sendinitialmessages (Customwebsocket userwebsocket); Task handlemessage (websocketreceiveresult result,byte[] buffer, Customwebsocket userwebsocket, icustomwebsocketfactory wsfactory); Task Broadcastothers (byte[] buffer, Customwebsocket userwebsocket, icustomwebsocketfactory wsfactory); Task Broadcastall (byte[] buffer, Customwebsocket userwebsocket, Icustomwebsocketfactory wsfactory);} Public classcustomwebsocketmessagehandler:icustomwebsocketmessagehandler{ Public AsyncTask sendinitialmessages (customwebsocket userwebsocket) {WebSocket WebSocket=Userwebsocket.websocket; varmsg =NewCustomwebsocketmessage {messagdatetime=DateTime.Now, Type=Wsmessagetype.anytype, Text=Anytext, Username="system" }; stringSerialisedmessage =jsonconvert.serializeobject (msg); byte[] bytes =Encoding.ASCII.GetBytes (serialisedmessage); awaitWebsocket.sendasync (Newarraysegment<byte> (Bytes,0, bytes. Length), Websocketmessagetype.text,true, Cancellationtoken.none); } Public AsyncTask handlemessage (websocketreceiveresult result,byte[] buffer, Customwebsocket userwebsocket, Icustomwebsocketfactory wsfactory) { stringmsg =Encoding.ASCII.GetString (buffer); Try { varmessage = jsonconvert.deserializeobject<customwebsocketmessage>(msg); if(Message. Type = =wsmessagetype.anytype) {awaitbroadcastothers (buffer, userwebsocket, wsfactory); } } Catch(Exception e) {awaitUserWebSocket.WebSocket.SendAsync (Newarraysegment<byte> (Buffer,0, result. Count), result. MessageType, result. Endofmessage, Cancellationtoken.none); } } Public AsyncTask Broadcastothers (byte[] buffer, Customwebsocket userwebsocket, Icustomwebsocketfactory wsfactory) { varothers =wsfactory.others (Userwebsocket); foreach(varUWsinchothers) { awaitUWs. Websocket.sendasync (Newarraysegment<byte> (Buffer,0, buffer. Length), Websocketmessagetype.text,true, Cancellationtoken.none); } } Public AsyncTask Broadcastall (byte[] buffer, Customwebsocket userwebsocket, Icustomwebsocketfactory wsfactory) { varall =Wsfactory.all (); foreach(varUWsinchAll ) { awaitUWs. Websocket.sendasync (Newarraysegment<byte> (Buffer,0, buffer. Length), Websocketmessagetype.text,true, Cancellationtoken.none); } }}
Finally, add the following in the startup class of the Configure method:
var New websocketoptions () { = timespan.fromseconds (+), 41024x768 };app. Usewebsockets (websocketoptions); app. Usecustomwebsocketmanager ();
In this way, the Starup class remains clean, and the logic of managing websockets can be extended so that you can organize it flexibly to your liking. Just like this article. Using middleware to manage WebSocket in ASP.