Blog
Oct 1, 2025 - 13 MIN READ
Real-Time Communication with ASP.NET Core: WebSockets, SignalR, and gRPC

Real-Time Communication with ASP.NET Core: WebSockets, SignalR, and gRPC

Complete guide to implementing real-time features including WebSocket fundamentals, SignalR best practices, and gRPC for high-performance communication.

Your Name

Your Name

Real-time communication has transformed user expectations. Applications that don't provide instant feedback feel broken. Building these features at scale requires understanding the different technologies available.

Understanding Real-Time Communication

Real-time communication requires bidirectional communication between client and server. Traditional HTTP request-response doesn't work—you need the server to push updates to clients.

Phase 1: WebSocket Fundamentals

WebSockets provide the low-level foundation for real-time communication.

Raw WebSocket Implementation

public class WebSocketManager
{
    private readonly ConcurrentDictionary<string, WebSocket> _connections;
    
    public async Task HandleWebSocketAsync(string connectionId, WebSocket webSocket)
    {
        var buffer = new byte[1024 * 4];
        
        while (webSocket.State == WebSocketState.Open)
        {
            var result = await webSocket.ReceiveAsync(
                new ArraySegment<byte>(buffer),
                CancellationToken.None);
            
            if (result.MessageType == WebSocketMessageType.Close)
            {
                await webSocket.CloseAsync(
                    WebSocketCloseStatus.NormalClosure,
                    "Closing",
                    CancellationToken.None);
            }
        }
    }
}

Phase 2: ASP.NET Core SignalR

SignalR abstracts away WebSocket complexity while providing powerful features.

SignalR Hub Implementation

public class NotificationHub : Hub
{
    private readonly IHubContext<NotificationHub> _hubContext;
    
    public override async Task OnConnectedAsync()
    {
        var userId = Context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        
        if (!string.IsNullOrEmpty(userId))
        {
            await Groups.AddToGroupAsync(Context.ConnectionId, $"user_{userId}");
        }
        
        await base.OnConnectedAsync();
    }
    
    public async Task SendNotificationAsync(string message)
    {
        var userId = Context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        
        await Clients.Caller.SendAsync("ReceiveNotification", new
        {
            Message = message,
            CreatedAt = DateTime.UtcNow
        });
    }
}

Startup Configuration

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR(options =>
    {
        options.MaximumReceiveMessageSize = 32 * 1024;
        options.KeepAliveInterval = TimeSpan.FromSeconds(15);
    });
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();
    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<NotificationHub>("/hubs/notifications");
    });
}

Phase 3: gRPC for High-Performance Communication

For service-to-service communication, gRPC is superior to REST.

Defining gRPC Services

syntax = "proto3";

package notification;

service NotificationService {
    rpc SendNotification (NotificationRequest) returns (NotificationResponse);
    rpc GetNotifications (GetNotificationsRequest) returns (stream Notification);
}

message NotificationRequest {
    string user_id = 1;
    string message = 2;
}

message NotificationResponse {
    string notification_id = 1;
    bool success = 2;
}

gRPC Service Implementation

public class NotificationGrpcService : 
    NotificationService.NotificationServiceBase
{
    private readonly INotificationService _notificationService;
    
    public override async Task<NotificationResponse> SendNotification(
        NotificationRequest request,
        ServerCallContext context)
    {
        var notification = new Notification
        {
            Id = Guid.NewGuid().ToString(),
            UserId = request.UserId,
            Message = request.Message
        };
        
        await _notificationService.SaveAsync(notification);
        
        return new NotificationResponse
        {
            NotificationId = notification.Id,
            Success = true
        };
    }
}

Choosing the Right Technology

WebSockets: When low-level control needed, custom protocol

SignalR: Browser-based real-time, user notifications, simple integration

gRPC: Service-to-service, high throughput, performance critical

Conclusion

Real-time communication is no longer optional—it's expected. Choosing the right technology matters. WebSockets give you power but require management. SignalR provides great defaults. gRPC excels for service-to-service communication.

Built with Nuxt UI • © 2025 Behnam Nouri