1

It seems that Microsoft has made changes to SignalR. At least I think. I created a new project and the dependencies are:

  • Microsoft.AspNetCore.SignalR.Common
  • Microsoft.AspNetCore.SignalR.Protocols.Json

It is not:

  • Microsoft.AspNet.SignalR ...which seems to be before .NET Core (where there is valid samples).

I want to send notification to the client but not from the hub itself like the sample available at: (Tutorial: Get started with ASP.NET Core SignalR)

According to Microsoft doc (purple note), Hub class is transient and we should access it from IHubContext (not the Hub directly).

I read: Microsoft how SignalR works but I can't figure out how to access the Hub through IHubContext<MyHub> because I can't find how to get my IHubContext<MyHub>. Either in the C# Corner (link below), I can't see how to call the background service to get a "IHubContext"?

So according to the doc, I can't instantiate MyHub directly. I have to pass through IHubContext. But I can't figured out how to get a valid IHubContext<MyHub> from anywhere in the web server in order to push notification to the client?

Note: I can't figured out, either based on these links:

Eric Ouellet
  • 10,996
  • 11
  • 84
  • 119
  • _"I can't see how to run or call the background service"_ - background services are run by the host ([see the docs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-7.0&tabs=visual-studio)). Usual approach is to just use the DI where needed - inject `IHubContext` where needed and that's it. Also AFAIK not explicit SignalR packages are needed to use it in ASP.NET Core. – Guru Stron Apr 05 '23 at 20:26
  • Can you please post a [mre]/code somewhere so the source of misunderstanding becomes clearer. – Guru Stron Apr 05 '23 at 20:28
  • [Is the effect in the first gif what you want?](https://stackoverflow.com/a/75831375/7687666) – Jason Pan Apr 06 '23 at 05:57
  • @GuruStron, Hello Guru, thank you for your feedback. I agree I just need to add IHubContext to Services by Dependency injection. The problem reside in the way to get that IHubContext. If you can tell me that, then I will be OK. – Eric Ouellet Apr 13 '23 at 13:52
  • TBH I don't understand the problem. AFAIK your just call `app.MapHub("/whatever");` in your ASP.NET Core app on startup and that's it. – Guru Stron Apr 13 '23 at 13:55
  • @GuruStron, I did call app.MapHub("/whatever"); in my ASP.NET Core app on startup. That does not give me a IHubContext??? – Eric Ouellet Apr 14 '23 at 17:35
  • Can you please post a full [mre] somewhere? – Guru Stron Apr 14 '23 at 17:47
  • Without a code example, it'll be difficult to see where the issue is, but you should be able to simply inject the IHubContext where you need it. @EricOuellet – Matt M Apr 14 '23 at 18:44
  • I will try to do a sample on monday... – Eric Ouellet Apr 14 '23 at 20:32

1 Answers1

0

I found 2 ways to get a SignalR HubContext. Both depends on Magic. The Magic of dependency injection where Microsoft uses with questionnable reasons.

First, as the doc says, you can't get the Hub itself: Hubs are transient. We should use HubContext instead. That appears to be silly to me because my intension was to put code related to Hub in the class itself but because I cannot have access to that class in any ways when from a worker thread, it makes no sense anymore.

I found 2 ways to get an instance:

Method 1 - Twisted one, by creating a HostedService and overloading the constructor like in code below. The hubContext will happen as an argument of the constructor by magic - don't ask me why and good luck to find it. ASP.NET is more and more using dependency injection and magic happen everywhere. Programmer need to guess where and why. I think it makes library very hard to understand for peoples not knowing the inner ASP.Net code or all the nits and bits of the library design.

In class program:

builder.Services.AddHostedService<LogHubService>();

LogHubService constructor:

public class LogHubService : BackgroundService
{
    IHubContext<LogHub> _hubContext;
    public LogHubService(IHubContext<LogHub> hubContext)
    {
        _hubContext = hubContext;
    }
    ...

Method 2 - Using the "WebApplication.Services". That solution also depends on Magic. Again, it is still depends on dependency injection and magic. I have no clue why Microsoft went for magic where there is no way to discover where to get the HubContext (there is no ref in code). That appears to me as being a totally stupid design, exactly like the magic that happen in Java-Spring (which makes me vomit). Also (just to show the weird design) they call a connection: client where a client can have more than a connection. You should also pass a connectionId to distinguish the proper Client (appears to be stupid to me). The way I was able to get my HubContext was using the WebApplication.Services like so (but don't ask me why):

var hubContext = Program.WebApplication.Services.GetService<IHubContext<ItemHub>>();

Important here: I created static public property into "Program" class to access my WebApplication object. I initialize that property on startup.

public class Program
{
    public static WebApplication WebApplication { get; set; }

    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Add services to the container.

        builder.Services.AddControllers();
        // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();

        //EO:
        builder.Services.AddSignalR();

        var app = builder.Build();

        //EO:
        WebApplication = app;
        ...
Eric Ouellet
  • 10,996
  • 11
  • 84
  • 119