Windows Workflow Foundation State Machine

State Machine türü duruma dayalı işakışı yaklaşımlarını uygulayabilmek için WWF içerisinde kullanabileceğimiz bazı yapılar bulunmaktadır. Bu tür senaryolarda belirli durumlar ve bu durumlar arasında geçişleri tetikleyen olaylardan bahsetmek mümkündür.

 

Şimdi bu yaklaşımı nasıl uygulayacağımızı, kullanıcından alınacak bir bilgiyi işleyip sonuca ulaştıracağımız bir durumu örnekleyen basit bir senaryo üzerinden inceleyelim. Öncelikle visual studio dan yeni bir proje oluşturarak işe başlıyoruz. Proje şablonu olarak State Machine Console Application türünü seçiyoruz.

 

* Projeyi yarattıktan sonra açılan tasarım aracında ilk olarak senaryomuzda geçen durumları State türü öğelerle oluşturuyoruz.

 

 

* İkinci adımda bu durumlar arasında geçiş için kullanılacak olayları (event) tanımlıyoruz. Bunun için projeye bir Interface ekliyoruz ve içerisini aşağıdaki gibi dolduruyoruz:

 

 

 

 

 

 

 

 

 

 

Events.cs

 


[ExternalDataExchange]
public interface
Events
{
event
EventHandler<ExternalDataEventArgs> Run;
event
EventHandler<ExternalDataEventArgs> Stop;
event
EventHandler<ExternalDataEventArgs> Restart;
}

 

Burada dikkat edilmesi gereken Interface in [ExternalDataExchange] özelliğinin belirtilmiş olması ve eventlerin parametre olarak EventHandler almasıdır.

 

* Üçüncü adımda bu eventleri kullanılabilir kılmak için durumlarımızın içerisinden erişilebilir olmasını sağlıyoruz. Bunun için her durumun içerisine EventDriven öğesini, onun da içine HandleExternalEventActivity öğesini koymamız ve bunun özelliklerini aşağıdaki gibi belirlememiz gerekiyor.

 

 

Daha önceden tanımlamış olduğumuz Events interface ini InterfaceType olarak ve bu duruma geçilmesi için gereken olayı da Stop olarak belirliyoruz.

 

* Daha sonra bu durum bittikten sonra geçilmesi gereken durumu belirlemek için EventDriven öğesi içerisine SetState öğesini de ekliyoruz. Ve TargetStateName özelliğini DevamEt olarak belirtiyoruz.



Buraya kadar yaptığımız işlemleri diğer bütün olaylar için de yapıyoruz. Bu sayede durumlar arasında akışın nasıl olması gerektiğine dair kuralları tanımlamış oluyoruz.



Başlangıç durumunun hangisi olacağına ise seçip sağ tıkladıktan sonra Set As Initial State diyerek karar veriyoruz.

Durumların kendi içlerinde bazı işler yapabilmesini sağlamak için de her durum içerisine StateInitializationActivity öğesi ekleyip onun da içerisine CodeActivity öğesi ekliyoruz. CodeActivity için ExecuteCode eventi tanımlayıp içerisine yapmak istediğimiz işlemleri yazıyoruz.

 


private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Başlangıç durumunda.");
}

private void codeActivity2_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("DevamEt durumunda");
}
private void codeActivity3_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Bitti durumunda");
}

 

* İşakışı tasarımımızı bitirdikten sonra bunun nasıl kullanılacağına bakalım. Önce yukarıda belirtilen Interface i tanımlayan Demo isimli bir sınıf oluşturuyoruz.

 


Demo.cs

[Serializable]
public class
Demo : Events
{

 


#region Events Members

 

 

public event EventHandler<SYSTEM.WORKFLOW.ACTIVITIES.ExternalDataEventArgs> Run;

 

public event EventHandler<SYSTEM.WORKFLOW.ACTIVITIES.ExternalDataEventArgs> Stop;

 

public event EventHandler<SYSTEM.WORKFLOW.ACTIVITIES.ExternalDataEventArgs> Restart;

 

 

#endregion

 

 

public Demo()
{
}

 

 

public void RunMachine(Guid id)
{
if (Run != null)
Run(this, new System.Workflow.Activities.
ExternalDataEventArgs(id));
}

 

public void StopMachine(Guid id)
{
if (Stop != null)
Stop(this, new System.Workflow.Activities.
ExternalDataEventArgs(id));
}

 

public void RestartMachine(Guid id)
{
if (Restart != null)
Restart(this, new System.Workflow.Activities.
ExternalDataEventArgs(id));
}

 

}

 

Daha onra üzerinde çalıştıracağımız uygulamada (host) aşağıdaki düzenlemeleri yaparak nasıl çalıştığını görebiliriz.

 

Program.cs

 


static void Main(string[] args)

 

{

 


using(
WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{

//Üzerinde çalıştıracağımız servis
ExternalDataExchangeService dataService = new ExternalDataExchangeService();
workflowRuntime.AddService(dataService);

 

// Servise hazırladığımız Demo sınıfından oluşturduğumuz nesneyi tanımlıyoruz

 

Demo stateMachineDemo = new Demo();
dataService.AddService(stateMachineDemo);

 

//Otomatik üretilen kod

 

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();
};

 

 

//Burada tanımlayacağımız Guid servisler arasında taşınarak iletişimde kimliklendirmeyi sağlayacak

//Bu kısıma dikkat !! Otomatik üretilen kod sadece 2 parametre alır

Guid instanceGuid = Guid.NewGuid();
WorkflowInstance instance =
workflowRuntime.CreateWorkflow(typeof(WorkflowStateMachineDemo.
Workflow1), null, instanceGuid);

 


instance.Start();

 

Console.WriteLine("Çalıştırmak için bir tuşa basınız.");
Console.ReadLine();
stateMachineDemo.RestartMachine(instanceGuid);

Console.WriteLine("Devam durumuna geçmesi için bir tuşa basınız.");
Console.ReadLine();
stateMachineDemo.RunMachine(instanceGuid);

Console.WriteLine("Bitti durumuna geçmesi için bir tuşa basınız.");
Console.ReadLine();
stateMachineDemo.StopMachine(instanceGuid);

Console.WriteLine("Başlangıç durumuna geçmesi için bir tuşa basınız.");
Console.ReadLine();
stateMachineDemo.RestartMachine(instanceGuid);

 

Console.ReadLine();
waitHandle.WaitOne();
}
}

 

 

Projeyi çalıştırırsak göreceğimiz ekran :