plugins/dotnet-blazor/skills/signalr-realtime/SKILL.md
SignalR for real-time communication in Blazor apps including hubs, groups, streaming, and scaling
npx skillsauth add markus41/claude signalr-realtimeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
public sealed class NotificationHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
public async Task JoinGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("UserJoined", Context.UserIdentifier);
}
public async Task SendToGroup(string groupName, string message)
{
await Clients.Group(groupName).SendAsync("ReceiveMessage", message);
}
public override async Task OnConnectedAsync()
{
await base.OnConnectedAsync();
// Track connection
}
}
builder.Services.AddSignalR()
.AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
app.MapHub<NotificationHub>("/hubs/notifications");
Blazor Server already uses SignalR for its circuit. For additional hubs:
@rendermode InteractiveServer
@inject NavigationManager Navigation
@implements IAsyncDisposable
@code {
private HubConnection? _hub;
protected override async Task OnInitializedAsync()
{
_hub = new HubConnectionBuilder()
.WithUrl(Navigation.ToAbsoluteUri("/hubs/notifications"))
.WithAutomaticReconnect()
.Build();
_hub.On<string, string>("ReceiveMessage", (user, message) =>
{
_messages.Add(new(user, message));
InvokeAsync(StateHasChanged);
});
await _hub.StartAsync();
}
public async ValueTask DisposeAsync()
{
if (_hub is not null)
await _hub.DisposeAsync();
}
}
public interface INotificationClient
{
Task ReceiveMessage(string user, string message);
Task UserJoined(string userId);
Task OrderUpdated(OrderStatusDto status);
}
public sealed class NotificationHub : Hub<INotificationClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
}
public sealed class OrderService(IHubContext<NotificationHub, INotificationClient> hub)
{
public async Task UpdateStatusAsync(int orderId, string status)
{
// Update DB...
await hub.Clients.Group($"order-{orderId}")
.OrderUpdated(new OrderStatusDto(orderId, status));
}
}
builder.Services.AddSignalR()
.AddStackExchangeRedis(builder.Configuration.GetConnectionString("Redis")!);
public class ChatHub : Hub
{
// Broadcast to ALL connected clients
await Clients.All.SendAsync("ReceiveMessage", user, message);
// Send to specific client by connection ID
await Clients.Client(targetConnectionId).SendAsync("ReceivePrivateMessage", message);
// Send to all EXCEPT caller
await Clients.Others.SendAsync("ReceiveMessage", message);
// Group operations
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("ReceiveGroupMessage", message);
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
// Send to group except caller
await Clients.GroupExcept(groupName, Context.ConnectionId)
.SendAsync("ReceiveMessage", message);
}
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.withAutomaticReconnect()
.build();
// Server calls this method on client
connection.on("ReceiveMessage", (user, message) => {
document.getElementById("messages").innerHTML += `<li>${user}: ${message}</li>`;
});
// Client calls server method
await connection.invoke("SendMessage", user, message);
// Connection lifecycle
connection.onreconnecting((error) => console.log("Reconnecting..."));
connection.onreconnected((connectionId) => console.log("Reconnected:", connectionId));
connection.onclose((error) => console.log("Connection closed"));
connection.start().catch(err => console.error(err));
SignalR automatically negotiates the best transport:
development
Enhanced plan-authoring skill with Pre-Writing context gathering, task metadata, non-TDD templates, Red Flags, telemetry, and an automated plan linter. Use when you have a spec or requirements for a multi-step task, before touching code.
tools
Documentation intelligence engine with graph-based API docs, algorithm library, and drift detection
tools
Ultraplan cloud planning — kick off a plan in the cloud from your terminal, review and revise in the browser, then execute remotely or send back to CLI
tools
--- name: mcp description: Configure MCP servers for Claude Code — stdio vs HTTP, authentication, Tools/Resources/Prompts distinction, channels (CI webhook, mobile relay, Discord bridge, fakechat), and cost of always-loaded tools. Use this skill whenever adding an MCP server, debugging connection issues, choosing between MCP Tools vs Prompts vs Resources, installing channel servers, or managing .mcp.json. Triggers on: "MCP server", "mcp config", "add Obsidian MCP", "install context7", "channels"