Home > Back-end >  Sending server generated events to the client
Sending server generated events to the client

Time:08-24

I have a Hub:

public sealed class NewValueHub : Hub
{
  private IDataRelay _dataRelay;
  private IConfig _configurator;
  public NewValueHub(IDataRelay dataRelay, IConfig configurator)
  {
    _dataRelay = dataRelay;
    _configurator = configurator;
    _dataRelay.NewData  = HandleNewData; //this gets unassigned on dispose.
  }

  public string GetMachineID()
  {
    IReadOnlyDictionary<string, string> config = _configurator.GetReadOnlyConfig();

    string id;

    if (config.TryGetValue("machineID", out id))
    {
        return id;
    }

    throw new HubException(Resource.machine_id_error);
  }

  private void HandleNewData(object? sender, string value)
  {
    Clients.All.SendAsync("ValueUpdate", value);
  }
}

And a javascript client:

const connection = new signalR.HubConnectionBuilder().withAutomaticReconnect().withUrl("/newValueHub").build();

connection.on("ValueUpdate", function(value) { console.log(value); });

async function run(connection)
{
    try
    {
        await connection.start();
        let machineid = await connection.invoke('GetMachineID');
        console.log('machine id', machineid);
    }
    catch (err)
    {
        console.error(err);
    }
}

run(connection);

I know the IDataRelay is working, as another thread is logging values to a file.

When I load the page, the console logs the machine ID, so I know the connection works.

However I'm never seeing any of the new values in the console.

I know that hubs don't exist for long, which is where the problem probably is, so what am I meant to do to handle the server events?

I mean, when there is data from the IDataRelay, how can I get signalR to send it to my client?

CodePudding user response:

You want to use a background service https://docs.microsoft.com/en-us/aspnet/core/signalr/background-services?view=aspnetcore-6.0#call-a-signalr-hub-from-a-background-service.

In your case, you don't have a loop that needs to await so you can just wire up the event handler.

I don't understand where the HandleNewData event comes from though.

CodePudding user response:

As per davidfowl's suggestion I have added an IHostedService that handles the event.

public class DataRelayWorker : IHostedService, IDisposable
{
  private readonly IDataRelay _dataRelay;
  private readonly IHubContext<NewValueHub> _hubcontext;

  public DataRelayWorker(IDataRelay dataRelay, IHubContext<NewValueHub> context)
  {
    _dataRelay = dataRelay;

    _dataRelay.NewData  = BoadcastValue;

    _hubContext = context;
  }

  private void BroadcastValue(object? sender, string value)
  {
    _hubcontext.Clients.All.SendAsync("ValueUpdate", value);
  }

  public void Dispose()
  {
    _dataRelay.NewData -= BoadcastValue;
  }
}

This is run by adding the following to Program.cs

builder.Services.AddHostedService<DataRelayWorker>();

And I have removed anything to do with the IDataRelay from the hub.

  • Related