Service Bus kavramını, Service-Oriented Architecture(SOA) yaklaşımı ile haşır neşir olanlar bir şekilde duymuş, hatta çeşitli tiplerini kullanmış bile olabilir. Service Bus kavramına, birbiri ile karşılıklı iletişim halinde olan, bu iletişimden dolayı çeşitli operasyonları paylaşan sistemleri tasarlamak ve geliştirmek için kullanılan bir model olarak çok yukarıdan bakabiliriz. Konuyu dağıtmamak için çok daha fazla derinlere girip Service Bus’ın ayrıntılarına girmek istemiyorum. Bu aşamada, bu basit tanım yeterli olacaktır.

Bu yazıda Windows Azure üzerindeki Service Bus’ı nasıl kullanabiliriz, hangi özelliklerinden nasıl faydalanabiliriz şeklinde, yine senaryo bazlı bir anlatımla, hem Windows Azure’u hem de Service Bus kavramını biraz anlatmaya çalışacağım. Hadi başlayalım…

Windows Azure’un sunduğu uygulama servislerinden biri de Service Bus. Bir birinden bağımsız ama ilişkili uygulamalar arasında iletişim kurmak adına kullanabileceğimiz bu servis kendi içinde, “Queue”, “Topics”, “Relay” ve şu an Preview olan “Notification Hub” şeklinde 4 alt kategoriye ayrılıyor. Bu yazıda “Topics” ile ilgili birşeyler paylaşıp, kullanım amacını özetlemeye çalışacağım.

Öncelikle Windows Azure’da ki Service Bus’ın “Topics” kavramı nasıl bir kavram bunu anlayalım. Publish/Subscription modeli olarak bilinen, bir sistemin yayınladığı şeyleri, bu sisteme üyelikle, üye olanların alabildiği bir model olarak ele alabiliriz “Topics”i…Bu modelde, sistemlerin yayınladığı/paylaştığı şeyler, direk olarak diğer sistemlere iletilmez. Yayınlanan şeyler, üye olanlara ara bir yapı ile iletilir. Bunun amacı, yayıncı ve alıcı arasındaki iletişimi bağımlılık değil de, ilişki şeklinde ele alabilmektir. İlişki kesildiği zaman iki sistem de, birbirlerine bağımlılığı olmadığı için işleyişlerini aksatmazlar. Windows Azure Service Bus’da bu ilişki “Topics”ler üzerinden yürütülmekte. Bir yayıncı bir “Topic”(konu diyelim) oluşturabiliyor. Windows Azure Service Bus sayesinde de, çeşitli client’lar, bu “Topic”e üye olup, bunun üzerinden ilişki sağlayabiliyor.

Biraz daha net olması adına, Queue kavramından örnek vermek isterim. Hem neden ihtiyaç olduğuna dair de netleşir belki. Queue kavramında, sıra mantığı işler bildiğiniz üzere. Sıraya konan verileri, bir istemci alır, daha sonra diğerini alacak şeklinde devam eder. Eğer veriyi başka bir istemci de almak isterse alamaz, çünkü o veri başka bir istemci tarafından alındığı için artık Queue’da değildir. Publish/Subsciption modelinde, paylaşılan veriyi üye olan herkes alabilir. Bu noktada “Topic”leri sıra mantığı olmayan ama Queue kavramına benzeyen kavramlar olarak ele alabiliriz.

Neyse bu kadar soyut şeyden biraz uzaklaşalım ve örneğimize geçelim. Şöyle bir senaryo oluşturalım; bir tane dergimiz olsun. Bu derginin sayılarını yaratalım çeşitli içerikle. Bu dergiye üye olanlar, yeni sayı çıktıkça ya da içerik eklendikçe üye oldukları için otomatikman haberdar olsunlar.

model

Öncelikle Windows Azure’da bunun için bir tane uygulama servisi,-ki bu Service Bus olacak, yaratmamız lazım. Bunun için Windows Azure Management Portal’dan aşağıdaki gibi bir Service Bus uygulamasını Topics alt kategorisi ile yaratmanız gerekmektedir.

topic
Servisi oluşturduktan sonra şimdilik, bağlantı sağlayabilmeniz için gerekli bağlantı bilgilerini almanız yeterli olacaktır. Konfigurasyon dosyamızı aşağıdaki gibi oluştrabiliriz.

connection

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <appSettings>
        <add key="ServiceBusConnectionString"
             value="BURAYA WINDOWS AZURE SERVICE BUS İÇİN ENDPOINT BİLGİSİNİ YAZMANIZ GEREKMEKTE" />
    </appSettings>
</configuration>

