Anlat Dinliyorum — SignalR
SignalR, uygulamalarımıza real-time (gerçek zamanlı) fonksiyonellik kazandıran open source (açık kaynak) kütüphanedir (framework). Üç aşağı beş yukarı 2011 yılında ortaya çıktı, geliştirildi, ince okuyup sık dokunuldu ve 2013 yılında AspNet tarafına katıldı. Bu cevherin💫 altında WebSocket teknolojisi yatmaktadır. Bu değeri de hem AspNet hem de AspNetCore uygulamalarımıza kazandırabiliriz.
AspNetCore tarafında SignalR kullanmak istiyorsanız 2.1 sürümünden itibaren kullanmanız gerekmektedir. AspNetCore projesi oluşturduğunuzda SignalR varsayılan (default) olarak gelmektedir. Herhangi bir şekilde paket yöneticisi aracılığıyla kütüphane eklemenize gerek yoktur. MVC veya Web API projelerinizde kullanabilirsiniz.
Yazıya geçmeden önce sen bana sorularını hazırlamadan ben sana bir soru sormak istiyorum. Herhangi bir chart ın (google charts, chart.js, apexcharts.js vb.) anlık olarak değişken olmasını nasıl sağlayabilirsin? Kullanıcıya güncel verileri görmek için lütfen sayfayı yenileyiniz gibi, modern teknolojiye uymayan bir istekte bulunmayacağını biliyorum. Kahve/Çay ☕️ hazır mı? devam edelim.
Real Time Nedir? 📡
Bir uygulamanın real-time olması client ile serverın anlık olarak çift yönlü bir şekilde sürekli haberleşmesi demektir. Http bağlantılarında client-server iletişiminde her request (istekte) yenilenirken SignalR ile sürekli bir bağlantı sağlayabiliriz. Benzetme aşağıdaki kısa skeç gibi.
Client: Sana karşı bir şeyler hissediyorum.
Server: Bende sana karşı boş değilim…
Burada verilecek en popüler ve fiks menümüz 👨🏻🍳, mesajlaşma (chat) uygulamalarıdır. Örneğin Facebook da mesajlaştığımız zaman tarayıcı hiç yenilenmeden arkadaşımızla haberleşiyoruz ve arkadaşımızın mesajları da bize anlık olarak geliyor.
Canlı açık arttırma siteleri de bunlara bir örnek olabilir. Örneğin ürünün satış fiyatının anlık olarak değişmesi ve tarayıcımızın bu süreçlerde yenilenmeden (refresh) bunu görebiliyoruz değil mi?
Görüntüleme (Monitoring) işlemleri de real-time konusuna dahildir. Örneğin logları canlı olarak izlemek istiyor ve bunu bir grafik 📈 üzerinde göstermek istiyorsak real-time uygulama kullanabilirsiniz.
WebSocket Nedir?
Tek bir tcp üzerinden client (istemci) ve server (sunucu) arasında çift yönlü iletişimi sağlayan protokoldür. Ayrıca SignalR için de en iyi transfer yöntemidir. Protokol beraberinde kurallar bütünü demektir. Eğer WebSocket, client ve server arasındaki iletişim sağlıyorsa bu demektir ki, client ile server arasındaki haberleşmenin sağlanması için bazı kuralların yerine getirilmesi gereklidir.
Eğer browser WebSocket protokolünü destekliyorsa SignalR da WebSocket teknolojisini kullanır. Desteklemiyorsa? Dert değil, Çünkü, WebSocket client-server arasındaki iletişimi 📞 kendi alt yapısı ile sağlamaya devam eder.
İletişim Yöntemleri
SignalR içerisinde LongPolling, Server Send Event (SSE), Websocket birer transport olarak nitelendirilir. Client ve server arasında çalışacak transport yöntemini yukarıda da belirttiğim gibi otomatik olarak seçmektedir. Yaptığı en önemli iş abstraction’dur.
SignalR client-server iletişiminin yanında RPC protokolünü onaylar. RPC nedir? Kaba tabirle, JavaScript metotlarını sunucu tarafında çağırmaktır. 🗣 İnce tabirle de sunucu tarafından client tarafta bulunan metotun tetiklenmesine neden olan protokoldür.
Neden SignalR Kullanmalıyım? 🤔
- Hub gibi kullanımı kolay bir seçenek sunması.
- Bağlantı denemeleri ve konfigürasyon konularının kütüphane tarafından basit şekilde yapılabilir olması.
- Ajax Long Polling, Forever Frame, WebSockets, Server Send Events bağlantılarının otomatik olarak yapılması.
WebSocket Server Uygulaması Nasıl Geliştirebiliriz?
Projenizin tipine göre aşağıdaki baş yapıt kütüphaneleri kullanabilirsiniz.
- AspNetCore: SignalR
- NodeJS : Socket.IO
- Pyhton: WebSockets
Nasıl Çalışır?
SignalR’ın kalbinde💖 Hub (Dağıtıcı) yatar. Client-server arasındaki haberleşmeyi bu hub gerçekleştiriyor. Hub diye isimlendirdiğim ise sınıf(class)tır. SignalR server oluşturmak istediğimizde Hub sınıfından miras alırız.
Mesela CLIENT 1 “merhaba” yazdığını düşünürsek, bu yazı önce hub’a gidiyor sonra hub’a abone olmuş tüm clientlara dağıtılıyor. (Clients.All) Eee tabii şimdi gidip bir chat odasına girdiniz. Sizee mesaj gelir mi? Gelmez. Çünkü siz mesajları almak için herhangi bir abone durumu gerçekleştirmediniz. Görselde de mantık aynı şekilde. Bir clientın SignalR serverinden mesaj alması için öncelikle ilgili metota abone olması gereklidir.
Clientlar ilk olarak server da bulunan metota istek atıyor. Bunu Ajax ile Web API endpointine(adresine) istek atmak olarak düşünebiliriz. İstek yaptığımız zaman SignalR server bu isteği dönmek yerine clientlarda çalışacak olan metotlara bildiri gönderiyor. Clientların abone olduğu metotlar serverda, server’in metotları da tabii ki client tarafta tanımlanıyor. Backend ise JavaScript metodunu çağırarak clienta haber verebiliyor.
Başa sarıp düşünürsek client isteği attı server metodunu çalıştırdı, server metodunda SignalR devreye girip client’a bildiri gönderdi. İşte bu kadar! 👏🏼Çift yönlü de iletişim oldu.
Client Log Mesajları (Düşük dereceden yükseğe)
- Trace
- Debug
- Information
- Warning (Uygulama çalışıyor ama bir sıkıntı var, el atsan iyi olur)
- Error (Hata var sana zahmet bana bir bak)
- Critical (Hata var ve uygulamanın genelinde problem oluşturuyor)
Client WithAutomaticReconnect (0 saniye, 2 saniye, 10 saniye, 30 saniye.)
Client üzerinde bu metotu kullandığımızda JavaScript kütüphanemiz bağlantı koptuktan sonra otomatik olarak tekrar bağlantı için istek yapmaya başlıyor. Hiç bağlantı yokken demiyorum, bir bağlantı var ve bağlantı koptuktan sonra diyorum, buraya dikkat etmemiz gerekir. Bağlantının koptuğu senaryoda 0 saniye bekliyor ve bir istek atıyor. Başarısız olursa 2 saniye sonra, başarısız olursa 10 saniye sonra ve başarısız olursa 30 saniye sonra tekrar istek yapıyor. Eğer bu denemelerden sonra başarısızsa “god damn it! 😠” deyip, istek yapmayı bırakıyor. Eğer başarılı olursa kaldığı yerden devam ediyor.
Bağlantı denemeleri yaparken, tekrar bağlantının sağlanmasıyla ilgili eventler fırlatılıyor ve bu eventleri OnReconnecting, OnReconnected, OnClose metotları üzerinden yakalayabiliyoruz.
OnReconnecting: İlk bağlantı koptuktan sonra, 0. saniyede ilk istek yaptıktan sonra bu event fırlatılır. Bu metota abone olan clientlara “bağlantı koptu kanka, tekrar bağlanmaya çalışıyorum 😨” gibi bir mesaj verebilirsiniz. Sadece ilk bağlantı yapmaya çalıştığında bu metot çalışır. 2, 3, 4. bağlantı denemelerinde çalışmaz.
OnReconnected: Eğer bağlantı koptuktan sonra tekrar bağlantı sağlanıyorsa bu event fırlatılır. Metot içerisinde eventi yakalayarak “Tekrar bağlandım kanka 😍” diye mesaj iletebiliriz.
OnClose: Eğer ki bağlantı denemelerimizin tamamında başarısız olursak bu metot içerisinde “Çok denedim, ama başaramadım 😭” mesajını gösterebiliriz. Bu durumda client sayfayı yeniden yükleyene kadar tekrar bir bağlantı denemesi gerçekleşmeyecektir.
Peki kullanıcı bağlantı kuramamış, tekrar bağlantı kurması için sayfayı yenilemesini de istemiyorsan ne yapabilirsin?
Connection.Start() metotunun Catch kısmında hatayı yakalayalıp setTimeOut fonksiyonu ile tekrar Connection.Start() metotunu tetikleyebilirsin. Burada senin belirleyeceğin sıklığa göre bağlantı denemeleri yapılacaktır.
Connection Id
Client servera her bağlantı kurduğunda bir connectionId alır. Bir başka deyişle Hub’a bağlandığında, hub client için bir id verip client’ı 🕵️♂️ kimliklendirir. Bu id üzerinden hangi clientın bağlantı kurduğunu anlayabiliriz. Bağlantı kopup tekrar bir bağlantı kurulduğunda server tarafında SignalR tekrar bir connectionId veriyor. Bunu bir SessionId gibi düşünebiliriz. ConnectionId’ye de context üzerinden erişebiliyoruz.
SignalR Server Hub Virtual Methods
Server Hub tarafında 3 adet override edilebilir metot bulunmaktadır, bunlardan 2 sini konuşalım.
- OnConnectedAsync(): Clientler bağlandıkça bu metot otomatik bir şekilde çalışır.
- OnDisconnectedAsync(): Clientların bağlantısı koptukça bu metot otomatik olarak çalışır.
Eee bana faydası ne yukarıdaki iki metotun?
Örneğin Hub’a kaç kişi bağlandı diye bir soru sorsam sana? İşte mesela burada kaç tane client bağlantı kurmuş onun sayısını tutabilirsin. Loglama yapabilirsin, canlı olarak grafik üzerinde kaç tane aktif client var bunu gösterebilirsin. bla.. bla.. blaa..
IHubContext<THub, T> 💉
Örneğin MVC uygulaman var, Controller içerisinde mesaj göndermek istiyorsun. İşte bu IHubContext ile bu isteğini gerçekleştirebilirsin. Constructora IHubContext’i geçerseniz gönderebilirsiniz. Bu hem MVC hem de Web API senaryosu içinde geçerlidir. Sonuç olarak API projenizde client endpoint’e eriştiğinde bildiri göndermek istiyor olabilirsiniz.
Clients
- Clients.Caller: Client bir istek yaptığı zaman hangi client istek yapmışsa sadece o clientın metodunu bilgilendirmek istediğimizde kullanırız.
- Clients.All: Tüm clientlara bildiri göndermek istediğimizde kullanırız.
- Clients.AllExcept: Belirlediğimiz clientlar hariç bildiri göndermek istediğimizde kullanırız.
- Clients.Client: Belirlediğimiz clienta bildiri göndermek için kullanırız. (connectionId)
- Clients.Group: Belirli bir gruba dahil olmuş clientlara bildiri göndermek için kullanırız. (Sadece LTunes takımına bildiri gönder gibi.)
Clients.Group özelliğini bir chat uygulamasına benzetebiliriz. Chat uygulamasında odaya girdiğinizde odada 20 kişi varsa sadece odadakiler birbiriyle mesajlaşabiliyor. O kullanıcı odadan çıkıp farklı bir odaya girdiği zaman, sadece o odadaki kişilerle mesajlaşabilir.
Şahsım adına Angular11 ve Jquery ile SignalR bağlantılı uygulama geliştirdim. Vue.js, React vb. UI teknolojileriyle geliştirme yapabileceğiniz konusunda ufak da bir araştırma yapmış bulunmaktadıyım. Projenize @microsoft/signalr kütüphanesini dahil etmeniz yeterlidir.
Ata sporumuz olan sohbet(chat) uygulaması dahil, real-time chart ve diğer örnek projeler için github adresini ziyaret edebilirsiniz.
Te veo despues 😎