【问题标题】:How do I add SignalR to a .NET Core Windows Service?如何将 SignalR 添加到 .NET Core Windows 服务?
【发布时间】:2020-11-15 00:01:12
【问题描述】:

我可以找到将它添加到 MVC 的教程,甚至从 2014 年开始,还有一篇文章解释了如何将它添加到 .NET 4.7 windows 服务。

但是对于 .NET Core 3.1 Windows 服务,我就是不知道该怎么做。

大多数教程似乎都围绕着 Windows 服务中不存在的 Startup.cs 文件。 This 是我可以从 Microsoft 找到的最新教程,但它使用的是 Web 应用程序而不是 Windows 服务。

windows 服务使用以下代码运行:

var builder = new HostBuilder() .ConfigureServices((hostContext, services) => { services.AddHostedService<MyWindowsService>(); });

我认为这里需要设置 SignalR。

我发现了一些你可以做的证据WebApp.Start("http://localhost:8080"); 但这是 OWIN。我找到的示例(上述示例的旧版本)然后有一个 Startup 类,但没有指示如何调用该类。它需要一个IAppBuilder,并且有一个方法可以添加 SignalR。但是 IAppBuilder 似乎不是 .NET Core,我也找不到任何类型的 SignalR 方法。

我想知道是否有人能指出我正确的方向?

