Оживляем приложение с помощью SignalR и .NET 6

  • Михаил
  • 15 мин. на прочтение
  • 156
  • 12 Apr 2023
  • 13 Apr 2023

Самое распространенное в разработке программного обеспечения — это приложения, которые делают запросы к серверу и ждут, пока сервер обработает этот запрос и вернет данные. Но что, если нам нужны эти данные именно в тот момент, когда мы делаем запрос, например, в игре, где у нас не может быть задержек? Чтобы удовлетворить эту потребность, в ASP.NET Core есть технология SignalR. В этой статье мы познакомимся с SignalR и создадим простой пример, который будет предоставлять данные в реальном времени приложению. Для этого мы будем использовать минимальные API, доступные в .NET 6.

SignalR — это библиотека для разработчиков ASP.NET, которая упрощает процесс добавления веб-функций в реальном времени в приложения. С помощью SignalR мы можем сделать содержимое сервера доступным для подключенных клиентов мгновенно, как только оно становится доступным, вместо того, чтобы сервер ждал, пока клиент запросит новые данные. SignalR — отличный выбор для обработки веб-функций «в реальном времени» через ASP.NET. Типичным примером его использования является разработка чатов, где пользователю необходимо, чтобы его сообщение было отправлено немедленно так же, как он его получил. Хотя чат распространен, это не единственный пример использования SignalR. Приложения для мониторинга, формы для совместной работы и игры в реальном времени также являются отличными вариантами использования. Для получения подробной информации о SignalR вы можете получить доступ к официальному веб-сайту Microsoft по этой ссылке: Introduction to SignalR .

Создание сервера

Во-первых, давайте создадим сервер. Итак, запустите в терминале команды:

dotnet new web -o MainSignalServer
cd MainSignalServer
dotnet add package Microsoft.AspNetCore.SignalR

С помощью этих команд мы создаем наш сервер (MainSignalServer) и добавляем пакет «Microsoft.AspNetCore.SignalR», который нам нужен для реализации SignalR на сервере.

Создание концентратора

Концентратор позволяет клиенту и серверу напрямую вызывать методы друг друга. SignalR использует концентратор вместо контроллеров, как в ASP.NET MVC. Для этого нам нужно создать класс, который будет наследоваться от класса Hub.

Итак, внутри проекта создайте класс под названием «MainHub» и замените свой код следующим:

using Microsoft.AspNetCore.SignalR;
public class MainHub : Hub
{
   public async IAsyncEnumerable Streaming(CancellationToken cancellationToken)
   {
       while (true)
       {
           yield return DateTime.UtcNow;
           await Task.Delay(1000, cancellationToken);
       }
   }
}

В этом примере мы возвращаем IAsyncEnumerable, который является типом, добавленным в более поздних версиях C#. Мы также передаем параметр «CancellationToken», который позволяет нам отменить действие в любое время. Мы также добавили «выход», чтобы клиенту не требовался класс для хранения состояния.

Теперь нам нужно добавить конфигурацию SignalR и создать маршрут к нашему серверу. Для этого замените код класса Program следующим:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSignalR();
var app = builder.Build();
app.MapHub("/current-time");
app.Run();

Наш сервер готов — теперь просто запустим в терминале, и сервер будет готов принимать подключения от клиентов.

dotnet watch run

Создание клиента (консольное приложение)

Теперь давайте создадим простое приложение для использования информации, предоставляемой нашим сервером, в режиме реального времени.

Затем в другом терминале выполните следующие команды:

dotnet new console -o MainSignalClient
cd MainSignalClient
dotnet add package Microsoft.AspNetCore.SignalR.Client

Теперь внутри созданного проекта создайте класс под названием MainClient и замените код на код ниже:

using Microsoft.AspNetCore.SignalR.Client;
public class MainClient
{
   public static async Task ExecuteAsync()
   {
       //Replace port "7024" with the port running the MainSignalServer project
       var uri = "https://localhost:7024/current-time";
       await using var connection = new HubConnectionBuilder().WithUrl(uri).Build();
       await connection.StartAsync();
       await foreach (var date in connection.StreamAsync("Streaming"))
       {
           Console.WriteLine(date);
       }
   }
}

В созданном нами классе мы определяем метод для использования данных, которые сервер делает доступными в режиме реального времени. Для этого мы создаем соединение с концентратором, передавая URL-адрес нашего сервера, который возвращает список дат и отображает его в терминал.

Теперь нам просто нужно вызвать этот метод в Program нашего приложения. Итак, замените код класса Program кодом ниже:

await MainClient.ExecuteAsync();

Теперь просто запустите клиентский проект этой командой в консоли и проверьте результат:

dotnet watch run

Консоль клиента отображает текущую дату и время, предоставленные нашим сервером.

Создание клиента (web приложение)

Теперь давайте создадим web приложение для использования информации, предоставляемой нашим сервером, в режиме реального времени.

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <title>Real date-time</title>
</head>
<body>
   <div class="row">
       <div class="col-12">
           <ul id="serverDate"></ul>
       </div>
   </div>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>
   <script>
       var connection = new signalR.HubConnectionBuilder().withUrl("/gettime").build();
       connection.on("DisplayTime", function (time) {
           var li = document.createElement("li");
           li.textContent = time;
           document.getElementById("serverDate").appendChild(li);
       });
       connection.start().then(function () {
       }).catch(function (err) {
           return console.error(err.toString());
       });
       setInterval(function () {
           connection.invoke("PrintTime").catch(function (err) {
               return console.error(err.toString());
           });
       }, 1000);
   </script>
</body>
</html>

Получить доступ к полному коду примера, использованного в этой статье, по этой ссылке: исходный код