Pazar, Şubat 14, 2010

WF - Parallel Activity

Windows Workflow (WF) teknolojisini kullanarak uygulama geliştirmek istediğimizde kullanabileceğimiz adımları incelemeye devam ediyoruz. Şu ana kadar incelemiş olduğumuz iş akışı tipleri sürekli olarak tek sequence activty 'den oluşmakta ve tek yönlü bir iş akışı süreci oluşmaktadır. Eğer ki şu ana kadar görmüş olduğumuz yöntemler de akış esnasında herhangi bir adım sonrasında aynı anda iki akış başlatmak istediğimizde bu durumu gerçekleştirme şansımız olmayacaktı. Eğer ki bir şekilde yapmaya çalışırsakta oldukça uğraştırıcı bir yöntem olacaktır. Bu tür ihtiyaçlarımızı karşılamak için toolbox 'ımızın içeriğini incelediğimizde parallel activity bileşenini görüyor olacağız. Bu bileşen yardımı ile herhangi bir adımdan sonra uygulamamıza ya da tasarladığımız akış esnasında birden fazla işlemi aynı anda yapabilmemize olanak tanıyacaktır. Bu yazımızda ilk olarak paralel activity 'i tanıyacağız. Sonrasında örnekler ile nasıl kullanabileceğimize göz attıktan sonra nelere değindiğimizi özet olarak göz attıktan sonra yazımızı tamamlamış olacağız.

Parallel Activity 'ler iki ya da daha fazla Sequence Activity 'lerden oluşmaktadır. Bu aktivite bileşeni birden fazla sequence activity 'i ve içerisinde yapılmış olan işlemlerin teorik olarak aynı anda başlamasını planlamaktadır. Ancak teorik olarak yer olan bütün sequence activity lerin aynı anda başlayacağı söylense de gerçekte böyle bir durum oluşmaz. Belirsiz bir rastgelelik ile birbirilerini takip ederek gerçekleşmektedir. Yani a aktivitesi tamamlandıktan sonra b aktivitesi başlar ve sonrasında yeniden a aktivitesinin başlayabileceği gibi b aktivitesi de başlayıp tamamlanabilir. Ancak bu rastgelelik iki işleminde sorunsuzca gerçekleşmesini ve tamamlanmasında herhangi bir engel taşımamaktadır. İşlemin en sonunda her iki aktiviteninde sorunsuzca tamamlandığı gözlemlenecektir.

Parallel activity 'lerin ektileyici özelliklerinden biri de dallarda yer alan sequence aktivitelerden herhangi biri Delay Activity yer alırsa, bunun bitmesi beklenmez ve bir diğer daldaki activiteye geçilir ve akışın sorunsuzca işlemesi sağlanmış olur. Bu işlemlerin bu şekilde çalışmasının en basit açıklaması ise bizim hazırlamış olduğumuz uygulamaların işletim sistemleri üzerinde çalışıyor olması ve işletim sistemi de üzerinde çalışan işlemleri thread 'ler ile işletmesinden kaynaklanmaktadır. Thread 'lerde birbirlerinin tamamlanmasını beklemek yerine herhangi bir rastgelelik ile çalışmasından ötürü uygulamanın beklemesi ya da herhangi bir sebepten ötürü bozulması durumunda sırada bekleyen diğer iş parçacığına geçerek işlemi devam ettiriyor olmasıdır.

Delay Activity, iş akışını belirli bir süre duraklamasını ve sonrasında da çıkmasına olanak tanımaktadır. TimeoutDuration ve TimeSpan özelliklerini kullanılır.

Parallel Activity sınıfı System.Workflow.Activities isim alanı altında yer almaktadır. Parallel aktiviteleren sık olarak while döngüsünün kullanılması gereken durumlarda görülmektedir.

Genel olarak paralel actviteyi tanıdığımıza göre artık örneklere geçiş yapabiliriz. Bu yazımızda geliştireceğimiz örneği Visual Studio 2010 RC1 sürümünde geliştiriyor olacağız. Ancak .Net Framework 3.0 sürümünü kullanacağımız için Visual Studio 2008 ya da gerekli eklentileri yüklenmiş 2005 sürümünde de sorunsuzca geliştirilebilir.

Projemizi Workflow seçeneği altında yer alan Sequential Workflow Console Application proje şablonu üzerinde geliştiriyor olacağız. Proje oluştulduğunda karşımıza Sequential Workflow tasarım ekranı gelecektir.


