MS Sql Database ile SignalR Etkileşimleri

Selamlar;

Bugüne kadar farklı birçok signalR örneği yaptık. Genelde hepsi bellirli değişikliklerden sonra clientları notify etmek üzerine kurulu idi. Bazen data’ya erişim farklı birçok kaynaktan olabilir. Mesela bir e-ticaret sitesinde servisler ile birbirinden bağımsız portallar veya iframe olarak verilen küçük reklam bannerları ile onlarca kaynaktan database editlenebilir. Bu durumlardan birinden dolayı database de oluşan  değişiklikleri diğer tüm clientlara bildirebilmek için proje bazında ayrı ayrı çözüm üretmek yerine daha database katmanında çözüme gidilmelidir. İşte böyle bir durumda neler yapabileceğimizi alttaki video’da tartışacağız.

db

screen2

Tanıtım: Aşağıda bazen clientların bilgilendirme işleminin SignalR teknolojisi kullanılarak neden database bazında yapılması gerektiğini güncel iş hayatından örneklerle açıkladık.

Sql Bazında SignalR:  Aşağıda öncelikle MS  Sql database’i bir windows services ile belli zaman aralıkları ile izlenmiş ve kayıt update durumunda ilgili signalR methodu tetiklenerek client’lara var olan değişiklik push edilmiştir. Daha sonra bu yöntemin, yani her 3 sn de bir ilgili datanın değişip değişmediğine bakılması amacı ile çekilmesinin server’a büyük bir yük getireceği düşünülmüştür. Bu yükten kurtulmak için tablo üzerine update durumu için bir trigger yazılmıştır. Bu trigger update durumunda ilgili procedure’ü execute etmektedir. Sql üzerinden GameHub classındaki refreshData() method’una erişilemez. Bu nedenle ilgili procedure yazılmış olan WebApi servisine sql’den request atmaktadır. İlgili request, WebApi servisinde GamesHub classındaki refreshData() methodunu çağırmaktadır. İlgili method da gösterilen tüm datayı tekrar çekip o anda aktif olan tüm clientlara push etmektedir. Böylece database’e sürekli gidilip değişen datanın kontrol edilmesine gerek kalmamıştır. Ancak daha sonra refreshData() methodunda hangi datanın değiştiğine bakılmaksızın tüm datanın çekilip clientlara push edilmesinin Big Data durumunda sql server’a yine çok yük getireceği tespit edilmiştir. Bu nedenle triger işleminde değişen datanın ID’si ilgili procedure’e parametre olarak gönderilmiştir. Gelen parametre procedureden WebApi servisine request yapılırken gönderilir. WebApi servisi de GameHub class’ındaki refreshData() methodun’u tetiklerken kendisine gönderilen bu ID’yi de beraberinde gönderir. Böylece refreshData method’u da bu update edilen ürünün ID’si sayesinde tüm data yerine sadece ilgili ürünü çekerek var olan listeden değiştirir.


( PartilaView) GameList.cshtml :

 Index.cshtml:

 HomeController.cs:

 Helper.cs:

 DAL:

 Windows Application – CheckGameListDB (Form1.cs):

 WebApi – CallAllClients(GamesController.cs):

Sql Procedure) callWebServices:

 Trigger(callWebServicesTrigger):

 Sql bazında WebApi Servisine Request’e İzin Verilmesi Aşağıdaki Gibidir:

sp_configure ‘show advanced options’, 1;
GO
RECONFIGURE;
GO
sp_configure ‘Ole Automation Procedures’,1
reconfigure

Bu çözüm için Çağlar Özenç‘e teşekkür ederim :)

Yukarıdaki örnek’de halen optimizasyon isteyen bir konu vardır. O da clientlara partial view’un tüm string halinin değil sadece değişen datanın json formatındaki halinin push edilmesi gerekmesidir. Bunu için Mvc RenderPartial yerine MVVM design pattern’a bağlı olarak Angular veya Knockoutjs gibi javascript frameworkleri kullanılarak bir ViewModel  yaratılmalı ve güncelenen bu data yaratılan ViewModel’de değiştirilerek clientlara yansıtılmalıdır. İsterseniz bu örneği de siz yapmaya çalışın. İlgili view kodları da yorumlar kısmına koyabilirsiniz. Takıldığınız her noktada çekinmeden soru sorabilirsiniz. Görüldüğü gibi yazılımda hiçbir zaman oldum denilmemelidir. Yazilan bir kodun herzaman daha ileriye götürülebilecek bir hali vardir. O an ki teknoloji ile olmasa da sonradan cikan yeni teknolojiler ile revize edilebilir. Bu is ayni bir müzisyene benzer. Gelismekte sınır yoktur.

