Using SignalR in Worker Service Project

Viewed 426

I have been searching high and low on how to configure this properly and nothing seems to be working for me.

I have been mostly following the following article from Microsoft and adjusting for my own needs as I go.

Using .Net 5.0

For starters, what I am trying to do is create a SignalR connection between my Web UI and my BackgroundService. When creating the background service I used File -> New Project -> Worker Service template to create this service. I need to be able to both send data to clients and recieve data from clients within the BackgroundService.

Program.cs

Here I add SignalR. Which seems pretty straightforward.

 public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                IConfiguration configuration = hostContext.Configuration;
                services.AddDbContext<ApplicationDbContext>(options =>
                        options.UseSqlServer(configuration.GetConnectionString("myContext")));
                services.AddSignalR();
                services.AddHostedService<Worker>();
            });
}

Interface:

This is where my understanding starts to break down. I think this is an interface to send data to the client?

public interface IDesoutterController
{
    Task SendData(DateTime currentTime);
}

Controller Hub:

Here is my hub contained in the worker service project with a function to send data to all clients.

public class ControllerHub : Hub<IDesoutterController>
{
    public async Task SendDataToClients(DateTime dateTime)
    {
        await Clients.All.SendData(dateTime);
    }
}

Controller Hub Client:

This is where I am the most confused. Why is my service using a hub, and a hub client in this case or is it all poor wording? Is this just the portion to receive data from my Web UI? Would my web UI project call the endpoint /hubs/controller??

public partial class ControllerHubClient : IDesoutterController, IHostedService
{
    private readonly ILogger<ControllerHubClient> _logger;
    private HubConnection _connection;

    public ControllerHubClient(ILogger<ControllerHubClient> logger)
    {
        _logger = logger;

        _connection = new HubConnectionBuilder()
            .WithUrl("/hubs/controller")
            .Build();

        _connection.On<DateTime>("onSend", SendData);
    }
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        // Loop is here to wait until the server is running
        while (true)
        {
            try
            {
                await _connection.StartAsync(cancellationToken);

                break;
            }
            catch
            {
                await Task.Delay(1000);
            }
        }
    }
    public Task StopAsync(CancellationToken cancellationToken)
    {
        return _connection.StopAsync();
    }
    public Task SendData(DateTime currentTime)
    {
        _logger.LogInformation("{CurrentTime}", currentTime.ToShortTimeString());

        return Task.CompletedTask;
    }
}

Worker Service:

 public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IHubContext<ControllerHub, IDesoutterController> _controllerHub;
    public Worker(ILogger<Worker> logger, IHubContext<ControllerHub, IDesoutterController> controllerHub)
    {
        _logger = logger;
        _controllerHub = controllerHub;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            //Other Stuff
        }
    }
}

Really all I am trying to do is have a SignalR connection between by Web UI and Worker Service project to allow events to be sent (quickly). Each instance of my background service needs its own hub. Granted I am FAIRLY certain I am doing this all wrong. I do however get the following error whenever I start my worker service project.

System.TypeLoadException: 'Method 'GetStreamItemType' in type 'Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1' from assembly 'Microsoft.AspNetCore.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.'

Any help or direction would be greatly appreciated as I am completely new to background services and signalr.

EDIT

Here is a diagram of essentially the system I am trying to create. After reading some of the comments I wanted to clarify my worker service project does NOT have a startup.cs (a big part of why I was confused reading the Microsoft article). I think because I used the worker service template? In my case I "think" I was trying to put both the client and the hub in the same project. After another suggestion in the comment I believe I would want the hub in my web UI project and make my background service the client connecting to the hub?

So in the picture switch around the UI to be the Hub and the Background Worker service(s) to be the client(s)? When I say worker services, I mean I am creating a task for each device. So 1 "worker" thread per device.

enter image description here

0 Answers
Related