Makale Özeti

Windows Workflow Foundation içerisinde Workflow Runtime Engine’e servisler kayıt etmek mümkündür. Bu özellik workflow runtime’ın davranışlarını düzenlemek için esnek bir yoldur. Thread planlaması(Thread Scheduling), iş akışı kalıcılığı(workflow persistance), transaction yönetimi(transaction management), iş akışı izleme(workflow tracking) mekanizmalarını içerisinde bulunduran Workflow Core Services, WF ile birlikte imlemente edilmiş olarak gelen servis türledir. Yalnız WF uygulamalarını geliştirirken Workflow Core Services dediğimiz mekanizma ile sınırlı kalmayız. Burada Workflow Runtime ile Host uygulaması arasındaki iletişimi sağlayan Yerel İletişim Servisleri(Local Communication Services) devreye girer.

Makale

WWF - Yerel İletişim Servisleri(Local Communication Services)

 

Windows Workflow Foundation içerisinde Workflow Runtime Engine’e servisler kayıt etmek mümkündür. Bu özellik workflow runtime’ın davranışlarını düzenlemek için esnek bir yoldur. Thread planlaması(Thread Scheduling), iş akışı kalıcılığı(workflow persistance), transaction yönetimi(transaction management), iş akışı izleme(workflow tracking) mekanizmalarını içerisinde bulunduran Workflow Core Services, WF ile birlikte imlemente edilmiş olarak gelen servis türledir. Yalnız WF uygulamalarını geliştirirken Workflow Core Services dediğimiz mekanizma ile sınırlı kalmayız. Burada Workflow Runtime ile Host uygulaması arasındaki iletişimi sağlayan Yerel İletişim Servisleri(Local Communication Services) devreye girer.

 

 

 

Yerel Servisleri(Local Services) Anlamak

 

.Net içerisinde Local Services olarak geçen ve bazı kaynaklarda Data Exchange Service olarak ta tanımlanabilem Yerel Servisler, Workflow Core Services ile çözemediğimiz ve kendi implementasyonumuza bırakılmış servis türleridir. Yaptığı şey ise, Workflow Runtime’ın host edildiği uygulama ile Workflow Runtime arasında bir kontrat yapısı aracılığıyla iletişimi sağlamasıdır. WF uygulamalarını geliştirirken herhangi bir anda çalıştırdığımız workflow’a veriler yollayabilir ya da workflow’dan veriler almak isteyebiliriz. Bu işi tanımladığımız servis kontratını implement ederek gerçekleştiririz.

 

Yerel servislerle çalışmak için öncelikle worklfowlarınızın isteklerine hizmet veren bir yapı sağlamak. Örneğin uygulamanız çalışıyorken sorgulama yapmak isteyebilir, uygulamanıza yeni bir durum ataması yapabilir, sabit bir veri tabanı içerisindeki verileri listeleyebilir ya da güncelleme işlemi yapabilir, workflow nesnesi olmayan diğer bileşenlerle iletişime geçmek isteyebilirsiniz.

 

Bir yerel servis ile iletişime geçmenin iki yolu varıdr.

 

  1. Yerel servis üzerindeki bir metodu çağırma.
  2. Yerel servis tarafından olay tetiklenmesini bekleme.

 

Workflow Yerel Servis ile etkileşime geçtiğinde, dolaylı olarak uygulamanızın başka bölümleri ile etkileşim yaşanabilir. Örnek olarak; Workflow Yerel Servisin bir metodunu çağırır, çağrılan metot başka bir metodu çağırır ve bu uygulamanın herhangi bir yerinde yönetim altına alınmış bir olayı tetikleyebilir. Olay tetiklendiğinde uygulama başka aktiviteler gösterebilir.

 

 

Yerel Servis(Local Service) Implementasyonu

 

  1. Interface kullanarak Servis Kontratı tanımlayın. Interface içerisine Workflow için uygun metot ve olayları tanımlayın.
  2. Interface’i ExternalDataExchangeAttribute nesnesi ile işaretleyin. Bu nesneyi System.Workflow.Activities isimalanı altında bulabilirsiniz. Bu attribute’un yaptığı şey; Interface’i Yerel Servis kontratı olarak tanımlamak.
  3. Bu interface’i implement eden bir sınıf tanımlayın.
  4. Bu sınıfın örneğini oluşturun ve Workflow Runtime Engine’e bu sınıfı ekleyin.

 

