A lightweight publisher / subscriber implementation using WebSockets.
.NET Standard 2.0, .NET Core 2.1 and ASP .NET Core
NuGet
Example of dipsocket being used as a chat application where users connect to a channel and join the discussion.
.NET Standard 2.0
DipSocketServer hosts and manages a collection of DipSocketClient connections. It also manages a collection of Channels. A Channel is a group of client connections that subscribe to it. Messages from one client connection to another client or to a channel get routed via the server. When a client sends a message to a channel the message is broadcast to all connections subscribing to the channel.
.NET Standard 2.0
DipSocketClient represents a client connection to the DipSocketServer. Client connections can send messages to each other, routed via the server. Client connections can also create and subscribe to channels hosted by the DipSocketServer.
.NET Core 2.1 and ASP NET Core
DipSocket.NetCore.Extensions.dll provides the middleware and extension methods necessary for ASP .NET Core. Simply add dip socket to the services collection and get the app builder to use it.
Establish a DipSocketClient connection to the DipSocketServer.
var dipSocketClient = new DipSocketClient(@"ws://localhost:6000/chat", "clientId");
dipSocketClient.Closed += DipSocketClientClosed; ;
dipSocketClient.Error += DipSocketClientError;
dipSocketClient.On("OnConnected", (result) =>
{
OnConnected(result);
});
dipSocketClient.On("OnMessageReceived", (result) =>
{
OnMessageReceived(result);
});
await dipSocketClient.StartAsync();
Send a message from one DipSocketClient to another. Messages are routed via the server.
var clientMessage = new Message
{
SenderConnectionId = senderConnectionId,
RecipientConnectionId = recipientConnectionId,
Data = myMessage,
MessageType = MessageType.SendToClient
};
await dipSocketClient.SendMessageAsync(clientMessage);
Send a message from a DipSocketClient to a channel on the DipSocketServer. The message is broadcast to all clients subscribing to the channel.
var clientMessage = new Message
{
SenderConnectionId = senderConnectionId,
RecipientConnectionId = channelConnectionId,
Data = myMessage,
MessageType = MessageType.SendToChannel
};
await dipSocketClient.SendMessageAsync(clientMessage);
Inherit the abstract DipSocketServer class and override abstract methods OnClientConnectAsync and ReceiveAsync.
public class Chat : DipSocketServer
{
public async override Task OnClientConnectAsync(WebSocket websocket, string clientId)
{
if (string.IsNullOrWhiteSpace(clientId))
{
throw new ArgumentNullException("clientId cannot be null or empty.");
}
var connection = await base.AddWebSocketAsync(websocket).ConfigureAwait(false);
connection.Name = clientId;
var connectionInfo = connection.GetConnectionInfo();
var json = JsonConvert.SerializeObject(connectionInfo);
var message = new Message { MethodName = "OnConnected", SenderConnectionId = "Chat", Data = json };
await SendMessageAsync(websocket, message).ConfigureAwait(false);
}
public async override Task ReceiveAsync(WebSocket webSocket, Message message)
{
switch (message.MessageType)
{
case MessageType.SendToAll:
message.MethodName = "OnMessageReceived";
await SendMessageToAllAsync(message).ConfigureAwait(false);
break;
case MessageType.SendToClient:
message.MethodName = "OnMessageReceived";
await SendMessageAsync(message).ConfigureAwait(false);
break;
case MessageType.SubscribeToChannel:
var channel = SubscribeToChannel(message.Data, webSocket);
await ChannelUpdateAsync().ConfigureAwait(false);
break;
}
}
}
In the Startup class use the IServiceCollection extension method AddDipSocket and the IApplicationBuilder extension method UseDipSocket<T>. This will register each implementation of the DipSocketServer as a singleton in the service collection and add the middleware.
The following shows how to set up the Chat implementation of the DipSocketServer in the example code.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDipSocket();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseDipSocket<Chat>("/chat");
}
}
The example solution provided is a simple chat application. It consists of a WPF client and a ASP .NET Core server.
First launch the server. Then run multiple instances of the Client.exe.
For each instance of the client provide a unique user name:
The client will automatically attempt to connect to the server.
Either add a new channel, or select an existing connection or channel from the drop down list:
Write your message in the text box at the bottom and hit enter: