Burak Selim Senyurt(MVP)
Matematik Mühendisi bir .NET Severin Yazıları...

Correlation Nedir? Yenir mi? İçilir mi?

Pazartesi, 1 Şubat 2010 09:25 by bsenyurt

Merhaba Arkadaşlar,

Bazen bir kavramı yada konuyu anlamakta inanılmaz zorlandığınızı hatırlayın. Ne yaparsınız? Kimisi kendisini yemeğe verir. Kimisi hayat küsermişçesine bir köşeye çekilir. Kimisi kendiyle baş başa kalır ve çığlık çığlık haykırır. Kimisi de daha akıllı davranıp bir süre tatile çıkar veya anlayamadığı kavramla ilişkili herhangibir dökümanı bir süreliğine araştırmamaya, okumamaya karar verir. Neredeyse unuturcasına bir zaman koyar araya. Sonrasında ise aynı konuyu tekrar araştırmaya karar verir. İnanın başarılı olma şansı bir önceki denemeye göre çok daha yüksek olacaktır. Önemli olan noktalardan birisi, yılmadan bu iterasyona devam edebilmektir. Okudunuz, hala anlamadınız...Kısa bir ara daha...Sonra tekrar aynı konu ama mümkünse farklı kaynaklarla...Wink

Bende bir süredir Workflow Service' lerde oldukça önemli olan konulardan birisi üzerinde araştırmalarımı tamamen durdurmuştum. Correlation. Çünkü; Matematikte "bağlılaşım/korelasyon", ekonomide "bağlanım", nükleer bilimlerde "bağlantı/eş ilişki", denizbilimde "kaçınım", tıpta "Aferent uyarıların gerekli cevabı oluşturmak üzere beyinin ilgili merkezinde birleşmesi" olarak çevirileri yer alan bu kavramın, Workflow Services içerisinde ne anlama geldiğini anlamak için epey bir süre tepinmem gerekmişti. Geçtiğimiz günlerde aynı konu üzerinde yeniden durmaya ve araştırmaya ve edindiğim bilgileri sizlere paylaşmaya karar verdim. İşte elde ettiğim sonuçlar;

Correlation kavramını mesajları bir arada gruplamanın bir yolu olarak düşünülebilir ilk etapta. Örneğin bir talep(Request) ve bu talebe karşılık gönderilen cevap(Reply) arasındaki ilişki Correlation olarak ifade edilmektedir. Özellikle WCF(Windows Communication Foundation) tarafında Session bazlı haberleşmelerde mesajlar arasında bir Correlation oluştuğu söylenebilir. Ancak Correlation' ın farklı bir yönü daha vardır. Bir servis örneği(Instance) ile bir oturum(Session) arasında da bağıntı kurulabilir. Yani bir SessionId değerine ait olaraktan hareket eden mesajların içeriğinde yer alan bazı veri parçalarının, Session ile alakalı bir servis örneği ile eşleştirilmesi mümkün olabilir. Bir başka deyişle aynı SessionId değeri altındaki mesajların her zaman için aynı servis örneğine ait olduğunun anlaşılmasında, SessionID=Service Instance ID eşitliğinin sağlanması da Correlation olarak ifade edilebilir. Bu ilişki çoğunlukla bilinçsiz(Implicit) olarak sağlanır. Yani, geliştiricinin çoğu zaman bir aksiyonda bulunmasına gerek yoktur. Aslında bu durumu aşağıdaki şekilde olduğu gibi canlandırabiliriz.

Ancak Workflow örneklerinde uzun zaman süren süreçlerin ele alınması da söz konusudur(Long Running Process). İstemcilerin, Workflow Service' ler ile olan haberleşmelerinde aradaki oturumu kapatıp ayrılmaları bu tip süreçlerde son derece yaygındır. Buna göre istemci ile servis arasındaki oturumun her an sonlanabilir olması önemli bir sorunu ortaya çıkarmaktadır; Correlation nasıl sağlanacak? Undecided

Bu amaçla Workflow Service' lerde Correlation' ın sağlanması için kullanılan çeşitli teknikler mevcuttur. Aslında burada da tam bir kavram kargaşası vardır. En güvenilir kaynaklardan birisi olarak ele alacağımız MSDN, Correlation' ı Content-Based ve Protocol-Based olmak üzere iki çeşide ayırmıştır. Protocol-Based Correlation' da kendi içerisinde Context ve Request-Reply isimli iki farklı Correlation tekniğini daha barındırmaktadır.

Content-Based Correlation' da service örneği(Instance) ile ilişkili olan veri(Map edilmiş veri olaraktan da düşünebiliriz) mesajın içeriğinde yer alır. Örneğin mesajın Header veya Body kısımlarında bulunabilir. Dolayısıyla Correlation' ı sağlayan arabirimlerin XML tabanlı olan bu veri içeriğini kontrol edebilmesi gerekmektedir. İşte bu noktada XPath gibi sorgu teknikleri devreye girmektedir. Protocol-Based Correlation ise iletişim mekanizmasını baz alır ve buna göre mesajlar arasında yada mesajlar ile doğru servis örneği arasında gerekli eşleştirmeyi sağlar.

Bu giriş yazımızda özellikle Content-Based Correlation üzerinde durabiliriz. En çok örneklenen model genellikle budur. Workflow Service' lerde servise gelen ve servisten giden mesajların içerdiği veri parçaları ile çalışma zamanındaki servis örnekleri arasında eşleştirme yapmak(yani Correlation' ı sağlamak) son derece kolaydır. Tüm mesajlaşma aktivitelerinin CorrelationInitializers isimli bir koleksiyonu bulunur. Bu koleksiyon içerisinde Key-Query çiftleri yer almaktadır. Tahmin edileceği üzere Key değerleri ile Query' lerin birbirlerinden ayrıştırılması sağlanır. En önemli nokta ise Query' dir. Query içerisinde yer alan XPath sorgusu ile Content içerisindeki veri işaret edilir. Tabi bir mesajlaşma aktivitesi, diğer bir mesajlaşma aktivitesinin başlattığı Correlation' u takip edebilmelidir. Bunun içinde CorrelationWith isimli özellikten yararlanılır. Bu bilgilere göre Correlation' ın bir şekilde başlatılması(Initialize) ve takip edilmesi(Follow) gerektiği anlaşılmaktadır. Başlatılan bir Correlation' ın takip edilmemesi halinde mesajlar ve servis örneği arasında bir eşleştirmenin yapılması söz konusu olmayacaktır. Elbette Workflow Foundation 4.0 içerisinde bir Correlation' ın başlatılmasını kolaylaştıran bir aktivitede gelmektedir. InitializeCorrelation bileşeni.

Sanırım şu ana kadar anlattıklarımız ile kafamızda Correlation' ın ne olduğuna dair bir fikir oluşmuştur. Tabi konuyu kavramak tek başına yeterli değildir. Pratiğe dökmemizde yarar vardır. Ancak şu an için bu konudaki araştırmaya ara verip tatile çıkmak niyetindeyim. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

WCF 4.0 Yenilikleri - Workflow Services [Beta 2]

Pazartesi, 19 Ekim 2009 22:22 by bsenyurt

Merhaba Arkadaşlar,

WCF ve WF arasında ilişkiyi anlatan güzel bir cümle vardır. .Net Framework 3.0' da arkadaş olan WCF ve WF, .Net Framework 3.5 sürümünde nişanlanmış, .Net Framework 4.0 sürümünde ise evlenmişlerdir. Wink Bu ikilinin bir arada ele alınması sonucu Workflow Services adı verilen bir ufaklıkta ortaya çıkmıştır. Aslında bir akışın servis bazlı olması son derece önemlidir. Nitekim WF tarafında, uzun süreli işlemlerin ele alınması(Long Running Process), akışın çeşitli noktalarından farklı anlar için kalıcı olarak saklanabilmesi(Persistence), asenkron çalışma zamanı motorunun zaten hazır olarak bulunması söz konusudur. Bu özelliklerin WCF Servis Noktaları(Endpoints) ile desteklenmesi, bir akışın ağ üzerindeki istemciler tarafından başlatılabilmesine olanak tanımaktadır. Üstelik bu akışlar sonuçlar üreterek bunları geriye de döndürülebilir. Bu durum aslında WCF 3.5 sürümünde de gerçeklenebilmektedir. Ne varki, WCF 4.0 tarafında tamamen declerative olarak tanımlanabilen ve saf XAML(eXtensible Application Markup Language) içeriğinden oluşan bir Workflow Servisinin geliştirilebilmesi mümkündür. Üstelik Visual Studio 2010 WF Designer sayesinde bu XAML içeriğinin üretilmesi için IDE desteği de sunulmaktadır.

Kişisel Not : Windows XP, Vista ve 7 sürümlerinde kullandığım Visual Studio 2010 Beta 1 ürününde, WF Designer sürekli olarak hata verip IDE' yi Restart işlemine zorlamaktaydı.Undecided Neyseki bu sorun Visual Studio 2010 Beta 2 sürümünde ortadan kaldırılmış durumdadır.Wink

Dolayısıyla bu yazımızın konusu şimdiden belli oldu. Çok basit ve büyük ihtimalle pek işe yaramayan bir Workflow Service' in nasıl geliştirilebileceğini incelemeye çalışıyor olacağız. İşe ilk olarak Declerative Sequential Service Library tipinden bir WCF projesi oluşturarak başlayacağız. Aşağıdaki ekran görüntüsünde olduğu gibi.

Örnek olarak AdventureWFServices ismiyle oluşturduğumuz projede Service1.Xamlx dosyası hemen dikkati çekmektedir. Bu örnek olarak oluşturulan Workflow Service örneğidir. Yani Microsoft tarafından sunulan hazır Hello World örneği Wink Tamamen XAML içeriğinden oluşmaktadır ve istemcilere servis olarak nasıl sunulacağına ilişkin çalışma zamanı bilgileri(WCF Servis konfigurasyon bilgileri) Web.config dosyasında tutulmaktadır. (Bu bir WCF kütüphanesi projesi olduğundan doğrudan çalıştırılabilir ve Web.config içerisindeki ayarlar sayesinde HTTP bazlı olarak host edilir. Diğer taraftan test etmek için WcfTestClient aracından kolayca yararlanılabilir.)

Biz tabiki bu içerik yerine kendi Workflow Service örneğimizi kullanacağız. Ama öncesinde ReceiveRequest ve SendResponse isimli bileşenlerin ne işe yaradıklarını kısaca anlamaya çalışmakta yarar vardır. ReceiveRequest isimli bileşen aslında Receive tipinden bir aktivitedir. Benzer şekilde SendResponse isimli bileşende, SendReply tipinden bir aktivitedir. Tahmin edileceği üzere Receive aktivitesi ile, istemci tarafından gelen talep(Request) alınmakta ve SendReply aktivitesi yardımıylada bir cevap(Response) döndürülmektedir.(Bu iki bileşen arasında ise istenen bir akışın yürütüldüğü düşünülebilir) Bir başka deyişle WCF bazlı mesaj alınması ve cevap döndürülmesi amacıyla kullanılan iki aktivite tipi söz konusudur. ReceiveRequest isimli bileşen aynı zamanda istemci tarafından çağırabilecek bir operasyon sunduğundan OperationName isimli bir özelliği de sahiptir. Diğer taraftan istemci tarafından gelecek olan talep içerisindeki değişkenler Content özelliği tarafından taşınabilirler ki bu özellik aslında bir koleksiyon olarak düşünülebilir. Çünkü operasyonun birden fazla parametre alması gerekebilir. Receive aktivitesi için önem arz eden noktalardan biriside, CanCreateInstance özelliğinin değeridir. Bu değer örneğimizde true olarak set edilmiştir ve söz konusu aktiviteye bir talep gelmesi ile birlikte Workflow örneğinin oluşturulup oluşturulmayacağını işaret etmektedir. Önemli olan noktalardan biriside, SendResponse isimli bileşenin Request özelliğinin değerinin, Receive tipinden olan ReceiveRequest isimli bileşen olmasıdır. Dolayısıyla bu iki mesajlaşma aktivitesinin birbirleriyle haberleştiklerini söyleyebiliriz. (İlerki yazılarımızda burada sözü edilen korelasyon konusuna değiniyor olacağız ki XAML içeriğinde bu konunun izlerini görmekteyiz.)

Bu arada Sequential Service tipinin üzerinde tanımlanmış bazı değişkenler(Variables) olduğu görülebilir.

data isimli Int32 tipinden olan değişken, Receive aktivitesi için Content değerini de temsil etmektedir. Diğer taraftan, SendReply aktivitesine ait Content özelliğinde kullanılmış ve string karşılığı üretilerek geriye döndürülmüştür. Buna göre akışın senaryosunu şu şekilde düşünebiliriz. İstemci talep olarak Int32 tipinden bir değer gönderir. Bu değer ReceiveRequest isimli aktivite bileşeni tarafından alınır ve üst aktivitesi olan Sequential Service' in data değişkenine atanır. Bu değişken SendResponse isimli aktivite bileşeninin de ulaşabileceği kapsamda(Scope) olduğundan, istemciye geriye gönderilecek cevabın içeriğinde kullanılabilir. Şimdi bu bilgilerden yola çıkarak kendi Workflow Servisimizi oluşturalım.

