0Pricing
C# Academy · Урок

Строго типизированные центры

Определяйте типизированные интерфейсы центров, чтобы получать безопасность на этапе компиляции и IntelliSense для вызовов методов клиента.

«Строго типизированные центры» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Проблема с именами методов в виде строк

Стандартные вызовы SignalR используют SendAsync("MethodName", ...) с «магическими строками». Опечатка в имени метода приводит к незаметной ошибке — клиент просто никогда не получает сообщение. Строго типизированные хабы решают эту проблему.

Определение интерфейса клиента

Создайте интерфейс, объявляющий все методы, которые сервер может вызывать на клиенте. Имена методов и типы параметров образуют ваш контракт.

// INotificationClient.cs
public interface INotificationClient
{
    Task ReceiveMessage(string user, string message);
    Task OrderShipped(int orderId, string trackingNumber);
    Task UserJoined(string username);
    Task UserLeft(string username);
    Task SystemAlert(string message);
}

Создание строго типизированного хаба

Унаследуйте хаб от Hub<T>, где T — интерфейс вашего клиента. Свойство Clients теперь типизировано: IntelliSense показывает доступные методы, а опечатки становятся ошибками компиляции.

public class ChatHub : Hub<INotificationClient>
{
    public async Task SendMessage(string message)
    {
        var user = Context.User!.Identity!.Name ?? "Anonymous";

        // Compile-time safety — no magic strings!
        await Clients.All.ReceiveMessage(user, message);
        await Clients.Others.UserJoined(user); // IntelliSense works
    }
}

Обращение к конкретным клиентам через типизированный хаб

Все стандартные методы выбора клиентов работают и в типизированном хабе: Clients.User, Clients.Group, Clients.Caller, Clients.Client — все они возвращают типизированный интерфейс.

public async Task NotifyOrderShipped(int orderId, string customerId)
{
    await Clients.User(customerId)
                 .OrderShipped(orderId, "TRK-12345");

    await Clients.Group("admins")
                 .SystemAlert($"Order {orderId} shipped to {customerId}");

    await Clients.Caller.ReceiveMessage("System", "Notification sent");
}

Типизированный IHubContext

Внедряйте IHubContext<THub, TClient> в службы, чтобы получать такую же проверку типов на этапе компиляции при отправке сообщений из кода за пределами хаба.

public class ShipmentService
{
    private readonly IHubContext<ChatHub, INotificationClient> _hub;

    public ShipmentService(
        IHubContext<ChatHub, INotificationClient> hub) => _hub = hub;

    public async Task ProcessShipmentAsync(int orderId, string customerId)
    {
        // Fully typed — no magic strings
        await _hub.Clients.User(customerId)
                  .OrderShipped(orderId, "TRK-99999");
    }
}

Правила интерфейса клиента

Методы в интерфейсе клиента должны возвращать Task, а не Task<T>. SignalR запускает вызовы клиента без ожидания результата — клиент ничего не возвращает серверу.

// CORRECT
public interface IMyClient
{
    Task ReceiveMessage(string msg);         // OK
    Task UpdateProgress(int percent);        // OK
    Task<string> GetUserInput();            // NOT SUPPORTED
}
// Return types other than Task are not supported in hub client interfaces
// For request-response patterns, use client-callable hub methods instead

Объединение типизированных хабов с группами

Типизированные группы работают так же, как нетипизированные: API тот же, но имена методов проверяются на этапе компиляции.

public class RoomHub : Hub<IRoomClient>
{
    public async Task JoinRoom(string room)
    {
        await Groups.AddToGroupAsync(Context.ConnectionId, room);
        await Clients.Group(room).UserJoined(Context.User!.Identity!.Name!);
    }

    public async Task BroadcastToRoom(string room, string message)
    {
        var user = Context.User!.Identity!.Name!;
        await Clients.Group(room).ReceiveMessage(user, message);
    }
}

Тестирование строго типизированных хабов

Поскольку вызовы методов клиента проходят через интерфейс, в модульных тестах можно создать имитацию клиента и проверить, что были вызваны правильные методы с нужными аргументами.

// NSubstitute test
var mockClients = Substitute.For<IHubCallerClients<INotificationClient>>();
var mockAllClients = Substitute.For<INotificationClient>();
mockClients.All.Returns(mockAllClients);

var hub = new ChatHub { Clients = mockClients };
await hub.SendMessage("Hello!");

await mockAllClients.Received(1).ReceiveMessage("System", "Hello!");

Несколько хабов в одном приложении

В приложении может быть несколько конечных точек хабов для разных функций реального времени, и у каждой может быть собственный строго типизированный интерфейс клиента.

// Three separate hubs
app.MapHub<ChatHub>("/hubs/chat");
app.MapHub<NotificationHub>("/hubs/notifications");
app.MapHub<DashboardHub>("/hubs/dashboard");

// Each with its own client interface:
// Hub<IChatClient>, Hub<INotificationClient>, Hub<IDashboardClient>

Отправка структурированных данных

Методы интерфейса клиента могут принимать сложные объекты передачи данных (DTO). SignalR автоматически сериализует их в JSON — убедитесь, что ваши типы поддерживают сериализацию.

public interface IOrderClient
{
    Task OrderUpdated(OrderStatusDto status);
}

public record OrderStatusDto(
    int OrderId,
    string Status,
    decimal Total,
    DateTime UpdatedAt);

// Usage in hub:
await Clients.User(customerId).OrderUpdated(
    new OrderStatusDto(order.Id, order.Status.ToString(),
                       order.Total, DateTime.UtcNow));

Быстрая проверка

Какое ограничение на тип возвращаемого значения действует для методов интерфейса клиента хаба SignalR?

Итоги: строго типизированные хабы

Главные выводы:

  • Определите интерфейс (IMyClient), перечисляющий все методы, которые сервер может вызывать на клиентах
  • Унаследуйте хаб от Hub<IMyClient> — свойство Clients станет полностью типизированным
  • Внедряйте IHubContext<THub, TClient> для типизированной отправки сообщений из кода за пределами хаба
  • Методы интерфейса клиента должны возвращать Task, а не Task<T>
  • Клиенты на основе интерфейсов можно имитировать — строго типизированные хабы проще тестировать

Часто задаваемые вопросы

Урок «Строго типизированные центры» бесплатный?

Да — полный текст урока «Строго типизированные центры» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Строго типизированные центры»?

Определяйте типизированные интерфейсы центров, чтобы получать безопасность на этапе компиляции и IntelliSense для вызовов методов клиента. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Строго типизированные центры»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Центры и подключения SignalR
  2. Группы, пользователи и управление подключениями
  3. Строго типизированные центры
  4. Масштабирование с помощью Redis Backplane
← Назад к C# Academy