Bütün yerel servisler kendi interface tipi ile benzersiz olarak tanımlanmalıdır. Bu her servis arayüzünden sadece bir örnek oluşturulabilmesine izin verildiği anlamına geliyor. Farklı interfaceleri implement eden birden fazla Yerel Servis Workflow Runtime Engine’e eklenebilir. Buradaki çalışma mantığı interfaceler üzerine kurulmuştur. Uygulamasında da göreceksiniz ki, bu interface’i implement eden sınıflar değil de, direkt olarak interface üzerinden işlemleri yürüteceğiz.

 

 

 

Yerel Servis(Local Service) Kullanımı

 

Yerel Servisleri üzerinde bulunan metotları çağırmanın iki yöntemi bulunmaktadır.

 

  1. IServiceProvider interface’i tarafından tanımlanmış GetService metodunu kullanarak belirli bir servise erişmek ve erişilen servisin bir metodunu çağırmak.
  2. CallExternalMethodActivity kullanmak. Bu aktivite bize tanımlama şeklindeki workflow’un bir adımı gibi Yerel Servis içerisindeki metodu kod aktivitesi kullanmaksızın çağırmayı sağlar.

 

 

Not: Bu örneği yapmak için MyLocalOgrenciService adında boş bir solution başlatın.

 

Yerel Servis Tanımlaması

 

Yerel Servis tanımlaması yapmak için MyLocalOgrenciService projesine LocalOgrenciService adında bir ClassLibrary projesi ekleyin. Bu proje içerisinde IOgrenciService, OgrenciService ve Ogrenci adında üç eleman bulunacak. Aşağıda bu üç elemana ait çıktılar bulunmaktadır. Bu ClassLibrary’nin bizim Yerel Servis’imiz olduğunu fark etmişsinizdir.

 

 

 

Bu ClassLibrary içerisini kodlamaya Ogrenci sınıfını oluşturmaktan başlayalım.

 

Ogrenci sınıfını Serializable olarak işaretleyin.

 

 

Ogrenci sınıfı içerisnde OgrenciNo, Ad ve Soyad özelliklerini tanımlayın ve ToString metodunu ezin.

 

 

Yerel servisimiz içerisindeki Ogrenci sınıfını tanımlamış oldunuz.  Şimdi ise Host uygulaması ile Workflow Runtime arasındaki kontrat ilişkisini kuracak IOgrenciService interface’ini kodlayalım. Kodlamaya başlamadan önce ClassLibrary’inize System.Workflow.Activities referansını ekleyin.

 

 

Yukarıdaki bölümde geriye Ogrenci tipinde bir değer döndüren OgrenciBul metodu tanımlamış oldunuz. Geliştirdiğiniz bu interface’in Yerel Servis olarak çalışmasını sağlamak için System.Workflow.Activities isimalanında bulunan ExternalDataExchange attribute’ü ile işaretlemeniz gerekmektedir. Böylelikle servis kontratını da geliştirmiş oldunuz.

 

Şimdi IOgrenciService interface’ini implement eden OgrenciService sınıfını tanımlayalım. Bu sınıf aracılığıyla interface tarafından sağlanan kontrattaki işlemleri yerine getireceğiz. Projenize OgrenciService adında bir sınıf ekleyin ve bu sınıfa IOgrenciService interface’ini implement ettirin.

 

 

Bu sınıf içerisinde Dictionary<int, Ogrenci>  yapısında anahtar-değer çiftleri tutan bir koleksiyon ekleyin. Bu koleksiyona ogrenciler adını verin. Ogrenciler koleksiyonunu bu sınıf içerisinde test verilerini tutmak için kullanacağız.

 

 

Sınıf içerisinde bulunan ogrenciler koleksiyonunu doldurma işlemini yapacak olan TestVerisiOlustur metodunu tanımlayın.

 

 

TestVerisiOlustur metodu içerisinde ogrenciler koleksiyonunun örneğini oluşturuyoruz ve bu koleksiyon içerisine 4 tane Ogrenci sınıfından oluşturulmuş örnek koyuyoruz.

 

Son olarak IOgrenciService interface’i aracılığıyla getirilen OgrenciBul metodunu tanımlıyoruz.

 

 

Bu metot içerisinde gelen int tipindeki OgrenciNo parametresine göre koleksiyon içerisindeki Ogrenci nesnesini geri döndürüyoruz. Eğer parametre olarak alınan OgrenciNo herhangi bir öğrenciye ait değilse, geriye null değerini döndürüyoruz.

 