Örnek olarak istemciden gelen iki sayının toplamını bulup geriye bu sonucu döndürecek bir Workflow Servis geliştirmeyi planlayabiliriz. Böylece XAML içeriğini anlamamız daha kolay olacaktır. Bu amaçla projemize yeni bir Declerative Sequential Service öğesi ekleyerek devam edebiliriz.

MathService.xamlx servisinin tasarım görüntüsü aşağıdaki gibidir.

Aslında global seviyede tanımladığımız GlobalX ve GlobalY isimli iki değişken haricinde çok fazla detay görülmemektedir. Bu nedenle konuyu anlamanın en iyi yolu XAML içeriğine bakmamız olacaktır(Zaten ilerleyen zamanlarda bu blog girişinin destekleyici görsel videosunuda yayınlıyor olacağım) İşte MathService.xamlx içeriği;

<Service mc:Ignorable="sad1" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/servicemodel" xmlns:a="clr-namespace:AdventureServices;assembly=AdventureServices" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:p="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:p1="http://adventure/" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s1="clr-namespace:System;assembly=System" xmlns:s2="clr-namespace:System;assembly=System.Xml" xmlns:s3="clr-namespace:System;assembly=System.Core" xmlns:sad="clr-namespace:System.Activities.Debugger; assembly=System.Activities" xmlns:sad1="http://schemas.microsoft.com/netfx/2009/xaml/activities/design" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System" xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel" xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core" xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sd="clr-namespace:System.Data;assembly=System.Data" xmlns:sd1="clr-namespace:System.Data;assembly=System.Data.DataSetExtensions" xmlns:sl="clr-namespace:System.Linq;assembly=System.Core" xmlns:st="clr-namespace:System.Text;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <WorkflowServiceImplementation ConfigurationName="MathService" Name="MathService">
    <p:Sequence DisplayName="Basic Math Service" sad:XamlDebuggerXmlReader.FileName="C:\My Dot Net World\Projects\2010\WCF\AdventureWFServices\AdventureWFServices\MathService.xamlx" sad1:VirtualizedContainerService.HintSize="303,348.553333333333" mva:VisualBasic.Settings="Assembly references and imported namespaces serialized as XML namespaces">
      <p:Sequence.Variables>
        <p:Variable x:TypeArguments="CorrelationHandle" Name="handle" />
        <p:Variable x:TypeArguments="x:Int32" Name="GlobalX" />
        <p:Variable x:TypeArguments="x:Int32" Name="GlobalY" />
      </p:Sequence.Variables>
      <sad1:WorkflowViewStateService.ViewState>
        <scg3:Dictionary x:TypeArguments="x:String, x:Object">
          <x:Boolean x:Key="IsExpanded">True</x:Boolean>
        </scg3:Dictionary>
      </sad1:WorkflowViewStateService.ViewState>
      <Receive x:Name="__ReferenceID0" CanCreateInstance="True" DisplayName="Sum" sad1:VirtualizedContainerService.HintSize="257,85.2766666666667" OperationName="Sum" ServiceContractName="p1:IMathService">
        <Receive.CorrelatesOn>
          <MessageQuerySet />
        </Receive.CorrelatesOn>
        <Receive.CorrelationInitializers>
          <RequestReplyCorrelationInitializer CorrelationHandle="[handle]" />
        </Receive.CorrelationInitializers>
        <Receive.KnownTypes>
          <x:Type Type="x:Int32" />
        </Receive.KnownTypes>
        <ReceiveParametersContent>
          <p:OutArgument x:TypeArguments="x:Int32" x:Key="X">[GlobalX]</p:OutArgument>
          <p:OutArgument x:TypeArguments="x:Int32" x:Key="Y">[GlobalY]</p:OutArgument>
        </ReceiveParametersContent>
      </Receive>
      <SendReply Request="{x:Reference __ReferenceID0}" DisplayName="Sum Response" sad1:VirtualizedContainerService.HintSize="257,85.2766666666667">
        <SendParametersContent>
          <p:InArgument x:TypeArguments="x:Int32" x:Key="Result">[GlobalX + GlobalY]</p:InArgument>
        </SendParametersContent>
      </SendReply>
    </p:Sequence>
  </WorkflowServiceImplementation>
</Service>