Öncelikle IssueContent adında, içeriğimizi belirtebileceğimiz basit bir sınıf yaratalım.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace ServiceBus.Common
{

    //Burada WCF ile uğraşmış kişilere çok tanıdık gelecek
    //Attribute'lar dikkatinizi çekecektir.
    //DataContract ve DataMember, paylaşılacak verinin
    //serialize edilip, service bus üzerinde paylaşılacak
    //olmasını belirtiyor. Eğer bu attribute'ları belirtmez
    //isek, kendi yarattığımız custom sınıfları Service Bus
    //üzerinden geçiremeyiz.

    [DataContract]
    public class IssueContent
    {
        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string Content { get; set; }

        public override string ToString()
        {
            return Title;
        }
    }
}

Bu sınıfımızdan sonra içeriklerimizi oluşturacak ve Service Bus’a göndericek, basit konsol uygulamamıza geçebiliriz.

using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure;
using ServiceBus.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace ServiceBus
{
    class Program
    {
        static void Main(string[] args)
        {

            //Konfigürasyon dosyamızdan, Service Bus'ı yaratırken bize verilen
            //bağlantı bilgilerini alıyoruz.
            string connectionString = CloudConfigurationManager.GetSetting("ServiceBusConnectionString");

            //Daha sonra NamespaceManager objesi ile, Azure'da ki ServiceBus
            //servisimize bağlantı oluşturup, Service Bus'ın özellikleri
            //kullanabileceğimiz objemizi yaratıyoruz.
            var ServiceBusManager = NamespaceManager.CreateFromConnectionString(connectionString);

            //Topics servisini kullanacağımız için, yukarıda da bahsettiğim
            //üzere bir Topic yaratmamız lazım. Bu Topic'ler, üye olacak
            //client'ların hangi konu üstünden üye olacaklarını belirten ve
            //Windows Azure tarafında tutulan kavramlar.Yani bir kere
            //yarattığımız zaman bu Topic silmediğimiz sürece, Windows Azure'da
            //yer alacaktır.Dolayısıyla yaratırken önce TopicExsits()
            //şeklinde kontrol etmekte fayda var.
            if (!ServiceBusManager.TopicExists("Issue1"))
            {
                //İlgili topic yok ise yaratıyoruz. Bu uygulamayı kapatıp
                //tekrar çalıştırdığımızda Topic daha önceden yaratıldığı
                //için tekrar CreateTopic() metodu bu senaryoda
                //çalışmayacaktır.
                ServiceBusManager.CreateTopic("Issue1");
            }

            //Daha sonra Topic'lere üyeliğin olabilmesi için Subscription
            //yaratmamız lazım. Yani Issue1 Topic'ine, WhatIsNew path'i
            //ile üye olunabilmekte.Bu da yine bir kereliğine yaratılan
            //bir şey. Subscription'lar Service Bus'da tutulup,
            //bunlar üstünden subscribe olunabiliniyor.
            if (!ServiceBusManager.SubscriptionExists("Issue1", "WhatIsNew"))
            {
                ServiceBusManager.CreateSubscription("Issue1", "WhatIsNew");
            }

            //Kendi custom yarattığımız nesneyi oluşturuyoruz.
            IssueContent azureContent = new IssueContent();
            azureContent.Title = "Service Bus";
            azureContent.Content = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Etiam mattis, dui quis vehicula congue, sapien purus rhoncus libero, vitae convallis
dui nulla a ante. Donec nec varius neque, vel rhoncus nunc. Nunc sed mi hendrerit, cursus eros et,
lacinia ipsum. Mauris non laoreet libero. Praesent et molestie justo. Ut feugiat risus eget
euismod gravida. Mauris posuere neque luctus libero mollis bibendum. Duis iaculis,
dui at egestas pellentesque, sapien mauris porttitor lacus, et rhoncus nulla neque
eu felis. Nullam accumsan, orci et iaculis ultrices, orci magna iaculis tellus,
eget sodales nibh velit at libero. Mauris eleifend nisi sit amet tempus accumsan.";

            //Bir diğer içeriğimizi de oluşturalım.
            IssueContent netFrameworkContent = new IssueContent();
            netFrameworkContent.Title = "C# 10.0 çıkıyor";
            netFrameworkContent.Content = @"Şaka şaka daha çıkmıyor.";

            //Bütün bu yaptıklarımızı Service Bus'a gönderebilmek için,
            //TopicClient oluşturmamız lazım. Bu client'ı yaratırken,
            //bağlantı bilgilerimiz ve hangi Topic
            //ile ilgili olacağını belirtiyoruz.
            TopicClient client = TopicClient.CreateFromConnectionString(connectionString, "Issue1");

            //BrokeredMessage, Service Bus üzerinden göndereceğimiz mesaja
            //denk geliyor.Bu mesajın içerisine bizim kendi objemizi koymak
            //için, Constructor'dan faydalanıyoruz. BrokeredMessage'dan
            //kendi custom mesajlarımızı ne yazık ki bu aşamada sealed bir
            //class olduğu için türetemiyoruz.
            BrokeredMessage issue = new BrokeredMessage(azureContent);

            //İlk içeriğimizi gönderiyoruz.
            client.Send(issue);

            //Yeni içeriğimizle BrokeredMessage'ı tekrar yaratıyoruz.
            issue = new BrokeredMessage(netFrameworkContent);

            //İkinci içeriğimizi de gönderiyoruz.
            client.Send(issue);
        }
    }
}

Bu ana uygulamamızı yazdıktan sonra, yine basit bir konsol uygulaması ile client uygulamamızı simule edelim.


using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure;
using ServiceBus.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ServiceBus.Client
{
    class Program
    {
        static void Main(string[] args)
        {
            //Önceki kod bloğunda olduğu gibi Client için
            //de yine bağlantı bilgilerini alıyoruz.
            string connectionString =
                CloudConfigurationManager.GetSetting("ServiceBusConnectionString");

            //Subscribe olacağımız için SubscriptionClient
            //yaratıyoruz.Burada önemli olan noktalar,
            //hangi Topic'e ve hangi Subscription'a bağlanacağımızı
            //belirtiyor olmamız.
            SubscriptionClient client =
                SubscriptionClient.CreateFromConnectionString(connectionString, "Issue1", "WhatIsNew");

            //Bu noktada asenkron bir modelle istediğiniz
            //gibi yapabilirsiniz.Şimdilik standart bir
            //while loop'u içinde, client'ın Windows Azure
            //Service Bus uygulama servisinden mesajları
            //almasını sağlıyoruz.
            while (true)
            {
                //Burada Service Bus'da dolaşan BrokeredMessage'ı alıyoruz.
                BrokeredMessage message = client.Receive();

                if (message != null)
                {
                    try
                    {
                        //Mesajın GetBody<>() metodu ile hangi
                        //tipte mesajı alacağımızı söylüyoruz.
                        //IssueContent sınıfımız DataContract
                        //olduğu için sorunsuz bir şekilde
                        //serialize/deserialize olup client'lara gelecektir.
                        IssueContent content = message.GetBody<IssueContent>();

                        Console.WriteLine("Başlık : " + content.Title);
                        Console.WriteLine("İçerik : " + content.Content);

                        //Mesajı aldıktan sonra, complete edip bu mesajla
                        //işimizin bittiğiniz
                        //Service Bus'a iletiyoruz.
                        message.Complete();
                    }
                    catch (Exception ex)
                    {
                        //Eğer herhangi bir beklenmedik hata olursa,
                        //mesajın üzerindeki
                        //oluşabilecek kilitleri kaldırmamız lazım.
                        //Daha sonra tekrardan mesajı alalabilelim.
                        Console.WriteLine(ex.Message);
                        message.Abandon();
                    }
                }
            }

        }
    }
}

Evet artık herşeyimiz hazır. İlk yarattığımız konsol uygulamasını çalıştırıp daha sonra hemen client uygulamamızı çalıştırdığımız da aşağıdaki gibi bir görüntümüz olacaktır. Client uygulaması ile ana uygulamamız, Windows Azure Service Bus aracılığıyla iletişim kurup çeşitli operasyonları ve veriyi birbirleri arasında taşıyabilmiştir.

output

Şimdi ek olarak client uygulamamızı kapatmadan, ana uygulamamıza yeni bir içerik ekleyeyelim.Tabi koda müdahale ederek.

            IssueContent phpContent = new IssueContent();
            phpContent.Title = "PHP 5.0 çıktı";
            phpContent.Content = @"Geçtiğimiz günlerde PHP'nin yeni versiyonu 5.0 çıktı";

            issue = new BrokeredMessage(phpContent);
            client.Send(issue);

Ana uygulamamızı tekrar çalıştırdığımızda, bu sefer Client’a yeni eklediğimiz içeriğinde de geldiğini görüyor olacağız.

output1

Çok basitçe ve kısaca Windows Azure’da Service Bus uygulama servisinin Topics altyapısından nasıl yararlanabileceğimizi anlatmaya çalıştım. Sadece fikir vermesi adına ve ilerleyen günlerde bahsedeceğim güvenlikle ilgili şeylere başlangıç olması adına da umarım faydalı olur.