Örneğimizi paralel atvitileer ile yapacağımız için bir adet bu aktivite tipinden tasarım ekranına sürükleyoruz.



Göreceğiniz üzere paralel aktiviteyi tasarım ekranına eklediğimizde iki tane sequence acticity 'nin eklendiğini göreceğiz. Peki iki değilde daha fazla akışı aynı anda çalıştırmak istediğimizde nasıl bir yol izlememiz gerekmektedir. Bunun için paralel aktivite üzerinde sağ tıklama yaptıktan sonra açılan menüden Add Branch seçeneğine tıklamamız yeterli olacaktır. Bu işlem sonrasında artık karşımızda aynı anda çalıştıracağımız üç adet akış olacaktır. Bu işlemi tekrarlayarak ihtiyacımız kadar akış ekleyebilmemiz mümkündür.



Ayrıca paralel aktiviteler içerisinde de akışın iptal olması ya da bozulması durumunda yapılacak işlemler için gerekli özellikler yer almaktadır.

Şimdi uygulama geliştirmek için gerekli olan bileşenleri ekliyoruz ve tasarım ekranında geliştirmiş olduğumuz akış aşağıdaki görünüme kavuşuyor.


Şimdi ise eklemiş olduğumuz CodeActivity lerin arka plan kodlarını yazarak işlemlerimize devam ediyoruz.

using System;

using System.Workflow.Activities;

namespace ParallelActivity
{
    public sealed partial class Workflow1 : SequentialWorkflowActivity
    {
        public Workflow1()
        {
            InitializeComponent();
        }

        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            Console.WriteLine("Sol taraf çalıştı.");
            solTarafSay++;
        }

        private void codeActivity2_ExecuteCode(object sender, EventArgs e)
        {
            Console.WriteLine("Sag taraf çalıştı.");
            sagTarafSay++;
        }

        private int solTarafSay;
        private int sagTarafSay;
    }
}

Ayrıca while döngüleri içerisinde kullanacak olduğumuz özellikleri de tanımladık. Sonrasında while bileşenin üzerinde sağ tıkladıktan sonra özelliklerinden condition değerine System.Workflow.Activities.Rules.RuleConditionReference değerini atıyoruz. Condition özelliğine ise aşağıda belirtiğimiz şekilde tanımlıyoruz.



Hem sol tarafı hem de  sağ tarafı tanımladıktan sonra while döngülerinin özelliklerinde yer alan condition seçeneğine baktığımızda aşağıdaki görünüme benzer bir hal alması gerekmektedir.



SoSon olarak aktivitenin dallarına delay activity eklerek bekleme durumunda nasıl bir işlem yapacağını gözlemleyeceğiz. Ayrıca tamamlandığını belirtmesi için akışın en sonuna bir tane daha kod aktivitesi ekliyoruz ve geliştirme işlemini tamamlıyoruz.



Sol taraftaki bekleme değerini bir saniye, sağ taraftaki bekeleme değerini iki saniye olarak verdiğimizi hatıralatarak hazırlamış akışı çalıştırıyoruz.



Oluşan program çıktısından da göreceğiniz üzere paralel aktivite bizim belirtmiş olduğumuz bekleme sürelerinin aksine ilk başta sıra ile çalışmasının aksine rastgelelik ile çalıştığını da bu sayede gözlemlemiş oluyoruz.

Sonuç olarak yazımızı toparlamak gerekirse, paralel aktivitelerin birden fazla iş akışını çalıştırabildiğini ve bu akışları aynı anda değil thread lere bağlı olarak rastgele bir sıradanlıkla çalıştırdığını öğrendik. Sonrasında hazırlamış olduğumuz örnek yardımı ile bu anlattış olduğumuz bilgileri doğrulyarak yazımızı tamamladık. Bir sonraki WWF yazımızda Condition kavramına değiniyor olacağız.

Umarım yararlı olabilmiştir.

Turhal Temizer
info@turhaltemizer.com

Salı, Şubat 02, 2010

WF - Parametre Kullanımı

Windows Workflow (WF) teknolojisini şu ana kadar temel uygulama tipleri ve istisnai durumlar (Exceptions) konularını inceledik. WF ile uygulama geliştirirken hangi adımlara dikkat etmemiz gerektiği ve kafamıza takılan geliştirme işlemlerini nasıl yapabileceğimizi detaylı bir şekilde inceleyerek yazılarımıza devam ediyor olacağız. Bu sefer ise WF 'da parametre kullanılmasını inceliyor olacağız.

