https://buraksenyurt.com/Burak Selim Şenyurt - WF 4.0 Beta 12009-10-21T09:34:23+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://buraksenyurt.com/post/WF-40-Kod-Yoluyla-Workflow-Service-Olusturmak-KullanmakWF 4.0 - Kod Yoluyla Workflow Service Oluşturmak, Kullanmak [Beta 1]2009-10-16T00:00:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2009%2f10%2fblg90_Giris.jpg" alt="" />Merhaba Arkadaşlar,</p>
<p>Yükseklik korkum olmasına rağmen her zaman yandaki gibi tırmanışta olanlara imrenmişimdir. Bu fotoğrafa konu olan kişinin tek yaptığı yoğun bir mücadele ve efor ile yukarı doğru tırmanmaktır. Bana göre sonuçta elde edilebilecek tek şey zirveye ulaşmak ve oranın eşsiz manzarasını izlemekten ibarettir. Tabi bunun birde inişi olduğunu düşünmek gerekiyor <img title="Sealed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-sealed.gif" alt="Sealed" border="0" /> Hangi açıdan bakarsak bakalım bizde hayatımızda zaman zaman böyle mücadeleler içerisine gireriz. Özellike yazılım geliştirirken <img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /></p>
<p>Örneğin her zaman elimizin altında <strong>Visual Studio IDE' </strong>sinin sunduğu gibi gelişmiş arayüzler bulunmayabilir. Örneğin <strong>Visual Studio 2010 Beta 1</strong> üzerinde yaşadığım sorunlardan birisi <strong>WPF</strong> tabanlı <strong>Designer' </strong>ı<strong> Workflow </strong>uygulamaları için kullanamıyor oluşumdu. Bu gerçekten çok üzücü bir durum. <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> Ama çaresiz değiliz. Çaresizliğin çözümü bazı işlemleri basit bir <strong>Console</strong> uygulamasında, gereklilikleri fark ederek<em>(örneğin hangi <strong>Assembly'</strong> ların referans edilmesinin gerektiğinin bilinmesi...)</em>, kod bazında yapmaktan ibarettir. Bunun bize sağlayacağı pek çok fayda bulunmaktadır.</p>
<p>Kod tarafında her ne kadar mücadeleci bir yol izlesekte, neyin nasıl oluşturulması gerektiğini, hangi durumlarda ne gibi istisnalara(Exceptions) düşebileceğimizi, nelere ihtiyaç duyduğumuzu ve arka planda aslında işlemlerin nasıl değerlendirildiğini görmek açısından yararlı bir yoldur. Bu kadar cümleyi elbetteki sizi yazının kalanına motive etmek için sarfettiğimi düşünebilirsiniz. <img title="Cool" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cool.gif" alt="Cool" border="0" /> Haydi gelin kamera arkasına bakalım.</p>
<blockquote>
<p>Kişisel Not : Aslında Beta 2 sürümünde(ki henüz public olarak yayınlanmadığını biliyorsunuz), designer tarafındaki sorunların aşıldığını ifade edebilirim. Bizzat tecrübe ile sabitlenmiştir <img title="Smile" src="/editors/tiny_mce3/plugins/emotions/img/smiley-smile.gif" alt="Smile" border="0" /> Hatta bu konu ile ilişkili bir yazımı söz konusu sürüm public hale geldikten sonra yayınlıyor olacağım.</p>
</blockquote>
<p>Bu yazımızda <strong>.Net Framework 4.0 Beta 1</strong> ile bir <strong>Workflow Service' </strong>in oluşturulması, host edilmesi ve bir istemci tarafından kullanılması konusu irdelenmeye çalışılacaktır. <strong>Workflow Service </strong>tek yönlü bir operasyon<strong>(One Way)</strong> için hizmet vermekte olup istemci tarafına bir geri bildirimde bulunmamaktadır. Her iki uygulamada birer <strong>Console Application</strong> olarak tasarlanmıştır. İstemci tarafında <strong>Workflow Service' </strong>in kullanılabilmesi için gerekli <strong>Proxy </strong>nesnesi yine kod yardımıyla<em>(WSDL dökümanından yararlanmadan)</em> oluşturulmaktadır. Aslında tamamlanmış olan uygulamalara baktığımızda servis ve istemci tarafı için gerekli olan referans <strong>Assembly'</strong> ların aşağıdaki şekilde görüldüğü gibi olduğunu fark edebiliriz.</p>
<p><img src="/pics/2009%2f10%2fblg90_RequiredReferences.gif" alt="" /></p>
<p>Tamam çok güzel ama biz bu yazımızda tam olarak neyi hedeflemekteyiz?</p>
<p>Yapmak istediğimiz ilk şey <strong>WF 4.0</strong> bazlı olarak bir <strong>Workflow Service</strong> geliştirmek olacaktır. Bilindiği üzere <strong>Workflow Service'</strong> ler, istemcilerin uzaktan erişerek başlatabileceği akışları içerebilecek hizmetler olarak düşünülebilir. Öyleyse <strong>Workflow Service' </strong>in istemciden gelecek talepleri alabilmesi, gerektiğinde istemciye dönüş yapabilmesi ve kendi içerisinde bir akışı barındırması gerekmektedir.</p>
<p>Tahmin edileceği üzere istemci üzerinden gelecek taleplerin alınması veya cevapların gönderilmesi sırasında hazır aktivite bileşenlerinden yararlanılır. Örneğin <strong>Receive</strong> veya <strong>SendReply</strong>...Elbette bu tip bir servisin geliştirilmesi yeterli değildir. Bu servisin istemcilere hizmet verebilmesi için ayrıca host edilmesi de gerekmektedir. İstemci tarafı ise standart bir <strong>Console, WinForms, WPF, Asp.Net </strong>ucu olabileceği gibi başka bir <strong>Workflow Service </strong>de olabilir. Biz işe ilk olarak <strong>Workflow Service</strong> tarafını geliştirerek başlayacağız. Bu amaçla <strong>WithWCF</strong> isimli <strong>Console </strong>uygulamamızın kodlarını aşağıdaki gibi geliştirdiğimizi düşünebiliriz.</p>
<p>Workflow Service tarafı kodları;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
using System.Activities.Statements;
using System.ServiceModel;
using System.ServiceModel.Activities;
using System.Xml.Linq;
namespace WithWCF
{
class Program
{
static void Main(string[] args)
{
// Örnekte yer alan akış tek-yönlü bir Workflow Service' idir. Sequence tipinden olan bu akış, Receive aktivitesi ile başlamakta olup istemciden gelen double tipinden değişkenin karekökünü hesaplamakta ama istemci tarafına bir bilgilendirmede bulunmamaktadır.
#region Sequence Aktivitesi Oluşturulma İşlemleri
// Sequence tipinden bir aktivite örneklenir
Sequence squareRootFlow = new Sequence();
// Aktivitede kullanılacak olan Variable tanımlamaları yapılır
Variable<double> number = new Variable<double>(); // Receive aktivitesi tarafından alınan değişken
Variable<double> square = new Variable<double>(); // Sonuç değişkeni
Variable<CorrelationHandle> corHandle = new Variable<CorrelationHandle>();
// Xml Namespace tanımlaması yapılır. XNamespace kullanılmadığı takdirde örneğin Receive aktitivesinin ServiceContractName özelliğine adres bilgisi text tabanlı olarak atandığında şekilde görülen exception üretilir.
XNamespace ns = "http://www.buraksenyurt.com/WF4";
// Variable tanımlamaları Sequence aktivitesinin Variables koleksiyonuna dahil edilir.
squareRootFlow.Variables.Add(number);
squareRootFlow.Variables.Add(square);
squareRootFlow.Variables.Add(corHandle);
// Akışın içerisinde yer alan ilk aktivite Receive tipindendir.
Receive receive1 = new Receive
{
OperationName="SquareRoot",
DisplayName="Square Root Calculation",
ServiceContractName = ns + "CalculatorService",
CanCreateInstance=true,
Value=new OutArgument<double>(number),
AdditionalCorrelations={
{"ChannelBasedCorellation",new InArgument<CorrelationHandle>(corHandle)}
}
};
// Receive aktivitesi ile istemciden gelen sayısal değer number değişkenine alındıktan sonra çalışan InvokeMethod aktivitesi ile Calculator isimli sınıf içerisindeki FindSquareRoot metodu çağırılır.
InvokeMethod<double> invokeMethod1 = new InvokeMethod<double>
{
TargetType=typeof(Calculator),
MethodName = "FindSquareRoot",
Result=new OutArgument<double>(square) // FindSquareRoot metodunun çalıştırılması sonucu elde edilen sonuç square isimli değişken tarafında yakalanabilecektir.
};
// Metoda parametre olarak number değişkeninin değeri gönderilir. Bu değer Receive aktivitesi içerisinde set edilmiş olup istemci tarafından gelmektedir.
invokeMethod1.Parameters.Add(new InArgument<double>(number));
// Ekrana bilgilendirme yapılır. Bu bilgilendirmede istemciden akışa gelen sayının karekökü yazdırılmaktadır.
WriteLine writeLine1 = new WriteLine
{
Text=new InArgument<string>(e=>String.Format("Sonuç {0}",square.Get(e).ToString()))
};
// Aktivitelere sırasıyla Sequence aktivitesi içerisine ilave edilir
squareRootFlow.Activities.Add(receive1);
squareRootFlow.Activities.Add(invokeMethod1);
squareRootFlow.Activities.Add(writeLine1);
#endregion
#region Workflow Servis Oluşturma İşlemleri
// Workflow' un Service olarak host edilmesi için gerekli hazırlıklar başlar.
// İlk olarak bir Service nesne örneği oluşturulur
Service service = new Service();
// Service nesne örneğinin Implementation özelliğine WorkflowServiceImplementation türünden bir referans atanırken, Body özelliğine yukarıda oluşturulan Workflow aktivitesi bildirilir
service.Implementation = new WorkflowServiceImplementation
{
Name = ns+"CalculatorService",
Body=squareRootFlow
};
// Sonuçta Workflow bir WCF servisi olarak host edileceğinden bir Endpoint bilgisine sahip olmalıdır
// Bu nedenle basit bir Endpoint bildirimi yapılır
// Örnekte Tcp bazlı servis iletişimi tercih edilmiştir
service.Endpoints.Add(new Endpoint
{
Uri = new Uri("SquareRoot", UriKind.Relative), //Address bilgisi
Binding=new NetTcpBinding(), // Binding bilgisi
ServiceContractName = ns + "CalculatorService" // Contract bilgisi(Burada verilen isim ile Receive aktivitesine ait ServiceContractName özelliğindeki değerler aynı olmalıdır. Aksi halde Exception2 alınır)
});
#endregion
// Workflow Service' i çalıştıracak olan WorkflowServiceHost nesnesi örneklenir
// İlk parametre host edilecek olan servistir. İkinci parametre ise servisin host edileceği adres bilgisidir.
WorkflowServiceHost host = new WorkflowServiceHost(service, new Uri("net.tcp://localhost:4501/Calculator/Workflows/"));
host.Open(); // Host açılır
Console.WriteLine(host.State.ToString()); //Hostun durumu hakkında bilgilendirme yapılır
Console.WriteLine("Kapatmak için bir tuşa basınız.");
Console.ReadLine();
host.Close(); //Host kapatılır
}
}
class Calculator
{
public double FindSquareRoot(double number)
{
return Math.Sqrt(number);
}
}
}</pre>
<p>Kod içerisinde işleyiş ile ilişkili gerekli açıklamalar bulunmaktadır.</p>
<p>Ancak geliştirme sırasında dikkat edilmesi gereken bazı durumlar da vardır. Örneğin <strong>XNamespace</strong> tipinin kullanılmaması, bunun yerine <strong>URL</strong> bilgisinin <strong>text</strong> tabanlı olarak atanması halinde çalışma zamanında aşağıdaki ekran görüntüsünde yer alan <strong>XmlException</strong> istisnası alınacaktır.</p>
<p><strong>Exception 1 (Xml Namespace kullanılmaması halinde);</strong></p>
<p><img src="/pics/2009%2f10%2fblg90_Exception.gif" alt="" /></p>
<p>Diğer yandan <strong>ServiceContractName</strong> değerinin hem <strong>Endpoint</strong> hemde <strong>Receive </strong>aktivitesi için aynı olması gerekmektedir ki aksi durumda aşağıdaki ekran görüntüsünde yer alan çalışma zamanı istisnası fırlatılmaktadır.</p>
<p><strong>Exception 2 (ServiceContractName' lerin Receive aktivitesi ve Endpoint içerisinde farklı olmaları halinde);</strong></p>
<p><img src="/pics/2009%2f10%2fblg90_Exception2.gif" alt="" /></p>
<p>Gelelim istemci tarafına. Bu noktada kendimizi yine zora sokuyor olacağız. <img title="Yell" src="/editors/tiny_mce3/plugins/emotions/img/smiley-yell.gif" alt="Yell" border="0" /> Elimizde servisin <strong>Publish</strong> edilen bir <strong>WSDL </strong>dökümanı olmadığını ve herhangibir şekilde <strong>Proxy </strong>üretimi için bir araç kullanmadığımızı farz edeceğiz. Bu durumda istemci tarafındaki <strong>proxy </strong>sınıfının ve hatta istemciden servis tarafına gönderilecek olan mesaj sözleşmesinin manuel kod ile oluşturulması gerekmektedir. Aynen aşağıda olduğu gibi;</p>
<p>İstemci tarafı sınıf diagramı;</p>
<p><img src="/pics/2009%2f10%2fblg90_ClientDiagram.gif" alt="" /></p>
<p>ve kodları;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.ServiceModel;
namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Başlamak için bir tuşa basınız");
Console.ReadLine();
// Binding oluşturulur
NetTcpBinding binding = new NetTcpBinding();
// Endpoint tanımlaması yapılır. Adres bilgisinin servisin yeri ve çağırılmak istenen operasyonun adıo yer almaktadır. Bu bilgileri service tarafındakiler ile aynı olmalıdır
EndpointAddress endpoint = new EndpointAddress("net.tcp://localhost:4501/Calculator/Workflows/SquareRoot");
// Kanal fabrikası üretilir. İlk parametre bağlayıcı ikinci parametre ise EndPoint bilgisidir
ChannelFactory<CalculatorService> factory = new ChannelFactory<CalculatorService>(binding, endpoint);
// Kanal fabrikasından yararlanılarak istemcinin kullanacağı Transparant Proxy nesnesi üretilir.
CalculatorService proxy = factory.CreateChannel();
// Talep oluşturulur ve parametre olarak servis tarafındaki akışın ilk aktivitesi olan Receive aktivitesinin alacağı sayısal değer bildirilir
SquareRootRequest request = new SquareRootRequest()
{
Number = 16
};
// Operasyon çağırılır
proxy.SquareRoot(request);
Console.WriteLine("İşlemler tamamlandı. Kapatmak için bir tuşa basınız.");
Console.ReadLine();
}
}
// Talep olarak gidecek mesaj sözleşmesi tanımlanır
[MessageContract(IsWrapped = false)]
public class SquareRootRequest
{
[MessageBodyMember(Namespace= "http://schemas.microsoft.com/2003/10/Serialization/",Name = "double")]
public double Number { get; set; }
}
// Proxy tanımlaması yapılır
// Workflow Servisi varsayılan isim alanı(namespace) ile sunulmadığından Namespace bildiriminin istemci tarafındaki proxy için açık bir şekilde yapılması gerekmektedir.
[ServiceContract(Namespace = "http://www.buraksenyurt.com/WF4")]
interface CalculatorService
{
[OperationContract(IsOneWay=true)] // Operasyonun OneWay olduğunu belirtmessek Exception3' teki çalışma zamanı hatasını alırız.
void SquareRoot(SquareRootRequest request);
}
}</pre>
<p>Yine istemci tarafı açısından olaya baktığımızda dikkat etmemiz gereken bazı hususlar olduğu ortadadır. Örneğin, <strong>Workflow Service</strong> içerisinden geriye bir dönüş yapılmamaktadır. Bir başka deyişle tek yönlü bir istek söz konusu olabilir. Bu nedenle istemci tarafındaki <strong>SquareRoot </strong>metoduna uygulanan <strong>OperationContract </strong>niteliğinde <strong>IsOneWay </strong>özelliğine <strong>true </strong>değeri atanmıştır. Bu yapılmadığı takdirde çalışma zamanında aşağıdaki istisna mesajı ile karşılaşılacaktır.</p>
<p><strong>Exception 3 (Service operasyonunun OneWay olduğunu belirtmediğimiz durumda);</strong></p>
<p><img src="/pics/2009%2f10%2fblg90_Exception3.gif" alt="" /></p>
<p>Piuuuuuvvvvv!!! <img title="Smile" src="/editors/tiny_mce3/plugins/emotions/img/smiley-smile.gif" alt="Smile" border="0" /> Biraz uğraştık ama faydalı bir çalışma oldu sanıyorum ki. Gerçi elde edeceğimiz sonuç hiç bir anlam ifade etmesede, bir Workflow Service' in kod yardımıyla nasıl oluşturulabileceğini ve kullanılacağını görmüş olduk. İşte bir yazılımcı olarak tırmandığımız dağın zirvesindeki görüntü...</p>
<p><img src="/pics/2009%2f10%2fblg90_Runtime.gif" alt="" /></p>
<p>Ne kadar muhteşem değil mi? <img title="Tongue out" src="/editors/tiny_mce3/plugins/emotions/img/smiley-tongue-out.gif" alt="Tongue out" border="0" /> Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f10%2fWithWCF.rar">WithWCF.rar (42,98 kb)</a></p>
<blockquote>
<p style="text-align: left;">Kişisel Not : Örnekler bildiğiniz üzere Visual Studio 2010 Beta 1 sürümünde ve .Net Framework Beta 1 üzerinde geliştirilmektedir. Beta 2 ile arasında farklılıklar olabilir. Hatta Relase sürümde çok daha fazla farklılık görülebilir<strong><em>.</em></strong></p>
</blockquote>2009-10-16T00:00:00+00:00wfwf 4.0wcfwcf 4.0bsenyurtÖrneğin her zaman elimizin altında Visual Studio IDE' sinin sunduğu gibi gelişmiş arayüzler bulunmayabilir. Örneğin Visual Studio 2010 Beta 1 üzerinde yaşadığım sorunlardan birisi WPF tabanlı Designer' ı Workflow uygulamaları için kullanamıyor oluşumdu. Bu gerçekten çok üzücü bir durum.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=c447a286-e853-4458-9e26-197b0e9a20870https://buraksenyurt.com/trackback.axd?id=c447a286-e853-4458-9e26-197b0e9a2087https://buraksenyurt.com/post/WF-40-Kod-Yoluyla-Workflow-Service-Olusturmak-Kullanmak#commenthttps://buraksenyurt.com/syndication.axd?post=c447a286-e853-4458-9e26-197b0e9a2087https://buraksenyurt.com/post/WF-40-Veri(Data)WF 4.0 - Veri(Data)[Beta 1]2009-10-12T14:48:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Bir süredir <strong>Workflow Foundation 4.0 </strong>ile ilişkili blog yazılarını, makaleleri ve görsel dersleri takip etmekteyim. Bu araştırmalarım sırasında <strong>Workflow Foundation 4.0 </strong>modelinde <strong>veriye(Data) </strong>olan bakış açısının <strong>WF 3.X </strong>sürümüne göre oldukça farklılaştığını gördüm. <strong>WF 3.X </strong>tabanlı modelde, aktivite bazlı verileri temsil etmek için genellikle standart sınıf <strong>özelliklerinden(Property)</strong> veya <strong>WPF'</strong> ten esinlenilen <strong>bağımlı özelliklerden(Dependency Property)</strong> yararlanılmaktadır. <strong>WF 4.0</strong> modelinde ise veriyi temsil etmek amacıyla <strong>Variable</strong> veya <strong>Argument</strong> türevli tiplerden yararlanıldığı görülmektedir.</p>
<p>Bu tiplerin türevleri veriyi doğrudan tutmazlar. Bunun yerine veriyi tanımlar ve elde edilmesini sağlarlar. Verinin içeriği <strong>Workflow</strong> üzerinde bir yerlerde saklanmaktadır. Bu noktada <strong>Variable </strong>kavramını aynen <strong>Imperative</strong> programlama dillerindeki kullanılış biçimi ile düşünebiliriz. Bu nedenle <strong>Variable</strong> veya <strong>Argument </strong>türevli tipler tanımlandıkları scope dahilinde kullanılabilirler. Dolayısıyla bir <strong>Variable </strong>bir Workflow için <strong>kök seviyede(Root Level) </strong>tanımlanırsa tüm alt aktiviteler tarafından kullanılabilir. Bugünkü örneğimizde <a title="WF 4.0 - Workflow ve Object Initialization" href="https://buraksenyurt.com/post/WF-40-Workflow-ve-Object-Initialization.aspx" target="_blank">bir önceki blog </a>yazımızda olduğu gibi kod bazlı bir <strong>Workflow</strong> örneği geliştirecek ve <strong>Variable</strong> kullanımı ile veriyi nasıl ele alacağımızı görmeye çalışacağız. Aslında .Net 4.0 içerisindeki oluşuma baktığımızda <strong>Variable<T></strong> için <strong>Variable</strong> isimli bir abstract sınıftan türetme yapıldığını görebiliriz. Aşağıdaki sınıf diyagramında bu durum görülmektedir.</p>
<p><img src="/pics/2009%2f10%2fblg89_ClassDiagram.gif" alt="" /></p>
<p>Burada dikkat edilmesi gereken noktalardan birisi, <strong>Variable<T></strong> tipinin <strong>sealed </strong>olarak tanımlanmış olmasıdır. Yani kendisinden türetme yapamayız. Diğer yandan <strong>Variable </strong>tipi <strong>abstract </strong>bir sınıftır ve bu nedenle kendisinden türetme yapılarak özel <strong>Variable </strong>türevlerinin üretilmesi mümkündür.</p>
<p>Evet bu kadar laf kalabalığından sonra yeni veri modeline kısaca bakmaya çalışalım. Bu amaçla<strong> Visual Studio 2010 Beta 1</strong> üzerinden açtığımız basit bir <strong>Console</strong> projesini kullanıyor olacağız. Projede <strong>Workflow</strong> alt yapısını ele almak için tek yapmamız gereken<strong> System.Activities</strong> isimli <strong>assembly' </strong>ın referans edilmesi olacaktır.</p>
<p><img src="/pics/2009%2f10%2fblg89_ActivityReference.gif" alt="" /></p>
<p>Uygulama kodlarını ise aşağıdaki gibi geliştirdiğimizi düşünebiliriz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
using System.Activities.Statements;
namespace UsingVariables
{
class Program
{
static void Main(string[] args)
{
// Değişken tanımlanır. Tanımlanırken varsayılan olarak(Default) bir nesne örneğide verilir
Variable<Player> firstPlayer = new Variable<Player>
{
Name = "FirstPlayer",
Default = new Player { Name = "Zen-R2", Location = new Location { X = 10, Y = 12, Altitude = 100 }, PlayerType = PlayerType.Computer, TotalPoint=10 }
};
// Bir Sequence aktivitesi tanımlanır. Root aktivite.
Sequence gameFlow = new Sequence();
// Variable Sequence nesne örneğinin Variables koleksiyonuna eklenir.
gameFlow.Variables.Add(firstPlayer);
// Atama işlemi için basit bir Assign aktivitesi gameFlow isimli Sequence nesne örneğinin Activities koleksiyonuna eklenir.
// To kısmında kime atama yapılacağı belirlenir. Tasarım zamanından farklı olarak bir expression kullanılır. firstPlayer isimli değişkenin işaret ettiği veri alanında TotalPoint değeri alınır.
// Value özelliğine verilen değer ile atama yapılır. Atamada o anki variable' ın TotalPoint değeri 10.1 birim arttırılmaktadır.
gameFlow.Activities.Add(
new Assign<double>() {
To=new OutArgument<double>(v=>firstPlayer.Get(v).TotalPoint),
Value=new InArgument<double>(v=>firstPlayer.Get(v).TotalPoint+10.1)
}
);
// Örnek olarak birde Location özelliğinin işaret ettiği içerik değiştirilmektedir.
gameFlow.Activities.Add(
new Assign<Location>()
{
To = new OutArgument<Location>(v => firstPlayer.Get(v).Location),
Value = new Location { X = 10, Y = 15, Altitude = 99 }
}
);
// Ekrana bilgi yazdırmak için WriteLine tipinden bir aktivite daha eklenir
// Text özelliğinde ekrana bilgi yazdırabilmek için InArgument nesne örneğinden yararlanılır ve o anki firstPlayer variable' ının Name ve TotalPoint değerleri yazdırılır.
gameFlow.Activities.Add(
new WriteLine {
Text=new InArgument<string>(v=>String.Format("{0} isimli oyuncunun puanı {1}. Deniz seviyesinden yüksekliği {2}",firstPlayer.Get(v).Name,firstPlayer.Get(v).TotalPoint.ToString(),firstPlayer.Get(v).Location.Altitude))
}
);
// gameFlow isimli Workflow çağırılır ve başlatılır
WorkflowInvoker.Invoke(gameFlow);
}
}
class Player
{
public string Name { get; set; }
public Location Location { get; set; }
public PlayerType PlayerType { get; set; }
public double TotalPoint { get; set; }
}
class Location
{
public double X { get; set; }
public double Y { get; set; }
public double Altitude { get; set; }
}
enum PlayerType
{
Computer,
Human,
Hybrid
}
}</pre>
<p>Örneğin herhangibir gerçek hayat işlevselliği bulunmamaktadır ancak kullanıcı tanımlı bir tipten<em>(örneğimizde Player isimli sınıf)</em> oluşturulan <strong>Variable'</strong> ın <strong>Sequence </strong>tipinden bir nesne örneği içerisinde nasıl değerlendirilebildiği açık bir şekilde görülmektedir. Aslında konsept son derece basittir. <strong>Variable<T> </strong>tipinden bir nesne örneği tanımlanırken <strong>Default </strong>özelliği ile ilk değer ataması yapılmaktadır ki zorunlu değildir. Yani <strong>Variable' </strong>ın içeriği akışa dışarıdan gelebilir. Sonrasında bu değişkenin kullanılmak istenen scope içerisine bildirilmesi gerekmektedir. Örnekte <strong>gameFlow </strong>isimli <strong>Sequence </strong>aktivite örneğinin <strong>Variables </strong>koleksiyonuna yapılan ekleme ile bu bildirim gerçekleştirilmektedir. Nitekim söz konusu değişkeninin, içeride yer alan tüm aktiviteler tarafından kullanılması istenmektedir.</p>
<p>Kodun ilerleyen kısımlarında sembolik olarak <strong>firstPlayer </strong>isimli <strong>Variable<Player> </strong>tipine ait özelliklerin bazılarında değişiklikler yapılmıştır. Bu işlemler için <strong>Expression' </strong>lardan yararlanılmaktadır. Değiştirme işlemlerinde dikkat edileceği üzere <strong>Assign<T> </strong>isimli aktiviteden yararlanılmaktadır. İlk Assign aktivitesine ait <strong>To </strong>ve <strong>Value </strong>özelliklerinde <strong>InArgument </strong>ve <strong>OutArgument </strong>tiplerinden yararlanılarak verinin elde edilmesi ve değer ataması işlemleri yapılmaktadır.</p>
<p>İkinci Assign aktivitesinde ise generic olarak Location tipi belirtildiğinden Value kısmında doğrudan yeni bir Location nesne örneğine atama yapılmaktadır. Her iki aktivite içinde dikkat edilmesi gereken noktalardan birisi, değeri alınmak istenen özelliğe erişilirken <strong>firstPlayer </strong>isimli değişkenin <strong>Get </strong>metodundan yararlanılıyor olmasıdır. Zaten kodlama sırasında <strong>intelli-sense </strong>özelliği devreye girmekte ve <strong>Get </strong>metodu sonrasında kullanılabilecek tüm <strong>Player</strong> tipi özellikleri gösterilmektedir. Programda son olarak <strong>Workflow </strong>örneğinin çalıştırılması sağlanmaktadır. Uygulamanın çalışma zamanı görüntüsü aşağıdaki gibi olacaktır.</p>
<p><img src="/pics/2009%2f10%2fblg89_WfRuntime.gif" alt="" /></p>
<p>Dikkat edileceği üzere başlangıçta 10 olan puan 10.1 birim arttırılmış ve Location tipi üzerinde tutulan Altitude değeride 1 birim azaltılmıştır.</p>
<p>Elbette <strong>Workflow 4.0' </strong>ın <strong>WPF </strong>tabanlı bir <strong>IDE </strong>kullanıyor olması göz ardı edilemez. Bir başka deyişle söz konusu <strong>Variable </strong>ekleme işlemleri aslında tasarım zamanında çok daha kolay bir şekilde gerçekleştirilebilmektedir. Ancak yazıyı hazırladığım zaman diliminde kullandığım ve public olan <strong>Visual Studio 2010 Beta 1 </strong>sürümüne ait <strong>WF designer </strong>ne yazıkki IDE tekrardan başlatılmasına nedenl olmaktadır. <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> Bu nedenle şimdilik kod tarafı ile idare etmeniz gerekiyor.<img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f10%2fUsingVariablesV2.rar">UsingVariablesV2.rar (26,44 kb)</a></p>2009-10-12T14:48:00+00:00wfwf 4.0bsenyurtBir süredir Workflow Foundation 4.0 ile ilişkili blog yazılarını, makaleleri ve görsel dersleri takip etmekteyim. Bu araştırmalarım sırasında Workflow Foundation 4.0 modelinde veriye(Data) olan bakış açısının WF 3.X sürümüne göre oldukça farklılaştığını gördüm.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=a6a5eee2-dc36-450c-ac87-e334853dc5e40https://buraksenyurt.com/trackback.axd?id=a6a5eee2-dc36-450c-ac87-e334853dc5e4https://buraksenyurt.com/post/WF-40-Veri(Data)#commenthttps://buraksenyurt.com/syndication.axd?post=a6a5eee2-dc36-450c-ac87-e334853dc5e4https://buraksenyurt.com/post/WF-40-Workflow-ve-Object-InitializationWF 4.0 - Workflow Yapısı ve Object Initialization[Beta 1]2009-10-04T23:29:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p><strong>Workflow Foundation 4.0</strong> ile ilgili yenilikleri araştırdığım şu günlerde, yaptığım araştırmalar sırasında ilgimi çeken noktalardan biriside, bir <strong>Workflow' </strong>un kod tarafında tek bir <strong>ifade satırı </strong>ile oluşturulabiliyor olmasıydı. Burada <strong>Workflow </strong>sisteminin hiyerarşik yapısının, <strong>Object Oriented </strong>seviyede etkili bir kullanımının söz konusu olduğunu belirtmek isterim. Ancak konuya çekirdek bilgilerden başlayarak yaklaşmakta yarar var.</p>
<p><strong>Workflow</strong> içerisindeki lego parçalarının temelini <strong>aktiviteler(Activities) </strong>oluşturmaktadır. <strong>WF 4.0</strong> mimarsinde tüm aktiviteler <strong>WorkflowElement</strong> bileşeninden türemektedir. Aktivitleri aslında <strong>Workflow' </strong>ların <strong>iş birimleri(Work Units) </strong>olarak düşünebiliriz. İki ve daha fazla iş biriminin bir araya gelerekten aktivite oluşturmaları da çok doğal olarak mümkündür. Aslında buradan ilginç olan bir tespit vardır. Bir aktivite, hiyerarşinin en üstünde yer alıyorsa bir <strong>Workflow </strong>halini alır ve kendi içerisinde pek çok aktiviteyi barındırabilir. Bunu şu şekilde de düşünebiliriz; <strong>"Bir metodun kendi içerisinde birden fazla metodu çağırması". </strong></p>
<p>Nitekim metodun kendi içerisinde çağırdığı ardışıl fonksiyonlar, yukarıdan aşağıya doğru hareket eden bir iş akışını oluşturmaktadır. Bu açıdan bakıldığında<strong> Workflow Foundation </strong>olmasa dahi, kod bazında iş akışlarının en temel seviyede fonksiyonlar yardımıyla gerçekleştirilebileceğini bilmek gerekir<em>(Hatta çalıştığım son projede bu tip bir mimari kullanılmaktadır).</em> <strong>Workflow Foundation 3.X </strong>sürümünden beridir <strong>Sequence </strong>gibi <strong>üst seviye(Top Level) </strong>aktiviteleri barındırmaktadır. Bunlar <strong>Top Level </strong>olarak kullanıldıklarında bir Workflow' u ifade etmektedir. Tabiki <strong>Sequence </strong>örnekleri kendi içlerinde başka <strong>Sequence </strong>örnekleri de barındıralabilirler. </p>
<p>Burada ilginç olan noktalardan birisi, <strong>Workflow'</strong> ları sadece tek bir ifade içerisinde oluşturabilmemizdir. <img title="Surprised" src="/editors/tiny_mce3/plugins/emotions/img/smiley-surprised.gif" alt="Surprised" border="0" /> Bunun için <strong>nesne başlatıcılarından(Object Initializers)</strong> yararlanılmaktadır. Nasıl mı? Gelin <strong>Visual Studio 2010 Beta 1</strong> üzerinde basit bir <strong>Console Application </strong>oluşturup <strong>Program.cs </strong>içeriğini aşağıdaki gibi oluşturduğumuz düşünelim.</p>
<blockquote>
<p>Not: Console uygulaması üzerinde Workflow aktivitileri kullanılacağından, projeye System.Activities.dll Assembly' ının referans edilmesi gerekmektedir.</p>
</blockquote>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace WorkflowStructure
{
using System;
using System.Activities;
using System.Activities.Statements;
class Program
{
static void Main(string[] args)
{
// Yeni bir Sequence aktivitesi oluşturulur. Top Level olduğu için workflow' un kendisidir.
// Tek satırlık ifade içerisinde bir Workflow tanımlandığına dikkat edilmelidir
Sequence flow1 =new Sequence
{
DisplayName = "Hello Workflow World",
// Activity tipinden elamanlar taşıyan koleksiyonun içerisinde alt aktiviteler tanımlanır
Activities =
{
new WriteLine{ DisplayName="Workflow Start", Text="Starting..."},//Basit bir WriteLine aktivitesi
new InvokeMethod{ DisplayName="5 Times Say Hello", MethodName="SayHello", TargetType=typeof(Logic)} // Logic sınıfından SayHello metodunu çağıracak olan InvokeMethod aktivitesi tanımlanır
}
};
WorkflowInvoker.Invoke(flow1); // Workflow örneği çalıştırılır :)
}
}
// Harici bir sınıf ve metod
class Logic
{
public static void SayHello()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("\tHello");
}
}
}
}</pre>
<p>Bu örnek kod parçasında <strong>Sequence</strong> tipinden bir nesne örneği oluşturulmaktadır. Nesne oluşturulurken, <strong>Activities </strong>özelliği içerisinde alt aktivite örnekleri kullanılmıştır. <strong>Activities </strong>özelliği <strong>Collection<Activity> </strong>tipinden bir koleksiyonu işaret etmektedir. Dolayısıyla herhangibir <strong>Activity </strong>referansına ait örnek, söz konusu koleksiyona eklenerek akışın gövdersi oluşturulabilir. Örnekte ilk olarak <strong>System.Activities.Statements </strong>isim alanında yer alan <strong>WriteLine </strong>aktivite bileşeni kullanılarak ekrana basit bir çıktı verilmektedir. Takip eden adımda, <strong>InvokeMethod </strong>aktivite bileşeni kullanılmaktadır. Bu bileşenin özellikleri ile, <strong>Logic </strong>sınıfı içerisinde yer alan <strong>SayHello </strong>metodunun çalıştırılacağı belirtilmiştir<em>(Burada <strong>TargetType </strong>veya <strong>TargetObject </strong>özelliklerinden birisinin mutlaka set edilmesi gerekir. </em></p>
<p><em>Böylece <strong>MethodName </strong>özelliğinde belirtilen fonskiyonun çalışma zamanında hangi tipe ait nese örneği içerisinden çağırılacağı belirtilmiş olur)</em> Tabiki <strong>flow1 </strong>isimli <strong>Sequence </strong>nesne örneğinin çalıştırılması için <strong>WorkflowInvoker</strong> tipi üzerinden <strong>static Invoke </strong>metodu kullanılmıştır. Olaya noktalı virgüller açısından baktığımızda sadece iki satırda bir Workflow' un tasarlanıp yürütüldüğünü ifade edebiliriz. Ancak görsel bir tasarım ortamının olması elbetteki çok daha mühimdir ve tercih edilmelidir. Nitekim gerçek hayat çözümlerindeki iş akışlarının çoğu bu kadar basit Workflow örnekleri ile ifade edilememektedir. Geliştirdiğimiz <strong>Workflow</strong> herhangibir anlam içermesede <img title="Smile" src="/editors/tiny_mce3/plugins/emotions/img/smiley-smile.gif" alt="Smile" border="0" /> önemli olan, tek satırlık bir ifade ile <strong>object initializer</strong> kavramından da yararlanarak, bir <strong>Workflow </strong>örneğinin tesis edilebileceğinin farkında olmaktır. Örneği yürüttüğümüzde çalışma zamanı için aşağıdaki sonuçları aldığımızı görürüz.</p>
<p><img src="/pics/2009%2f10%2fblg88_Runtime.gif" alt="" /></p>
<p>Görüldüğü üzere akış başarılı bir şekilde işletilmiştir. Bu kısa yazımızda <strong>Workflow</strong> yapısının kod tarafında <strong>Object Initializers </strong>yardımıyla ele alınışını incelemeye çalıştık. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f10%2fWorkflowStructure.rar">WorkflowStructure.rar (19,38 kb)</a></p>2009-10-04T23:29:00+00:00wf 4.0bsenyurtWorkflow Foundation 4.0 ile ilgili yenilikleri araştırdığım şu günlerde, yaptığım araştırmalar sırasında ilgimi çeken noktalardan biriside, bir Workflow' un kod tarafında tek bir ifade satırı ile oluşturulabiliyor olmasıydı.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=43b741c1-89aa-4e7b-afdc-31373cca38670https://buraksenyurt.com/trackback.axd?id=43b741c1-89aa-4e7b-afdc-31373cca3867https://buraksenyurt.com/post/WF-40-Workflow-ve-Object-Initialization#commenthttps://buraksenyurt.com/syndication.axd?post=43b741c1-89aa-4e7b-afdc-31373cca3867https://buraksenyurt.com/post/5000-Feet-Yuksekten-Workflow-Foundation-405000 Feet Yüksekten Workflow Foundation 4.0[Beta 1]2009-10-01T13:54:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2009%2f9%2fblg86_Giris.jpg" alt="" />Merhaba Arkadaşlar,</p>
<p>Paraşütle atlamak gerçekten zevkli olsa gerek. Yerden binlerce feet(1 feet=30,48 cm) yüksekten atlayıp özgür bir şekilde kendinizi yer çekimi gücüne bırakıp, saniyeler boyunca serbest düşüşü yaşamak...Size yandaki resimde atlayan kişinin ben olduğumu söylemek isterdim ama ne yazık ki değilim. Olmayı istermiydim bilemiyorum. Oldukça yüksek görünüyor. <img title="Sealed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-sealed.gif" alt="Sealed" border="0" /> Bir paraşütçü için en güzel duygulardan birisi sanıyorum ki atladığı noktadan itibaren altındaki Dünyayı görebildiği kadar yüksekten izleyebilmenin verdiği mutluluktur.</p>
<p>Tabiki atlanılan noktadan aşağıya doğru düştükçe ve paraşütü çekme noktasına yaklaştıkça alttaki Dünyanın resimlerinin daha da büyüdüğü çok açık bir gerçektir. Büyük bir dikdörten alan...Sonrasında içerisinde başka geometrik şekiller...Sonrasında bu geometrik şekiller içerisinde daha da netleşen çayırlar, dağlar, kayalar, yollar, binalar...Sonrasında bir anlık yavaşlama ve sakin bir şekilde(bazende hızlı bir şekilde) yere ayak basmak. Kısaca yaşanan bu duruma<strong> "yüksekten görülebileceği kadar büyük bir alanı görüp, yaklaştıkça daha fazla detay fark edebilmek durumu"</strong> <img title="Cool" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cool.gif" alt="Cool" border="0" /> adını verebiliriz. Şimdi bu noktaya nereden vardım diyebilirsiniz. Hemen açıklayayım.</p>
<p>Yazılım ile ilişkili pek çok kaynakta şu tip başlıklar görmüşsünüzdür.<strong> 50 bin feet yukarıdan X mimarisi</strong>...İşte bizde bu felsefeyi bu günkü blog yazımızda kullanıyor olacağız. Ama biraz daha alçak mesafeden <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /></p>
<p><strong>5000 feet yukarıdan fotoğraflandığında, WF 4.0 modelinin ne gibi özellikleri dikkat çekiyor?</strong> İşte görülen tespitler...</p>
<ul>
<li><strong>WF 3.X</strong>' teki kısıtlı olan <strong>XAML </strong>bazlı <strong>Workflow </strong>modeli yerini <strong>tam desteklenen(Full XAML Based) Workflow </strong>modeline bırakıyor. Böylece bir Workflow' un basit bir text editorü yardımıyla tamamen <strong>dekleratif(declerative)</strong> olarak geliştirilmesi ve çalışma zamanına devredilmesinin mümkün olabildiğini <em>(Bu özelliğin en önemli açılımlarından biriside, çeşitli 3ncü parti araçların <strong>XAML </strong>içeriklerini ele alarak akışları koda girmeden değiştirebilecek olmaları. <strong>Oslo, Dublin </strong>ve <strong>Quadrant </strong>üçlemesinin önemle üzerinde durduğu noktalardan biriside zaten bu dekleratif açılım.)</em></li>
<li><strong>WF 3.X' </strong>te daha zor olan <strong>özel aktivite(Custom Activity) </strong>geliştirme yeteneğinin <strong>WF 4.0 </strong>için daha da basitleştirildiğini ve bu amaçla temel workflow hiyerarşisinde de değişikliklere gidildiğini ve ata tip olarak <strong>WorkflowElement </strong>ve kendisinden türeyen <strong>Activity, CodeActivity, NativeActivity </strong>gibi alt tiplerin geliştirildiğini,</li>
<li><strong>WF 3.X' </strong>te ilkel ve daha az genişletilebilir olan <strong>kurallar motorunun(Rules Engine) </strong>dahada zenginleştirilmiş olduğunu,</li>
<li>Yeni <strong>Workflow</strong> bileşenlerinin <strong>System.Activities.* assembly' </strong>ları altında olduğunu ama <strong>.Net Framework 4.0 </strong>içerisinde yer alan ve <strong>geriye uyumluluk(Backwards Compatibility)</strong> amacıyla kullanılan <strong>Workflow </strong>bileşenlerininse <strong>System.Workflows.* assembly' </strong>ları içerisinde yer aldığını, bu anlamda WF 4.0' da geriye uyumluluğa da büyük önem verildiğini,</li>
<li>Tamamen <strong>WPF(Windows Presentation Foundation) </strong>temelli bir tasarım ortamının söz konusu olduğunu ve bu sayede geliştirici deneyiminin dahada zenginleştiğini,</li>
<li>Bir <strong>Workflow </strong>içerisine veya dışarısına yapılan <strong>veri akışlarının(Data Flow) </strong>çok daha kolay ele alınması için <strong>Designer </strong>desteği ile birlikte <strong>Arguments </strong>kavramının geldiğini,</li>
<li>Bir aktivitenin kendi içerisinde veriyi saklaması ve farklı seviyedeki alanlarda(Scope) kullanabilmesinde rol oynayan <strong>Variables</strong> kavramını ayrıca <strong>Arguments</strong> kavramında olduğu gibi, Variables içinde <strong>Designer </strong>desteğinin olduğunu,</li>
<li>Bir veya daha fazla <strong>input</strong> argümanı alıp bunlar üzerinde çeşitli operasyonlar gerçekleştiren ve geriye değer döndürebilen <strong>ifadeler(Expressions)</strong> yazılabildiğini, üstelik bunların <strong>XAML</strong> bazlı olabildiğini,</li>
<li><strong>FlowChart, ForEach, Parallel, ParallelForEach </strong><em>(Parallel versiyonların Ekimdeki <a title="Microsoft Proffessional Developer Conference" href="http://microsoftpdc.com/" target="_blank">PDC' </a>de yayınlanacak sürümde olması bekleniyor) </em>ve daha pek çok aktivite tipi ile zengineştirilmiş olan <strong>temel aktivite kütüphanesi(Base Activity Library) </strong>ni,</li>
<li><strong>Sequential</strong> ve <strong>State Machine </strong>arasında duran ama geliştirici ve iş analistlerinin, bilinen iş akışı tasarım modeline çok yakın olması nedeniyle kolayca kullanabildiği yeni <strong>Flow Chart </strong>modelini,</li>
<li><strong>Workflow</strong> ve <strong>Activity' </strong>ler için <strong>Unit Test' </strong>lerin kolayca geliştirilebiliyor olduğunu,</li>
<li><strong>Workflow' </strong>ların, dışarıdaki <strong>Activity' </strong>ler ile haberleşmenin dahada kolaylaştırılmış olduğunu,</li>
<li><strong>4.0</strong> versiyonunda evlenebilmerleri için <strong>WCF </strong>ve <strong>WF </strong>tarafında;
<ul>
<li>Workflow tarafında yenilenen çalışma zamanı motoru bulunduğunu,</li>
<li>Workflow Service' lerin <strong>host</strong> edilebiliyor olduğunu,</li>
<li>Workflow' lar içerisinde <strong>XAML</strong> bazlı olarak <strong>WCF</strong> servis materyallerinin tanımlanabiliyor olduğunu,<em>(Service Contract, Data Contract, EndPoint vb...)</em></li>
<li>Visual Studio' da <strong>Workflow</strong> <strong>Service' </strong>ler için <strong>Add Service Reference </strong>desteğinin getirildiğini,</li>
<li>Yeni mesajlaşma aktivitileri<strong><em>(SendAndReceiveReply, ReceiveAndSendReply gibi)</em></strong> ve bunların <strong>mesaj korelasyon(Message Corellation)</strong> desteğine de sahip olduğunu,</li>
</ul>
</li>
<li><strong>WF 3.X</strong> ile yazılmış olan <strong>Workflow' </strong>ların <strong>4.0 </strong>çalışma zamanı tarafından da yürütülebildiğini,</li>
<li><strong>WF 3.X</strong> tarafından yazılmış olan aktivitelerin <strong>sarmalanarak(Wrap) 4.0 </strong>içerisinde de kullanılabildiğini,<strong><em>(Interop activity) </em></strong></li>
<li>Ayrıca WF 3.0' dan geçiş yapacaklar için bir <a title="Guide WF 3.X to WF 4.0" href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=bd94c260-b5e0-4d12-93ec-53567505e685" target="_blank">klavuzun </a>bulunduğunu,</li>
<li>Daha detaylı bilgiler içinse<a title="The .Net Endpoint" href="http://blogs.msdn.com/endpoint/archive/2009/05/01/the-road-to-4-wf-changes-between-beta-1-and-ctp.aspx" target="_blank"> şu adrese </a>başvruabileceğimizi,</li>
</ul>
<p>görüyoruz. Vooovvvvv!!!! Artık paraşütümüzü açalım mı ne dersiniz? <img title="Cool" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cool.gif" alt="Cool" border="0" /> Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2009-10-01T13:54:00+00:00wf 4.0bsenyurtParaşütle atlamak gerçekten zevkli olsa gerek. Yerden binlerce feet(1 feet=30,48 cm) yüksekten atlayıp özgür bir şekilde kendinizi yer çekimi gücüne bırakıp, saniyeler boyunca serbest düşüşü yaşamak...Size yandaki resimde atlayan kişinin ben olduğumu söylemek isterdim ama ne yazık ki değilim. Olmayı istermiydim bilemiyorum. Oldukça yüksek görünüyor. Sealed Bir paraşütçü için en güzel duygulardan birisi sanıyorum ki atladığı noktadan itibaren altındaki Dünyayı görebildiği kadar yüksekten izleyebilmenin verdiği mutluluktur.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=fe40cc31-85e1-45e1-9da4-9ac7904e85850https://buraksenyurt.com/trackback.axd?id=fe40cc31-85e1-45e1-9da4-9ac7904e8585https://buraksenyurt.com/post/5000-Feet-Yuksekten-Workflow-Foundation-40#commenthttps://buraksenyurt.com/syndication.axd?post=fe40cc31-85e1-45e1-9da4-9ac7904e8585https://buraksenyurt.com/post/WF-4-0-WCF-Servislerini-Kullanmak-bsenyurt-com-danWF 4.0 - WCF Servislerini Kullanmak2009-04-01T12:00:00+00:00bsenyurt<p>Değerli Okurlarım Merhabalar,</p>
<p>Bir <a href="https://buraksenyurt.com/post/Windows-Workflow-Foundation-4-0-Ilk-Izlenimler-bsenyurt-com-dan.aspx">önceki</a> yazımızda <strong>Windows Workflow Foundation 4.0 (WF 4.0)</strong> ile birlikte gelmesi muhtemel<em>(yüksek bir olasılıkla çok az değişikle gelecekler)</em> kavramları incelemeye çalışmıştık ve pek çok yeni aktivite tipinin alt yapıya dahil edilmiş olduğunu gördük. <strong>WF</strong> örnekleri bilindiği üzere çoğu zaman servisler ile haberleşmek durumundadır. Bu özellikle gerçek hayat senaryolarında çok sık karşılaşına ve ihtiyaç duyulan bir durumdur. Nitekim WF içerisinde yer alan akışların dış ortamlara olan bir bağımlılığı söz konusu olabilir. Bir Bankacılık sisteminde yer alan akışlarda, servisler yardımıyla ulaşılabilen bazı operasyonlar bu bağımlılığa örnek gösterilebilir örneğin.</p>
<p><strong>WF</strong> alt yapısı bu anlamda <strong>WCF(Windows Communication Foundation)</strong> servisleri ile haberleşilebilmesini kolaylaştırmak amacıyla <strong>.Net Framework 3.5</strong> ile birlikte yeni aktivite bileşenlerine sahip olmuştur. <strong>SendActivity</strong> ve <strong>ReceiveActivity</strong> isimli bu tipler temel olarak servislere ait operayonların çağırılması veya <strong>WF</strong> içerisinde servis bazlı operasyonların dış dünyaya sunulmasında etkin olarak kullanılmaktadır. Ancak WF 4.0 ile birlikte servisler ile olan iletişimde daha yetenekli aktivite tipleri yer almaktadır. Özellikle görsel açıdan geliştiriciye kolaylıklar sağlayan ama asıl etkisini <strong>XAML</strong> bazlı servis tanımlamalarının yapılabilmesinde gösteren aktiviteler söz konusudur. Zaten <strong>WF</strong> ve <strong>WCF</strong> <strong>4.0</strong> içerisinde XAML tabanlı deklerafit tanımlamaların son derece etkin bir şekilde kullanıldığı bir gerçektir. <strong>WF 4.0 </strong>açısında bakıldığında bir <strong>WCF</strong> operasyonu ile sağlanan <strong> istek/cevap(Request/Response)</strong> odaklı iletişim temel olarak aşağıdaki şekilde görüldüğü gibidir.</p>
<p><img src="/makale/images/mk272_1.gif" alt="" width="410" height="289" border="0" /></p>
<p>Buna göre <strong>WF</strong> içerisinde herhangibir noktada servis operasyonlarını çağırmak için <strong>ClientOperation</strong> isimli aktivite kullanılmaktadır. Bu operasyonun yer aldığı <strong>WCF</strong> servisi bir veya daha fazla <strong>EndPoint</strong> üzerinden istemcilere hizmet verebilir. <strong>WF</strong> örnekleri kendi içerisinde, bu <strong>EndPoint</strong>' in belirttiği <strong>Address</strong>, <strong>Binding</strong> ve <strong>Contract</strong> tipine göre uygun bir mesajlaşma trafiği başlatabilir. Buna göre servis operasyonları çağırabilir ve sonuçlarını ele alabilir. <strong>ClientOperation</strong>, <strong>Workflow Foundation 4.0</strong> ile birlikte gelen yeni aktivite tiplerinden birisidir. Peki bu yeni tipin <strong>.Net Framework 3.5</strong> sürümü ile gelen ve aynı amaçla kullanılan <strong>SendActivity</strong> tipine göre farklılıkları, özellikle avantakları neler olabilir? İşte bu yazımızda kısaca bu sorulara cevap bulmaya çalışacak ve aynı zamanda bizleri bekleyen yenilikleri göreceğiz. Bu nedenle bir örnek üzerinden adım adım ilerleyerek devam etememizde yarar olacağı kanısındayım.</p>
<p>Senaryomuza göre basit ve herzamanki gibi gerçek hayatta kullanılmayacak bir <strong>Sequential Workflow</strong> uygulaması geliştireceğiz. Akışımız yine geliştirici tarafından tasarlanmış özel bir aktivite tipini kullanarak istemciden iki sayısal değer alacaktır. Bu değerler bir servise gönderilerek işlenecek ve sonuçlar yine akış içerisine yönlendirilerek diğer bir özel aktivite tipi yardımıyla ekrana yazdırılacaktır. İlk olarak servis uygulamasının tasarlanmasında yarar vardır.</p>
<blockquote>
<p>Yazımızda geliştirmekte olduğumuz örnek henüz Relase olmamış .Net Framework 4.0 sürümü üzerinde geliştirilmekte ve bu amaçla Visual Studio 2010' un PDC 2008' de yayımlanan Virtual PC versiyonu kullanılmaktadır. Dolayısıyla yazılan ve işlenen kavramlarda veya Visual Studio 2010 sürümünde köklü değişiklikler olabilir, olması muhtemeldir.</p>
</blockquote>
<p><strong>CalculusService</strong> isimli <strong>WCF</strong> uygulamamız <strong>WCF</strong> <strong>Service</strong> <strong>Application</strong> tipinde geliştirilmektedir.</p>
<p><img src="/makale/images/mk272_2.gif" alt="" width="529" height="448" border="0" /></p>
<p>Serviste kullanılan sözleşme içeriği ise aşağıdaki kod parçasında görüldüğü gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
namespace CalculusService
{
[ServiceContract]
public interface IMatService
{
[OperationContract]
double Sum(double x, double y);
}
}</pre>
<p>Servis sözleşmesinde<strong>(Service Contract)</strong>, çok basit olarak <strong>double</strong> tipinden iki sayısal değerin toplamını alarak geriye sonucunu döndüren <strong>Sum</strong> isimli bir operasyon yer almaktadır. <strong>IMatService</strong> isimli servis arayüz tipini<strong>(Interface) </strong>uygulayan sınıfa ait kod içeriği ise aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace CalculusService
{
public class MatService
: IMatService
{
public double Sum(double x, double y)
{
return x + y;
}
}
}</pre>
<p>Servis üzerinde tanımlanmış olan operasyonlar basit <strong>HTTP</strong> protokolüne göre sunulmaktadır. Bu nedenle bağlayıcı tip olarak <strong>BasicHttpBinding</strong> kullanılmaktadır. Servis için birde <strong>HTTP</strong> üzerinden <strong>metadata</strong> bilgisinin verilebilmesi amacıyla <strong>MexHttpBinding</strong> bazlı bir <strong>EndPoint</strong> daha söz konusudur.<em>(Gerçi biraz sonra görebileceğimiz gibi, <strong>WF</strong> örneğinin servise ait bir <strong>Metadata</strong> indirmesine gerek kalmayacaktır :) ) </em>Örnek <strong>WCF</strong> servis uygulamamıza <strong>EndPoint</strong> ayarları aşağıdaki <strong>Web.config </strong>dosyasının içeriğinde olduğu gibi tanımlanabilir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true"></compilation>
<authentication mode="Windows"/>
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="CalculusService.MatServiceBehavior" name="CalculusService.MatService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="" contract="CalculusService.IMatService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CalculusService.MatServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration></pre>
<p><strong>WCF</strong> servis uygulamamız test amacıyla geliştirildiğinden <strong>IIS(Internet Information Services)</strong> üzerine atılmamıştır. Bu nedenle <strong>Solution</strong> içerisinde yer alan istemci uygulamalar ile haberleşmesi sırasındaki geliştirme sürecini kolaylaştırmak adına, sabit bir <strong>HTTP</strong> portu kullanması sağlanabilir. Sabit <strong>port</strong> ayarlaması için <strong>WCF</strong> projesinin özelliklerinden<em><strong>(Properties)</strong></em> aşağıdaki ekran görüntüsünde olduğu gibi <strong>Specific Port</strong> özelliğine bir değer atamak yeterli olacaktır. <em> (Elbetteki bu <strong>WCF</strong> uygulamasını, <strong>IIS</strong> altına atmak kolay bir şekilde özellikler penceresinde yer alan <strong>Use</strong> <strong>Local</strong> <strong>IIS</strong> <strong>Web</strong> <strong>server</strong> seçeneği ile mümkün olabilir. Yada bu amaçla <strong>Publish</strong> işlemlerinden yararlanılabilir.)</em></p>
<p><img src="/makale/images/mk272_4.gif" alt="" width="445" height="306" border="0" /></p>
<p>Bu aşamada ilerlemeden önce servisin <strong>HTTP</strong> üzerinden çağırılabildiğinden emin olmak gerekir. Bu amaçla, <strong>MatService.svc</strong> dosyasının bir tarayıcı içerisinde açılması yeterlidir. Eğer aşağıdaki ekran görüntüsünde yer alan sonuçlar elde edilebiliyorsa <strong>WCF</strong> servisinin çağırılabilir olduğu sonucuna varılabilir.</p>
<p><img src="/makale/images/mk272_3.gif" alt="" width="539" height="289" border="0" /></p>
<p>Gelelim <strong>WF</strong> tarafına. Her zamanki gibi basit bir <strong>Sequential</strong> <strong>Workflow</strong> <strong>Console</strong> <strong>Application</strong> üzerinden ilerliyor olacağız. Servise gönderilecek parametreleri ekrandan almak ve yazdırmak içinse bir önceki yazı dizimizdekilere benzer iki basit aktivite tipi kullanıyor olacağız. <strong>Console</strong> ekranından bilgi okumak için kullanılan <strong>Read</strong> aktivitesine ait kod içeriği aşağıdaki gibi geliştirilebilir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.WorkflowModel;
namespace CalculusWF
{
public class Read
:WorkflowElement
{
public OutArgument<double> Value1 { get; set; }
public OutArgument<double> Value2 { get; set; }
protected override void Execute(ActivityExecutionContext context)
{
Console.WriteLine("Value 1 ?");
Value1.Set(context, Convert.ToDouble(Console.ReadLine()));
Console.WriteLine("Value 2 ?");
Value2.Set(context, Convert.ToDouble(Console.ReadLine()));
}
}
}</pre>
<p><strong>Read</strong> aktivitesi görüldüğü üzere iki adet <strong>OutArgument<T></strong> tipinden özellik kullanmakta ve <strong>override</strong> ettiği <strong>Execute</strong> metodu içerisinde ekrandan aldığı değerleri dış ortama sunmaktadır. Yine dikkat edilmesi gereken noktalardan birisi, aktivitenin <strong>WF Base Library</strong> içerisindeki yeni ata sınıf olan <strong>WorkflowElement</strong> tipinden türemiş olmasıdır. <strong>Write</strong> aktiviteside <strong>Read</strong> aktivitesi gibi <strong>WorkflowElement</strong> türevlidir ve <strong>WF</strong> içeriğinden(<strong>ActivityExecutionContext</strong> yardımıyla) gelen sonuç değerini ekrana yazdırmak için kullanılmaktadır. <strong>Write</strong> aktivitesine ait kod içeriği aşağıda görüldüğü gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.WorkflowModel;
namespace CalculusWF
{
class Write
:WorkflowElement
{
public InArgument<double> Result { get; set; }
protected override void Execute(ActivityExecutionContext context)
{
double r=Result.Get(context);
Console.WriteLine("İşlem sonucu {0} dır",r.ToString());
}
}
}</pre>
<p><strong>Workflow</strong> içerisinde toplama işlemi için kullanılacak değerler ile işlem sonucuna tüm aktivite boyunca ulaşılması istendiğinden aşağıdaki ekran görüntüsünde yer aldığı gibi üç adet <strong>Variable</strong> tanımlaması yapılmaktadır. Bu tanımlamalar <strong>Matflow.xaml</strong> isimli <strong>Sequential</strong> <strong>Activity</strong> tipinin tamamı için geçerlidir.</p>
<p><img src="/makale/images/mk272_6.gif" alt="" width="371" height="374" border="0" /></p>
<p><strong>A</strong>, <strong>B</strong> ve <strong>Total</strong> isimli değişkenler <strong>double</strong> tipinden tanımlanmıştır. Bu değerler <strong>Read</strong>, <strong>Write</strong> aktiviteleri ile <strong>ClientOperation</strong> tarafından kullanılabilecektir. Bu işlemin ardından artık aktivite dizisinin oluşturulmasına başlanabilir. İlk olarak Read aktivitesi sürüklenir. Söz konusu aktivitenin özellikleri aşağıdaki gibi ayarlanabilir.</p>
<p><img src="/makale/images/mk272_7.gif" alt="" width="599" height="197" border="0" /></p>
<p>Dikkat edileceği üzere <strong>Read</strong> aktivitesi içerisinde tanımlanmış olan <strong>Value1</strong> ve <strong>Value2</strong> isimli özelliklere, <strong>Sequence</strong> aktivitesi içerisinde tanımlanan <strong>A</strong> ve <strong>B</strong> değişkenleri atanmıştır. Bir başka deyişle <strong>Read</strong> aktivitesi ile <strong>komut satırından</strong> okunup set edilen <strong>Value1</strong> ve <strong>Value2</strong> değerleri diğer aktiviteler tarafından kolayca ele alınabileceklerdir. Nitekim <strong>A</strong> ve <strong>B</strong> isimli <strong>global</strong> değişkenleri taşınmaktadırlar. <strong>Read</strong> ve <strong>Write</strong> aktiviteleri arasına <strong>ClientOperation</strong> aktivitesini eklemeden önce, <strong>Write</strong> aktivitesi içinde aşağıda görülen özellik ayarlamalarını yapmamız yeterli olacaktır.</p>
<p><img src="/makale/images/mk272_8.gif" alt="" width="530" height="289" border="0" /></p>
<p>Dikkat edileceği üzere <strong>Write</strong> aktivitesi içerisinde tanımlanmış olan <strong>Result</strong> isimli özelliğe <strong>global</strong> değişkenlerden <strong>Total</strong> atanmıştır. Artık <strong>Write</strong> aktivitesi ile okunarak global seviyedeki <strong>A</strong> ve <strong>B</strong> değişkenlerine atanan değerleri, kullanılmak üzere ele alacak ve toplam sonucunu <strong>Total</strong> isimli değişkene verecek olan <strong>ClientOperation</strong> aktivitesini geliştirmeye başlayabiliriz.</p>
<p><img src="/makale/images/mk272_5.gif" alt="" width="239" height="190" border="0" /></p>
<p><strong>ClientOperation</strong> aktivitesini <strong>Read</strong> ve <strong>Write</strong> aktiviteleri arasına sürükleyip bıraktığımızda ilk etapta aşağıdaki ekran görüntüsü ile karşılaşırız. Dikkat edileceği üzere <strong>Operation</strong> <strong>Contract</strong>, <strong>Binding</strong> ve <strong>EndPoint</strong> <strong>Address</strong> isimli 3 önemli özellik göze çarpmaktadır.</p>
<p><img src="/makale/images/mk272_9.gif" alt="" width="213" height="272" border="0" /></p>
<p>Tahmin edileceği üzere bu özelliklerin değerleri ile istemci için gerekli bir <strong>EndPoint</strong> bilgisi oluşturulabilir. Bir başka deyişle bir <strong>EndPoint</strong> tanımını oluşturan <strong>adresleme(Address), bağlayıcı tip(Binding Type)</strong> ve <strong>sözleşme(Contract)</strong> bilgilerinin tamamı bu aktivite tipi içerisinde belirlenmektedir. İlk olarak aşağıdaki ekran görüntüsünde yer alan adımlar takip edilerekten <strong>servis sözleşmesinin(Service Contract)</strong> adı girilir.</p>
<p><img src="/makale/images/mk272_10.gif" alt="" width="462" height="355" border="0" /></p>
<p><strong>Visual Studio 2010</strong> ürün olarak sunulduğunda servis sözleşmesi gibi kısımların elle değil otomatik olarak girilebilecek şekilde ayarlanabileceğini düşünmekteyim. Şimdilik servis tarafındaki sözleşme arayüzü tipinin adını elle(büyük küçük harf duyarlılığına da dikkat ederekten) yazmamız gerekmektedir. Servis sözleşmesinin belirlenmesi tek başına yeterli değildir. <strong>ClientOperation</strong> aktivitesinin bu servis operasyonu üzerinde hangi operasyonu çağıracağınında belirlenmesi gerekmektedir. Burada <strong>New</strong> <strong>ServiceContract</strong> düğmesi yardımıyla sözleşme tanımlandığında, başlığın <strong>New</strong> <strong>OperationContract</strong> olarak değiştiği gözlemlenir. Tahmin edileceği gibi <strong>New</strong> <strong>OperationContract</strong> düğmesi ve takip eden adımlar ile <strong>Sum</strong> operasyonuna ait tanımlamalar görsel olarak yapılabilmektedir. Aynen aşağıdaki ekran görüntüsünde yer aldığı gibi.</p>
<p><img src="/makale/images/mk272_11.gif" alt="" width="545" height="366" border="0" /></p>
<p>Burada çok detaylı operasyon ayarlamaları yapılabilmektedir. Güvenlik ile ilişkili işlemler<strong>(Protection Level)</strong>, <strong>Transaction</strong> aktarma opsiyonları, operasyonun <strong>tek yönlü(One-Way)</strong> olup olmadığı, operasyondan dönebilecek <strong>Fault</strong> tipleri vb... Geliştirdiğimiz örnekte sadece operasyon parametrelerinin girilmesi yeterlidir. <strong>x</strong> ve <strong>y</strong> isimli argümanlar, <strong>Sum</strong> operasyonuna ait girdi parametreleri olduklarından <strong>Direction</strong> özellikleri <strong>In</strong> olarak belirlenmiştir. Diğer taraftan <strong>SumResult</strong> isimli argüman, operasyonun dönüş değerini işaret etmekte olduğundan, <strong> Direction</strong> özelliğine <strong>Out</strong> değeri verilmiştir. Şu anda çağırılacak servis operasyonu ile ilişkili tanımlamalar yapılmıştır. Artık bu servis ile hangi bağlayıcı tip ve adres ile iletişime geçileceğine dair özelliklerin belirlenmesi gerekmektedir. Bu amaçla aşağıdaki ekran görüntüsünde yer alan atamaların yapılması yeterlidir.</p>
<p><img src="/makale/images/mk272_12.gif" alt="" width="475" height="472" border="0" /></p>
<p>Unutulmaması gereken noktalardan biriside <strong>WCF</strong> servisleri ile haberleşecek olan istemci uygulamaların, servis tarafında belirtilen <strong>EndPoint</strong> içeriğine uygun <strong>EndPoint</strong> bildirimlerine sahip olması zorunluluğudur. Geliştirilen örnekte servis tarafında <strong>BasicHttpBinding</strong> tipi kullanıldığından istemci tarafındaki <strong>EndPoint</strong> içinde aynı tipte bir bağlayıcının kullanılması gerekmektedir. Benzer olarak servis tarafındaki operasyon <strong>HTTP</strong> bazlı olaraktan <strong>localhost</strong> isimli makineden ve <strong>49100</strong> nolu <strong>port</strong> üzerinden sunulmaktadır. Bu nedenle istemci tarafından bu kritere uygun bir <strong>adres</strong> için talepte bulunulmalıdır. Dikkat çekici noktalardan biriside adres kısmında <strong>C#</strong> notasyonuna pek uymayan bir şekilde büyük harfle başlayan bir <strong>New</strong> anahtar kelimesi olmasıdır. (<strong>WF 4.0</strong> ile ilişkili yenilikleri öğrendiğim <strong>Microsoft LAB</strong> dökümanlarında bu durumun final sürümünde değişeceğine dair bir bilgi yer almaktadır. Tabi final sürümünde bizleri neler bekliyor neler...) Artık istemci tarafındaki <strong>EndPoint</strong> için gerekli <strong>ABC(AddressBindingContract)</strong> bilgileri tanımlanmış durumdadır.</p>
<p>Yapılması gereken önemli işlemlerden biriside <strong>WF</strong> içerisindeki değişkenleri <strong>ClientOperation</strong> ile servise aktarmak ve servisten dönen değeride tekrardan <strong>WF</strong> içerisine yönlendirmektir. Bunun için <strong>ClientOperation</strong> elementinin özelliklerinde aşağıdaki ekran görüntüsünde yer alan ayarlamaların yapılması yeterli olacaktır.</p>
<p><img src="/makale/images/mk272_13.gif" alt="" width="397" height="506" border="0" /></p>
<p>Görüldüğü üzere <strong>SumResult</strong> isimli servis operasyon argümanı <strong>Total</strong> isimli <strong>WF</strong> değişkenine, <strong>x</strong> isimli servis operasyon argümanı <strong>A</strong> isimli <strong>WF</strong> değişkenine ve son olarak <strong>y</strong> isimli servis operasyonu argümanı <strong>B</strong> isimli <strong>WF</strong> değişkenine set edilmiştir. İşte bu kadar. Görüldüğü üzere görsel olarak pek çok ayarlama yapılmıştır. Sonuç olarak <strong>MatFlow.xaml</strong> adlı <strong>Workflow</strong> örneğimiz için aşağıdaki <strong>XAML(eXtensible Application Markup Language)</strong> içeriği üretilmektedir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><p:Activity x:Class="CalculusWF.MatFlow" xmlns:c="clr-namespace:CalculusWF;assembly=CalculusWF" xmlns:p="http://schemas.microsoft.com/netfx/2009/xaml/workflowmodel" xmlns:p1="http://schemas.microsoft.com/netfx/2008/xaml/schema" xmlns:p2="http://schemas.microsoft.com/netfx/2009/xaml/servicemodel" xmlns:s="clr-namespace:System;assembly=System" xmlns:swd="clr-namespace:System.WorkflowModel.Debugger;assembly=System.WorkflowModel" xmlns:swdx="clr-namespace:System.WorkflowModel.Design.Xaml;assembly=System.WorkflowModel.Design" xmlns:sx="clr-namespace:System.Xml;assembly=System.Runtime.Serialization" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<p:Sequence swd:XamlDebuggerXmlReader.FileName="C:\Orneklerim\CalculusService\CalculusWF\MatFlow.xaml">
<p:Sequence.Variables>
<p:Variable x:TypeArguments="p1:Double" Name="A" />
<p:Variable x:TypeArguments="p1:Double" Name="Total" />
<p:Variable x:TypeArguments="p1:Double" Name="B" />
</p:Sequence.Variables>
<c:Read DisplayName="Read Parameters" Value1="[A]" Value2="[B]" />
<p2:ClientOperation EndpointAddress="[New s:Uri("http://localhost:49100/MatService.svc")]" OperationName="Sum">
<p2:ClientOperation.Endpoint>
<p2:Endpoint Name="ClientOperationEndpoint">
<p2:Endpoint.Binding>
<p2:BasicHttpBinding TextEncoding="utf-8">
<p2:BasicHttpBinding.ReaderQuotas>
<sx:XmlDictionaryReaderQuotas />
</p2:BasicHttpBinding.ReaderQuotas>
<p2:BasicHttpBinding.Security>
<p2:BasicHttpSecurity Mode="None">
<p2:BasicHttpSecurity.Message>
<p2:BasicHttpMessageSecurity AlgorithmSuite="Default" ClientCredentialType="UserName" />
</p2:BasicHttpSecurity.Message>
<p2:BasicHttpSecurity.Transport>
<p2:HttpTransportSecurity />
</p2:BasicHttpSecurity.Transport>
</p2:BasicHttpSecurity>
</p2:BasicHttpBinding.Security>
</p2:BasicHttpBinding>
</p2:Endpoint.Binding>
<p2:Endpoint.ContractProjection>
<p2:SoapContractProjection>
<p2:SoapContractProjection.Contract>
<p2:ServiceContract Name="IMatService">
<p2:OperationContract Name="Sum">
<p2:OperationArgument Name="x" Type="p1:Double" />
<p2:OperationArgument Name="y" Type="p1:Double" />
<p2:OperationArgument Direction="Out" Name="SumResult" Type="p1:Double" />
</p2:OperationContract>
</p2:ServiceContract>
</p2:SoapContractProjection.Contract>
</p2:SoapContractProjection>
</p2:Endpoint.ContractProjection>
</p2:Endpoint>
</p2:ClientOperation.Endpoint>
<p2:ClientOperation.OperationArguments>
<p:OutArgument x:Key="SumResult" x:TypeArguments="p1:Double">[Total]</p:OutArgument>
<p:InArgument x:Key="x" x:TypeArguments="p1:Double">[A]</p:InArgument>
<p:InArgument x:Key="y" x:TypeArguments="p1:Double">[B]</p:InArgument>
</p2:ClientOperation.OperationArguments>
</p2:ClientOperation>
<c:Write DisplayName="Write Result" Result="[Total]" />
</p:Sequence>
</p:Activity></pre>
<p>Burada durup aslında biraz soluklanmak belki bir yudum kahve içmek ve sonrasında <strong>XAML</strong> içeriğine yoğunlaşarak düşünmek gerekmektedir. Dikkat edileceği üzere <strong>WF</strong>' in tüm içeriği, <strong>Write</strong>, <strong>Read</strong>, <strong>ClientOperation</strong> aktiviteleri, <strong>global</strong> <strong>WF</strong> değişkenleri bu <strong>XAML</strong> içeriğinde bildirilmektedir. Tabiki bu <strong>XAML</strong> içeriği çalışma zamanı tarafında değerlendirilmektedir. <strong>Dekleratif(Declerative)</strong> bir yaklaşımdan ziyade <strong>ClientOperation</strong> aktivitesinin <strong>XAML</strong> içerisine nasıl gömüldüğüne dikkat etmemizde yarar vardır. Öyleki <strong>EndPoint</strong> ve buna ait <strong>AddressBindingContract</strong> bilgilerinin tamamı <strong>XAML</strong> elementleri içerisinde oluşturulmuştur.</p>
<p>Buna göre <strong>XAML</strong> içeriği basit bir editor yardımıyla değiştirildiği takdirde <strong>Workflow</strong> örneğinin yeni ortam şartlarına göre adapte edilmesi kolayca sağlanabilir. Söz gelimi, servis adresinin değişmesi veya operasyon adında yada parametrik yapısında oluşabilecek değişiklikleri koda girmeden düzenleyebilir ve <strong>WF</strong>' in güncellenmesini sağlayabiliriz. Bunun sağlanmasının en büyük etkenlerinden birisi <strong>Workflow</strong> bazlı <strong>WCF</strong> servislerinin kod yazmadan <strong>XAML</strong> tabanlı geliştirilip kullanılabiliyor olmasıdır. <em>(Bu alt yapıyı ve <strong>Workflow</strong> bazlı bir <strong>WCF</strong> servisinin <strong>XAML</strong> ile dekleratif olarak nasıl tanımlanabileceğini ilerleyen makalelerimizde veya görsel derslerimizde incelemeye çalışacağız.) </em>Artık örneğimizi test etmeye başlayabiliriz. Bundan önce <strong>Solution</strong>' ımızın son halinin aşağıdaki ekran görüntüsüne benzer olacağını düşünebiliriz.</p>
<p><img src="/makale/images/mk272_15.gif" alt="" width="271" height="325" border="0" /></p>
<p>Programın çalışmasının sonucu aşağıdakine benzer bir ekran çıktısı oluşacaktır.</p>
<p><img src="/makale/images/mk272_14.gif" alt="" width="315" height="121" border="0" /></p>
<p>Dikkat edilmesi ve unutulmaması gereken noktalardan biriside programın çalışması için servisinde çalışıyor olması gerekliliğidir. Nitekim servisin ayakta olmaması halinde istemcilerin taleplerine karşılık <strong>çalışma zamanı istisnaları(Runtime Exception)</strong> alması söz konusudur.</p>
<p>Peki <strong>ClientOperation</strong> kullandığımızda <strong>.Net 3.5</strong> sürümü ile Workflow Foundation alt yapısına kazandırılan <strong>SendActivity</strong> tipine göre en büyük farklılık(farklılıklar) nedir?</p>
<blockquote>
<p>SendActivity tarafından kullanılan WCF servisinin Host uygulama üzerinde ele alınabilmesi için Add Service Reference(veya svcutil ile komut satırından) ile proxy üretiminin yapılması gerekmektedir.</p>
<p><img src="/makale/images/mk249_3.gif" alt="" width="535" height="436" border="0" /></p>
</blockquote>
<p>Herşeyden önce servis kullanan bir istemci geliştirilirken, <strong>Add Service Reference</strong> seçeneği ile <strong>proxy</strong> tiplerinin eklenmesi gerekmektedir. Oysaki geliştirdiğimiz örnekte böyle bir işleme başvurulmamıştır. Bunun yerine <strong>ClientOperation</strong> elementi için <strong>XAML</strong> tabanlı tanımlamalar yapılmıştır. Dolayısıyla yeni çalışma zamanı motorunun bu içeriğe bakaraktan servis ile iletişime geçtiğini ve fiziki bir proxy' ye ihtiyaç duymadığını söyleyebiliriz. Bir başka deyişle örneğin servis tarafında oluşabilecek bazı değişikliklerin <strong>WF</strong> tarafına bildirilmesi için bir referans güncellemesi yapılmasına gerek kalmamaktadır. Buda önemli bir avantajdır.</p>
<p>Böylece geldik bir makalemizin daha sonuna. Bu makalemizde yeni <strong>WF 4.0</strong> ve<strong> WCF 4.0</strong> kabiliyetlerinin örnek bir sonucunu değerlendirmeye çalıştık. Bu amaçla yeni gelen aktivite tiplerinden <strong>ClientOperation</strong> tipini ele aldık ve bir servis operasyonunun referansını eklemeden, dekleratif olarak tanımlanıp <strong>XAML</strong> ile oluşturulmasını ve kullanılmasını gördük. Tabi bu konuda konuşulabilecek farklı vakalarda vardır. En önemli sorunlardan biriside servis operasyonlarının uzun süreli<strong>(Long Running Workflows)</strong> olabileceğidir. Bu durumda <strong>WF</strong>' in <strong>kalıcı</strong> <strong>olarak</strong> <strong>saklanması(Persistence)</strong> gibi durumlar söz konusudur ki bunu <strong>WF 4.0</strong> üzerinde kurmak ve <strong>yönetmek(Management) </strong>son derece kolaydır. Özellikle yönetim ve izleme safhasında devreye giren <strong>Dublin</strong> kod adlı <strong>Windows</strong> <strong>Application</strong> <strong>Server</strong>' ın yeteneklerini en kısa sürede sizinle paylaşmaya çalışıyor olacağım. Bir sonraki makalemizde görüşünceye dek hepinize mutlu günler dilerim.</p>2009-04-01T12:00:00+00:00wf 4.0workflow foundationbsenyurtBir önceki yazımızda Windows Workflow Foundation 4.0 (WF 4.0) ile birlikte gelmesi muhtemel(yüksek bir olasılıkla çok az değişikle gelecekler) kavramları incelemeye çalışmıştık ve pek çok yeni aktivite tipinin alt yapıya dahil edilmiş olduğunu gördük. WF örnekleri bilindiği üzere çoğu zaman servisler ile haberleşmek durumundadır. Bu özellikle gerçek hayat senaryolarında çok sık karşılaşına ve ihtiyaç duyulan bir durumdur. Nitekim WF içerisinde yer alan akışların dış ortamlara olan bir bağımlılığı söz konusu olabilir. Bir Bankacılık sisteminde yer alan akışlarda, servisler yardımıyla ulaşılabilen bazı operasyonlar bu bağımlılığa örnek gösterilebilir örneğin.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=a6837053-e2d3-4086-8eff-5e0890a12d230https://buraksenyurt.com/trackback.axd?id=a6837053-e2d3-4086-8eff-5e0890a12d23https://buraksenyurt.com/post/WF-4-0-WCF-Servislerini-Kullanmak-bsenyurt-com-dan#commenthttps://buraksenyurt.com/syndication.axd?post=a6837053-e2d3-4086-8eff-5e0890a12d23