1

我正在尝试使用 .net 核心服务器上的 IHosted 后台服务创建到 SignalR HUB 的客户端连接。我希望能够读取/处理从 signalR 客户端接收到的数据,一旦它到达服务器。将其想象为一种在消息通过服务器集线器时拦截和读取消息的方式。

似乎我可以将一些进一步的逻辑附加到 SignalR 集线器类中服务器上正在调用的方法,但我认为这不能确保线程安全,因为我想读取跨各种接收到的消息SignalR 连接并将消息内容添加到可以索引的静态列表中。消息内容将是您在 IList 中的项目集合,我可以在添加/删除等上运行查询。

到目前为止,Microsoft 上的文档对我没有帮助,但它似乎使用带有 .NET Core 3 的最新 SignalR 包,应该可以创建一个 .NET SignalR 客户端,但他们提供的示例基于一个单独的 C# 控制台项目。

我认为我可能遇到的问题部分与我实现 IHosted 后台服务的方式有关,即一旦 SignalR 连接开始,后台服务 Task 就会完成执行。看来我缺少的部分/逻辑是一个线程进程,它坐下来等待消息到达,然后吸出内容并从那里做我决定做的任何事情。

SignalR 集线器本身和我从 Microsoft 使用的客户端浏览器聊天示例在使用测试剃须刀页面时工作正常,因此问题不太可能是集线器。

在下面的 IHosted Service 代码部分中,我看到在后台服务首次启动时生成的第一个日志事件“STARTING SIGNALR at...”,但是查看调试控制台,看起来服务任务在 SignalR 连接完成后完成建立,然后什么都不做。我意识到我的方法可能是不正确的,当我所做的只是使用 javascript 通过浏览器客户端在客户端端点之间传递数据时,我对 SignalR 很满意,但是这个要求需要不同的方法并且没有很好的文档记录。

 namespace MyProjectNamespace.Classes.Events
 {
  public class SystemEventsService : IHostedService
  {
    // Create an instance of a CancellationTokenSource that will be used to stop the system mappings from running.
    public static CancellationTokenSource cancelSource;

    private readonly ILogger<SystemEventsService> _logger;

    public SystemEventsService(ILogger<SystemEventsService> logger)
    {
        _logger = logger;
    }

    HubConnection connection;

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        connection = new HubConnectionBuilder()
            .WithUrl("http://localhost:44372/dataHub")
            .WithAutomaticReconnect()
            .Build();

        _logger.LogInformation("STARTING SIGNALR at {Time}", DateTime.UtcNow);

        connection.On<string, string>("ReceiveMessage", (user, message) =>
        {
            _logger.LogInformation("String [" + message + "] received on server side at {Time}", DateTime.UtcNow);
        });

        connection.Closed += async (error) =>
        {
            await Task.Delay(new Random().Next(0, 5) * 1000);
            await connection.StartAsync();
        };

        try
        {
            await connection.StartAsync();
        }
        catch (Exception ex)
        {
            _logger.LogInformation(ex.Message, DateTime.UtcNow);
        }
    }

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

我启动后台服务的 Program.CS 文件:

 public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        .ConfigureLogging((context, logging) =>
        {
            logging.ClearProviders();
            logging.AddConfiguration(context.Configuration.GetSection("Logging"));
            logging.AddDebug();
            logging.AddConsole();
            // EventSource, EventLog, TraceSource, AzureAppServicesFile, AzureAppServicesBlob, ApplicatioInsights
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .ConfigureServices(services =>
        {
            services.AddHostedService<SystemEventsService>(); // This the service
        });

Razor Page - Javascript 客户端(运行良好)

    <div class="container">
    <div class="row">&nbsp;</div>
    <div class="row">
        <div class="col-2">User</div>
        <div class="col-4"><input type="text" id="userInput" /></div>
    </div>
    <div class="row">
        <div class="col-2">Message</div>
        <div class="col-4"><input type="text" id="messageInput" /></div>
    </div>
    <div class="row">&nbsp;</div>
    <div class="row">
        <div class="col-6">
            <input type="button" id="sendButton" value="Send Message" />
        </div>
    </div>
</div>
<div class="row">
    <div class="col-12">
        <hr />
    </div>
</div>
<div class="row">
    <div class="col-6">
        <ul id="messagesList"></ul>
    </div>
</div>

<script src="~/js/signalr/dist/browser/signalr.js"></script>

    <script>
    var connection = new signalR.HubConnectionBuilder().withUrl("/dataHub").build();

    //Disable send button until connection is established
    document.getElementById("sendButton").disabled = true;

    connection.on("ReceiveMessage", function (user, message) {
        var msg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
        var encodedMsg = user + " says " + msg;
        var li = document.createElement("li");
        li.textContent = encodedMsg;
        document.getElementById("messagesList").appendChild(li);
    });

    connection.start().then(function () {
        document.getElementById("sendButton").disabled = false;
    }).catch(function (err) {
        return console.error(err.toString());
    });

    document.getElementById("sendButton").addEventListener("click", function (event) {
        var user = document.getElementById("userInput").value;
        var message = document.getElementById("messageInput").value;
        connection.invoke("SendMessage", user, message).catch(function (err) {
            return console.error(err.toString());
        });
        event.preventDefault();
    });
</script>

SignalR 集线器类:

public class DataHub : Hub
{

    private readonly ILogger<DataHub> _logger;

    public DataHub(ILogger<DataHub> logger)
    {
        _logger = logger;
    }


    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
        _logger.LogInformation("String [" + message + "] received on server hub at {Time}", DateTime.UtcNow);
    }
}
4

0 回答 0