在后台服务中宿主 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 请求管道中的中心终结点。

  1. public class Startup
  2. {
  3. public void ConfigureServices(IServiceCollection services)
  4. {
  5. services.AddSignalR();
  6. services.AddHostedService<Worker>();
  7. }
  8. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  9. {
  10. if (env.IsDevelopment())
  11. {
  12. app.UseDeveloperExceptionPage();
  13. }
  14. app.UseRouting();
  15. app.UseEndpoints(endpoints =>
  16. {
  17. endpoints.MapHub<ClockHub>("/hubs/clock");
  18. });
  19. }
  20. }

在后台工作进程的上下文中托管 ASP.NET Core SignalR 中心与在 ASP.NET Core web 应用中托管集线器完全相同。Startup.ConfigureServices 方法中,调用 services.AddSignalR 会将所需的服务添加到 ASP.NET Core 依赖关系注入(DI)层以支持 SignalR。Startup.Configure中,调用 UseSignalR 方法连接 ASP.NET Core 请求管道中的中心终结点。

  1. public class Startup
  2. {
  3. public void ConfigureServices(IServiceCollection services)
  4. {
  5. services.AddSignalR();
  6. services.AddHostedService<Worker>();
  7. }
  8. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  9. {
  10. if (env.IsDevelopment())
  11. {
  12. app.UseDeveloperExceptionPage();
  13. }
  14. app.UseSignalR((routes) =>
  15. {
  16. routes.MapHub<ClockHub>("/hubs/clock");
  17. });
  18. }
  19. }

在前面的示例中,ClockHub 类实现了 Hub<T> 类,以创建强类型化的中心。已在 Startup 类中配置 ClockHub,以响应终结点 /hubs/clock的请求。

有关强类型化集线器的详细信息,请参阅在 SignalR 中使用中心 ASP.NET Core

备注

此功能并不限于集线器<t >类。中心继承的任何类(如DynamicHub)也将起作用。

  1. public class ClockHub : Hub<IClock>
  2. {
  3. public async Task SendTimeToClients(DateTime dateTime)
  4. {
  5. await Clients.All.ShowTime(dateTime);
  6. }
  7. }

强类型 ClockHub 所使用的接口是 IClock 接口。

  1. public interface IClock
  2. {
  3. Task ShowTime(DateTime currentTime);
  4. }

从后台服务调用 SignalR 集线器Call a SignalR Hub from a background service

在启动过程中,将使用 AddHostedService启用 WorkerBackgroundService

  1. services.AddHostedService<Worker>();

由于 SignalR 也是在 Startup 阶段启用的,在这种情况下,每个中心均附加到 ASP.NET Core 的 HTTP 请求管道中的单个终结点,每个中心由服务器上的 IHubContext<T> 表示。使用 ASP.NET Core 的 DI 功能,由宿主层实例化的其他类(如 BackgroundService 类、MVC 控制器类或 Razor 页面模型)可通过在构造期间接受 IHubContext<ClockHub, IClock> 的实例来获取对服务器端集线器的引用。

  1. public class Worker : BackgroundService
  2. {
  3. private readonly ILogger<Worker> _logger;
  4. private readonly IHubContext<ClockHub, IClock> _clockHub;
  5. public Worker(ILogger<Worker> logger, IHubContext<ClockHub, IClock> clockHub)
  6. {
  7. _logger = logger;
  8. _clockHub = clockHub;
  9. }
  10. protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  11. {
  12. while (!stoppingToken.IsCancellationRequested)
  13. {
  14. _logger.LogInformation("Worker running at: {Time}", DateTime.Now);
  15. await _clockHub.Clients.All.ShowTime(DateTime.Now);
  16. await Task.Delay(1000);
  17. }
  18. }
  19. }

由于在后台服务中以迭代方式调用 ExecuteAsync 方法,因此使用 ClockHub将服务器的当前日期和时间发送到已连接的客户端。

通过后台服务对 SignalR 事件做出反应React to SignalR events with background services

与使用 SignalR 的 JavaScript 客户端或 .NET 桌面应用程序一样,使用 JavaScript 客户端的单页面应用程序也可以使用 .NET 客户端 SignalR ASP.NET CoreBackgroundServiceIHostedService 实现也可用于连接到 SignalR 中心和响应事件。

ClockHubClient 类既实现了 IClock 接口,又实现了 IHostedService 接口。这样,便可以在 Startup 期间启用此功能,以便连续运行和响应来自服务器的集线器事件。

  1. public partial class ClockHubClient : IClock, IHostedService
  2. {
  3. }

在初始化期间,ClockHubClient 将创建一个 HubConnection 的实例,并将 IClock.ShowTime 方法启用为中心的 ShowTime 事件的处理程序。

  1. private readonly ILogger<ClockHubClient> _logger;
  2. private HubConnection _connection;
  3. public ClockHubClient(ILogger<ClockHubClient> logger)
  4. {
  5. _logger = logger;
  6. _connection = new HubConnectionBuilder()
  7. .WithUrl(Strings.HubUrl)
  8. .Build();
  9. _connection.On<DateTime>(Strings.Events.TimeSent,
  10. dateTime => _ = ShowTime(dateTime));
  11. }
  12. public Task ShowTime(DateTime currentTime)
  13. {
  14. _logger.LogInformation("{CurrentTime}", currentTime.ToShortTimeString());
  15. return Task.CompletedTask;
  16. }

IHostedService.StartAsync 实现中,HubConnection 以异步方式启动。

  1. public async Task StartAsync(CancellationToken cancellationToken)
  2. {
  3. // Loop is here to wait until the server is running
  4. while (true)
  5. {
  6. try
  7. {
  8. await _connection.StartAsync(cancellationToken);
  9. break;
  10. }
  11. catch
  12. {
  13. await Task.Delay(1000);
  14. }
  15. }
  16. }

IHostedService.StopAsync 方法期间,HubConnection 将异步释放。

  1. public Task StopAsync(CancellationToken cancellationToken)
  2. {
  3. return _connection.DisposeAsync();
  4. }
  5. }

其他资源Additional resources