Training
Module
Replace client-side polling with ASP.NET Core SignalR - Training
In this module, you use ASP.NET Core SignalR to replace client-side polling functionality in an existing web app.
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
By Dave Pringle and Brady Gaster
This article provides guidance for:
View or download sample code (how to download)
Hosting ASP.NET Core SignalR Hubs in the context of a background worker process is identical to hosting a Hub in an ASP.NET Core web app. In Program.cs
, calling builder.Services.AddSignalR
adds the required services to the ASP.NET Core Dependency Injection (DI) layer to support SignalR. The MapHub
method is called on the WebApplication
app
to connect the Hub endpoints in the ASP.NET Core request pipeline.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSignalR();
builder.Services.AddHostedService<Worker>();
var app = builder.Build();
app.MapHub<ClockHub>("/hubs/clock");
app.Run();
In the preceding example, the ClockHub
class implements the Hub<T>
class to create a strongly typed Hub. The ClockHub
has been configured in Program.cs
to respond to requests at the endpoint /hubs/clock
.
For more information on strongly typed Hubs, see Use hubs in SignalR for ASP.NET Core.
Note
This functionality isn't limited to the Hub<T> class. Any class that inherits from Hub, such as DynamicHub, works.
public class ClockHub : Hub<IClock>
{
public async Task SendTimeToClients(DateTime dateTime)
{
await Clients.All.ShowTime(dateTime);
}
}
The interface used by the strongly typed ClockHub
is the IClock
interface.
public interface IClock
{
Task ShowTime(DateTime currentTime);
}
During startup, the Worker
class, a BackgroundService
, is enabled using AddHostedService
.
builder.Services.AddHostedService<Worker>();
Since SignalR is also enabled up during the startup phase, in which each Hub is attached to an individual endpoint in ASP.NET Core's HTTP request pipeline, each Hub is represented by an IHubContext<T>
on the server. Using ASP.NET Core's DI features, other classes instantiated by the hosting layer, like BackgroundService
classes, MVC Controller classes, or Razor page models, can get references to server-side Hubs by accepting instances of IHubContext<ClockHub, IClock>
during construction.
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);
}
}
}
As the ExecuteAsync
method is called iteratively in the background service, the server's current date and time are sent to the connected clients using the ClockHub
.
Like a Single Page App using the JavaScript client for SignalR, or a .NET desktop app using the ASP.NET Core SignalR .NET Client, a BackgroundService
or IHostedService
implementation can also be used to connect to SignalR Hubs and respond to events.
The ClockHubClient
class implements both the IClock
interface and the IHostedService
interface. This way it can be enabled during startup to run continuously and respond to Hub events from the server.
public partial class ClockHubClient : IClock, IHostedService
{
}
During initialization, the ClockHubClient
creates an instance of a HubConnection
and enables the IClock.ShowTime
method as the handler for the Hub's ShowTime
event.
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;
}
In the IHostedService.StartAsync
implementation, the HubConnection
is started asynchronously.
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);
}
}
}
During the IHostedService.StopAsync
method, the HubConnection
is disposed of asynchronously.
public async Task StopAsync(CancellationToken cancellationToken)
{
await _connection.DisposeAsync();
}
View or download sample code (how to download)
Hosting ASP.NET Core SignalR Hubs in the context of a background worker process is identical to hosting a Hub in an ASP.NET Core web app. In the Startup.ConfigureServices
method, calling services.AddSignalR
adds the required services to the ASP.NET Core Dependency Injection (DI) layer to support SignalR. In Startup.Configure
, the MapHub
method is called in the UseEndpoints
callback to connect the Hub endpoints in the ASP.NET Core request pipeline.
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");
});
}
}
In the preceding example, the ClockHub
class implements the Hub<T>
class to create a strongly typed Hub. The ClockHub
has been configured in the Startup
class to respond to requests at the endpoint /hubs/clock
.
For more information on strongly typed Hubs, see Use hubs in SignalR for ASP.NET Core.
Note
This functionality isn't limited to the Hub<T> class. Any class that inherits from Hub, such as DynamicHub, works.
public class ClockHub : Hub<IClock>
{
public async Task SendTimeToClients(DateTime dateTime)
{
await Clients.All.ShowTime(dateTime);
}
}
The interface used by the strongly typed ClockHub
is the IClock
interface.
public interface IClock
{
Task ShowTime(DateTime currentTime);
}
During startup, the Worker
class, a BackgroundService
, is enabled using AddHostedService
.
services.AddHostedService<Worker>();
Since SignalR is also enabled up during the Startup
phase, in which each Hub is attached to an individual endpoint in ASP.NET Core's HTTP request pipeline, each Hub is represented by an IHubContext<T>
on the server. Using ASP.NET Core's DI features, other classes instantiated by the hosting layer, like BackgroundService
classes, MVC Controller classes, or Razor page models, can get references to server-side Hubs by accepting instances of IHubContext<ClockHub, IClock>
during construction.
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);
}
}
}
As the ExecuteAsync
method is called iteratively in the background service, the server's current date and time are sent to the connected clients using the ClockHub
.
Like a Single Page App using the JavaScript client for SignalR, or a .NET desktop app using the ASP.NET Core SignalR .NET Client, a BackgroundService
or IHostedService
implementation can also be used to connect to SignalR Hubs and respond to events.
The ClockHubClient
class implements both the IClock
interface and the IHostedService
interface. This way it can be enabled during Startup
to run continuously and respond to Hub events from the server.
public partial class ClockHubClient : IClock, IHostedService
{
}
During initialization, the ClockHubClient
creates an instance of a HubConnection
and enables the IClock.ShowTime
method as the handler for the Hub's ShowTime
event.
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;
}
In the IHostedService.StartAsync
implementation, the HubConnection
is started asynchronously.
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);
}
}
}
During the IHostedService.StopAsync
method, the HubConnection
is disposed of asynchronously.
public Task StopAsync(CancellationToken cancellationToken)
{
return _connection.DisposeAsync();
}
View or download sample code (how to download)
Hosting ASP.NET Core SignalR Hubs in the context of a background worker process is identical to hosting a Hub in an ASP.NET Core web app. In the Startup.ConfigureServices
method, calling services.AddSignalR
adds the required services to the ASP.NET Core Dependency Injection (DI) layer to support SignalR. In Startup.Configure
, the UseSignalR
method is called to connect the Hub endpoint(s) in the ASP.NET Core request pipeline.
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");
});
}
}
In the preceding example, the ClockHub
class implements the Hub<T>
class to create a strongly typed Hub. The ClockHub
has been configured in the Startup
class to respond to requests at the endpoint /hubs/clock
.
For more information on strongly typed Hubs, see Use hubs in SignalR for ASP.NET Core.
Note
This functionality isn't limited to the Hub<T> class. Any class that inherits from Hub, such as DynamicHub, works.
public class ClockHub : Hub<IClock>
{
public async Task SendTimeToClients(DateTime dateTime)
{
await Clients.All.ShowTime(dateTime);
}
}
The interface used by the strongly typed ClockHub
is the IClock
interface.
public interface IClock
{
Task ShowTime(DateTime currentTime);
}
During startup, the Worker
class, a BackgroundService
, is enabled using AddHostedService
.
services.AddHostedService<Worker>();
Since SignalR is also enabled up during the Startup
phase, in which each Hub is attached to an individual endpoint in ASP.NET Core's HTTP request pipeline, each Hub is represented by an IHubContext<T>
on the server. Using ASP.NET Core's DI features, other classes instantiated by the hosting layer, like BackgroundService
classes, MVC Controller classes, or Razor page models, can get references to server-side Hubs by accepting instances of IHubContext<ClockHub, IClock>
during construction.
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);
}
}
}
As the ExecuteAsync
method is called iteratively in the background service, the server's current date and time are sent to the connected clients using the ClockHub
.
Like a Single Page App using the JavaScript client for SignalR, or a .NET desktop app using the ASP.NET Core SignalR .NET Client, a BackgroundService
or IHostedService
implementation can also be used to connect to SignalR Hubs and respond to events.
The ClockHubClient
class implements both the IClock
interface and the IHostedService
interface. This way it can be enabled during Startup
to run continuously and respond to Hub events from the server.
public partial class ClockHubClient : IClock, IHostedService
{
}
During initialization, the ClockHubClient
creates an instance of a HubConnection
and enables the IClock.ShowTime
method as the handler for the Hub's ShowTime
event.
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;
}
In the IHostedService.StartAsync
implementation, the HubConnection
is started asynchronously.
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);
}
}
}
During the IHostedService.StopAsync
method, the HubConnection
is disposed of asynchronously.
public Task StopAsync(CancellationToken cancellationToken)
{
return _connection.DisposeAsync();
}
ASP.NET Core feedback
ASP.NET Core is an open source project. Select a link to provide feedback:
Training
Module
Replace client-side polling with ASP.NET Core SignalR - Training
In this module, you use ASP.NET Core SignalR to replace client-side polling functionality in an existing web app.