Ospitare ASP.NET Core SignalR nei servizi in background

Di Dave Pringle e Brady Gaster

Questo articolo fornisce indicazioni per:

  • Hosting SignalR di Hub usando un processo di lavoro in background ospitato con ASP.NET Core.
  • Invio di messaggi ai client connessi da un servizio background .NET Core.

Visualizzare o scaricare il codice di esempio (come scaricare)

Abilitare SignalR all'avvio dell'app

L'hosting di ASP.NET Core SignalR Hub nel contesto di un processo di lavoro in background è identico all'hosting di un hub in un'app Web ASP.NET Core. In Program.csla chiamata builder.Services.AddSignalR aggiunge i servizi necessari al livello ASP.NET core dependency injection (DI) per supportare SignalR. Il MapHub metodo viene chiamato su WebApplicationapp per connettere gli endpoint hub nella pipeline di richiesta ASP.NET Core.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR();
builder.Services.AddHostedService<Worker>();

var app = builder.Build();

app.MapHub<ClockHub>("/hubs/clock");

app.Run();

Nell'esempio precedente la ClockHub classe implementa la Hub<T> classe per creare un hub fortemente tipizzato. L'oggetto ClockHub è stato configurato in Program.cs per rispondere alle richieste nell'endpoint /hubs/clock.

Per altre informazioni sugli hub fortemente tipizzato, vedere Usare hub in SignalR per ASP.NET Core.

Nota

Questa funzionalità non è limitata alla classe T dell'hub<.> Qualsiasi classe che eredita da Hub, ad esempio DynamicHub, funziona.

public class ClockHub : Hub<IClock>
{
    public async Task SendTimeToClients(DateTime dateTime)
    {
        await Clients.All.ShowTime(dateTime);
    }
}

L'interfaccia usata dall'oggetto fortemente tipizzato ClockHub è l'interfaccia IClock .

public interface IClock
{
    Task ShowTime(DateTime currentTime);
}

Chiamare un SignalR hub da un servizio in background

Durante l'avvio, la Worker classe , è BackgroundServiceabilitata tramite AddHostedService.

builder.Services.AddHostedService<Worker>();

Poiché SignalR è abilitato anche durante la fase di avvio, in cui ogni hub è collegato a un singolo endpoint nella pipeline di richiesta HTTP di ASP.NET Core, ogni hub è rappresentato da un IHubContext<T> nel server. Usando le funzionalità di inserimento delle dipendenze di ASP.NET Core, altre classi create dal livello di hosting, ad esempio BackgroundService classi, classi di controller MVC o Razor modelli di pagina, possono ottenere riferimenti agli hub lato server accettando istanze di IHubContext<ClockHub, IClock> durante la costruzione.

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IHubContext<ClockHub, IClock> _clockHub;

    public Worker(ILogger<Worker> logger, IHubContext<ClockHub, IClock> clockHub)
    {
        _logger = logger;
        _clockHub = clockHub;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Worker running at: {Time}", DateTime.Now);
            await _clockHub.Clients.All.ShowTime(DateTime.Now);
            await Task.Delay(1000, stoppingToken);
        }
    }
}

Poiché il ExecuteAsync metodo viene chiamato iterativamente nel servizio in background, la data e l'ora correnti del server vengono inviate ai client connessi usando .ClockHub

Reagire agli SignalR eventi con i servizi in background

Analogamente a un'app a pagina singola che usa il client JavaScript per SignalRo un'app desktop .NET tramite il client .NET di ASP.NET Core SignalR , è possibile usare un'implementazione BackgroundService o IHostedService per connettersi a SignalR Hub e rispondere agli eventi.

La ClockHubClient classe implementa sia l'interfaccia IClock che l'interfaccia IHostedService . In questo modo è possibile abilitarlo durante l'avvio per l'esecuzione continua e rispondere agli eventi hub dal server.

public partial class ClockHubClient : IClock, IHostedService
{
}

Durante l'inizializzazione, crea un'istanza ClockHubClient di e HubConnection abilita il IClock.ShowTime metodo come gestore per l'evento dell'hub ShowTime .

private readonly ILogger<ClockHubClient> _logger;
private HubConnection _connection;

public ClockHubClient(ILogger<ClockHubClient> logger)
{
    _logger = logger;
    
    _connection = new HubConnectionBuilder()
        .WithUrl(Strings.HubUrl)
        .Build();

    _connection.On<DateTime>(Strings.Events.TimeSent, ShowTime);
}

public Task ShowTime(DateTime currentTime)
{
    _logger.LogInformation("{CurrentTime}", currentTime.ToShortTimeString());

    return Task.CompletedTask;
}

Nell'implementazione l'oggetto IHostedService.StartAsyncHubConnection viene avviato in modo asincrono.

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, cancellationToken);
        }
    }
}

Durante il IHostedService.StopAsync metodo , l'oggetto HubConnection viene eliminato in modo asincrono.

public async Task StopAsync(CancellationToken cancellationToken)
{
    await _connection.DisposeAsync();
}

Visualizzare o scaricare il codice di esempio (come scaricare)

Abilita SignalR all'avvio

L'hosting di ASP.NET Core SignalR Hub nel contesto di un processo di lavoro in background è identico all'hosting di un hub in un'app Web ASP.NET Core. Startup.ConfigureServices Nel metodo, la chiamata services.AddSignalR aggiunge i servizi necessari al livello di inserimento delle dipendenze di base (DI) ASP.NET per supportare SignalR. In Startup.Configureil MapHub metodo viene chiamato nel UseEndpoints callback per connettere gli endpoint hub nella pipeline di richiesta ASP.NET Core.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSignalR();
        services.AddHostedService<Worker>();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<ClockHub>("/hubs/clock");
        });
    }
}

Nell'esempio precedente la ClockHub classe implementa la Hub<T> classe per creare un hub fortemente tipizzato. L'oggetto ClockHub è stato configurato nella Startup classe per rispondere alle richieste nell'endpoint /hubs/clock.

Per altre informazioni sugli hub fortemente tipizzato, vedere Usare hub in SignalR per ASP.NET Core.

Nota

Questa funzionalità non è limitata alla classe T dell'hub<.> Qualsiasi classe che eredita da Hub, ad esempio DynamicHub, funziona.

public class ClockHub : Hub<IClock>
{
    public async Task SendTimeToClients(DateTime dateTime)
    {
        await Clients.All.ShowTime(dateTime);
    }
}

L'interfaccia usata dall'oggetto fortemente tipizzato ClockHub è l'interfaccia IClock .

public interface IClock
{
    Task ShowTime(DateTime currentTime);
}

Chiamare un SignalR hub da un servizio in background

Durante l'avvio, la Worker classe , è BackgroundServiceabilitata tramite AddHostedService.

services.AddHostedService<Worker>();

Poiché SignalR è abilitato anche durante la Startup fase, in cui ogni hub è collegato a un singolo endpoint nella pipeline di richiesta HTTP di ASP.NET Core, ogni hub è rappresentato da un IHubContext<T> nel server. Usando le funzionalità di inserimento delle dipendenze di ASP.NET Core, altre classi create dal livello di hosting, ad esempio BackgroundService classi, classi di controller MVC o Razor modelli di pagina, possono ottenere riferimenti agli hub lato server accettando istanze di IHubContext<ClockHub, IClock> durante la costruzione.

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IHubContext<ClockHub, IClock> _clockHub;

    public Worker(ILogger<Worker> logger, IHubContext<ClockHub, IClock> clockHub)
    {
        _logger = logger;
        _clockHub = clockHub;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Worker running at: {Time}", DateTime.Now);
            await _clockHub.Clients.All.ShowTime(DateTime.Now);
            await Task.Delay(1000);
        }
    }
}

Poiché il ExecuteAsync metodo viene chiamato iterativamente nel servizio in background, la data e l'ora correnti del server vengono inviate ai client connessi usando .ClockHub

Reagire agli SignalR eventi con i servizi in background

Analogamente a un'app a pagina singola che usa il client JavaScript per SignalRo un'app desktop .NET tramite il client .NET di ASP.NET Core SignalR , è possibile usare un'implementazione BackgroundService o IHostedService per connettersi a SignalR Hub e rispondere agli eventi.

La ClockHubClient classe implementa sia l'interfaccia IClock che l'interfaccia IHostedService . In questo modo è possibile abilitarlo durante Startup l'esecuzione continua e rispondere agli eventi hub dal server.

public partial class ClockHubClient : IClock, IHostedService
{
}

Durante l'inizializzazione, crea un'istanza ClockHubClient di e HubConnection abilita il IClock.ShowTime metodo come gestore per l'evento dell'hub ShowTime .

private readonly ILogger<ClockHubClient> _logger;
private HubConnection _connection;

public ClockHubClient(ILogger<ClockHubClient> logger)
{
    _logger = logger;
    
    _connection = new HubConnectionBuilder()
        .WithUrl(Strings.HubUrl)
        .Build();

    _connection.On<DateTime>(Strings.Events.TimeSent, ShowTime);
}

public Task ShowTime(DateTime currentTime)
{
    _logger.LogInformation("{CurrentTime}", currentTime.ToShortTimeString());

    return Task.CompletedTask;
}

Nell'implementazione l'oggetto IHostedService.StartAsyncHubConnection viene avviato in modo asincrono.

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);
        }
    }
}

Durante il IHostedService.StopAsync metodo , l'oggetto HubConnection viene eliminato in modo asincrono.

public Task StopAsync(CancellationToken cancellationToken)
{
    return _connection.DisposeAsync();
}

Visualizzare o scaricare il codice di esempio (come scaricare)

Abilita SignalR all'avvio

L'hosting di ASP.NET Core SignalR Hub nel contesto di un processo di lavoro in background è identico all'hosting di un hub in un'app Web ASP.NET Core. Startup.ConfigureServices Nel metodo, la chiamata services.AddSignalR aggiunge i servizi necessari al livello di inserimento delle dipendenze di base (DI) ASP.NET per supportare SignalR. In Startup.Configureil UseSignalR metodo viene chiamato per connettere gli endpoint hub nella pipeline di richiesta core ASP.NET.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSignalR();
        services.AddHostedService<Worker>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseSignalR((routes) =>
        {
            routes.MapHub<ClockHub>("/hubs/clock");
        });
    }
}

Nell'esempio precedente la ClockHub classe implementa la Hub<T> classe per creare un hub fortemente tipizzato. L'oggetto ClockHub è stato configurato nella Startup classe per rispondere alle richieste nell'endpoint /hubs/clock.

Per altre informazioni sugli hub fortemente tipizzato, vedere Usare hub in SignalR per ASP.NET Core.

Nota

Questa funzionalità non è limitata alla classe T dell'hub<.> Qualsiasi classe che eredita da Hub, ad esempio DynamicHub, funziona.

public class ClockHub : Hub<IClock>
{
    public async Task SendTimeToClients(DateTime dateTime)
    {
        await Clients.All.ShowTime(dateTime);
    }
}

L'interfaccia usata dall'oggetto fortemente tipizzato ClockHub è l'interfaccia IClock .

public interface IClock
{
    Task ShowTime(DateTime currentTime);
}

Chiamare un SignalR hub da un servizio in background

Durante l'avvio, la Worker classe , è BackgroundServiceabilitata tramite AddHostedService.

services.AddHostedService<Worker>();

Poiché SignalR è abilitato anche durante la Startup fase, in cui ogni hub è collegato a un singolo endpoint nella pipeline di richiesta HTTP di ASP.NET Core, ogni hub è rappresentato da un IHubContext<T> nel server. Usando le funzionalità di inserimento delle dipendenze di ASP.NET Core, altre classi create dal livello di hosting, ad esempio BackgroundService classi, classi di controller MVC o Razor modelli di pagina, possono ottenere riferimenti agli hub lato server accettando istanze di IHubContext<ClockHub, IClock> durante la costruzione.

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IHubContext<ClockHub, IClock> _clockHub;

    public Worker(ILogger<Worker> logger, IHubContext<ClockHub, IClock> clockHub)
    {
        _logger = logger;
        _clockHub = clockHub;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Worker running at: {Time}", DateTime.Now);
            await _clockHub.Clients.All.ShowTime(DateTime.Now);
            await Task.Delay(1000);
        }
    }
}

Poiché il ExecuteAsync metodo viene chiamato iterativamente nel servizio in background, la data e l'ora correnti del server vengono inviate ai client connessi usando .ClockHub

Reagire agli SignalR eventi con i servizi in background

Analogamente a un'app a pagina singola che usa il client JavaScript per SignalRo un'app desktop .NET tramite il client .NET di ASP.NET Core SignalR , è possibile usare un'implementazione BackgroundService o IHostedService per connettersi a SignalR Hub e rispondere agli eventi.

La ClockHubClient classe implementa sia l'interfaccia IClock che l'interfaccia IHostedService . In questo modo è possibile abilitarlo durante Startup l'esecuzione continua e rispondere agli eventi hub dal server.

public partial class ClockHubClient : IClock, IHostedService
{
}

Durante l'inizializzazione, crea un'istanza ClockHubClient di e HubConnection abilita il IClock.ShowTime metodo come gestore per l'evento dell'hub ShowTime .

private readonly ILogger<ClockHubClient> _logger;
private HubConnection _connection;

public ClockHubClient(ILogger<ClockHubClient> logger)
{
    _logger = logger;
    
    _connection = new HubConnectionBuilder()
        .WithUrl(Strings.HubUrl)
        .Build();

    _connection.On<DateTime>(Strings.Events.TimeSent, 
        dateTime => _ = ShowTime(dateTime));
}

public Task ShowTime(DateTime currentTime)
{
    _logger.LogInformation("{CurrentTime}", currentTime.ToShortTimeString());

    return Task.CompletedTask;
}

Nell'implementazione l'oggetto IHostedService.StartAsyncHubConnection viene avviato in modo asincrono.

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);
        }
    }
}

Durante il IHostedService.StopAsync metodo , l'oggetto HubConnection viene eliminato in modo asincrono.

public Task StopAsync(CancellationToken cancellationToken)
{
    return _connection.DisposeAsync();
}

Risorse aggiuntive