c# - .Net Core 3.1 SignalR - 无法使用 .NET 客户端包从客户端读取服务器上的消息
问题描述
我正在尝试使用 .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"> </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"> </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, "&").replace(/</g, "<").replace(/>/g, ">");
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);
}
}
解决方案
推荐阅读
- html - VBA按钮单击具有相同的类(无ID,无类名)
- sql - 有没有办法使用 SQL Developer 中的查询生成的数据自动填写 PDF 表单?
- pycharm - 如何在pycharm中向黑色格式化程序添加其他设置
- vba - Webbrowser2_newwindow2 打开空白 newwindow2
- c# - 状态类作为单元类的变量
- javascript - 未定义硒测试后的功能
- haproxy - haproxy 在 ACL 表达式中缺少 fetch 方法
- python - 编写将使用 min max 方法或 z-score 方法进行归一化的函数
- c# - 处理做同步工作的异步函数
- php - PHP Mailer 显示错误:Mailer 错误 smtp 连接失败。怎么修?