在后台服务中宿主 ASP.NET Core SignalRHost ASP.NET Core SignalR in background services
本文内容
作者: Brady Gaster
本文提供以下内容的指导:
- 使用托管 ASP.NET Core 的后台工作进程承载 SignalR 中心。
- 从 .NET Core BackgroundService中将消息发送到已连接的客户端。
启用启动中的 SignalREnable SignalR in startup
在后台工作进程的上下文中托管 ASP.NET Core SignalR 中心与在 ASP.NET Core web 应用中托管集线器完全相同。在 Startup.ConfigureServices
方法中,调用 services.AddSignalR
会将所需的服务添加到 ASP.NET Core 依赖关系注入(DI)层以支持 SignalR。在 Startup.Configure
中,MapHub
方法在 UseEndpoints
回调中调用,以连接 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.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ClockHub>("/hubs/clock");
});
}
}
在后台工作进程的上下文中托管 ASP.NET Core SignalR 中心与在 ASP.NET Core web 应用中托管集线器完全相同。在 Startup.ConfigureServices
方法中,调用 services.AddSignalR
会将所需的服务添加到 ASP.NET Core 依赖关系注入(DI)层以支持 SignalR。在 Startup.Configure
中,调用 UseSignalR
方法连接 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");
});
}
}
在前面的示例中,ClockHub
类实现了 Hub<T>
类,以创建强类型化的中心。已在 Startup
类中配置 ClockHub
,以响应终结点 /hubs/clock
的请求。
有关强类型化集线器的详细信息,请参阅在 SignalR 中使用中心 ASP.NET Core。
备注
此功能并不限于集线器<t >类。从中心继承的任何类(如DynamicHub)也将起作用。
public class ClockHub : Hub<IClock>
{
public async Task SendTimeToClients(DateTime dateTime)
{
await Clients.All.ShowTime(dateTime);
}
}
强类型 ClockHub
所使用的接口是 IClock
接口。
public interface IClock
{
Task ShowTime(DateTime currentTime);
}
从后台服务调用 SignalR 集线器Call a SignalR Hub from a background service
在启动过程中,将使用 AddHostedService
启用 Worker
类 BackgroundService
。
services.AddHostedService<Worker>();
由于 SignalR 也是在 Startup
阶段启用的,在这种情况下,每个中心均附加到 ASP.NET Core 的 HTTP 请求管道中的单个终结点,每个中心由服务器上的 IHubContext<T>
表示。使用 ASP.NET Core 的 DI 功能,由宿主层实例化的其他类(如 BackgroundService
类、MVC 控制器类或 Razor 页面模型)可通过在构造期间接受 IHubContext<ClockHub, IClock>
的实例来获取对服务器端集线器的引用。
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);
}
}
}
由于在后台服务中以迭代方式调用 ExecuteAsync
方法,因此使用 ClockHub
将服务器的当前日期和时间发送到已连接的客户端。
通过后台服务对 SignalR 事件做出反应React to SignalR events with background services
与使用 SignalR 的 JavaScript 客户端或 .NET 桌面应用程序一样,使用 JavaScript 客户端的单页面应用程序也可以使用 .NET 客户端 SignalR ASP.NET Core,BackgroundService
或 IHostedService
实现也可用于连接到 SignalR 中心和响应事件。
ClockHubClient
类既实现了 IClock
接口,又实现了 IHostedService
接口。这样,便可以在 Startup
期间启用此功能,以便连续运行和响应来自服务器的集线器事件。
public partial class ClockHubClient : IClock, IHostedService
{
}
在初始化期间,ClockHubClient
将创建一个 HubConnection
的实例,并将 IClock.ShowTime
方法启用为中心的 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;
}
在 IHostedService.StartAsync
实现中,HubConnection
以异步方式启动。
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);
}
}
}
在 IHostedService.StopAsync
方法期间,HubConnection
将异步释放。
public Task StopAsync(CancellationToken cancellationToken)
{
return _connection.DisposeAsync();
}
}