Bu adımları izlediğinizde Yerel Servisi tanımlamış olacaksınız. Tanımladığınız Yerel Servisi kullanmak için Solution içerisine MyOgrenciWFLib adında bir Sequential Workflow Class Library ekleyin.

 

Yerel Servis’i Direkt Olarak Kullanmak

 

Eklediğiniz MyOgrenciWFLib içerisinde varsayılan olarak Workflow1 adlı bir Sequential Workflow gelelecektir. Projenize LocalOgrenciService referansını ekleyin. Workflow1’in kod bölümüne geçin ve aşağıdaki özellikleri tanımlayın.

 

 

OgrenciNo özelliğini Workflow1’i kullanan host uygulamasından alacağız. OgrenciSerive özelliğini ise Ogrenciyi bulmak için kullanacağız. Ogrenci özelliğini de bulunan öğrenciyi host uygulamasına döndürmek için kullanacağız.

 

Workflow1 sınıfının OnActivityExecutionContextLoad metodunu ezin.

 

 

Bu metot workflow içerisindeki aktivite yüklenirken çalışacaktır. Burada yaptığınız, Workflow1 sınıfının miras aldığı sınıftaki OnActivityExecutionContext metodunu çalıştırarak ExecutionContext’in çalışmasını devam ettirmek ve IOgrenciService tipindeki özelliği yapılandırmak. Yapılandırma işini IServiceProvider tipindeki interface içerisinde bulunan GetService metodunu kullanarak yapıyoruz. GetService Metodu bize bir servis döndürüyor. Döndürülen servisi IOgrenciService tipine çevirerek kendi IOgrenciService tipindeki OgrenciServis özelliğimizi yapılandırmış oluyoruz. Eğer OgrenciService bu işlemden sonra null değeri alıyorsa büyük bir problemle karşı karşıya kalmış olacaksınız. Bu yüzden OgrenciService özelliğinin değeri null ise InvalidOperationException fırlatırız.

 

Workflow içerisine bir tane Code aktivitesi koyun ve Code aktvitesinin ExecuteCode eventine gelin. Bu event tetiklendiğinde çalışan metotta aşağıdaki kodları yazın.

 

 

Bu metot içerisinde bir önceki adımda yapılandırdığımız OgrenciService’ini kullanarak, geriye döndüreceğimiz Ogrenci özelliğine değer ataması yapmış olduk. Atadığımız değer ise OgrenciBul metodundan dönen Ogrenci tipindeki nesnemizdir.

 

Bu aşamalardan geçtiğinizde geliştirdiğiniz Yerel Servisi kullanan Workflow1 adında Sequential Workflow tanımlaması yapmış oldunuz. Bir sonraki adım Workflow1 adlı iş akışınızı host etmek olacaktır.

 

 

 

Yerel Servis’i CallExternalMethodActivity İle Kullanmak

 

Yerel Servisinize bir önceki bölümdeki gibi direkt olarak erişebilirken, ben kod yazmakla uğraşmak istemiyorum diyorsanız CallExternalMethodActivity kullanmalısınız. CallExternalMethodActivity, interface aracılığı ile tanımladığınız servis kontratına direkt olarak erişmek ve kontrat içerisindeki üyeleri kullanmak için kullanılır. Bir önceki bölümdeki gibi OnActivityExecutionContextLoad metodunu ezmek zorunda kalmazsınız.

 

CallExternalMethodActivity’i kullanabilmeniz için MyOgrenciWFLib Sequential workflow projeniz içerisinde Workflow2 adında sequential workflow ekleyin. Eklediğiniz Workflow2’ye toolbox’tan bir tane CallExternalMethodActivity ekleyin.

 

 

callExternalMethodActivty’i seçin ve özelliklerinden InterfaceType’a gelerek, InterfaceType’ın yanındaki butona basın.

 

 

InterfaceType özelliğinin yanındaki butona tıkladığınızda açılan menüden LocalOgrenciService.IOgrenciService interface’ini seçerek tamam butonuna basın.

 

 

Pencere kapandıktan sonra CallExternalMethodActivity’nin MethodName özelliğini OgrenciBul olarak değiştirin. Değiştirme işlemini yapar yapmaz özellikler penceresine (ReturnValue) ve ogrenciNo adında iki alanın eklendiğini göreceksiniz. Bu alanları sınıf içerisinde tanımladığımız özelliklerle bağlamamız gerekmektedir.

 

 

