Reading mode

signalr

Best way to call client methods in a Hub class

This is a common way to call a client-side method via SignalR:

public class WebHub : Hub
{
...
   public async Task SomeMethod(string something)
   {
       //Calls CheckItOut method in all Clients and passes string parameter 'something'
       await Clients.All.SendAsync("CheckItOut", something);
   }
...
}

Although, you can see such practice in many Real-time connection libraries and examples, this may lead to messing up your code with hardcoded values, duplications and missunderstanding of what a particular command should do.
There is an alternative way to call client-side methods that matches OOP design and looks simple:

Declare an interface with client side methods and pass it to generic type of Hub class.

public class WebHub : Hub<IWebInterface>
{
...
   public async Task SomeMethod(string something)
   {
       await Clients.All.CheckItOut(something);
   }
...
}
public interface IWebInterface
{
    public Task CheckItOut(string something);

    public Task Refresh();
}

How to get query parameter during client connection to Hub

Client code:

//example on js with SignalR.js library
...
let player = 1;
let connection = new signalR.HubConnectionBuilder()
                    .withUrl("/web?player=" + player)
                    .build();
...
connection.start();
...

Server code:

public class WebHub : Hub
{
...
   public override async Task OnConnectedAsync()
   {
       var httpContext = Context.Features.Get<IHttpContextFeature>().HttpContext;
       string id = httpContext.Request.Query["player"];
       Console.WriteLine("Player: " + id == null ? "none" : id);
       ...
       await base.OnConnectedAsync();
   }
...
}

How to send message to particular user(s)?

public class WebHub : Hub<IWebInterface>
{
...
   public async Task SomeMethod(string something)
   {
       //Call in All connected Clients
       await Clients.All.CheckItOut(something);

       //Call in current connected Client
       await Clients.Caller.CheckItOut(something);

       //Call in Others connected Clients - this means All without Caller
       await Clients.Others.CheckItOut(something);

       //Call in Client by its connection Id
       await Clients.Client("[connectionId]").CheckItOut(something);
   }
...
}

How to get current client connection Id

public class WebHub : Hub<IWebInterface>
{
...
   public async Task SomeMethod(string something)
   {
       string currentId = Context.ConnectionId;
       Console.WriteLine(currentId + " has called SomeMethod and passed - " + something);
   }
...
}

How to call a method in group without current connection

public class WebHub : Hub<IWebInterface>
{
...
   public async Task SomeMethod(string groupName)
   {
       await Clients.OthersInGroup(groupName).CheckItOut("all group participants without current client will recieve this");
   }
...
}

How to setup Authentication with JWT token in SignalR hub

Assume that «/web» is our Hub endpoint. Configure JWT auth in Asp Net Core application:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                   .AddJwtBearer(options =>
                   {
                       options.RequireHttpsMetadata = true;
                       options.TokenValidationParameters = new TokenValidationParameters
                       {
                          ...
                          //your TokenValidationParameters
                          ...
                       };
                       options.Events = new JwtBearerEvents
                       {
                           OnMessageReceived = context =>
                           {
                               var accessToken = context.Request.Query["access_token"];
                               var path = context.HttpContext.Request.Path;
                               if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/web")))
                               {
                                   context.Token = accessToken;
                               }
                               return Task.CompletedTask;
                           }
                       };
                   });

Assume that you have an endpoint to get jwt token «/Account/token?username=[username]&password=[password]». Take token and add it during connection to SignalR hub in client-side:

...
const response = await fetch("/Account/token?username=admin&password=admin123");
let token = await response.json();
let connection = new signalR.HubConnectionBuilder()
                .withUrl("/web", { accessTokenFactory: () => token.access_token })
                .withAutomaticReconnect()
                .build();
...
connection.start();
...

Add Authorize attribute to Hub class:

[Authorize]
public class WebHub : Hub<IWebInterface>
...
Поделиться этой записью