Son kullanıcının kullanımına açılacak uygulamalar çok büyük oranda istek cevap mantığına göre çalışmaktadır. Bu istekleri taşıyabilmek için ise uygulamalarda parametrelerden yararlanılmaktadır. Bu parametreler hem uygulama içerisinden herhangi bir değerden gelirken dış veri giriş ya da istek controlleri yardımı ile de kullanılabilmektedir. Özellikle portal sistemlerinde iş akışı kullanımı çok yoğundur ve gönderilen parametreler doğrultusunda izin talepleri, araç istekleri, döküman paylaşımları ve akla gelmeyen diğer iş akışlarının hazırlanmasında parametre kullanımı çok ama çok fazladır. Bu sebepten ötüdür ki bu konu WF teknolojisi ile uygulama geliştiren geliştiriciler de çok önceliklidir.

Şimdi biz bu işlemleri WF teknolojisi üzerinde nasıl kullanabilceeğimizi incelemeye başlayalım. Visual Studio 2010 (VS2008 ya da WF eklentileri yüklenmiş VS2005 'te olabilir. Aynı özellikler her ikisinde de geçerlidir.) üzerinde Workflow seçeneği seçili iken .Net Framework 3.0 sürümü altında yer alan Sequential Workflow Console Application proje şablonunu seçiyor ve ismini ParameterParsing vererek  projeyi oluşturuyoruz. Sonrasında karşımıza alışık olduğumuz WF tasarım ekranı ve bileşenlerimiz gelecektir.

Tasarım ekranı üzerine Code Activity bileşenini sürüklüyor ve ExecuteCode olayınına parametre alabilmesi için gerekli işlemleri uygulamaya başlıyoruz.


Sonrasında kod tarafına basit bir string özellik oluşturup codeActivity bileşeninin içerisinde kullanılmak üzere ekliyoruz.

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
    Console.WriteLine("Bulunan string değer: [{0}]",StringToPrint);
}

private string _stringToPrint;

public string StringToPrint
{
    get { return _stringToPrint; }
    set { _stringToPrint = value; }
}

Eklemiş olunan CodeActivity bileşeni üzerinde parametre kullanılması için gerekli hazırlıklar tamamlandı. Peki, parametreler nereden gelecek? Bu örneğimiz için Program.cs içerisinde yer alan WorkflowRuntime.CreateWorkflow metodunun içerisine Dictionary<> olarak bir parametre daha vereceğiz. Bu parametre bizim hazırlamış olduğumuz Workflow tasarım ekranını hazırlarken belirlemiş olduğumuz özelliklerin isimlerini ve alacakları değerleri vermemiz durumunda onlar global olarak değişkenleri kabul edecek ve gerekli değerleri tanımlayacaktır.

Yukarıda belirttiğimiz şekilde Program.cs dosyasının içerisini düzenledikten sonraki son görünüm aşağıdaki gibi olacaktır.

using System;
using System.Collections.Generic;

using System.Threading;
using System.Workflow.Runtime;

namespace ParameterParsing
{
    class Program
    {
        static void Main(string[] args)
        {
            using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {
                AutoResetEvent waitHandle = new AutoResetEvent(false);
                workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); };
                workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
               {
                   Console.WriteLine(e.Exception.Message);
                   waitHandle.Set();
               };
               Dictionary<string, object> parameters = new Dictionary<string, object>();
                    parameters.Add("StringToPrint", "Parametreleri kullanarak sonuçları elde ettik...");
               WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(ParameterParsing.Workflow1),parameters);
               instance.Start();

               waitHandle.WaitOne();
            }
        }
    }
}

Workflow1.cs dosyasına eklemiş olduğumuz StringToPrint özelliğini program.cs dosyasında bir koleksiyonun içerisinde tanımladıktan sonra iş akışı başladığında çağırılacak parametrelerin arasında olması için intance 'ın parametreleri arasına ekledikten sonra işlemimizi tamamlamış oluyoruz.

Yapmış olduğumuz işlemler sonrasında uygulamamızı çalıştırdığımızda karşımıza aşağıdaki gibi bir ekran çıktısı çıkacaktır.



