Skip to content

Server Methods

ServerMethods<T> classes let you organize hub logic into separate, focused classes instead of putting everything into a single hub. They are auto-discovered, support full dependency injection, and implement shared contract interfaces.

Basic usage

Create a class that extends ServerMethods<T> where T is your hub type. Implement a shared contract interface:

csharp
[SignalARRRContract]
public interface IChatHub
{
    Task SendMessage(string user, string message);
    Task<List<string>> GetHistory();
}

public class ChatMethods : ServerMethods<ChatHub>, IChatHub
{
    public Task SendMessage(string user, string message)
    {
        var client = ClientContext.GetTypedMethods<IChatClient>();
        client.ReceiveMessage(user, message);
        return Task.CompletedTask;
    }

    public Task<List<string>> GetHistory() =>
        Task.FromResult(new List<string> { "Hello", "World" });
}

No registration needed — AddSignalARRR() discovers all ServerMethods<T> classes in the scanned assemblies.

Multiple classes per hub

Split your hub into domain-specific classes:

csharp
public class ChatMethods : ServerMethods<AppHub>, IChatHub { ... }
public class UserMethods : ServerMethods<AppHub>, IUserHub { ... }
public class AdminMethods : ServerMethods<AppHub>, IAdminHub { ... }

All three classes serve methods on the same AppHub endpoint.

Method naming

Clients call methods using the pattern ClassName.MethodName:

csharp
// .NET client
var chat = connection.GetTypedMethods<IChatHub>();  // uses interface name mapping
await chat.SendMessage("Alice", "Hello!");
ts
// TypeScript client
await connection.invoke('ChatMethods.SendMessage', 'Alice', 'Hello!');

When using typed proxies on the .NET client, the naming is handled automatically through the interface mapping.

Available properties

Every ServerMethods class has these properties auto-injected at invocation time:

PropertyTypeDescription
ClientContextClientContextCurrent client's context (ID, user, attributes)
ContextHubCallerContextStandard SignalR caller context
ClientsIHubCallerClientsSend messages to other clients
GroupsIGroupManagerAdd/remove clients from groups
LoggerILoggerLogger instance

Dependency injection

ServerMethods classes are resolved from DI as transient services. Inject dependencies through the constructor:

csharp
public class ChatMethods : ServerMethods<AppHub>, IChatHub
{
    private readonly IChatRepository _repo;
    private readonly ILogger<ChatMethods> _logger;

    public ChatMethods(IChatRepository repo, ILogger<ChatMethods> logger)
    {
        _repo = repo;
        _logger = logger;
    }

    public async Task<List<string>> GetHistory()
    {
        _logger.LogInformation("Client {Id} requested history", ClientContext.Id);
        return await _repo.GetRecentMessages();
    }
}

Parameter injection with [FromServices]

Individual method parameters can be injected from DI using [FromServices]:

csharp
public async Task ProcessData(
    string input,
    [FromServices] IDataProcessor processor)
{
    await processor.Process(input);
}

Server-to-client calls

Inside a ServerMethods class, use ClientContext.GetTypedMethods<T>() to call back the current client:

csharp
public async Task<string> Greet()
{
    var client = ClientContext.GetTypedMethods<IChatClient>();
    string name = await client.GetClientName();  // awaits client response
    return $"Hello, {name}!";
}

To call other clients, inject ClientManager and use the typed extension methods:

csharp
public class ChatMethods : ServerMethods<AppHub>, IChatHub
{
    private readonly ClientManager _clients;

    public ChatMethods(ClientManager clients) => _clients = clients;

    public void BroadcastMessage(string message)
    {
        // GetTypedMethodsForHub returns (ClientContext, T) tuples
        foreach (var (ctx, methods) in _clients.GetTypedMethodsForHub<IChatClient, AppHub>())
        {
            methods.ReceiveMessage("System", message);
        }
    }

    public async Task<string> AskClient(string connectionId)
    {
        // GetTypedMethods extension combines GetClientById + GetTypedMethods
        var methods = _clients.GetTypedMethods<IChatClient>(connectionId);
        return await methods.GetClientName();
    }
}

See Client Manager for more details.

Custom method names

Use [MessageName] to override the default method name:

csharp
[MessageName("CustomName")]
public Task MyMethod() { ... }

Clients call this as ClassName.CustomName instead of ClassName.MyMethod.

Next steps

Released under the Apache-2.0 License.