Hubcon 1.6.0

dotnet add package Hubcon --version 1.6.0
                    
NuGet\Install-Package Hubcon -Version 1.6.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Hubcon" Version="1.6.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Hubcon" Version="1.6.0" />
                    
Directory.Packages.props
<PackageReference Include="Hubcon" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Hubcon --version 1.6.0
                    
#r "nuget: Hubcon, 1.6.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Hubcon@1.6.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Hubcon&version=1.6.0
                    
Install as a Cake Addin
#tool nuget:?package=Hubcon&version=1.6.0
                    
Install as a Cake Tool

Hubcon is a library that abstracts SignalR messages/returns using a custom interface, solving SignalR's hassle of implementing each message and method individually.

It currently supports:

  • Async methods
  • Sync methods (automatically wrapped as Async)
  • Void methods
  • Methods with and without return value
  • Methods with and without parameters
  • Nullable parameters
  • Default parameters
  • Variable parameters (params)
  • IEnumerable
  • Dictionary
  • Classes in general

The project now uses MessagePack, greatly enhancing speed and bandwidth usage, and JSON to provide strong type safety and complex object conversion.

Usage

Domain Project

After installing this package, create a two interfaces that implement IClientHubController and IServerHubController in your Domain project. Client and server MUST share this interface, or at least implement exactly the same interface on both sides. You can choose to implement just one of them, this example just covers both cases.

public interface IMyClientController : IClientController
{
    Task<int> GetClientTemperature();
}

public interface IMyServerHub : IServerHubController
{
    Task<int> GetServerTemperature();
}

Client

This project can be anything, a console application, a background worker or even a singleton service.

Create MyClientController, inherit ClientController, then implement IMyClientController. This will receive server calls and execute the requested methods.

public class MyClientController(string hubUrl) : ClientController(hubUrl), IMyClientController
{
    public async Task<int> GetTemperature() => await Task.Run(() => new Random().Next(-10, 50));
}

You can inherit from ClientController like the last example, or use ClientController<> generic with an interface that implements IServerHubController to enable the Server property. Server property allows executing server methods using the specified interface. This is optional.

public class MyClientController(string url) : ClientController<IMyServerHub>(url), IMyClientController
{
    public async Task<int> GetTemperature() => await Task.Run(() => new Random().Next(-10, 50));

    // Some example method
    private async Task CallServer()
    {
        // Some call to server
        Server.SomeServerMethod();
    }
}

On your SignalR client's program.cs (in this case, an empty console application), you can now create it and Start it:

static async Task Main()
{
    var myClientController = new MyClientController("http://localhost:5001/myclienthub").StartServerInstance();
    var connector = myClientController.GetConnector<IMyServerHub>(); // Gets a "connector", which is used to call server methods.

    var temperature = connector.GetTemperatureFromServer();

    Console.WriteLine(temperature);

    Console.ReadKey();
}

Server

The server should be an ASP.NET Core 8 API, but should also work for Blazor and ASP.NET Core MVC.

Create ServerTestHubController.cs. This is the server's hub. It can implement methods and be called from clients.

public class MyServerHub : ServerHub<IMyClientController>, IMyServerHub
{
    // Returns some random temperature to client
    public async Task<int> GetTemperatureFromServer() => await Task.Run(() => new Random().Next(-10, 50));
}

// You can just inherit from ServerHub, or use ServerHub<T> to enable the Client variable, which refers to the current calling client.
// Client variable allows executing calling client methods using the specified interface.

On your server program.cs's services:

builder.Services
        .AddHubcon();
        .AddHubconClientAccessor(); // This is explained later

Same file, after builder.Build():

app.MapHub<MyServerHub>("/myclienthub");

// Just a test endpoint, it can also be injected in a controller.
app.MapGet("/test", async (IClientAccessor<MyServerHub, IMyClientController> clientAccessor) =>
{
    // Getting some connected clientId
    var clientId = clientAccessor.GetAllClients().First();

    // Gets a client instance
    var client = clientAccessor.GetClient(clientId);

    var temperature = await client.GetTemperature();

    return temperature.ToString();
});

And that's it. Execute both projects at the same time and go to localhost:<port>/test, you should see the GetTemperature() method return a value. You can experiment with any method.

New Dependency Injection methods

AddHubcon() method registers all dependencies needed for hubcon to work properly.

builder.Services
        .AddHubcon();

AddHubconClientAccessor() method allows injecting, like the name states, a client accessor. This means that, when you need interacting with a client from some scoped class, you can do it through this interface. This one is specially made for scoped contexts. Allows interacting with connected clients, for example, from a Blazor page, or an ASP.NET controller, like so: NOTE: This is for server hubs. You can change IClientAccessor generic to your ServerHub/IClientController combinations as you please, with no additional configuration.

builder.Services
        .AddHubcon();
        .AddHubconClientAccessor();

After adding the client accessor, you can now inject it anywhere you need. For example:

    [ApiController]
    [Route("[controller]")]
    public class SomeAspNetController(IClientAccessor<MyServerHub, IMyClientController> clientAccessor) : ControllerBase
    {              
        [HttpGet]
        [Route("SomeMethod")]
        public async Task<int> SomeMethod()
        {
            // Using GetAllClients to get access to the current connected clients.
            var instances = clientAccessor.GetAllClients().First();

            // Using Getclient to retrieve a specific client, then executing a command.
            return await clientAccessor.GetClient(instances).GetTemperature();
        }
    }

AddHubconClientController() method registers and starts your ClientController as a Singleton, as only the server can access it. This method also register IMyServerHub as a server instance, allowing you to call the server from anywhere you want.

builder.Services
    .AddHubcon()
    .AddHubconClientController<MyClientController, IMyServerHub>("https://localhost:5001/myclienthub");

You can also use the dependency injection both methods provided at the same time, in case your project need to act both as a ServerHub and a Client of another server. Doesn't need a particular order after AddHubcon method.

builder.Services
    .AddHubcon()
    .AddHubconClientAccessor()
    .AddHubconClientController<MyClientController, IMyServerHub>("https://localhost:5001/myclienthub");

Adding more methods

To implement more methods, just add them to the interfaces, implement them in MyClientController, then use it somewhere from the server, it will just work. This also applies on reverse, using IMyServerHub and clients.

Use case

This fits perfectly if you need to communicate two instances in real time, in an easy and type-safe way. The wrappers are persisted in memory to avoid rebuilding overhead (will be further improved).

Version changes

  • Version updated to 1.6.0
  • Simplified class names for better readability and understandability.
  • Implemented IClientAccessor<THub,TIClientController> for easy client access.
  • Refactored ClientController and fixed internal memory leaks.
  • Added new dependency injection methods.
  • Added scoped support for ClientController.
  • Removed some unused classes and usings.
  • Fixed memory leaks when creating the artificial client implementations.
  • Updated readme

Note

This project is under heavy development. The APIs might change.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.6.0 117 11/16/2024
1.5.0 106 11/6/2024
1.4.0 109 10/29/2024
1.3.0 122 10/20/2024
1.2.0 140 10/20/2024
1.1.0 130 10/20/2024
1.0.2 122 10/11/2024