İlk etapta biraz korkutucu görünebilir. Sealed Ancak şu an için üzerinde duracağımız önemli noktalar Bold olarak işaretlenmiştir. Sequence.Variables elementi içerisinde 3 değişken tanımı görülmektedir. Bizim eklediklerimiz GlobalX ve GlobalY isimli int tipinden olanlardır. Bu değişkenler Sequence elementi içerisinde tanımlandıklarından, takip eden Receive ve SendReply elementleri veya gelecek başka aktiviteler tarafından ortaklaşa kullanılabilirler. Receive elementinde operasyon ile ilişkili bilgiler dışında, servisin sözleşme ismide belirtilmektedir. Receive aktivitesi için en önemli parça ReceiveParametersContent kısmıdır. Burada X ve Y isimli OutArgument tipinden argümanlar tanımlamıştır. Bu argümanlarda önemli olan kısım GlobalX ve GlobalY atamalarıdır. X ve Y aslında istemcinin çağıracağı servis operasyonunun parametreleridir. İstemciden gelen bu değerler, aktivitenin GlobalX ve GlobalY değerlerine set edilmektedir. SendReply aktivitesi içerisinde yer alan SendParametersContent kısmında ise InArgument tipinden bir argüman tanımlanmıştır. Result ismi ile tanımlanan bu argümanın içeriği, GlobalX ve GlobalY değerlerinin toplamından oluşmaktadır. Bir başka deyişle istemci tarafına döndürelecek cevap içeriği belirlenmiş olur. İçeriğin tipi ise TypeArguments niteliğine atanan Int32 yapısıdır. Görüldüğü üzere herhangibir kod dosyası kullanılmamıştır. Tüm işlemler XAML bazlı olaraktan tanımlanabilmektedir. Buda çalışma zamanı için önemli bir esnekliktir.

Oluşturduğumuz sınıf kütüphanesinin Web.config dosyasının içeriği ise son derece sadedir.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceDebug includeExceptionDetailInFaults="False" />
          <serviceMetadata httpGetEnabled="True"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Görüldüğü gibi belirli bir Endpoint tanımlaması yoktur. Ancak exception detayının gönderilmesi ve Metadata bilgisinin elde edilebilmesi için gerekli davranışlar(Behaviors) tanımlanmıştır. Buna göre Workflow Servisimiz, HTTP bazlı olaraktan host edilecektir. Uygulamayı F5 ile başlattığımızda ve MathService.xamlx içeriğini talep ettiğimizde aşağıdaki ekran görüntüsü ile karşılaşırız.

Görüldüğü üzere WSDL içeriğide doğrudan talep edilebilmektedir. Buda istemciler için gerekli Proxy üretiminin kolayca yapılabileceği anlamına gelmektedir. Burada WSDL içeriğinide inceleyebiliriz. SealedAncak benim özellikle göstermek istediğim nokta http://localhost:65193/MathService.xaml?xsd=xsd1 talebinin sonucudur. Nitekim WSDL dökümanına baktığımızda, Sum isimli operasyonun kullandığı X ve Y parametrelerini göremeyiz. Ancak bu parametrelerin tanımlandığı XSD içeriğine bir referans bildirildiğini fark edebiliriz. Bu XSD içeriğinde aşağıdaki ekran görüntüsünde olduğu gibi, X,Y ile istemci tarafına döndürelecek Result değişkenlerine ait tanımlamalar yer almaktadır.

Dilerseniz artık servisimizi test edelim. Bu amaçla daha önceden de belirttiğimiz gibi WcfTestClient aracını kullanabiliriz. İşte örnek bir toplama işlemi;

İlk olarak Request için X ve Y değerleri girilir sonrasında Invoke düğmesine tıklanır. Bir süre beklemenin ardından servisten geri dönüş elde edilir. BasicHttpBinding tabanlı olarak host edilen Workflow Servisimiz başarılı bir şekilde çalıştırılmıştır. Yapılan Invoke işlemi sonrası üretilen XML içeriğine bakıldığında ise aşağıdaki çıktının oluştuğu görülebilir. 

İşte bu kadar. Smile Workflow Servisleri sayesinde bir iş akışının servis bazlı olarak başlatılabilmesi ve WF Çalışma zamanının nimetlerinden yararlanabilmesi mümkün olmaktadır. Üstelik, .Net 4.0 tarafında gelen yeni modele göre söz konusu Workflow Servislerinin tamamen XAML içeriğinden oluşacak şekilde dekleratif olarak tanımlanabilmesi söz konusudur. Bu da çalışma zamanında koda müdahale etmeye gerek duymadan akış ile ilişkili bazı değişikliklerin yapılabileceğinin bir göstergesidir. Bakalım WCF&WF kardeşliğinde başka ne gibi yenilikler bizleri bekliyor. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

AdventureWFServices.rar (442,66 kb)

Tags:   , , ,
Categories:   WCF 4.0 Beta 2
Actions:   E-mail | del.icio.us | Permalink | Yorumlar (2) | Comment RSSRSS comment feed
Bookmark and Share