Günümüzün dinamik web uygulamalarında kullanıcı etkileşimi ve anlık bilgi akışı kritik öneme sahiptir. Gerçek zamanlı bildirimler, kullanıcı deneyimini zenginleştirmenin ve uygulamaların duyarlılığını artırmanın temel yollarından biridir. C# ve .NET ekosisteminde bu ihtiyacı karşılamak için geliştirilen SignalR, gerçek zamanlı web fonksiyonelliğini kolayca entegre etmenizi sağlayan güçlü bir kütüphanedir. Bu makale, SignalR kullanarak C# projelerinizde nasıl anlık bildirimler oluşturabileceğinizi detaylandıracaktır.
SignalR Nedir ve Neden Gerçek Zamanlı Bildirimler İçin Tercih Edilir?
SignalR, ASP.NET Core uygulamaları için gerçek zamanlı web fonksiyonelliği eklemeyi kolaylaştıran bir açık kaynak kütüphanedir. Geleneksel HTTP istek-yanıt modelinin aksine, SignalR sunucu ve istemciler arasında kalıcı bağlantılar kurarak sunucunun istemcilere doğrudan içerik göndermesini sağlar. Bu, sohbet uygulamaları, canlı gösterge tabloları, oyunlar ve tabii ki gerçek zamanlı bildirim sistemleri gibi senaryolar için vazgeçilmezdir.
SignalR’ın başlıca avantajları şunlardır:
- Basit API: Karmaşık gerçek zamanlı iletişim protokollerini (WebSockets, Server-Sent Events, Long Polling) soyutlar ve tek bir basit API sunar.
- Otomatik Bağlantı Yönetimi: Bağlantı türünü otomatik olarak algılar ve uygun olanı seçer; bağlantı kesilmelerini yönetir.
- Çok Yönlü İletişim: Sunucudan istemciye, istemciden sunucuya ve sunucudan tüm istemcilere veya belirli istemcilere mesaj gönderebilir.
- Platformlar Arası Destek: JavaScript, .NET, Java, Swift gibi çeşitli istemci kütüphaneleriyle geniş bir platform desteği sunar.
SignalR’ın Temel Bileşenleri
SignalR mimarisi birkaç temel bileşenden oluşur:
Hublar (Hubs)
SignalR’ın merkezidir. Bir Hub, istemcilerin çağırabileceği sunucu tarafı metotları ve sunucunun istemcilerde çağırabileceği metotları içerir. İş mantığınızı Hub sınıflarına yerleştirirsiniz. Örneğin, bir bildirim Hub’ı, “bildirimGönder” metodu ile istemciden bildirim alıp, “bildirimAl” metodu ile istemcilere bildirim gönderebilir.
Kalıcı Bağlantılar (Persistent Connections)
Hublar, altında yatan kalıcı bağlantılar üzerine kuruludur. SignalR, bağlantı kurmak için WebSockets’i tercih eder. Eğer WebSockets desteklenmiyorsa, Server-Sent Events veya Long Polling gibi alternatif taşıma mekanizmalarını kullanarak bağlantıyı sürdürür. Bu, geliştiricinin altta yatan karmaşık protokol detaylarıyla uğraşmasına gerek kalmadan en iyi performansı elde etmesini sağlar.
İstemciler (Clients)
Çeşitli platformlar için SignalR istemci kütüphaneleri mevcuttur. En yaygın olanları web uygulamaları için JavaScript istemcisi, masaüstü veya mobil uygulamalar için .NET istemcisi ve diğer diller için uygun SDK’lardır. Bu istemciler, Hub’a bağlanır, Hub metotlarını çağırır ve sunucudan gelen metot çağrılarını dinler.
C# ile SignalR Sunucusu Kurulumu
Bir .NET Core uygulamasında SignalR sunucusu kurmak oldukça basittir.
1. Gerekli NuGet Paketini Kurma
Projenize `Microsoft.AspNetCore.SignalR` paketini eklemelisiniz:
dotnet add package Microsoft.AspNetCore.SignalR
2. `Program.cs` veya `Startup.cs` Dosyasını Yapılandırma
.NET 6 ve sonrası için `Program.cs` dosyasında, SignalR hizmetini ekleyip Hub’ınızı eşlemeniz gerekir:
var builder = WebApplication.CreateBuilder(args);
// SignalR hizmetini ekle
builder.Services.AddSignalR();
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder => builder.WithOrigins("http://localhost:portunuz") // İstemcinizin adresini buraya yazın
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
});
var app = builder.Build();
app.UseRouting();
app.UseCors("AllowSpecificOrigin"); // CORS'u kullan
// Hub'ınızı bir URL'ye eşle
app.MapHub<NotificationHub>("/notificationHub");
app.Run();
Bu örnekte, `NotificationHub` adında bir Hub oluşturulacağını ve `/notificationHub` URL’si üzerinden erişilebilir olacağını varsayıyoruz. CORS yapılandırması, farklı bir kökenden (origin) gelen istemcilerin SignalR sunucusuna bağlanabilmesi için önemlidir.
3. Bir SignalR Hub’ı Oluşturma
NotificationHub.cs adında bir dosya oluşturun ve Hub sınıfından türeyen bir sınıf tanımlayın:
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
public class NotificationHub : Hub
{
// İstemciden çağrılabilecek bir metot
public async Task SendNotificationToAll(string user, string message)
{
// Tüm bağlı istemcilere bildirim gönder
await Clients.All.SendAsync("ReceiveNotification", user, message);
}
// Belirli bir kullanıcıya bildirim göndermek için (örneğin kimlik doğrulaması sonrası)
public async Task SendNotificationToUser(string userId, string message)
{
// Belirli bir kullanıcıya (ConnectionId veya UserId) bildirim gönder
await Clients.User(userId).SendAsync("ReceiveNotification", "System", message);
}
public override async Task OnConnectedAsync()
{
// Bağlantı kurulduğunda yapılacak işlemler
// Örneğin, kullanıcıyı bir gruba ekleyebilir veya ConnectionId'yi kaydedebilirsiniz.
// await Groups.AddToGroupAsync(Context.ConnectionId, "myGroup");
await Clients.All.SendAsync("UserConnected", Context.ConnectionId);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
// Bağlantı kesildiğinde yapılacak işlemler
await Clients.All.SendAsync("UserDisconnected", Context.ConnectionId);
await base.OnDisconnectedAsync(exception);
}
}
Yukarıdaki örnekte:
- `SendNotificationToAll`: İstemciden çağrıldığında, `ReceiveNotification` metodunu tüm bağlı istemcilerde çalıştırır.
- `Clients.All`: Tüm bağlı istemcileri temsil eder. `Clients.User(userId)` belirli bir kullanıcıya, `Clients.Group(groupName)` ise bir gruba bildirim göndermek için kullanılır.
- `SendAsync(“ReceiveNotification”, user, message)`: İstemcilerde `ReceiveNotification` adında bir JavaScript fonksiyonunu çağırır ve `user` ile `message` parametrelerini iletir.
- `OnConnectedAsync` ve `OnDisconnectedAsync`: Bir istemci bağlandığında veya bağlantısı kesildiğinde tetiklenen olaylardır. Kullanıcıları gruplara atamak veya bağlantı bilgilerini yönetmek için ideal yerlerdir.
Hub Dışından Bildirim Gönderme
Genellikle bildirimleri bir Hub metodundan değil, bir servis katmanından, bir API denetleyicisinden veya başka bir iş mantığından göndermek isteyebilirsiniz. Bunun için `IHubContext` arayüzünü kullanırsınız.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
[ApiController]
[Route("[controller]")]
public class NotificationController : ControllerBase
{
private readonly IHubContext<NotificationHub> _hubContext;
public NotificationController(IHubContext<NotificationHub> hubContext)
{
_hubContext = hubContext;
}
[HttpPost("send-system-notification")]
public async Task<IActionResult> SendSystemNotification([FromBody] string message)
{
// Tüm istemcilere sistem bildirimi gönder
await _hubContext.Clients.All.SendAsync("ReceiveNotification", "System", message);
return Ok("Bildirim gönderildi.");
}
[HttpPost("send-notification-to-user/{userId}")]
public async Task<IActionResult> SendNotificationToSpecificUser(string userId, [FromBody] string message)
{
// Belirli bir kullanıcıya bildirim gönder
await _hubContext.Clients.User(userId).SendAsync("ReceiveNotification", "Admin", message);
return Ok($"Bildirim kullanıcıya {userId} gönderildi.");
}
}
`IHubContext`’i DI (Dependency Injection) ile alarak, uygulamanızın herhangi bir yerinden SignalR Hub’ınıza erişebilir ve istemcilere bildirim gönderebilirsiniz.
İstemci Tarafında Bildirimleri Alma (JavaScript Örneği)
Bir web tarayıcısında SignalR bildirimlerini almak için JavaScript istemci kütüphanesini kullanırız.
1. SignalR JavaScript İstemcisini Dahil Etme
Paketi kurabilir veya CDN’den çekebilirsiniz:
npm install @microsoft/signalr
HTML dosyanızda:
<script src="node_modules/@microsoft/signalr/dist/browser/signalr.min.js"></script>
<script>
// Client-side SignalR logic will go here
</script>
2. Hub’a Bağlanma ve Bildirimleri Dinleme
const connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:5000/notificationHub", {
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets // WebSockets'ı zorla
}) // Sunucu URL'niz ve Hub yolu
.configureLogging(signalR.LogLevel.Information)
.build();
// Sunucudan "ReceiveNotification" metodu çağrıldığında
connection.on("ReceiveNotification", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messagesList").appendChild(li);
console.log(`Bildirim alındı: ${user}: ${message}`);
});
// Sunucudan "UserConnected" metodu çağrıldığında
connection.on("UserConnected", (connectionId) => {
console.log(`Yeni kullanıcı bağlandı: ${connectionId}`);
});
// Bağlantıyı başlat
connection.start()
.then(() => {
console.log("SignalR bağlantısı başarılı!");
// İsteğe bağlı: Sunucuya bir mesaj göndermek
// connection.invoke("SendNotificationToAll", "Client", "Merhaba, ben bir istemciyim!").catch(err => console.error(err));
})
.catch(err => console.error("SignalR bağlantısı başarısız: " + err.toString()));
// Bağlantı kesildiğinde tekrar bağlanmayı dene
connection.onclose(async () => {
console.log("SignalR bağlantısı kesildi. Yeniden bağlanmaya çalışılıyor...");
await start();
});
// İstemciden sunucuya bildirim gönderme (örneğin bir buton tıklamasıyla)
document.getElementById("sendButton").addEventListener("click", event => {
const user = document.getElementById("userInput").value;
const message = document.getElementById("messageInput").value;
connection.invoke("SendNotificationToAll", user, message).catch(err => console.error(err));
event.preventDefault();
});
Bu JavaScript kodu, SignalR Hub’ınıza bağlanır, sunucudan `ReceiveNotification` ve `UserConnected` mesajlarını dinler ve bu mesajları bir HTML listesine ekleyerek görüntüler. Ayrıca, bir buton tıklamasıyla sunucuya `SendNotificationToAll` metodunu çağırarak bildirim gönderme yeteneği de sağlar.
Performans, Ölçeklenebilirlik ve Güvenlik Konuları
Ölçeklenebilirlik
Tek bir sunucu üzerindeki SignalR uygulaması belirli bir sayıda eşzamanlı bağlantıyı yönetebilir. Daha büyük uygulamalar için ölçeklendirme gereklidir:
- Redis Backplane: Birden fazla sunucuya dağıtılmış SignalR uygulamaları için Redis Backplane kullanabilirsiniz. Bu, bir sunucunun gönderdiği bir mesajın diğer sunuculara ve onların bağlı istemcilerine ulaşmasını sağlar.
- Azure SignalR Service: Azure bulut platformunda, SignalR bağlantılarını yöneten tam olarak yönetilen bir hizmettir. Bağlantı sayısından bağımsız olarak yüksek ölçeklenebilirlik ve performans sunar, sunucu kaynaklarınızı uygulama mantığınıza odaklamanıza olanak tanır.
Güvenlik
SignalR ile gerçek zamanlı bildirim sistemleri geliştirirken güvenlik büyük önem taşır:
- Kimlik Doğrulama ve Yetkilendirme: `Authorize` özniteliğini Hub sınıflarınıza veya metotlarınıza ekleyerek kimliği doğrulanmış kullanıcıların erişimini zorunlu kılabilirsiniz.
- Bağlantı Kimliği Yönetimi: `Context.ConnectionId` geçicidir ve tarayıcı yenilendiğinde değişebilir. Kullanıcıya özel bildirimler göndermek için `ClaimsPrincipal`’dan gelen `Context.User.Identity.Name` veya özel bir kullanıcı kimliğini kullanmak daha güvenlidir. Bu durumda, kullanıcı kimliği ile `ConnectionId` arasında bir eşleşmeyi bir depoda (veritabanı, Redis vb.) tutmanız gerekebilir.
- Giriş Doğrulama: İstemciden gelen verilerin her zaman sunucuda doğrulanması gerekir.
Sonuç
C# dilinde SignalR ile gerçek zamanlı bildirimler geliştirmek, modern ve etkileşimli uygulamalar oluşturmanın güçlü ve verimli bir yoludur. Karmaşık gerçek zamanlı iletişim altyapısını soyutlayarak geliştiricilerin iş mantığına odaklanmasını sağlar. Kolay kurulumu, esnek API’si ve geniş platform desteği sayesinde, SignalR anlık güncellemeler, sohbetler ve bildirimler için vazgeçilmez bir araç haline gelmiştir. Performans, ölçeklenebilirlik ve güvenlik konularına dikkat ederek, sağlam ve kullanıcı dostu gerçek zamanlı çözümler inşa edebilirsiniz.