0Pricing
C# Academy · 课时

强类型中心

定义类型化中心接口,为客户端方法调用获得编译时安全性和 IntelliSense 支持。

强类型中心 是 CoddyKit 上的免费 C# Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 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>
  • 基于接口的客户端可以进行模拟——强类型中心更易于测试

常见问题解答

「强类型中心」课时是免费的吗?

是的 — 「强类型中心」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「强类型中心」这节课中我会学到什么?

定义类型化中心接口,为客户端方法调用获得编译时安全性和 IntelliSense 支持。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「强类型中心」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. SignalR 中心与连接
  2. 组、用户与连接管理
  3. 强类型中心
  4. 使用 Redis 后端扩展
← 返回 C# Academy