Bağlama işlemini yapmnak için ogrenciNo özelliğine geldiğinize yanda açılan butona tıklayın.

 

 

Açılan penceredeki Bind to new member sekmesine gelin. CreateProperty seçeneğini seçin ve New member name metninin altında bulunan metin kutusuna bir özellik adı yazın. Ben burada özellik adı olarak OgrenciNo yazmayı tercih ettim. OK butonuna bastığınızda Workflow2’nin kod bölümüne OgrenciNo adında bir DependencyProperty eklendiğini göreceksiniz.

 

 

Uygulamanızın tasarım bölümüne geçin ve callExternalMethodActivity için bir de (ReturnValue) özelliği için bağlama işlemi yapın. Bunu yapmak için yine (ReturnValue) özelliğinin yanındaki butona tıklayın ve açılan penceredeki Bind to new member sekmesine geçin. Bu sekmedeki bölümde CreateProperty alanını seçip, bir de özellik adı yazarak OK butonuna basın.

 

 

Bu işlemi yaptığınızda kod bölümünde sizin yerinize OgrenciAdında bir DependencyProperty oluştuğunu göreceksiniz. Böylelikle CallExternalMethodActivity kullanarak Yerel Serivisimizle çalışan bir Workflow uygulaması geliştirmiş oldunuz. Bu bölümde yaptığınız işlem ile direkt olarak kod ile erişim arasında fark yok. CallExternalActivity kullanımı diğerine oranla daha kolay bir yöntem.

 

 

Workflow2’nin son görüntüsü.

 

 

 

 

Host Uygulaması Tanımlaması

 

Host uygulamasını geliştirirken Workflow Hosting – 2 adlı makalemde geliştirdiğim hosting framework’ünü kullanacağım.  Bu framework’ün adı Cagdas.Workflow.Hosting idi. Hatırlatmak isterim.

 

MyLocalOgrenciService solution’ı içerisine bir tane WPF Applicaton projesi ekleyin. Bu sefer ara yüzümüzü Windows Presentaion Foundation kullanarak yapalım. :))) Eklediğiniz WPF uygulaması üzerine bir tane Label ve bir tane Buton koyun.

 

 

Projenize .net sekmesinde bulunan System.Workflow.Activities, System.Workflow.ComponentModel, System.Workflow.Runtime, System.Workflow.Services referanslarını ekleyiniz. Daha sonra projects sekmesinde bulunan LocalOgrenciService ve MyOgrenciWFLib referanslarını ekleyiniz. Ayrıca browse sekmesinden daha önce oluşturmuş olduğunuz Cagdas.Workflow.Hosting dll’ini ekleyiniz. Ekleme işlemlerini yaptıktan sonra buton üzerine çift tıkayarak WPF uygulamanızın kod bölümüne geçiniz ve aşağıdaki kodu yazınız.

 

 

Yukarıdaki kodun ne anlama geldiğini Workflow Hosting – 2 adlı makalemi okuyarak anlayabilirsiniz. LocalOgrenciService ile başlayan satırda, Yerel Servis içerisinde tanımladığımız Ogrenci sınıfından bir nesneye, çalışan Workflow’dan dönen Ogrenci output parametresinin değerini atıyoruz. Başlangıçta Workflow’a 1 değerini yolladığımız için Servis içerisindeki 1 numaralı öğrenci getirilecektir.

 

 

AddService metodunda, gelen WorkflowRuntime tipideki instance parametresine ExternalDataExchangeService tipinde bir yerel servis ekleniyor. Bu yerel servis içerisine de bizim tanımladığımız LocalOgrenciService isimalanı içerisinde bulunan OgrenciService ekleniyor. Böylelikle servisimizi hayata geçirmiş oluyoruz.

 

Uygulamayı çalıştırarak aşağıdaki çıktıyı elde edebilirsiniz.

 

 

 

 

Özet

 

Bu makalemde sizlere Yerel Servislerden söz ettim. Yerel servisler içersindeki yapının ExternalDataExchangeAttribute ile işaretlenmiş bir interface aracılığıyla gerçekleşirildiğinden ve CallExternalMethodActivity’nin kullanımının bize getirdiği kolaylıklardan söz ettim. Diğer makalelerden farklı olarak bu uygulamanın ara yüzünü Windows Presentation Foundation teknolojisini kullanarak geliştirmem sizleri de şaşırtmış olsa gerek.