Erhan Ballıeker

Asp.Net Core API Backend ve Xamarin.Forms İle Kelime Oyunu Bölüm 2 (Asp.Net Core SignalR ve Azure SignalR Service)

Selamlar,

Xamarin Forms Mobile App ve Asp.Net Core backend tabanlı kelime oyunumuzdan bir önceki yazımda bahsetmiştim. Bu 1 aylık macerada yaşadıklarımızı ve kullandıklarımızı örneklerle anlatmaya devam ediyorum

Bu yazımda kullanıcıları aynı üzerinde oynatmak ve online olarak göstermek için faydalandığımız teknolojiden – ki herhangi bir .net projenizde bir şekilde bir realtime ihtiyacınız varsa kullanmanızı önereceğim teknoloji olan –  SignalR dan bahsedeceğim.

Aslında daha da doğrusu Asp.Net Signalr Core dan bahsedeceğim. SignalR ve SignalR Core farklı iki API. Asp.Net Core ile beraber yeniden geliştirilmeye başlandı.

Biliyorsunuz ki bir uygulama da realtime ihtiyacımız olduğunda kullanabileceğimiz birçok yöntem var, bunlar;

  • Web Socket
  • Server Sent Events (SSE)
  • Long Polling
  • Short Polling

vs gibi birden çok seçeneğimiz var. En tavsiye edilen en yeni yöntem tabii ki websocket kullanmak. Ama yazdığınız uygulama her ne ise (web-mobil-desktop vs) kullanacak olan clientları ve kullanacakları donanım ve yazılımları bilemeyeceğiniz için sadece kalkıpta tüm iletişimi WebSocket ile kurmak çok doğru olmayacaktır, size kullanıcılar kaybettirecektir.

Peki SignalR ne yapıyor?

SignalR önce gerçek zamanlı haberleşme isteyen client ın kontrolünü yapıyor. İlk denediği seçenek WebSocket kullanarak haberleşmek eğer client bu teknolojiyi desteklemiyorsa sırası ile SSE, LongPolling vs deneyerek en sonunda doğru yöntemi bulup iletişimi sağlıyor.

Bir asp.net core projemizde signalr kullanmakta çok basit artık. Biliyorsunuz ki Asp.Net core da artık koca MVC akışı bi pipeline olarak proje ekleniyor. SignalR da bu şekilde projeye ekleniyor ve kullanmaya başlıyorsunuz.

Öncelikle biz Asp.Ne Core API projemizde bunun için neler yaptık buna bakalım.

Microsoft.AspNetCore.SignalR paketini kullandık. Bu paketi eğer projenizde Microsoft.AspNetCore.App paketi varsa indirmenize gerek yok zaten bu paket mevcut halde gelmiş oluyor.

Bundan sonra yapmanız gereken Signalr ın projenizle ilişki kurduğu Hub sınıfını oluşturmak.

Bizim projemiz içerisinde GameHub adında bir hub ımız mevcut.Aşağıdaki gibi bir kısmını inceleyelim.

