This post shows how SignalR could be used to send messages between different C# console clients using Message Pack as the protocol. An ASP.NET Core web application is used to host the SignalR Hub.
Code: https://github.com/damienbod/AspNetCoreAngularSignalR
Posts in this series
- Getting started with SignalR using ASP.NET Core and Angular
- SignalR Group messages with ngrx and Angular
- Using EF Core and SQLite to persist SignalR Group messages in ASP.NET Core
- Securing an Angular SignalR client using JWT tokens with ASP.NET Core and IdentityServer4
- Implementing custom policies in ASP.NET Core using the HttpContext
- Sending Direct Messages using SignalR with ASP.NET core and Angular
- Using Message Pack with ASP.NET Core SignalR
- Uploading and sending image messages with ASP.NET Core SignalR
History
2019-07-30 Updated Angular 8.1.3, ASP.NET Core 3.0 Preview 7
2018-12-12 Updated .NET Core 2.2, ASP.NET Core SignalR 1.1.0, Angular 7.1.3
2018-05-31 Updated Microsoft.AspNetCore.SignalR 2.1
2018-05-08 Updated Microsoft.AspNetCore.SignalR 2.1 rc1
Setting up the Message Pack SignalR server
Add the Microsoft.AspNetCore.SignalR and the Microsoft.AspNetCore.SignalR.MsgPack NuGet packages to the ASP.NET Core server application where the SignalR Hub will be hosted. The Visual Studio NuGet Package Manager can be used for this.
Or just add it directly to the .csproj project file.
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="3.0.0-preview7.19365.7" />
Setup a SignalR Hub as required. This is done by implementing the Hub class.
using Dtos; using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace AspNetCoreAngularSignalR.SignalRHubs { // Send messages using Message Pack binary formatter public class LoopyMessageHub : Hub { public Task Send(MessageDto data) { return Clients.All.SendAsync("Send", data); } } }
A DTO class is created to send the Message Pack messages. Notice that the class is a plain C# class with no Message Pack attributes, or properties.
using System; namespace Dtos { public class MessageDto { public Guid Id { get; set; } public string Name { get; set; } public int Amount { get; set; } } }
Then add the Message Pack protocol to the SignalR service.
services.AddSignalR() .AddMessagePackProtocol();
And configure the SignalR Hub in the Startup class Configure method of the ASP.NET Core server application.
app.UseEndpoints(endpoints => { endpoints.MapHub<LoopyHub>("/loopy"); endpoints.MapHub<NewsHub>("/looney"); endpoints.MapHub<LoopyMessageHub>("/loopymessage"); endpoints.MapHub<ImagesMessageHub>("/zub"); endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapRazorPages(); });
Setting up the Message Pack SignalR client
Add the Microsoft.AspNetCore.SignalR.Client and the Microsoft.AspNetCore.SignalR.Client.MsgPack NuGet packages to the SignalR client console application.
The packages are added to the project file.
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="3.0.0-preview7.19365.7" />
Create a Hub client connection using the Message Pack Protocol. The Url must match the URL configuration on the server.
public static async Task SetupSignalRHubAsync() { _hubConnection = new HubConnectionBuilder() .WithUrl("https://localhost:44324/loopymessage") .AddMessagePackProtocol() .ConfigureLogging(factory => { factory.AddConsole(); factory.AddFilter("Console", level => level >= LogLevel.Trace); }).Build(); await _hubConnection.StartAsync(); }
The Hub can then be used to send or receive SignalR messages using the Message Pack as the binary serializer.
using Dtos; using System; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.SignalR.Protocol; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; namespace ConsoleSignalRMessagePack { class Program { private static HubConnection _hubConnection; public static void Main(string[] args) => MainAsync().GetAwaiter().GetResult(); static async Task MainAsync() { await SetupSignalRHubAsync(); _hubConnection.On<MessageDto>("Send", (message) => { Console.WriteLine($"Received Message: {message.Name}"); }); Console.WriteLine("Connected to Hub"); Console.WriteLine("Press ESC to stop"); do { while (!Console.KeyAvailable) { var message = Console.ReadLine(); await _hubConnection.SendAsync("Send", new MessageDto() { Id = Guid.NewGuid(), Name = message, Amount = 7 }); Console.WriteLine("SendAsync to Hub"); } } while (Console.ReadKey(true).Key != ConsoleKey.Escape); await _hubConnection.DisposeAsync(); } public static async Task SetupSignalRHubAsync() { _hubConnection = new HubConnectionBuilder() .WithUrl("https://localhost:44324/loopymessage") .AddMessagePackProtocol() .ConfigureLogging(factory => { factory.AddConsole(); factory.AddFilter("Console", level => level >= LogLevel.Trace); }).Build(); await _hubConnection.StartAsync(); } } }
Testing
Start the server application, and 2 console applications. Then you can send and receive SignalR messages, which use Message Pack as the protocol.
Links:
https://github.com/aspnet/SignalR
[…] Using Message Pack with ASP.NET Core SignalR | Software Engineering – Damien Bowden […]
The big question remains, would you want to do this? How much longer does it take (with all the extra js needed) for the hub connection to be established? Is is faster than using json payloads? Can it compete with gzip content from controller methods? At least this is what I’d like to know 🙂
Hi mortenmertner, yes correct, but depending on your payload, the message pack serializer payload is smaller, and faster so it makes sense for example with a backend service to service communication
Greetings Damien
Maybe. It only makes sense if it’s actually faster. Given that browsers deserialize JSON natively it is not a given that a binary format (which is decoded by JS) is faster. The only given is that it takes up fewer bytes on the wire. Performance benchmarks for large and small payloads are needed.
yes, you are correct when the client is a browser app, but in this example, the client is a console application, or could be a second backend service, and then it would be faster.
Greetings Damien
What is the message delivery reliability here, and how this compares against Akka.NET.
[…] Using message pack with ASP.NET Core SignalR […]