Yeni bir makalede görüşmek üzere hoşçakalın.

Source Code: http://www.borakasmer.com/projects/signalRSql.rar

Herkes Görsün:

Sevebilirsin...

34 Yanıt

  1. Barkın diyor ki:

    Hocam elinize sağlık. Gerçekten çok özgün ve başarılı bir yazı olmuş. Daha önce hiçbir yerde buna benzer bir yaklaşım görmedim. İlgili view için angularjs kullanmaya karar verdim; bitirince yorumlar kısmına ekliyecem. Yorumunuzu ve gerekli düzeltmelerinizi bekliyicem hocam.

    • borsoft diyor ki:

      Teşekkürler. Siz yeterki çaba gösterin. Ben kendimce gerekli her düzeltmeyi yaparım.
      İyi çalışmalar.

  2. Sinan diyor ki:

    Selamlar hocam;

    Mükemmel bir makale olmuş. Nedenleri ile herşeyi detaylıca anlatmışsınız. Bir konu için videoyu izlemeye başladım. O kadar çok bilmediğim konu varmış ki buda nasıl oluyormuş buda neymiş derken gerçek konudan uzaklaştım:) Merak ettiğim iç içe döngüde, değişen oyunu var olan listede ararken alttaki döngüye gerek varmıdır? İstenirse ilgili ID ye göre oyun linq’ ile çekemezmiydik?

    Böyle muhteşem bir kaynak yarattığınız için yine çok teşekkür ederim.
    Hoşçakalın.

    • borsoft diyor ki:

      Teşekkürler Sinan. Evet haklısın alttaki döngüye gerek olmadan da sonuca gidilebilir. Linq ile yazılabilecek 2. yöntem aşşağıdaki gibidir.
      İyi çalışmalar.
      foreach (tblGames item in data)
      {
      var item2 = oldData.FirstOrDefault(dt => dt.ID == item.ID);
      if (item2.ImageUrl != item.ImageUrl || item2.Name != item.Name ||
      item.Price != item2.Price)
      {
      oldData.Clear();
      oldData = data;
      Triger();
      break;
      }
      }

  3. Alikoç diyor ki:

    Selamlar Hocam;
    Ben bu videodan çok memnun kaldım. Ağzınıza sağlık çok açıklayıcı olmuş. Açıkçası ben bu MVVM’i tam anlamadım. Acaba siz bu view’ı angularJS ile yazıp sadece değişen oyunu json ile gönderebilirmisiniz. Benim de buna benzer yapmam gereken bir iş var. Hem en doğrusunu görmüş oluruz hem de bize referans olur hocam.

    İyi Çalışmalar.

    • borsoft diyor ki:

      Teşekkürler Alikoç;

      Tamam yazıp yayınlarım enkısa zamanda.
      Sana tavsiyem webinarlarımı izlemendir. Çok faydasını görürsün.

      Hoşçakal.

  4. Berk diyor ki:

    Öncelikle yazınız çok güzel ve Türkiye’de bu kadar detaylı anlatılan ilk yazı. Ben bu sistemi yazmıştım fakat Entity Framework ile trigger olduğu için kayıt işleminde hata veriyordu. Bunun çözümü nasıl bu konudada bilgilendirir misiniz ?

    • borsoft diyor ki:

      Selam Berk;

      Öncelikle Teşekkürler.
      Hataya gelirsek, Entity Framework ile verdiği hatayı belirtirsen daha doğru bir çözüm bulabiliriz. Ama tahminimce ya application ile sql’e bağlandığın user’ın tabloda alter yetkisi yoktur. Yada tabloda değiştirmek istediğin kolon başka bir tablo ile relationlıdır. İstersen verdiği hataya göre tekrar konuşalım.

      İyi çalışmalar.

  5. Uğur diyor ki:

    Merhabalar Hocam,

    Yine süper bir yazı. Çok teşekkür ederiz.

    Bir sorum var.

    Tablo büyükdükçe triggerda sıkıntı olur mu? Yada tam tersi trigger tabloya zarar verir mi? Bu tür tablo dinleme işlemleri için en iyi yok belki trigger’dır ama bazıları trigger kullanmanın ilerleyen zamanlarda sıkıntılar yaratabileceğiniz söylüyor. Tabloya anlık 10.000 kaydın geldiğini düşünürsek gerçektende performans konusunda ciddi sıkıntılar yaşanabilir düşünüyorum.

    Sizin bu konu hakkındaki görüşünüz nedir hocam?

  6. kadir diyor ki:

    Elinize sağlık güzel bir çalışma olmuş. Bende kurs bitirme projemde bir sayfa için veri tabanında olusan anlık degişimleri sayfa üzerinde göstermek istiyordum yaptıgınız bu calısma bana yardımcı olucak gibi insallah bir sıkıntı yaşamam :)

    • borsoft diyor ki:

      Teşekkürler Kadir,

      Umarım işine yarar.
      İyi çalışmalar.

      • kadir diyor ki:

        hocam ,yaptıgım projede Manage Nuget Packages ‘den
        Microsoft.AspNet.SignalR ile Microsoft.AspNet.SignalR.Client’i yükledim projeyi acarkenn Empty / MVC secerek olusturdum fakat sizdeki App_Start klasöru ıcındeki startup klası bende olusmadı kendınız sonradan mı ekledınız ? Yanlıs bısey yapmamak ıcın sormak ıstedım

        • borsoft diyor ki:

          Selam Kadir,

          Evet elle sonradan ekledim. Herşeyi Visual Studio’dan beklememek lazım :)

          İyi çalışmalar.

          • kadir diyor ki:

            tabı kı de tesekkurler,
            sımdı sızın yaptıgınız gıbı trgıer ve webservıs procedurunu yazıp denıcem ınsallah sıkıntı yasamam :)

  7. kadir diyor ki:

    Hocam bu Triger calısınca bende su resım lınkındekı gıbı hata verıyor bu sorunu nasıl çözebilirim ?
    http://i.hizliresim.com/aXoyjg.png

    • kadir diyor ki:

      Triger da bır sıkıntı var ama goremedım

      ALTER trigger [dbo].[WebServisiuyar] on [dbo].[SatisListesi]
      for update
      as
      declare @id int
      select @id=ID from inserted
      begin
      execute prc_WebServiseGonder @id
      end
      return

      • kadir diyor ki:

        Sizin yazdıgınız projeyi indirdim verı tabanında degısıklık yapında anında clıent tarafında degısıklık yapmıyor sayfa yenıleyınce yapıyor degısır

        • kadir diyor ki:

          Bende Triger ve webserviste sıkıntı var sanırım sizin yaptıgınız projede webservıste calısmıyor fakat wınforms ta tımer kullanarak yaptıgınız calısıyor

  8. atagun diyor ki:

    Yaptıgınız uygulamayı ındırdım fakat calısmadı ” Lock ” oldugu yere breakpoint koydum hıc gırmedı oraya uygulamayı ındırdıkten sonra extra olarak bısey yapmamız gerekıyor mu ?

    • borsoft diyor ki:

      Selam atagun,
      Sql bazındaki ayarları yapman gerkiyor. Sql tarafında triger etmen için gerekli izinleri vermen gerekiyor.

      İyi çalışmalar.

  9. atagun diyor ki:

    sp_configure ‘show advanced options’, 1;
    GO
    RECONFIGURE;
    GO
    sp_configure ‘Ole Automation Procedures’,1
    reconfigure

    yukarda soyledıgınız su kodları calıstırdım procedure calıstırınca response degerı null donuyor

    • atagun diyor ki:

      visual studiodan web servısı calıstırınca response degerı duzeldı ama lock’a gırmıyor sınır ettı benı ya :(

  10. kadir diyor ki:

    s.a hoca ben sorunu buldum :) Tabi sizin daha once yaptıgınız buna benzer Anqular ile yaptıgınız projeyi inceledikten sonra fark etttım :) proje ıcersındekı webapi servisinde kullanılan kontrolun adı ValuesController oldugu ıcın gonderilen veriyi almıyordu yenı kontroller olusturdum Games adında hepsını ıcıne kopyaladım calıstı sanırım ATAGUN ‘ de aynı problem var bu sekılde duzeltırse calısacaaktır

  11. Koray diyor ki:

    Hocam yanlışım varsa düzeltin lütfen, yaptıgınız projede yeni verileri partial view uzerine cekip clientlere göstermiyor muyuz?
    Orda yazmis oldugunuz java script kodu ne iş görüyor anlamadım o kısmı

    • borsoft diyor ki:

      Selam Koray,

      Sayfa ilk yüklenirken data çekilip partial viewlar dediğin gibi doluyor. Daha sonra databasede ilgili datalar değişince, bunu clientlara Mvc ile değil o görüdüğün scriptler ile Signalr sayesinde real time olarak gösteriyoruz. Yani o anda sayfa post olmuyor. İlgili datayı client’a real time olarak script ile basıyor. :)

      İyi çalışmalar.

  12. Oguz diyor ki:

    Hocam olusturdugunuz helper klası normal klas mı ? Ben normal klas olusturunca farklı cıkıyor da sanırım yanlıs yapıyorum yardımcı olabılırsenız sevınırım kolay gelsın ….

    • borsoft diyor ki:

      Selam Oğuz,

      Helper class’ı bildiğin class. Düz class :) View’ı, stirng’e convert eden önemli sade bir class. “GetRazorViewAsString()” adında static bir methodu var. Böylece ilgili view string olarak signalR function’a parametre olarak gönderiliyor.
      Sendeki soun nedir? Yani farklı çıkan nedir?

      İyi çalışmalar.

      • Oguz diyor ki:

        NameSpace ‘in oldugu kısım bende projeadı.Models olarak yazıyor sizde Controller olarak yazıyor ve ben 2015 visual studio kullanıyorum asp.net uygulması acıp webapi secince webapi icindeki controller bolumunde HomerController ValuesController ve sizinkınden farklı olarakta AccountController gelıyor ekstra bıseyler cıkınca tedırgın oldum acaba yanlıs mı yapıyorum dıye .

        • borsoft diyor ki:

          Selam Oguz,

          Empty bir proje yarat ve WebApi seç o zaman diğer seçenekler gelmez.

          İyi çalışmalar.

  13. kadir diyor ki:

    Hocam kolay gelsin iyi calısmalar. sizin bu projeyi uzerınde calıstıgım bıtırme projesi uzerıne uyguladım .Firstcode kullanmadan kurdum entityframeworku projeyı calıstırıp verı tabanında degısılık yapınca Helper klasında
    “var context = new HttpContextWrapper(HttpContext.Current);” oldugun yerde hata verıyor ” deger null olamaz ” dıyor bu hata ıcın bır çözüm öneriniz var mı ?

    Kolay gelsin …

  14. fırat atmaca diyor ki:

    Abi selam;

    abi uygulama benim adıma çok faydalı oldu. fakat bir sorun ile karşılaştım internettede karşılığını tam bılamadım. mssql 2008 de sorunsuz çalışıyor fakat mssql 2012’de SP_OAGetProperty bu procedürü bulamıyor. yardımcı olman mümkün mü acaba.
    iyi günler.

  15. Soner diyor ki:

    Bora hocam. Çok teşekkür ederim bu güzel video için.
    Benim bir tavsiyem, bu şekilde sürekli bir timer ile sorgulama yapmak yerine, Data Access katmanındaki update metodu çağrıldığında yapsak olmaz mı? Hatta Repository Design Patternle çok hoş olmaz mı?
    Gerçekten çok teşekkürler.

    • borsoft diyor ki:

      Selam Sonra,

      Öncelikle teşekkürler.
      Bu makalede çok büyük bir trick var. Sen onu atlamışın. Timer sadece 1 yolu. Ve bence gerek yok:) Esas yol Sql’de trigger var. Tabloda değişiklik olunca Sql Trigger GamesController adındaki web services’ine call yapıyor. O da signalR GamesHub ‘ı çağrıyor ve ilgili data yı client’a real time gösteriyor. Bir de bunu dene :)

      İyi çalışmalar.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir