WCF Hizmeti Örnek Yönetimi

Windows Communication Foundation

    Windows Communication Foundation ile kod geliştirme konusunda sizlerle bilgiler paylaştığım makalelerimde şimdiye kadar giriş düzeyinde sunucu ve istemci tarafında yapılacak olan işlemleri gördük. Makalelerimdeki adımları takip ederek WCF ile kolaylıkla bir istemci ve sunucu uygulaması geliştirebildiğinizi umuyorum. Bu adımlar ardından artık biraz daha zevkli konulara geçmenin sanırım zamanı geldi. Bu makalemde sizlerle birlikte, Windows Communication Foundation’ın gelen isteklere yanıt vereceği hizmet sınıfı örneklerini nasıl oluşturduğuna ve yazılım geliştirici olarak bizlerin hizmet sınıf örneği oluşturulmasına nasıl müdahale edebileceğimizi paylaşıyor olacağım.

   Önceki makalelerimde geliştirmiş olduğumuz WCF sunucu uygulamamız basit bir arayüz ile açtığı hizmette istemciden Say fonksiyonuna gelen her bir çağrıda private olarak tuttuğu bir değişkenin değerini arttırmakta ve yeni değerini dönmekteydi.

[ServiceContract(Namespace = "http://www.enterprisecoding.com/WCFOrnekleri")]
public interface IOrnekHizmet {
    [OperationContract]
    int Say();
}

internal class OrnekHizmet : IOrnekHizmet {
    private int sayac = 0;

    public OrnekHizmet() { }

    public OrnekHizmet(int sayacBaslangici) {
        sayac = sayacBaslangici;
    }

    #region IOrnekHizmet Members

    public int Say() {
        return ++sayac;
    }

    #endregion
}

   Aşağıda bulabileceğiniz istemci kodumuz, WCF hizmetimize tek bir istemci ile ardıl olarak 10 istek göndererek sayacı arttırmakta ve genel sayaç bilgisini ekrana vermekte. İçerik olarak önceki makalemde paylaştıklarımdan çokta farklı bir kod değil;

var istemci = istemciFabrikasi.CreateChannel();
var oturum = 1;

for (int cagri = 1; cagri <= 10; cagri++) {
    Console.WriteLine("{0}. oturum {1}. çağrı, yanıt : {2}", oturum, cagri, istemci.Say());
} 

   Uygulamayı çalıştırdığımızda aşağıda ekran görüntüsünü alacaksınızdır;

istemci_tekOturum

   Sunucumuza tek oturum ile istek gönderdiğimiz uygulamamızın çıktısı tam da istediğimiz gibi görünüyor. İstemcimize sunucunun açık olduğu süre boyunca gelen toplam istek sayısı dönmekte; ama emin konuşmak için henüz erken. İsterseniz aynı kodu bu defa iki istemci ile deneyelim. Bunun için istemci uygulamasını iki defa çağırabileceğiniz gibi aşağıdaki şekilde ek bir döngü ile de istemci sayısını arttırmanız mümkün;

for (int oturum = 1; oturum <= 2; oturum++) {
    var istemci = istemciFabrikasi.CreateChannel();

    for (int cagri = 1; cagri <= 10; cagri++) {
        Console.WriteLine("{0}. oturum {1}. çağrı, yanıt : {2}", oturum, cagri, istemci.Say());
    } 
}

