Tag Archives: Switch

Workflow Foundation ile Argüman Geçişleri

Daha önceki yazılarımızda workflow içerisinde argüman ve değişkenlerin nasıl tanımlandığını göz attık. Benzer olarak, değişkenler tıpkı sınıf üyeleri gibi, argümanlar ise tıpkı method parametrelerine benzerler. Önceki yazılarımızda değişkenleri kullanmıştık. Bu yazımızda input ve output argümanlarını ve bunların kullanımlarını göreceğiz.

Hemen Siparisİslemi adında bir Workflow Console Application oluşturalım.

WF-Siparisİslemi

Bu projemizde bazı ürünler için bir sipariş oluşturacağız ve bu siparişi workflow’umuzun içerisine geçireceğiz. Daha sonra workflow’umuz toplam maaliyeti hesaplayacak ve uygulamaya döndürecektir.

Şimdi Solution Explorer kullanarak projemize sağ tıklayıp Add –> Class seçeneğinden projemize Siparis.cs adındaki sınıfımızı ekleyelim.

WF-SiparisSolution

Siparis adındaki sınıfımıza siparis detaylarını içeren tanımlamaları yapmaya başlayalım.


namespace Siparisİslemi
{
public class SiparisMaddeleri
{
public int SiparisOgeID { get; set; }
public int Miktar { get; set; }
public int OgeID { get; set; }
public string Tanım { get; set; }
}

public class Siparis
{
public Siparis()
{
Ogeler = new List<SiparisMaddeleri>();
}
public int SiparisID { get; set; }
public string Tanım { get; set; }
public decimal ToplamAgirlik { get; set; }
public string SiparisMetodu { get; set; }

public List<SiparisMaddeleri> Ogeler { get; set; }
}
}

 

Siparis sınıfı birkaç public üyeye sahiptir (SiparisID, Tanım, ToplamAgirlik, SiparisMetodu) ve bir adet SiparisMaddeleri sınıfı listesine sahiptir. Bunlar sipariş maaliyetlerini ölçeceğimiz workflow’umuzun detaylarıdır.

Ardından projemizde bulunan Workflow1.xaml dosyasının ismini SiparisWF.xaml olarak değiştirelim. Ayrıca bu xaml dosyasını “View Code” ile açarak ilk satırdaki x:Class=”Siparisİslemi.Workflow1″ sınıf niteliğini x:Class=”Siparisİslemi.SiparisWF” olarak değiştirelim.

SiparisWF.xaml dosyamızı dizayn modunda açalım. Ardından sol alt taraftaki Arguments kısmına tıklayıp argümanlarımızı ekleyeceğimiz pencereyi açalım.

NOT: Argümanlarda, değişkenlerden farklı olarak Scope kısmı bulunmaz. Bunun nedeni, değişkenlerin workflow’un tümünde ya da belirli aktivitelerde tanımlanmasına karşın, argümanların tanımlanması tüm workflow içindir çünkü bu yapılar workflow’a ya da workflow’dan veri geçişini tanımlarlar.

Açtığımız pencereden Create Argument’e tıkayıp argümanımızın ismini SiparisBilgisi olarak değiştirelim. Direction kısmı In olarak kalsın. Argument Type seçeneğinde ise Browse Type seçeneğinden Siparisİslemi.Siparis tipini seçelim. Eğer bu tip Argument Type kısmında gözükmüyorsa projemizi bir kere Build Solution ile build etmeliyiz.

WF-BrowseType

İkinci bir argümanımızı ToplamMaliyet adında tanımlayalım. Direction kısmını Out, ArgumentType kısmını Decimal olarak taımlayalım. İlk kez kullandığınız için Decimal tipi açtığınız drop-down’da yer almaz. Bu tip mscorlib assembly içerisinde System namespace’i altındadır. (System.Decimal)

Şimdi Workflow’umuzu tasarlayalım. Bir adet Sequence aktivitesi sürükleyip bırakalım. İçine de bir Writeline aktivitesi sürükleyip Text özelliğine “Sipariş Alındı” yazalım. Bu aktivitenin altına bir Assign aktivitesi sürükleyelim. DisplayName özelliğini İlk Toplam, To özelliğini ToplamMaliyet ve Value özelliğini de 0 (sıfır) olarak atayalım. Bu aktivite kısaca toplam maliyeti sıfır olarak ilk kullanıma hazırlar.

Switch Aktivitesi

Switch aktivitesi tıpkı C#’taki switch ifadesine benzer şekilde çalışır. İçerisinde çalıştırılan ifadeye göre belirli aktiviteleri çalıştırılmasına olanak verir. Bu aktiviteyi SiparisMetodu hesaplamak için kullanacağız. Switch aktivitesi Toolbox içerisinde Switch<T> olarak bulunur. Assign aktivitesi altına bir adet Switch<T> aktivitesi sürükleyip bırakalım. Sürükleyip bıraktığımızda bu aktivite bizden içerisinde çalıştıracağımız SiparisMetodu string olduğu için bu aşamada tipimizi String olarak seçelim. DisplayName özelliğini Kullanım Ücreti olarak değiştirelim.

WF-Switch

Switch aktivitesi bir Expression özelliğine sahiptir. Bu özelliği SiparisBilgisi.Siparis olarak tanımlayalım. Daha sonra Add new case seçeneğinden BirSonrakiGün ve İkiSonrakiGün adında iki adet durum ekleyelim.

Expression Aktiviteleri

Şimdiye kadar projemizde BirSonrakiGün ve İkiSonrakiGün adında SiparisMetodu sonucuna göre iki adet case oluşturduk. Bir de bunun yanında diagramda görüleceği gibi default durumumuz mevcut. Şimdi de bu spesifik durumlara göre aktiviteler tanımlayalım. Bu durumumuzda Add aktivitesini kullanacağız.

NOT: System.Activities.Expressions namespace’i workflow’unuzda kullanabileceğiniz birçok aktivite içerir. (Add, Subtract, Multiply ve Divide gibi) Ayrıca expression’ları değerlendirmek için Equal, GreaterThan, And ve Or gibi lojik aktiviteler de içerir.

Ne yazık ki, Add aktivitesi Toolbox’ta mevcut değil. Bu aktiviteyi .xaml dosyamızın kod kısmından elle eklememiz gerekecektir. XAML dosyamızı “View Code” seçeneği ile açalım. Switch aktivitesi aşağıdaki şekilde görülecektir;


<Switch x:TypeArguments="x:String" DisplayName="Kullanım Ücreti" Expression="[SiparisBilgisi.SiparisMetodu]" sap:VirtualizedContainerService.HintSize="473,151">
<x:Null x:Key="BirSonrakiGün" />
<x:Null x:Key="İkiSonrakiGün" />
</Switch>

Görüldüğü üzere, BirSonrakiGün ve İkiSonrakiGün case’leri için x:Null durumu görülür. Bunun anlamı, bu durumlar için herhangi bir aktivite henüz tanımlanmamıştır. Şimdi kod ile Add aktivitemizi tanımlayalım. Yukarıdaki <x:Null ile başlayan iki satırı silip aşağıdaki Add aktivitemizi içeren kodlarımızı yazalım.


<Add x:TypeArguments="s:Decimal, s:Decimal, s:Decimal" x:Key="BirSonrakiGün"
DisplayName="15 Ekle" Left="[ToplamMaliyet]" Result="[ToplamMaliyet]"
Right="[15.0D]" />
<Add x:TypeArguments="s:Decimal, s:Decimal, s:Decimal" x:Key="İkiSonrakiGün"
DisplayName="10 Ekle" Left="[ToplamMaliyet]" Result="[ToplamMaliyet]"
Right="[10.0D]" />

Bu adımdan sonra da default durumu için aşağıdaki kodumuzu tanımlayalım;


<Switch.Default>
<Add x:TypeArguments="s:Decimal, s:Decimal, s:Decimal" DisplayName="5 Ekle"
Left="[ToplamMaliyet]" Result="[ToplamMaliyet]" Right="[5.0D]" />
</Switch.Default>

Add aktivitemizin Left, Right ve Result adında 3 adet özelliği vardır. Özet olarak, Left özelliğine Right özelliği eklenir ve toplam Result özelliğinde saklanır. Left ve Result özellikleri ToplamMaliyet argümanına ayarlanır. Right özelliği statik bir değere sahiptir ve her durum için farklıdır. Switch aktivitemizin son hali şu şekildedir;


