
Complete guide to implementing real-time features including WebSocket fundamentals, SignalR best practices, and gRPC for high-performance communication.
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.
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.
WebSockets provide the low-level foundation for real-time communication.
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);
}
}
}
}
SignalR abstracts away WebSocket complexity while providing powerful features.
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
});
}
}
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");
});
}
For service-to-service communication, gRPC is superior to REST.
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;
}
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
};
}
}
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
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.