Hub Design¶
SignalR Hub, istemci-sunucu arası gerçek zamanlı iletişimin merkezidir; yanlış tasarım bellek sızıntılarına ve ölçeklenme sorunlarına yol açar.
1. Hub İçinde İş Mantığı Yazmak¶
❌ Yanlış Kullanım: Hub metodunda veritabanı erişimi ve iş mantığı yazmak.
public class ChatHub : Hub
{
private readonly AppDbContext _context;
public async Task SendMessage(string message)
{
var user = await _context.Users.FindAsync(Context.UserIdentifier);
if (user.IsBanned) return;
var chatMessage = new ChatMessage { UserId = user.Id, Content = message };
_context.Messages.Add(chatMessage);
await _context.SaveChangesAsync();
await Clients.All.SendAsync("ReceiveMessage", user.Name, message);
}
}
✅ İdeal Kullanım: Hub’ı ince tutun, iş mantığını servise taşıyın.
public class ChatHub : Hub
{
private readonly IChatService _chatService;
public ChatHub(IChatService chatService) => _chatService = chatService;
public async Task SendMessage(string message)
{
var result = await _chatService.SendMessageAsync(Context.UserIdentifier, message);
if (result.IsSuccess)
{
await Clients.All.SendAsync("ReceiveMessage", result.SenderName, message);
}
}
}
2. Connection Lifecycle Yönetmemek¶
❌ Yanlış Kullanım: Bağlantı açılıp kapandığında temizlik yapmamak.
public class GameHub : Hub
{
private static readonly Dictionary<string, string> _onlineUsers = new();
public async Task JoinGame(string username)
{
_onlineUsers[Context.ConnectionId] = username;
await Clients.All.SendAsync("UserJoined", username);
}
// Kullanıcı bağlantıyı kapatırsa _onlineUsers'dan silinmez
}
✅ İdeal Kullanım: OnConnectedAsync ve OnDisconnectedAsync ile lifecycle yönetin.
public class GameHub : Hub
{
private readonly IConnectionTracker _tracker;
public GameHub(IConnectionTracker tracker) => _tracker = tracker;
public override async Task OnConnectedAsync()
{
await _tracker.AddConnectionAsync(Context.ConnectionId, Context.UserIdentifier);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
var username = await _tracker.RemoveConnectionAsync(Context.ConnectionId);
await Clients.All.SendAsync("UserLeft", username);
await base.OnDisconnectedAsync(exception);
}
}
3. Group Yönetimini Yanlış Yapmak¶
❌ Yanlış Kullanım: Tüm istemcilere mesaj göndermek.
public async Task SendRoomMessage(string roomId, string message)
{
await Clients.All.SendAsync("ReceiveMessage", roomId, message);
// Tüm kullanıcılar tüm odaların mesajlarını alır
}
✅ İdeal Kullanım: Group’lar ile sadece ilgili kullanıcılara gönderin.
public async Task JoinRoom(string roomId)
{
await Groups.AddToGroupAsync(Context.ConnectionId, roomId);
await Clients.Group(roomId).SendAsync("UserJoined", Context.UserIdentifier);
}
public async Task LeaveRoom(string roomId)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, roomId);
await Clients.Group(roomId).SendAsync("UserLeft", Context.UserIdentifier);
}
public async Task SendRoomMessage(string roomId, string message)
{
await Clients.Group(roomId).SendAsync("ReceiveMessage", Context.UserIdentifier, message);
}
4. Strongly-Typed Hub Kullanmamak¶
❌ Yanlış Kullanım: Magic string ile metod çağrısı yapmak.
await Clients.All.SendAsync("ReceiveMessage", user, message);
await Clients.All.SendAsync("RecieveMessage", user, message); // Typo, runtime'da hata
✅ İdeal Kullanım: Strongly-typed hub interface tanımlayın.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
Task UserJoined(string user);
Task UserLeft(string user);
}
public class ChatHub : Hub<IChatClient>
{
public async Task SendMessage(string message)
{
await Clients.All.ReceiveMessage(Context.UserIdentifier, message);
}
public async Task JoinRoom(string roomId)
{
await Groups.AddToGroupAsync(Context.ConnectionId, roomId);
await Clients.Group(roomId).UserJoined(Context.UserIdentifier);
}
}
5. Hub Dışından Mesaj Gönderememek¶
❌ Yanlış Kullanım: Hub instance’ını oluşturup mesaj göndermeye çalışmak.
public class OrderService
{
public async Task CompleteOrderAsync(int orderId)
{
// Hub'a nasıl erişilir?
var hub = new NotificationHub(); // Çalışmaz!
}
}
✅ İdeal Kullanım: IHubContext ile Hub dışından mesaj gönderin.
public class OrderService
{
private readonly IHubContext<NotificationHub, INotificationClient> _hubContext;
public OrderService(IHubContext<NotificationHub, INotificationClient> hubContext)
=> _hubContext = hubContext;
public async Task CompleteOrderAsync(int orderId, string customerId)
{
await _hubContext.Clients.User(customerId)
.OrderCompleted(orderId, "Siparişiniz tamamlandı!");
}
}