【问题讨论】:

    标签: c# .net-core windows-services signalr


    【解决方案1】:

    对于想要开发在 Windows 服务中运行的自托管 ASPNETCore SignalR 集线器的人,这是我的准系统代码。 (免责声明:我是 ASPNET Core 的新手,我不知道这种方法是否会得到更多知识渊博的人的认可。)神奇之处在于“.UseStartup();”打电话。

    1. 使用 VS 2019 “Worker Service” C# 模板创建一个新的服务项目。

    2. 编辑服务的 .csproj 文件并插入以下行:

          <ItemGroup>
              <FrameworkReference Include="Microsoft.aspNetCore.App" />
          </ItemGroup>
      
    3. 创建一个启动类:

      using Microsoft.AspNetCore.Builder;
      using Microsoft.AspNetCore.Hosting;
      using Microsoft.Extensions.DependencyInjection;
      using System;
      using System.Collections.Generic;
      using System.Text;
      
      namespace My.SignalRCore.Service
      {
          public class Startup
          {
              public void ConfigureServices(IServiceCollection services)
              {
                  services.AddSignalR();
                  services.AddHostedService<Worker>();
              }
      
              public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
              {
                  app.UseRouting();               // pre-requisite for app.UseEndpoints()
                  app.UseEndpoints(endpoints =>
                  {
                      string url = $"/ServerHub";
                      endpoints.MapHub<MyHub>(url);
                  });
              }
          }
      }
      
    4. 创建一个 MyHub : Hub 类:

      using Microsoft.AspNetCore.SignalR;
      using Microsoft.Extensions.Logging;
      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace My.SignalRCore.Service
      {
          public class MyHub : Hub
          {
              public ILogger<Worker> _logger = null;
      
              public MyHub(ILogger<Worker> logger)
              {
                  _logger = logger;
                  //_logger.LogInformation($"{DateTimeOffset.Now} MyHub.Constructor()");
      
              }
              public async Task ProcessClientMessage(string user, string message)
              {
                  // process an incoming message from a connected client
                  _logger.LogInformation($"{DateTime.Now.ToString("hh:mm:ss.fff")}  MyHub.ProcessClientMessage({user}, {message})");
      
              }
          }
      }
      
    5. 修改 Program 类以使用“UseStartup”调用:

      using Microsoft.AspNetCore.Hosting;
      using Microsoft.Extensions.Hosting;
      using System;
      
      namespace My.SignalRCore.Service
      {
          public class Program
          {
              public static void Main(string[] args)
              {
                  CreateHostBuilder(args).Build().Run();
              }
      
              public static IHostBuilder CreateHostBuilder(string[] args) =>
                  Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
                  {
                      webBuilder.UseStartup<Startup>();
                      webBuilder.UseUrls("http://*:12457");
                  });
          }
      }
      
    6. 在 Worker 类中添加集线器引用(如果需要):

      using Microsoft.AspNetCore.SignalR;
      using Microsoft.Extensions.Hosting;
      using Microsoft.Extensions.Logging;
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Threading;
      using System.Threading.Tasks;
      
      namespace My.SignalRCore.Service
      {
          public class Worker : BackgroundService
          {
              private readonly ILogger<Worker> _logger;
              private readonly IHubContext<MyHub> _signalRHub;
      
              public Worker(ILogger<Worker> logger, IHubContext<MyHub> signalRHub)
              {
                  _logger = logger;
                  _signalRHub = signalRHub;
              }
      
              protected override async Task ExecuteAsync(CancellationToken stoppingToken)
              {
                  while (!stoppingToken.IsCancellationRequested)
                  {
                      await Task.Delay(15000, stoppingToken);
                      _logger.LogInformation($"{DateTime.Now.ToString("hh:mm:ss.fff")} Sending ping to all clients");
                      await _signalRHub.Clients.All.SendAsync("ReceiveMessage", "Server", "ping");
                  }
              }
          }
      }
      

    服务器代码就是这样。我还没有将它作为服务安装,但它可以作为控制台应用程序运行。 在非开发机器上,您可能需要安装 APSNET CORE 3.1 运行时,它在此处可用: https://dotnet.microsoft.com/download/dotnet/3.1

    对于客户:

    1. 安装 nuget 包:Microsoft.AspNetCore.SignalR.Client

    2. 按照以下方式创建一个客户端类(注意:此处的重新连接代码不起作用):

      using Microsoft.AspNetCore.SignalR.Client;
      using System;
      using System.Threading.Tasks;
      
      namespace My.SignalRCoreClientLib
      {
          public class SignalRCoreClientLib
          {
              public EventHandler<string> MessageEvent;
      
              private HubConnection _connection;
      
              public async Task Connect(string serverIp, int port)
              {
                  if (_connection == null)
                  {
                      _connection = new HubConnectionBuilder()
                          .WithUrl($"http://{serverIp}:{port}/ServerHub")
                          .Build();
      
                      _connection.Closed += async (error) =>
                      {
                          await Task.Delay(new Random().Next(0, 5) * 1000);
                          await _connection.StartAsync();
                      };
      
                      _connection.On<string, string>("ReceiveMessage", (user, message) =>
                      {
                          string fullMessage = $"{user}: {message}";
                          MessageEvent?.Invoke(this, fullMessage);
                      });
                  }
                  try
                  {
                      await _connection.StartAsync();
                  }
                  catch (Exception ex)
                  {
                      MessageEvent?.Invoke(this, $"{ex.Message}; base Exception: {ex.GetBaseException().Message}");
                      await Task.Delay(new Random().Next(0, 5) * 1000);
                      await Connect(serverIp, port);
                  }
              }
      
              public async Task SendMessage(string user, string message)
              {
                  try
                  {
                      await _connection.InvokeAsync("ProcessClientMessage", user, message);
                  }
                  catch (Exception ex)
                  {
                      MessageEvent?.Invoke(this, ex.Message);
                  }
              }
          }
      }
      

    就是这样。希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      SignalR 服务器端需要正常接收 Web 请求的服务器、Kestrel 或 IIS。所以你需要一个网络应用程序,你仍然可以向你的网络应用程序添加托管服务,甚至还有一个示例显示了一个带有 SignalR 和托管服务的网络应用程序:https://docs.microsoft.com/aspnet/core/signalr/background-services?view=aspnetcore-5.0

      【讨论】:

      • 它说您可以自托管,并且有在 Windows 服务中执行此操作的示例,但是它们不会扩展到 .net 核心
      • ASP.NET Core 默认是自托管的。关于 Windows 服务的文档提到将 Web 应用程序作为服务运行docs.microsoft.com/aspnet/core/host-and-deploy/…
      • 我不太明白,也许用.NET是不可能的。我将创建一个网站,并找出一种将消息转发到 Windows 服务的方法。不过还是谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 2018-03-15
      相关资源
      最近更新 更多