<Switch x:TypeArguments="x:String" DisplayName="Kullanım Ücreti" Expression="[SiparisBilgisi.SiparisMetodu]" sap:VirtualizedContainerService.HintSize="473,151">
<Switch.Default>
<Add x:TypeArguments="s:Decimal, s:Decimal, s:Decimal" DisplayName="5 Ekle"
Left="[ToplamMaliyet]" Result="[ToplamMaliyet]" Right="[5.0D]" />
</Switch.Default>
<Add x:TypeArguments="s:Decimal, s:Decimal, s:Decimal" x:Key="BirSonrakiGün"
DisplayName="15 Ekle" Left="[ToplamMaliyet]" Result="[ToplamMaliyet]"
Right="[15.0D]" />
<Add x:TypeArguments="s:Decimal, s:Decimal, s:Decimal" x:Key="İkiSonrakiGün"
DisplayName="10 Ekle" Left="[ToplamMaliyet]" Result="[ToplamMaliyet]"
Right="[10.0D]" />
</Switch>

Kısacası, SiparisMetodu, BirSonrakiGün olduğunda ToplamMaliyet değerine 15 eklenir, İkiSonrakiGün olduğunda 10 eklenir, diğer durumlarda ise default kısım çalıştırılacağından 5 eklenir. Switch aktivitemizi genişlettiğimizde aşağıdaki şekilde görülür.

WF-AddinSwitch

NOT: Add aktivitemizin Right seçeneğinin 15.0D olarak tanımlanmasının nedeni Visual Basic syntax’ında Decimal değerlerinin bu şekilde gösterimi olduğundandır.

Şimdi Switch aktivitemizin altına bir Assign aktivitesi ekleyelim ve DisplayName özelliğini Taşıma Ücreti, To özelliğini ToplamMaliyet, Value özelliğini de ToplamMaliyet + (SiparisBilgisi.ToplamAgirlik * 0.5D) olarak ayarlayalım. Bu formül kısaca Taşıma Ücretine, her toplam ağırlık için 0.5 değer katar.

Ardından Assign aktivitesinin altına bir Writeline aktivitesi sürükleyip bırakalım. Text özelliğine “Toplam Maliyet: ” + ToplamMaliyet.ToString() ifadesini ekleyelim.

Tasarım kısmında herşeyimiz tamam. Şimdi Program.cs içerisinde workflow’umuzu çağıracağımız kodlarımızı yazalım.


using System;
using System.Linq;
using System.Activities;
using System.Activities.Statements;
using System.Collections.Generic;

namespace Siparisİslemi
{

class Program
{
static void Main(string[] args)
{
Siparis siparisim = new Siparis
{
SiparisID = 1,
Tanım = "Sipariş Tanımı",
SiparisMetodu = "İkiSonrakiGün",
ToplamAgirlik = 200,
};

//Workflow için input argümanlarını oluşturalım
IDictionary<string, object> input = new Dictionary<string, object>
{
{"SiparisBilgisi", siparisim}
};

//Workflow'u çalıştıralım
IDictionary<string, object> output = WorkflowInvoker.Invoke(new SiparisWF(), input);

//Workflow'dan geri dönen ToplamMaliyet'i alalım
decimal toplam = (decimal)output["ToplamMaliyet"];
Console.WriteLine("Toplam Maliyet {0}", toplam);
Console.WriteLine("Enter to Exit");
Console.ReadLine();
}
}
}

Bu kod kısaca Siparis sınıfı oluşturur ve bu sınıfı bazı verilerle doldurur. Sonra bir Dictionary nesnesi oluşturur ve Siparis nesnesini bunun içinde muhafaza eder. WorkflowInvoker sınıfının statik Invoke() metodunu çağırır. Invoke() metodu uygulama içerisinde bir workflow örneği oluşturur ve çalıştırır.

Bunu bir Dictionary nesnesi olarak geçirmemiz bize birden fazla parametre geçişine olanak verir. Invoke() metodu geriye bir Dictionary nesnesi (In/Out Direction ile tüm workflow argümanlarını içeren) döndürür. Toplam Maliyet argümanı Dictionary içerisinden çıkartılır ve ekrana yazdırılır. Şimdi uygulamamızı F5 ile çalıştıralım.

Sipariş Alındı
Toplam Maliyet: 110,0
Workflow’un döndürdüğü Toplam Maliyet 110,0
Enter to Exit

 

Peki doğru mu hesapladı?

Toplam ağırlığımızı 200 olarak verdiğimizden bu değeri 0.5 ile çarpıp 100 değerini elde ettik. Buna da “İkiSonrakiGün”’ seçeneğinin Right özelliğindeki değer 10.0 olduğu için bu iki değerin toplamını yani 110 değerini elde ettik.