SignalR's Client list is empty when I use non-Controller Class in ASP.NET Core

Viewed 140

I have an ASP.NET Core Webservice and a Blazor client. When my method is triggered in a class (not a controller) in the webservice, I want to send my data to my clients.

When I use a controller, it works but in a regular class, I see the clients.All are empty even OnConnectedAsync is triggered (means connected)

As I understand, HubContext is not a singleton but transient. I tried many things but the connected clients list is empty.

In my Startup:

public void ConfigureServices(IServiceCollection services)
{
     services.AddSignalR();
     services.InstallServicesInAssembly(Configuration);
    services.AddTransient<IGeneralStockMarketHandler, GeneralStockMarketHandler>();

    services.AddCors(options =>
    {
       options.AddPolicy("CorsPolicy", policy =>
       {
         policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
        });
    });            
}


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
 app.UseCors("CorsPolicy");
 app.UseEndpoints(endpoints =>
 {
    endpoints.MapHub<NotificationHub>("/notificationhub");
    endpoints.MapControllers();
 }); 
}

My hub:

public class NotificationHub : Hub
{
     public override Task OnConnectedAsync()
     {
        Console.WriteLine("Client has connected");
        return base.OnConnectedAsync();
     }

     public override Task OnDisconnectedAsync(Exception exception)
     {
        Console.WriteLine("Client has disconnected");
       return base.OnDisconnectedAsync(exception);
     }
}

My GeneralStockMarketHandler class which I injected IHubContext:

 public GeneralStockMarketHandler(IHubContext<NotificationHub> hubContext)
 {
   _hubContext = hubContext;            
 }

 private async void MyStockMarketHandler_OnDataReceived(StreamSnapshotResponseModel response)
 {
   await HandleStreamSnapshotResponse(response);
   await _hubContext.Clients.All.SendAsync("notification", response.Data);
 }

As you see above _hubContext.Clients.All is empty even a client has connected, so it does not send any client.

In my Blazor app, Index.razor:

@code {
    string url = "http://localhost:1580/notificationhub";    
    HubConnection _connection = null;
    bool isConnected = false;
    string connectionStatus = "Ready";


    private async Task ConnectToServer()
    {
        _connection = new HubConnectionBuilder()
            .WithUrl(url)
            .Build();

        await _connection.StartAsync();
        isConnected = true;   
        connectionStatus = "Connected";

        _connection.Closed += async (s) =>
        {
            isConnected = false;
            connectionStatus = "Disconnected";
            await _connection.StartAsync();
            isConnected = true;
        };
            
        _connection.On<string>("notification", m =>
        {      
          connectionStatus = "I have data!";     
          StateHasChanged();
        });
    }
}

When my HubContext is injected into the controller, it works but when it is in a regular class, it does not work because the clients.All is empty. How can I solve this problem?

UPDATE:

I think, I found out the problem. In my installer, I create an instance from GeneralStockMarketHandler class and call a method which is StartToSubscribeAllStocksFromDb. I have to call this method once in the beginning

 services.AddScoped<IGeneralStockMarketHandler, GeneralStockMarketHandler>();    
 var serviceProvider = services.BuildServiceProvider();
 var stockMarketHandler serviceProvider.GetRequiredService<IGeneralStockMarketHandler>();
 stockMarketHandler.StartToSubscribeAllStocksFromDb();

If I do not create an instance from GeneralStockMarketHandler class then I can get the connected clients.

I dont understand why it effects the logic. It is not singleton and I use it only one time

0 Answers
Related