Daha önce de bahsettiğimiz gibi WorkflowInstance 'a atayacağımız değeleri CreateWorkflow metodunun sonucunda dönecek olanlardan elde ediyorduk. Bu metotta birden fazla aşırı yüklemeden oluşmaktadır. Bunlardan biri de kolleksiyonla birlikte işlem yapandır. Biz de bu metottan yararlanarak oluşturmuş olduğumuz Dictionary koleksiyonunu ekleyerek işlemimizi yaptık.

Şimdi örneğimizi biraz daha karmaşıklaştırarak parametre kullanımını incelemeye devam edelim. Bu sefer bir kullanıcı sınıfı oluşturalım. Sonrasında bu sınıfın içerisine Adı ve Soyadı diye iki adet eleman tanımlayalım. Sonrasında ise oluşturmuş olduğumuz bu sınıfın içerisinde yer alan elemanları Workflow tasarım ekranı üzerinde eklemiş olduğumuz CodeActivity bileşeninin çalışma esnasında görüntülenecek şekilde hazırlayalım.

Eklemiş olduğumuz işlem sonrasında Workflow1.cs 'nin içeriği aşağıdaki gibi olacaktır.

using System;
using System.Workflow.Activities;
using System.Collections.Generic;

namespace ParameterParsing
{
    public class Kullanici
    {
        public Kullanici(string ad, string soyAd)
        {
            this.adi = ad;
            this.soyAdi = soyAd;
        }

        private string adi;

        public string Adi
        {
            get { return adi; }
            set { adi = value; }
        }
        private string soyAdi;

        public string SoyAdi
        {
            get { return soyAdi; }
            set { soyAdi = value; }
        }
    }

    public sealed partial class Workflow1 : SequentialWorkflowActivity
    {
        public Workflow1()
        {
            InitializeComponent();
        }

        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            foreach (Kullanici k in Insan)
            {
                Console.WriteLine("İsminiz [{0},{1}] 'dir.", k.Adi, k.SoyAdi);
            }
        }

        private List<Kullanici> insan;

        public List<Kullanici> Insan
        {
            get { return insan; }
            set { insan = value; }
        }
    }
}

Kod parçasını yukarıdaki şekilde oluşturduk ve iş akışının çalışması esnasında oluşacak işlemleri de hazırladık. Şimdi program.cs üzerinden gerekli parametreleri oluşturabiliriz.

using System;
using System.Collections.Generic;

using System.Threading;
using System.Workflow.Runtime;

namespace ParameterParsing
{
    class Program
    {
        static void Main(string[] args)
        {
            using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {
                AutoResetEvent waitHandle = new AutoResetEvent(false);
                workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); };
                workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
               {
                   Console.WriteLine(e.Exception.Message);
                   waitHandle.Set();
               };
               Dictionary<string, object> parameters = new Dictionary<string, object>();
                    List<Kullanici> insan = new List<Kullanici>();
                    insan.Add(new Kullanici("Tur", "Tem"));
                    insan.Add(new Kullanici("Ser", "Tur"));

                    parameters.Add("Insan", insan);
               WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(ParameterParsing.Workflow1),parameters);
               instance.Start();

               waitHandle.WaitOne();
            }
        }
    }
}


Oluşturulan sınıfa ait varlıklara değerleri atadık ve sonrasında uygulamayı çalıştırdığımızda bu değerleri sorunsuzca göreceğiz.



Bir önceki örneğimizde string bir değeri tutan bir parametreyi akış bileşenin nasıl kullanacağımızı gördük. Bu örneğimizde de Oluşturduğumuz bir sınıfı (Veri tabanı tablosu gibi de düşünebilirsiniz) içerisinde yer alan varlıklardan yararlanarak buna değerler atadık ve yine codeactivity bileşenin içerisinde sorunsuzca gösterebildik.

Sonuç olarak Workflow Foundation ile geliştirilen uygulamlarda parametreleri el ile atayıp kullanabileceğimiz gibi bir veri topluluğu içerisinde de çekip kullanabiliriz. Ayrıca bu parametreleri kullanabilmemiz için program.cs sınıfının içerisinde CreateWorkflow metoduna parametre olarak  generic tipten bir parametre ekleyerek parametrelerin kullanılmasına olanak tanıyabiliriz.

Bir sonraki yazımızda Workflow Foundation ' da Paralel Aktiviteleri inceliyor olacağız.

Umarım yararlı olabilmiştir.

Turhal Temizer

info@turhaltemizer.com
turhal.temizer@csharpnedir.com