public class GameHub : Hub
    {
        public IServiceProvider Services { get; }
        public GameHub(IServiceProvider services)
        {
            Services = services;
        }

        public async void ConnectToHub(string username)
        {
            await Clients.Caller.SendAsync("ConnectedToHub", username, Context.ConnectionId);
            await Clients.AllExcept(Context.ConnectionId).SendAsync("NewUserConnectedToHub");
        }

        ...

Burada constructor tarafında kullandığımız ServiceProvider a çok takılmayın şimdilik. Bu aşağıda başka metodlar da application service ler tarafında yazdığımız ve container a register ettiğimiz serviceleri almak için kullandığımız yöntem. constructor injection yapamazdık çünkü Hub sınıfı parametresiz Constructor ı bulup çağıracaktır.

ConnectToHub metodunda iki şey yaptık.

  • Bu metodu çağıran Client ın kendisin deki –Clients.Caller diyerek-  Client tarafta ki ConnectedToHub metodunu çalıştırmasını söyledik. Parametre olarak ta signalr ın kendi oluşturmuş olduğu Context.ConnectionId yi geçtik, çünkü kullanıcıyı kendi db mizde online olarak update etmek ve bu kullanıcıyla doğrudan haberleşmelerde bu ContextId yi kullanmamız gerekeceği için o bağlantı boyunca saklamak istedik.
  • Kullanıcı bir şekilde disconnected olduğunda signalr client tarafta zaten böyle bir event i tetikleyecek bizde kullanıcıyı offline olarak işaretleyip sakladığımı ConnectionId sini sileceğiz, taa ki yeniden bağlanıp yeni connectionId sini öğrenene kadar.
  • İkinci satırda ise, uygulamada zaten mevcut oturum açmış insanların telefonunda online user sayını arttırabilmek yani yeni birinin geldğini söyleyebilmek adına, Clients.AllExcept(Context.ConnectionId) diyerek yani bu metodu çağıran kişi dışında herkese bir sinyal göndererek client tarafta NewUserConnectedToHub metodunu çalıştırmak istediğimizi söyledik.

Hub tarafında bu ve benzeri başka metodların tanımı dışında birşey yok.

Gelelim bu signalr ı Asp.net core un request pipeline ına nasıl eklediğimize.

public void ConfigureServices(IServiceCollection services)
        {
            // CORS
            services.AddCors();

            // MVC
            var mvc = services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            //SignalR 
            services.AddSignalR()
                    .AddAzureSignalR("Endpoint=...;AccessKey=...;Version=...;");

              ........

Startup tarafındaki ConfigureServices metoduna yukarıda gördüğünüz gibi AddSignalR diyerek SignalR service lerini kullanacağımızı söyledik. Biz bu projede signalr ın backend tarafı scale edilme yönetmi olarak Azure SignalR Service i kullandığımız için AddAzureSignalR diyerek içerisine azure tarafında oluşturmuş olduğumuz service url i ve accesskey i verdik. Azure SignalService tarafına daha sonra gelicem. Şimdilik SignalR ile devam edelim.

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            ...
            app.UseMvc();
            app.UseAzureSignalR(routes =>
            {
                routes.MapHub("/game");
            });
            ...
        }

Configure metodunda ise UseAzureSignalR diyerek AzureSignalService kullanacağımızı ve hub ımızı register etmiş olduk. Eğer AzureSignalService kullanmadan sadece SignalR ı eklemek isteseydik kod aşağıdaki gibi olacaktı.

app.UseSignalR(builder => builder.MapHub("/game"));

SignalR Client (Xamarin Forms)

Api tarafında Signalr ı ne şekilde kurup kullandığımızdan bahsettim. Xamarin Forms projemizde de signalr kullanmak için yaptığımız ilk şey aşağıdaki paketi tüm forms projelerine indirmekti

Microsoft.AspNetCore.SignalR.Client (1.1.0)

Bundan sonra uygulamanın App.cs tarafında aşağıdaki gibi HubConnectionBuilder  ı kullanarak kullanıcıyı hub a bağladık.

 public App()
        {
            InitializeComponent();

            Connection = new HubConnectionBuilder()
               .WithUrl("http://appserversitename.net/game")
               .Build();

            Connection.Closed += async (error) =>
            {
                IsConnectedToHub = false;
                await Task.Delay(new Random().Next(0, 15) * 1000);
                MessagingCenter.Instance.Send(this, "Disconnected");

                var disconnectResult = await ApiClient.UserApi.DisconnectUser(new Models.Models.Dto.Request.User.DisconnectUserRequestModel { Username = InMemorySettings.GetCurrentUser().Username });

                await Connection.StartAsync();
            };

            RegisterSignalrEvents();

            ....

Connection ın kapanması durumunda signalr bizim için bir event tetikliyor burada da istediğimiz diğer işlemleri yazdık.

RegisterSignalREvents metodumuz da ise, API tarafında kullanıcı tarafında şu metodları tetikle dediğimiz metodları oluşturduk. örnek olarak API tarafı client tarafında ConnectedToHub metodu tetiklediğinde ne olacağını, Connection.On metodu ile parametreleri de vererek, içeriye yazdık.

private void RegisterSignalrEvents()
        {
            Connection.On<string, string>("ConnectedToHub", (user, connectionId) =>
             {
                 Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
                 {
                     try
                     {
                         await ApiClient.UserApi.ConnectUser(new Models.Models.Dto.Request.User.ConnectUserReqModel { ConnectionId = connectionId, Username = user });

                         var onlineUserCount = await ApiClient.UserApi.GetOnlineUsers();

                         Device.BeginInvokeOnMainThread(() =>
                         {
                             MessagingCenter.Instance.Send(this, "OnlineUserCountReceived", onlineUserCount);
                         });

                         InMemorySettings.GetCurrentUser().ConnectionId = connectionId;
                         MessagingCenter.Instance.Send(this, "Connected");

                         IsConnectedToHub = true;
                     }
                     catch (Exception ex)
                     {
                           ...
                     }
                 });
             });

Burada basitçe kullanıcıyı db de online olarak set edip, signalrdan gelen connection id sini saklayıp, uygulama tarafında başka yerleri xamarin.forms un messaging center ını kullanarak tetikliyoruz. Aşağıdaki gibi o an kaş kişi oynuyor bunu görmemiz için kullandığımız yöntem bu idi.

WhatsApp Image 2019-05-31 at 22.10.45 (1)

ApiClient.. şeklindeki haberleşme yapısına benzer yapıyı nasıl kurduğumuza bakmak için aşağıdaki yazılarımı okuyabilirsiniz.

Client tarafında bundan fazla bir numara yok.

Gelelim Azure SignalR Service i neden kullandığımıza. Daha önceleri SignalR kullandıysanız bir gerçek hayat senaryosunda ve büyük bir projede signalr ı ya azure service bus ile ya redis ile yada mssqlserver ile desteklemişsinizdir. Bunun temel sebepleri hem signalrı scalable kılmak hemde daha persistant bir yapı oluşturmak diyebiliriz. İşte artık Azure Signalr Service ile bunları düşünmekten kurtuluyorsunuz. Bu şöyle oluyor. Artık kullanıcılar eskiden olduğu gibi doğrudan sizin appserver ına bağlanmıyorlar, sizin appserver ınızdan bir url alıp (negotiation url) Signalr Service e bağlanıyorlar, sizin app server ınızda buraya bağlanıyor ve nihayetinde client ile appserver ınız arasında realtime persistant bir connection kurulmuş oluyor.

Aşağıdaki görsel bunu anlatıyor.

Capture.PNG

Asp.net Core SignalR için, Signalr Service, hub başına 5 adet websocket açıyor. Bu service i ücretsiz olarak maximum 20 concurrent user için deneyebilirsiniz. Bu da zaten test etmeniz için yeterli bir sayı. Daha sonra concurrent kullanıcınız arttıkça paralı tarifeye geçip binlerce kullanıcıyı concurrent birşekilde yönetme ve realtime birbirini bağlama işini Azure a bırakabilirsiniz.

Azure portal e girdiğiniz de All Services den Web sekmesini tıklayarak ücretsiz bir SignalR Service oluşturun ve en kısa sürede denemeye çalışın derim.

Capture.PNG

Bu yazımda da yazmış olduğumuz kelime oyunu için realtime kısmını hem server hem de client tarafta nasıl çözdük ve azure signal service i neden nasıl kullandığımızı anlattım.

Bir sonraki yazımda görüşmek üzere.

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s

%d blogcu bunu beğendi: