SignalR ile Veritabanı Güncelleme Bildirimleri

Şöyle bir senaryo düşünelim: Bir kağıt fabrikamız var. Bu fabrikaya periyodik olarak ürünler gelmekte bizde şirket içerisinde kullanılan bir CRM yaptık ve bu CRM'in içerisinde stokları tuttuğumuz ayrı bir modülümüz var.

Merhabalar,

Şöyle bir senaryo düşünelim: Bir kağıt fabrikamız var. Bu fabrikaya periyodik olarak ürünler gelmekte bizde şirket içerisinde kullanılan bir CRM yaptık ve bu CRM'in içerisinde stokları tuttuğumuz ayrı bir modülümüz var. Bu modül'ü el terminallerine uygun tasarladık ve fabrikanın depo elemanlarına verdik. Depo elemanları gelen ürünleri değerlerine göre (kg, cins, birim) programa işledi. Biz de bu işlenen değerleri database yazdırdıktan sonra hemen ofiste önünde CRM açık olan yöneticilerin web ekranına basacağız. Bunu asenkron yapacağız yani; depodaki eleman bir kayıt girdiğinde yukarıdaki muhasebe birimleri veya yöneticilerin görmesi için CRM'mimizin üstüne bildirim olarak bu kaydı göstereceğiz.

Ama dediğim gibi bu asenkron olmalı yani sayfa reflesh olmamalı ya da ajaxla db sorgusu yapılmamalı tamamen canlı olmalı. Senaryomuz bu.

Konuyu çok uzattım ama mantığa oturtmak için bu şekilde açıkladım. SignalR nedir bilmiyorsunuz google'a signalR yazdıgınız anda karşınıza chat, chatSignalR vs vs keywordlar gelecektir. Çünkü signalR asenkron (canlı) bir iletişime olanak sağlıyor. Bu yapacağımız örneği bir işte kullanmam gerekti bende sizlerle paylaşmak istedim :) Şimdi başlayalım.

Öncelikle vs'mizi açalım ve new project diyelim;

Daha sonra MVC şablonunu seçelim ve projemizi oluşturalım. Projeyi oluşturduktan sonra signalR kütüphanesini projemize dahil etmemiz gerekiyor. Tools > Nuget Package Manager > Package Manager Console açın ve consola şu kodu yazıp enter’a basın:


PM> Install-Package Microsoft.AspNet.SignalR



Projenize signalR’ı bir başka yoldan’da ekleyebilirsiniz. Tools>Nuget Package Manager>Manage Nuget Packages for Solution dedikten sonra arama kısmına SignalR yazıp kütüphaneyi kolayca projenize dahil edebilirsiniz.



Şimdi bu senaryoya uygun bir database oluşturalım. Var olan projenizin database’ine yeni bir tablo olarak ekleyip’te kullanabilirsiniz veya yeni bir db oluşturabilirsiniz. Yeni bir db oluşturdum adına BlogDemos dedim. Ve tablomuzun ismi’de Messages tablomuz şu şekilde olsun;



Evet databasemizi de hazırladıktan sonra hemen projemize dönelim ve Messages adında model class’ımızı oluşturalım.


public class Messages

    {

        public int MessageID { get; set; }

 

        public string Message { get; set; }

 

        public string EmptyMessage { get; set; }

 

        public DateTime MessageDate { get; set; }

    }



Field’larımızı yazdıkta sonra Projemiz’in kök dizinine Hubs diye bir klasör oluşturup içerisine MessagesHub adında bir class oluşturalım. Ve içerisinde connection stringimizi alıp Hub’a göndereceğimiz mesajın methodunu yazalım.(SendMessages()) Burada gözden kaçmaması gereken detay class’ımız Hub’dan kalıtılmış olmalı. Bunun için yukarıda


using Microsoft.AspNet.SignalR;

using Microsoft.AspNet.SignalR.Hubs; ekli olmalı.

public class MessagesHub : Hub

    {

        private static string conString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString();

        public void Hello()

        {

            Clients.All.hello();

        }

 

        [HubMethodName("sendMessages")]

        public static void SendMessages()

        {

            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessagesHub>();

            context.Clients.All.updateMessages();

        }

 

        

    }



Bu işlemden sonra Model’imizin içerisinde MessagesRepository.cs adında bir class daha tanımlayalım. Ve burada Db’mizden mesajlarımızı okuyalım ve hub’a işleyelim. Bunu da şu şekilde yapıyoruz.



readonly string _connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;

 

        public IEnumerable<Messages> GetAllMessages()

        {

            var messages = new List<Messages>();

            using (var connection = new SqlConnection(_connString))

            {

                connection.Open();

                using (var command = new SqlCommand(@"SELECT [MessageID], [Message], [EmptyMessage], [Date] FROM [dbo].[Messages]", connection))

                {

                    command.Notification = null;

 

                    var dependency = new SqlDependency(command);

                    dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);

 

                    if (connection.State == ConnectionState.Closed)

                        connection.Open();

 

                    var reader = command.ExecuteReader();

            //Mesajlarımızı okuyoruz. Aslında burada klasik Db işlemi yapıyoruz.

                    while (reader.Read())

                    {

                        messages.Add(item: new Messages { MessageID = (int)reader["MessageID"], Message = (string)reader["Message"], EmptyMessage =  reader["EmptyMessage"] != DBNull.Value ? (string) reader["EmptyMessage"] : "", MessageDate = Convert.ToDateTime(reader["Date"]) });

                    }

                }

              

            }

            return messages;

           

            

        }

 

Şimdi arkadaşlar en önemli yere geldik sql dependency yapacağımız metodu yazalım. 

 

  private void dependency_OnChange(object sender, SqlNotificationEventArgs e)

        {

            if (e.Type == SqlNotificationType.Change)

            {

                MessagesHub.SendMessages();

            }

        }



Burada bir püf nokta var. SqlNotificationType.Change olduğunda dediğimiz anda gidip veritabanımızı rollback’e almaya calısıyor aslında bir nevi kitliyor. Aksi takdirde bu notification çalışmayacaktır. Databasenizin Rollback’e açık olması gerekmekte. Eğer açık değilse


ALTER DATABASE BlogDemos SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE ;



Bu query’i sqlînizde çalıştırmanız gerekmekte. Hem enable_broker yapıyor hemde rollback’e izin verdirtiyoruz. Bu izni vermediğiniz takdirde SqlNotification çalışmayacaktır.


Modelimizi oluşturduk Hubs class’ımızı yazdık sonra olarak Home/Index.cshtml view’imize geliyoruz ve içerisindeki html kodlarını silip diyoruz ki;


<div class="row">

    <div class="col-md-12">

       <div id="messagesTable"></div>

    </div>

</div>

 

@section Scripts{

<script src="/Scripts/jquery.signalR-2.1.1.js"></script>

    <script src="/signalr/hubs"></script>

 

<script type="text/javascript">

    $(function () {

        

        var notifications = $.connection.messagesHub;

 

        notifications.client.updateMessages = function () {

            getAllMessages()

           

        };

        // Bağlantı başlangıç

        $.connection.hub.start().done(function () {

            alert("connection started");

            getAllMessages();

        }).fail(function (e) {

            alert(e);

        });

    });

 

 

    function getAllMessages()

    {

        var tbl = $('#messagesTable');

        $.ajax({ 

            url: '/home/GetMessages',

            contentType: 'application/html ; charset:utf-8',

            type: 'GET',

            dataType: 'html'

        }).success(function (result) {

            tbl.empty().append(result);

        }).error(function () {

            

        });

    }

</script>

 

}



Ardından HomeController’a gidip GetMessages Action methodumuzu yazıyoruz.


public ActionResult GetMessages()

        {

            MessagesRepository _messageRepository = new MessagesRepository();

            return PartialView("_MessagesList", _messageRepository.GetAllMessages());

        }



Shared klasörümüzün altında _MessagesList adında bir partialView oluşturuyoruz. Ve burada klasik data listeleme işini yapıyoruz.




@model IEnumerable<SignalRDbUpdates.Models.Messages>

 

<p>

    @Html.ActionLink("Create New", "Create")

</p>

<table class="table">

    <tr>

        <th>@Html.DisplayNameFor(model => model.MessageID)</th>

        <th>

            @Html.DisplayNameFor(model => model.Message)

        </th>

        <th>

            @Html.DisplayNameFor(model => model.EmptyMessage)

        </th>

        <th>

            @Html.DisplayNameFor(model => model.MessageDate)

        </th>

        

    </tr>

 

@foreach (var item in Model) {

    <tr>

        <td>

            @Html.DisplayFor(modelItem => item.MessageID)

        </td>

        <td>

            @Html.DisplayFor(modelItem => item.Message)

        </td>

        <th>

            @Html.DisplayFor(modelItem => item.EmptyMessage)

        </th>

        <td>

            @Html.DisplayFor(modelItem => item.MessageDate)

        </td>

        

    </tr>

}

 

</table>



Ve büyük bir zevk ile projemizi debug edip test etmeye baslıyoruz. Sql’de message tablomuza bir kayıt gidiyoruz ve o sırada sayfamıza bakıyoruz bir de görüyoruz ki, o da ne, woww!



Projenin tüm kaynak kodlarını ekte aşağıdan edinebilirsiniz. Db’yi kendiniz 2 dk’da oluşturabilirsiniz onada üşeniyorsanız alttaki sorguyu çalıştırın.


USE [BlogDemos]

GO

 

/****** Object:  Table [dbo].[Messages]    Script Date: 10/16/2014 12:43:55 ******/

SET ANSI_NULLS ON

GO

 

SET QUOTED_IDENTIFIER ON

GO

 

CREATE TABLE [dbo].[Messages](

    [MessageID] [int] IDENTITY(1,1) NOT NULL,

    [Message] [nvarchar](50) NULL,

    [EmptyMessage] [nvarchar](50) NULL,

    [Date] [datetime] NULL,

 CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED 

(

    [MessageID] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]

 

GO

 

ALTER TABLE [dbo].[Messages] ADD  CONSTRAINT [DF_Messages_Date]  DEFAULT (getdate()) FOR [Date]

GO



Bir dahaki yazıda görüşmek üzere!

  • Etiketler;
Oğuzhan Abalı
Oğuzhan Abalı, Mehmet Akif Ersoy Üniversitesi Bilgisayar Programcılığı mezunu ve yaklaşık 4 senedir .Net programcısı olarak freelance ve ortak bir çok projede görev aldı. <p>Microsoft'un MCTS-MCPD ve MCT ünvanlarına sahip. <p>Kendince müzikle uğraşmayı seviyor. Ve bildiklerini paylaşmaktan hoşlanıyor.
Yorum Yaz

Yorum yazabilmek için üye girişi yapmanız gerekiyor!

Yukarı Git