Compartilhar via


Hospedar ASP.NET Core SignalR em serviços em segundo plano

Por Dave Pringle e Brady Gaster

Este artigo fornece diretrizes para:

  • Hospedar Hubs do SignalR usando um processo de trabalho em segundo plano hospedado com o ASP.NET Core.
  • Enviar mensagens para clientes conectados de dentro de um BackgroundService do .NET Core.

Exibir ou baixar código de exemplo (como baixar)

Habilitar o SignalR na inicialização do aplicativo

A hospedagem de Hubs do ASP.NET Core SignalR no contexto de um processo de trabalho em segundo plano é idêntica à hospedagem de um Hub em um aplicativo Web do ASP.NET Core. No Program.cs, chamar builder.Services.AddSignalR adiciona os serviços necessários à camada da DI (injeção de dependência) do ASP.NET Core para dar suporte ao SignalR. O método MapHub é chamado no WebApplication app para conectar os pontos de extremidade do Hub no pipeline de solicitação do 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();

No exemplo anterior, a classe ClockHub implementa a classe Hub<T> para criar um Hub fortemente tipado. O ClockHub foi configurado no Program.cs para responder a solicitações no ponto de extremidade /hubs/clock.

Para obter mais informações sobre Hubs fortemente tipados, confira o tópico Usar hubs no SignalR para ASP.NET Core.

Observação

Essa funcionalidade não se limita à classe Hub<T>. Qualquer classe que herda do Hub, como oDynamicHub, funciona.

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

A interface usada pelo ClockHub fortemente tipado é a interface IClock.

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

Chamar um Hub do SignalR a partir de um serviço em segundo plano

Durante a inicialização, a classe Worker, uma BackgroundService, é habilitada usando AddHostedService.

builder.Services.AddHostedService<Worker>();

Como o SignalR também está habilitado durante a fase de inicialização, na qual cada Hub é anexado a um ponto de extremidade individual no pipeline de solicitação HTTP do ASP.NET Core, cada Hub é representado por um IHubContext<T> no servidor. Usando os recursos de DI do ASP.NET Core, outras classes instanciadas pela camada de hospedagem, como classes BackgroundService, classes de Controlador MVC ou modelos de página do Razor, podem obter referências a Hubs do lado do servidor aceitando instâncias de IHubContext<ClockHub, IClock> durante a construção.

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

Como o método ExecuteAsync é chamado iterativamente no serviço em segundo plano, a data e a hora atuais do servidor são enviadas aos clientes conectados usando o ClockHub.

Reagir a eventos SignalR com serviços em segundo plano

Como um aplicativo de página única usando o cliente JavaScript para SignalR, ou um aplicativo da área de trabalho .NET usando o cliente .NET do ASP.NET CoreSignalR, uma implementação BackgroundService ou IHostedService também pode ser usada para se conectar a Hubs do SignalR e responder a eventos.

A classe ClockHubClient implementa a interface IClock e a interface IHostedService. Dessa forma, ela pode ser habilitada durante a inicialização para ser executada continuamente e responder a eventos de Hub do servidor.

public partial class ClockHubClient : IClock, IHostedService
{
}

Durante a inicialização, o ClockHubClient cria uma instância de um HubConnection e habilita o método IClock.ShowTime como o manipulador para o evento do 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;
}

Na implementação IHostedService.StartAsync, o HubConnection é iniciado de forma assíncrona.

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 o método IHostedService.StopAsync, o HubConnection é descartado de forma assíncrona.

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

Exibir ou baixar código de exemplo (como baixar)

Habilitar o SignalR na inicialização

A hospedagem de Hubs do ASP.NET Core SignalR no contexto de um processo de trabalho em segundo plano é idêntica à hospedagem de um Hub em um aplicativo Web do ASP.NET Core. No método Startup.ConfigureServices, chamar services.AddSignalR adiciona os serviços necessários à camada da DI (injeção de dependência) do ASP.NET Core para dar suporte ao SignalR. Na Startup.Configure, o método MapHub é chamado no retorno de chamada UseEndpoints para conectar os pontos de extremidade do Hub no pipeline de solicitação do 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");
        });
    }
}

No exemplo anterior, a classe ClockHub implementa a classe Hub<T> para criar um Hub fortemente tipado. O ClockHub foi configurado na classe Startup para responder a solicitações no ponto de extremidade /hubs/clock.

Para obter mais informações sobre Hubs fortemente tipados, confira o tópico Usar hubs no SignalR para ASP.NET Core.

Observação

Essa funcionalidade não se limita à classe Hub<T>. Qualquer classe que herda do Hub, como oDynamicHub, funciona.

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

A interface usada pelo ClockHub fortemente tipado é a interface IClock.

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

Chamar um Hub do SignalR a partir de um serviço em segundo plano

Durante a inicialização, a classe Worker, uma BackgroundService, é habilitada usando AddHostedService.

services.AddHostedService<Worker>();

Como o SignalR também está habilitado durante a fase de Startup, na qual cada Hub é anexado a um ponto de extremidade individual no pipeline de solicitação HTTP do ASP.NET Core, cada Hub é representado por um IHubContext<T> no servidor. Usando os recursos de DI do ASP.NET Core, outras classes instanciadas pela camada de hospedagem, como classes BackgroundService, classes de Controlador MVC ou modelos de página do Razor, podem obter referências a Hubs do lado do servidor aceitando instâncias de IHubContext<ClockHub, IClock> durante a construção.

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

Como o método ExecuteAsync é chamado iterativamente no serviço em segundo plano, a data e a hora atuais do servidor são enviadas aos clientes conectados usando o ClockHub.

Reagir a eventos SignalR com serviços em segundo plano

Como um aplicativo de página única usando o cliente JavaScript para SignalR, ou um aplicativo da área de trabalho .NET usando o cliente .NET do ASP.NET CoreSignalR, uma implementação BackgroundService ou IHostedService também pode ser usada para se conectar a Hubs do SignalR e responder a eventos.

A classe ClockHubClient implementa a interface IClock e a interface IHostedService. Dessa forma, ela pode ser habilitada durante a Startup para ser executada continuamente e responder a eventos de Hub do servidor.

public partial class ClockHubClient : IClock, IHostedService
{
}

Durante a inicialização, o ClockHubClient cria uma instância de um HubConnection e habilita o método IClock.ShowTime como o manipulador para o evento do 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;
}

Na implementação IHostedService.StartAsync, o HubConnection é iniciado de forma assíncrona.

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 o método IHostedService.StopAsync, o HubConnection é descartado de forma assíncrona.

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

Exibir ou baixar código de exemplo (como baixar)

Habilitar o SignalR na inicialização

A hospedagem de Hubs do ASP.NET Core SignalR no contexto de um processo de trabalho em segundo plano é idêntica à hospedagem de um Hub em um aplicativo Web do ASP.NET Core. No método Startup.ConfigureServices, chamar services.AddSignalR adiciona os serviços necessários à camada da DI (injeção de dependência) do ASP.NET Core para dar suporte ao SignalR. No Startup.Configure, o método UseSignalR é chamado para conectar os pontos de extremidade do Hub no pipeline de solicitação ASP.NET Core.

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

No exemplo anterior, a classe ClockHub implementa a classe Hub<T> para criar um Hub fortemente tipado. O ClockHub foi configurado na classe Startup para responder a solicitações no ponto de extremidade /hubs/clock.

Para obter mais informações sobre Hubs fortemente tipados, confira o tópico Usar hubs no SignalR para ASP.NET Core.

Observação

Essa funcionalidade não se limita à classe Hub<T>. Qualquer classe que herda do Hub, como oDynamicHub, funciona.

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

A interface usada pelo ClockHub fortemente tipado é a interface IClock.

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

Chamar um Hub do SignalR a partir de um serviço em segundo plano

Durante a inicialização, a classe Worker, uma BackgroundService, é habilitada usando AddHostedService.

services.AddHostedService<Worker>();

Como o SignalR também está habilitado durante a fase de Startup, na qual cada Hub é anexado a um ponto de extremidade individual no pipeline de solicitação HTTP do ASP.NET Core, cada Hub é representado por um IHubContext<T> no servidor. Usando os recursos de DI do ASP.NET Core, outras classes instanciadas pela camada de hospedagem, como classes BackgroundService, classes de Controlador MVC ou modelos de página do Razor, podem obter referências a Hubs do lado do servidor aceitando instâncias de IHubContext<ClockHub, IClock> durante a construção.

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

Como o método ExecuteAsync é chamado iterativamente no serviço em segundo plano, a data e a hora atuais do servidor são enviadas aos clientes conectados usando o ClockHub.

Reagir a eventos SignalR com serviços em segundo plano

Como um aplicativo de página única usando o cliente JavaScript para SignalR, ou um aplicativo da área de trabalho .NET usando o cliente .NET do ASP.NET CoreSignalR, uma implementação BackgroundService ou IHostedService também pode ser usada para se conectar a Hubs do SignalR e responder a eventos.

A classe ClockHubClient implementa a interface IClock e a interface IHostedService. Dessa forma, ela pode ser habilitada durante a Startup para ser executada continuamente e responder a eventos de Hub do servidor.

public partial class ClockHubClient : IClock, IHostedService
{
}

Durante a inicialização, o ClockHubClient cria uma instância de um HubConnection e habilita o método IClock.ShowTime como o manipulador para o evento do 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;
}

Na implementação IHostedService.StartAsync, o HubConnection é iniciado de forma assíncrona.

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 o método IHostedService.StopAsync, o HubConnection é descartado de forma assíncrona.

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

Recursos adicionais