Я пытаюсь создать клиентское соединение с концентратором SignalR с помощью фоновой службы IHosted на главном сервере .net. Я хочу иметь возможность читать / обрабатывать данные, полученные от клиента signalR, как только они поступят на сервер. Представьте себе, что это способ перехвата и чтения сообщений при их передаче через концентратор сервера.
Кажется, что я мог бы добавить дополнительную логику к методам, вызываемым на сервере в классе концентратора SignalR. , но я не думаю, что это обеспечит потокобезопасную ситуацию, учитывая, что я хочу прочитать сообщения, полученные через различные соединения SignalR, и добавить содержимое сообщения в статический список, который можно проиндексировать. Содержимое сообщения будет представлять собой набор элементов, аналогичных тем, которые есть в IList, и которые я могу выполнять при добавлении / удалении и т. Д.
Документы на Microsoft пока мне не помогают, но этопоявляется с использованием последнего пакета SignalR с .NET Core 3, создание клиента .NET SignalR должно быть возможным, но примеры, которые они приводят, основаны на отдельном консольном проекте C #.
Я думаю, что проблема, которая может возникнуть у меня, частично связана с тем, как я реализую фоновую службу IHosted, т. Е. Как только соединение SignalR установлено, фоновая служба Task завершает выполнение. Кажется, что часть / логика, которую я пропускаю, - это процесс потока, который сидит и ждет, пока не придет сообщение, затем высасывает содержимое и делает все, что я решу оттуда.
Сам концентратор SignalR ипример клиентского чата в браузере, который я использовал от Microsoft, работает нормально, используя страницу тестовой бритвы, поэтому проблема вряд ли будет в хабе.
В приведенном ниже разделе кода службы IHosted я вижу первое событие журнала "STARTING SIGNALR at ... "генерируется при первом запуске фоновой службы, но, глядя на консоль отладки, похоже, что задача службы завершается после установления соединения SignalR, и больше ничего не делается. Я понимаю, что мой подход к этому, скорее всего, неверен, мне удобно с SignalR, когда все, что я делаю, это передаю данные между конечными точками клиента через клиент браузера, используя javascript, но это требование требует другого подхода и плохо документировано.
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 - клиент 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);
}
}