istemci_ikiOturum

   Durun bir dakika; uygulamada bir terslik var gibi, hiçte beklediğimiz gibi bir çıktı yok karşımızda. Uygulamamız ikinci istemciyi oluşturup istek göndermeye başladığında sayacımızın 10’dan devam etmesini beklerken baştan başlayarak 1’den itibaren saymış. Bunun sebebini anlayabilmek için birlikte WCF örnek yönetimi inceleyelim;

   Windows Communication Foundation bir hizmetin örneği oluşturmada bize 3 farklı yol sunmaktadır;

  • Her bir açılan oturuma tek bir hizmet örneği atanmasını sağlayan PerSession
  • Yapılan her bir çağrı için bir hizmet örneği atanmasını sağlayan PerCall
  • Gelen istek ve istemcilerden bağımsız olarak hizmetin yaşam döngüsü boyunca tek bir örneğinin olmasını sağlayan Single

   Bu 3 yöntemin kendilerine göre artıları ve eksileri bulunmakta, dolayısıyla iş mantığınıza uygun olanı seçmeniz gerekecektir. Pek çok iş mantığında bu yöntemlerin seçimindeki temel belirleyici kullanılacak kaynakların ne olduğu ve hizmet örneklerinin bu kaynaklara ne şekilde ulaşacağıdır. Bir WCF hizmeti oluşturduğunuzda varsayılan olarak bu 3 yöntemden oturum başına bir hizmet örneği oluşturulması (PerSession) kullanılmakta, bu sebeple uygulamamızı iki istemci ile istek gönderecek şekilde yeniden düzenlediğimizde beklediğimizde farklı bir çıktı görmüş, sayacımızın yeni oturumda sıfırlandığını anlamıştık.

   Programsal olarak WCF hizmetinin ne şekilde hizmet örneği oluşturabileceği bilgisini hizmet sınıfımızın üzerine ekleyeceğimiz ServiceBehaviorAttribute özniteliği ile belirleyebiliriz. Aslında WCF hizmetinin pek çok özelliğini yapılandırmamıza izin veren ve detaylarını ilerleyen makalelerimde paylaşmayı planladığım bu öznitelik içerisindeki InstanceContextMode özelliği doğrudan müdahale etmemizi sağlamakta. Bu noktada akıllara bu özelliğin neden hizmetimizi tanımladığımız arayüze değil de doğrudan hizmet sınıfının kendisine eklediğimiz sorusu gelebilir. Bunun yanıtı bize bir esneklik sağlamak; ama asıl olarak da hizmet sınıf örneğinin ne şekilde oluşturulacağı bilgisinin arayüz ile doğrudan ilişkili bir konu olmamasıdır. Bu tanımlama arayüz üzerinden bulunmuş olsaydı arayüzü kullanan tüm hizmetleri aynı örnek yönetimini kullanmaya zorlamış olurduk. Pek çok WCF örneğinde arayüzün dışarıda, üçüncü bir assembly içerisinde olduğunu düşünürsek, aslında arayüz bizim için sadece hizmetimizin sınırlarını belirleyen bir kontrat olduğu ve istemci ile de paylaşıldığı noktasına varabilirsiniz. İstemcimizle paylaştığımız böylesi bir bilgi içerisine hizmetimizin örnek yönetiminin nasıl olduğunu da eklemek hem gereksiz olacak hem de bazı kullanımlarda güvenlik zaafiyeti oluşturabilecektir.

   Uygulamamızın başta düşündüğümüz şekilde hareket ederek toplam gelen istek sayısını doğru sayabilmesini sağlamak için hizmet sınıfımızın üzerine aşağıdaki şekilde ServiceBehaviorAttribute özniteliğini eklememiz gerekecektir;

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
internal class OrnekHizmet : IOrnekHizmet {
    private int sayac = 0;

    public OrnekHizmet() { }

    public OrnekHizmet(int sayacBaslangici) {
        sayac = sayacBaslangici;
    }

    #region IOrnekHizmet Members

    public int Say() {
        return ++sayac;
    }

    #endregion
}

   Bu şekildeki düzenleme  sonrasında uygulamamız aşağıdaki ekran görüntüsünde de görebileceğimiz gibi istediğimiz yönde çalışacaktır.

istemci_SingleInstanceContextMode

   Hizmetimizi her bir istek için yeni bir hizmet örneği oluşturacak şekilde yapılandırdığımızda ise aşağıdaki çıktı ile karşılaşırız;

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 
internal class OrnekHizmet : IOrnekHizmet {
    private int sayac = 0;

    public OrnekHizmet() { }

    public OrnekHizmet(int sayacBaslangici) {
        sayac = sayacBaslangici;
    }

    #region IOrnekHizmet Members

    public int Say() {
        return ++sayac;
    }

    #endregion
}

istemci_PerCallInstanceContextMode

   Yukarıda her üç yönteminde kendilerine göre artıları ve eksileri olduğundan bahsetmiştim. Oturum ya da istek bazlı hizmet örneği oluşturulması her istemcide/istekte yeni bir örnek oluşturacağından işlemci zamanında götürecektir. Örneğimizde kullandığımız hizmet sınıfımız örnek oluşturulması sırasında yoğun bir işlem yapmaması nedeniyle hissedilen bir fark yaratmayacak olsa da örneğin veritabanı bağlantısını ilklendiren ve ardından da yapılandırma bilgisi okuyan bir hizmet iş mantığında her bir istekte oluşacak hizmet sınıfı hem uygulama sunucusuna hem de veritabanına ek bir maliyet getirecektir. Böylesi bir örnekte uygulama yaşam döngüsü boyunca ayakta kalacak bir hizmet örneğinin olması daha mantıklı olabilir.

   Öte yandan tek bir hizmet örneği olması durumunda paylaşılan kaynakların doğru yönetilmesi gerekecektir. Örneğimiz üzerinden konuşacak olursak; InstanceContextMode.Single tanımlaması ile tek bir hizmet örneği oluşmasını istedikten sonra hizmetimize farklı istemcilerden gelecek aynı andaki istekler sayacın aynı anda okunarak aynı anda arttırılmasına, dolayısıyla da toplam istek sayısının hatalı olmasına neden olacaktır. Bu gibi durumlardan kaçınmak adına paylaşılan kaynakların doğru tespit edilerek doğru yönetilmesi gereklidir. Aşağıda, böylesi bir durumu engellemek için nasıl kodlanması gerektiğine dair basit bir örnek bulabilirsiniz;

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
internal class OrnekHizmet : IOrnekHizmet {
    private object monitor = new object();
    private int sayac = 0;

    public OrnekHizmet() { }

    public OrnekHizmet(int sayacBaslangici) {
        sayac = sayacBaslangici;
    }

    #region IOrnekHizmet Members

    public int Say() {
        lock (monitor) {
            return ++sayac; 
        }
    }

    #endregion
}

   Bazı iş mantıklarında hizmet örneği oluşturulurken çeşitli parametrelerin geçilmesi gerekebilir. Örneğin sayacımızın uygulama kapanırken son değerini veritabanına yazarak, bir sonraki çalışmasında da veritabanından bu edğeri okuyarak başlamasını isteyebiliriz. Bu durumda programsal olarak bir wcf hizmetinin nasıl oluşturulabileceğini paylaştığım makalemde belirttiğim sunucu uygulamamızda hizmetimizi oluşturduğumuz aşağıdaki satırı;

ServiceHost hizmetSunucusu = new ServiceHost(typeof(OrnekHizmet), hizmetTemelAdresi);

   Hizmet sınıf örneğimizi verecek şekilde yeniden düzenlemeliyiz;

var sayac = 0;

//Veritabanından sayacın son değerini okuyan
//iş mantığı buraya gelecek

ServiceHost hizmetSunucusu = new ServiceHost(new OrnekHizmet(sayac), hizmetTemelAdresi);

istemci_SingleInstanceCount

   Büyük resme baktığımızda, Windows Communication Foundation ile örnek yönetimi konusunda ileri düzey kullanımlarda özelleştirme yapılabilmesine olanak sunulurken, basit kullanımlar da düşünülerek varsayılan genel geçer bir tanımlama da yapılmıştır. Biz yazılım geliştiriciler iş mantığımız doğrultusunda bu yöntemlerden uygun olanı seçmeli, kodumuz içerisinde ortak kullanılan kaynaklarımızın bulunması durumunda bu kaynakların kullanımına daha fazla özen göstererek istenmeyen durumların oluşmasının önüne geçmeliyiz.

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal veri yolu sistemleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# ve Visual Studio teknolojileri konusundan Microsoft tarafından altı yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz. vCard - Twitter - Facebook - Google+

1 Yorum

  1. Ayşe muzaffer uğurhan   •  

    İyi günler Fatih bey ;
    wcf servisini kullanan bir wcf servisi hazırlamaprojesi örneği bulamilirmiyim?
    microsoft identitymodel protocols referansını projeme ekleyemiyorum.
    visual studio 2010 kullanıyorum.
    windows 7 işletim sisteminde çelışıtorum.
    microsoft identity foundation yükledim
    assemblied referance kalsörünün altında MIF altında framework 3,5 altında iki ntane dll oluştu. fakat protocollleri içeren referance elde edemedim. ben framework 4.0
    kullanıyorum.MIF da 3,5 yüklü

    teşekkür ederim.wcf videolarınızı izledim. çok yararlı oldu.
    İyi günler dilerim.

Bir Cevap Yazın

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