https://buraksenyurt.com/Burak Selim Şenyurt - WF 4.0 RC2010-03-22T11:24:14+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/Workflow-Services-Custom-AuthorizationWorkflow Services - Custom Authorization2010-03-22T04:30:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2010%2f2%2fblg145_Giris.jpg" alt="" />Merhaba Arkadaşlar,</p>
<p>Aşçılık zevkli ama bir o kadarda zor bir zanaattır. Hatta bazen o kadar zor bir zanaat olur ki, aşcının aldığı maaşı pek çok yazılımcı iki yılda kazanamaz. Tabi bu tip aşçılar işin ehli olan kişilerdir. Heleki tek bir mutfak değilde dünya mutfağının seçkin olanlarına ait becerileri bulunanlara paha biçilemez. Türk Mutfağından Japon mutfağına, Meksika yemeklerinden İtalyan spesiyallerine, Fransız tatlılarından Okyanus deniz ürünlerine ve daha nicelerine...</p>
<p>Tabi bir aşçı için olmassa olmazlardan birisi de yemeği için gerekli olan malzemelerin kalitesidir. Kaliteli zeytinyağı, hamur ve baharat ile yapılan spagettinin, kalitesiz olanlar ile yapılanı arasında dağlar kadar fark olabilir. Spagetti demişken bu günkü yazımızda neler yapacağımıza da bir bakalım dilerseniz. Aşçı olarak bu gün elimizde zor bir tarif var. Malzemelerimiz belli ama pişecek olan yemeğin yapımı biraz zahmetli. Haydi gelin hiç vakit kaybetmeden önlüğümüzü takıp klavyenin başına geçelim.<img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /></p>
<p>Bu yazımızda <strong>.Net Framework 4.0</strong> tarafında geliştireceğimiz <strong>Workflow Service'</strong> lerde yetkilendirme işlemini nasıl sağlayabileceğimizi görmeye çalışacağız. Ne yazık ki <strong>Authorization</strong> işlemini kolaylaştırmak adına hazır bir yapı mevcut değil. Bu nedenle biraz kodlama yapmamız ve çalışma zamanının işleyişine bu şekilde müdahale etmemiz gerekiyor. Hatta yapacağımız özelleştirme öylesine etkili olacak ki, aradan <strong>Doğrulamayı(Authentication)</strong> bile çıkaracağız farkına varmadan. <img title="Surprised" src="/editors/tiny_mce3/plugins/emotions/img/smiley-surprised.gif" alt="Surprised" border="0" /> Ama önce yemek için gerekli malzemelerimizin neler olduğuna bir bakalım.</p>
<ul>
<li>Bir adet <strong>Workflow Service.</strong></li>
<li>Bir adet konfigurasyon dosyası<strong>(Web.config).</strong></li>
<li><strong>System.IdentityModel.dll</strong> referansı.</li>
<li><strong>ServiceAuthorizationManager</strong> türevli bir sınıf.</li>
<li><strong>Windows</strong> üzerinde tanımlanmış roller ve bu roller içerisinde yer alan kullanıcılar.</li>
</ul>
<p>Tabiki malzemeleri tedarik etmek yeterli değil. Birde tarifi bilmek lazım <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Öncelikli olarak yetkilendirme işlemini üstelenen bir sınıf yazmamız gerekiyor. Çok doğal olarak bu sınıfın <strong>Workflow Service</strong> çalışma zamanı tarafından değerlendirilebilmesi için konfigurasyon dosyası üzerinde de gerekli düzenlemeleri yapmalıyız. Sonrasında ise işi istemci tarafından gelen taleplere bırakıyor olacağız. İşe ilk olarak aşağıdaki gibi bir <strong>Workflow Service</strong> projemiz olduğunu varsayarak başlayalım.</p>
<p><img src="/pics/2010%2f2%2fblg145_Wf.gif" alt="" /></p>
<p><strong>Calculus.xamlx</strong> içeriğimiz ise aşağıdaki gibidir;(<em>Sadece Sequence elementi içeriği verilmiştir)</em></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><p:Sequence DisplayName="Sequential Service" sad:XamlDebuggerXmlReader.FileName="D:\Projects\Workflow Foundation 4.0\UsingCustomAuthorization\UsingCustomAuthorization\CalculusService.xamlx" sap:VirtualizedContainerService.HintSize="277,336">
<p:Sequence.Variables>
<p:Variable x:TypeArguments="CorrelationHandle" Name="handle" />
<p:Variable x:TypeArguments="x:Int32" Name="X" />
<p:Variable x:TypeArguments="x:Int32" Name="Y" />
<p:Variable x:TypeArguments="x:Int32" Name="Sum" />
</p:Sequence.Variables>
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">True</x:Boolean>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<Receive x:Name="__ReferenceID0" CanCreateInstance="True" DisplayName="ReceiveRequest" sap:VirtualizedContainerService.HintSize="255,86" OperationName="SumOp" ServiceContractName="p1:IService">
<Receive.CorrelatesOn>
<MessageQuerySet />
</Receive.CorrelatesOn>
<Receive.CorrelationInitializers>
<RequestReplyCorrelationInitializer CorrelationHandle="[handle]" />
</Receive.CorrelationInitializers>
<ReceiveParametersContent>
<p:OutArgument x:TypeArguments="x:Int32" x:Key="XValue">[X]</p:OutArgument>
<p:OutArgument x:TypeArguments="x:Int32" x:Key="YValue">[Y]</p:OutArgument>
</ReceiveParametersContent>
</Receive>
<SendReply Request="{x:Reference __ReferenceID0}" DisplayName="SendResponse" sap:VirtualizedContainerService.HintSize="255,86">
<SendParametersContent>
<p:InArgument x:TypeArguments="x:Int32" x:Key="SumResult">[X + Y]</p:InArgument>
</SendParametersContent>
</SendReply>
</p:Sequence></pre>
<p>Aslında <strong>Calculus</strong> isimli <strong>Workflow Service</strong> içerisinde yer alan <strong>SumOp</strong> isimli operasyonun görevi çok basit ve bellidir. <strong>Int32</strong> tipinden iki sayısal değerin toplanması ve sonucunun istemci tarafına geri döndürülmesi. Bizim hedefimiz sadece yetkisi olan kişilerin bu operasyonu çalıştırmasıdır. Bu durumda güvenlik ile ilişkili olarak yetki kontrolünün özel bir sınıf tarafından yapılması gerekmektedir. Söz konusu sınıf <strong>System.ServiceModel</strong> <strong>isim alanı(Namespace)</strong> altında yer alan <strong>ServiceAuthorizationManager</strong> tipinden türetilmelidir. İçeriğini ise çok sade olarak aşağıdaki gibi tasarlayabiliriz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Collections.Generic;
using System.Security.Principal;
using System.ServiceModel;
namespace UsingCustomAuthorization
{
public class Authorizer
: ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
var authCtx = operationContext.ServiceSecurityContext.AuthorizationContext;
var identities=(List<IIdentity>)authCtx.Properties["Identities"];
foreach (var identity in identities)
{
var winIdentity = identity as WindowsIdentity;
if (winIdentity != null)
{
var winPrincipal = new WindowsPrincipal(winIdentity);
return winPrincipal.IsInRole("Administrators");
}
}
return false;
}
}
}</pre>
<p><strong>Authorizer</strong> sınıfı içerisinde <strong>CheckAccessCore</strong> metodu ezilmiş ve parametre olarak gelen <strong>operationContext</strong> değişkeninden yararlanarak gerekli yetki kontrolü yapılmıştır. Buna göre <strong>Workflow</strong> <strong>Service' </strong>ten talepte bulunan bir <strong>Windows</strong> kullanıcısı, servisin host edildiği makinede tanımlı ise, <strong>Administrators</strong> rolünde olup olmadığı kontrol edilmekte ve buna göre geriye <strong>true</strong> veya <strong>false</strong> değeri döndürülmektedir. Tahmin edileceği üzere <strong>CheckAccessCore</strong> metodunun geriye <strong>false</strong> değer döndürmesi güvenlik hatasına yol açacaktır. Burada unutulmaması gereken bir noktayı da hatırlatmak yarar var. Örneğimizde konuyu son derece basit bir şekilde ele almak istediğimizden, doğrudan <strong>Administrator</strong> rolünün kontrolünü yapıp işin içinden sıyrılmaktayız. Oysaki yetki kontrolü için harici bir listeden yararlanılabilir. Bu liste <strong>web.config</strong> dosyasında <strong>appSettings </strong>kısmında tutulabileceği gibi bir <strong>Text</strong> dosya içerisinde veya <strong>veritabanı</strong> üzerindeki bir <strong>tabloda</strong> konuşlandırılabilir. Yinede varmak istediğimiz noktayı anladığınızı düşünerek devam ediyorum.</p>
<p>Sırada çalışma zamanı için <strong>Authorizer</strong> sınıfının yetki kontrolü amacıyla kullanılacağını bildirmemiz gerekiyor. Bunun için <strong>web.config</strong> dosyasını aşağıdaki şekilde düzenlememiz yeterli olacaktır.<em>(Bu arada projemize <strong>System.IdentityModel.dll assembly'</strong> ını referans etmeyi unutmamalıyız. Aksi takdirde <strong>authCtx</strong> üzerinden hiç bir özelliğe erişemeyiz)</em></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceAuthorization serviceAuthorizationManagerType="UsingCustomAuthorization.Authorizer, UsingCustomAuthorization"/>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="http" binding="wsHttpBinding"/>
</protocolMapping>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration></pre>
<p>Dikkat edileceği üzere <strong>serviceAuthorization</strong> elementi ile yetkilendirme davranışını ele alacak <strong>Authorizer</strong> tipi belirlenmiştir. Ayrıca iletişimin güvenli olmasını sağlamak adına <strong>protocolMapping</strong> sekmesinde <strong>wsHttpBinding</strong> bağlayıcı tipinin kullanılacağı bildirilmiştir. İşte bu kadar. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Artık yemeğimizi orta ateşte 40 dakika kadar pişirip servis edebiliriz. Tabi servis etmeden önce tadına bakmak gerekmektedir. Nasıl mı?</p>
<p>Öncelikli olarak <strong>Administrator</strong> rolünde olan ve olmayan iki test kullanıcımız olduğunu düşünelim. Ben, örneği geliştirmekte olduğum makinede bu amaçla <strong>bsenyurt</strong> ve <strong>runi</strong> isimli iki kullanıcı oluşturdum. Bu kullanıcılardan <strong>bsenyurt</strong> <strong>Administrator </strong>rolünde iken <strong>runi User</strong> rolü içerisinde yer almakta. Dolayısıyla test sonuçlarımıza göre <strong>runi</strong> isimli kullanıcı talebi karşılığında <strong>Access Denied</strong> hata mesajını almalı. Bakalım gerçektende böylemi oldu?</p>
<p><strong>WcfTestClient </strong>uygulamamızı <strong>Run As..</strong> komutu yardımıyla önce <strong>bsenyurt</strong> kullanıcısı ile çalıştıralım. Eğer <strong>Asp.Net Developement Server'</strong> ı <strong>Visual Studio </strong>ortamına <strong>Attach' </strong>larsak <strong>CheckAccessCore </strong>metodu içeriğini de <strong>debug</strong> edebiliriz. Buna göre <strong>debug</strong> modunda aşağıdaki sonuçlar ile karşılaşırız.</p>
<p><img src="/pics/2010%2f2%2fblg145_Debug1.gif" alt="" /></p>
<p>Görüldüğü üzere <strong>bsenyurt</strong> kullanıcısı doğrulanmıştır. <strong>IsAuthenticated</strong> değerinin <strong>true</strong> olduğuna dikkat edelim. Şimdi <strong>WcfTestClient</strong> uygulamasının sonuç ekranına bakarsak toplama işleminin başarılı bir şekilde gerçekleştirildiğini görebiliriz.</p>
<p><img src="/pics/2010%2f2%2fblg145_AccessGaranted.gif" alt="" /></p>
<p>Şimdi de <strong>WcfTestClient</strong> aracını <strong>Runi</strong> isimli kullanıcı ile çalıştıralım. <strong>Debug</strong> modda aşağıdaki sonuçlar ile karşılaşırız.</p>
<p><img src="/pics/2010%2f2%2fblg145_Debug2.gif" alt="" /></p>
<p>Tahmin edileceği üzere <strong>Runi</strong> isimli kullanıcı da doğrulanmıştır. Nitekim servisin çalıştırıldığı makine de tanımlı bir <strong>Windows</strong> kullanıcısıdır. Ancak <strong>WcfTestClient</strong> uygulaması üzerinden bir toplama işlemi talebinde bulunulduğunda hata mesajı ile karşılaşılacaktır.</p>
<p><img src="/pics/2010%2f2%2fblg145_AccessDenied.gif" alt="" /></p>
<p>Volaaaaa!!! Bu çok doğaldır. Nitekim <strong>Runi</strong> isimli kullanıcı <strong>Administrators </strong>grubuna dahil değildir ve bu yüzden yetki kontrolünden geçememiştir.</p>
<p>Yapmış olduğumuz bu çalışmaya göre bir <strong>Workflow Service'</strong> ini host ettiğimiz sunucu üzerindeki <strong>Windows</strong> kullanıcılarından ve dahil oldukları grup bilgilerinden yararlanarak az bir kodlama ile doğrulama ve yetkilendirme işlemlerini gerçekleştirebiliriz. Afiyet olsun <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /></p>
<p><a href="https://buraksenyurt.com/pics/2010%2f2%2fUsingCustomAuthorization_RC.rar">UsingCustomAuthorization_RC.rar (17,67 kb)</a> <strong>[Örnek Visual Studio 2010 Ultimate RC sürümü üzerinde geliştirilmiş ve test edilmiştir]</strong></p>2010-03-22T04:30:00+00:00workflow serviceswf 4.0wcf 4.0bsenyurtBu yazımızda .Net Framework 4.0 tarafında geliştireceğimiz Workflow Service' lerde yetkilendirme işlemini nasıl sağlayabileceğimizi görmeye çalışacağız.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=a42af483-997f-467a-a56d-41159d0f99e30https://buraksenyurt.com/trackback.axd?id=a42af483-997f-467a-a56d-41159d0f99e3https://buraksenyurt.com/post/Workflow-Services-Custom-Authorization#commenthttps://buraksenyurt.com/syndication.axd?post=a42af483-997f-467a-a56d-41159d0f99e3https://buraksenyurt.com/post/Workflow-Foundation-40-Paralel-Olmak-ya-da-OlmamakWorkflow Foundation 4.0 - Paralel Olmak ya da Olmamak2010-03-16T02:15:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2010%2f2%2fblg155_Giris.jpg" alt="" width="250" height="174" />Merhaba Arkadaşlar,</p>
<p>Pek çoğumuz ünlü İngiliz şairi <strong>Shakespeare</strong>' in adını ve eserlerini bir şekilde duymuş, okumuş veya seyretmişizdir. Yaşadığı<strong> 1564-1616</strong> yılları arasında yazdığı sayısız <strong>Komedi, Trajedi </strong>ve <strong>Romanesk </strong>bulunmaktadır. Bunlar yüz yıllar boyu Tiyatrolarda sergilenmiş ve edebi değeri yüksek eserlerdir. <strong>Shakespeare </strong>dendiğinde insanın aklına hemen <strong>Romeo ve Juliet, Hamlet, Othello, Machbeth </strong>gibi eserleri gelmektedir. Aslında <strong>Edebiyat</strong>' tan çok fazla anlamam. Büyük bir ihtimalle <strong>Matematikçi </strong>olduğum içindir.</p>
<p>Dolayısıyla <strong>Shakespeare </strong>gibi ünlü şarilerin eserlerini hayatım boyunca çok fazla dikkate almamışımdır. Tabi son zamanlarda bu tip kült klasiklerin<strong> NTV Yayınlarından</strong> çıkan çizgi serileri yer almakta. En azından çocuklarımızın okuması için bir hamlede bulunabiliriz. Her ne kadar <strong>Shakespeare</strong>' i çok fazla okumasam da, <strong>Mel Gibson' </strong>ın oyunculuğuyla parladığı <strong>Hamlet </strong>filmini seyretmişimdir. Her ne kadar <strong>Shakespeare</strong>' in eserlerindeki anlamı, derinliği tam olarak bilemesem de, şiirindeki şu meşhur mısrayı hiç unutmam; <strong>"Olmak ya da olmamak; işte bütün mesele bu" </strong>. Bu konuya nereden mi geldik? Kısaca hikayeyi anlatayım.</p>
<p>Geçtiğimiz günlerde <strong>Workflow Foundation 4.0</strong> içerisinde <strong>NativeActivity </strong>türevli bileşenlerde hata yönetiminin nasıl yapılabileceğini incelerken, ne olduysa kendimi <strong>ParallelForEach<T> </strong>aktivitesini çalıştırmaya uğraşırken buldum. Bir türlü istediğim gibi ayrı <strong>Thread </strong>parçaları oluşturulmuyor dolayısıyla aktivite içerisine aldığım işler paralel olarak yürütülmüyordu. O sırada şöyle mırıldandığımı çok net hatırlıyorum;<strong> "Paralel olmak ya da olmamak. Sanırım tüm mesele bu..."</strong> <img title="Sealed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-sealed.gif" alt="Sealed" border="0" /> İşte bu yazımızda<strong> ParallelForEach<T></strong> aktivitesinin örnek senaryoya göre neden çalıştırılamadığını ve buna karşın basit olan çözümün ne olduğu görmeye çalışacağız. Öncelikli olarak sorunumuzu örnek bir senaryo üzerinden masaya yatıralım. Bu amaçla aşağıdaki sınıf diagramında görülen <strong>CodeActivity </strong>türevli bir bileşenimiz olduğunu düşünelim.</p>
<p><img src="/pics/2010%2f2%2fblg155_ClassDia1.gif" alt="" /></p>
<p>Kod içeriği;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
using System.Threading;
namespace ErrorHandlingForNativeActivities
{
public sealed class LetterCalculaterActivity
: CodeActivity
{
public InArgument<char> Letter { get; set; }
protected override void Execute(CodeActivityContext context)
{
Thread.Sleep(1000);
Console.WriteLine(
"{0} ASCII = {1} | Current Thread Id : {2}"
, Letter.Get(context)
,((byte)Letter.Get(context)).ToString()
, Thread.CurrentThread.ManagedThreadId.ToString());
}
}
}</pre>
<p><strong>CodeActivity </strong>türevli olan bu bileşenimiz <strong>InArgument<char></strong> tipinden olan <strong>Letter </strong>isimli özelliğin çalışma zamanı değerini almakta ve<strong> ASCII </strong>kodu karşılığı ile o anki <strong>yönetimli(Managed) Thread Id</strong> değerlerini ekrana yazdırmaktadır. <strong>Execute </strong>metodunda dikkat edileceği üzere şakacıktan ana <strong>Thread</strong>' in 1 saniye süreyle duraksatılması söz konusudur. Peki bu <strong>Activite </strong>bileşeni ne işimize yarayacak? Bu amaçla tasarım görünümü aşağıdaki gibi olan bir <strong>Workflow </strong>geliştirdiğimizi düşünelim.</p>
<p><img src="/pics/2010%2f2%2fblg155_DesignTime.gif" alt="" /></p>
<p><strong>Xaml içeriği;</strong></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Activity........>
<x:Members>
<x:Property Name="vSentence" Type="InArgument(x:String)" />
</x:Members>
<sap:VirtualizedContainerService.HintSize>349,370</sap:VirtualizedContainerService.HintSize>
<mva:VisualBasic.Settings>Assembly references and imported namespaces for internal implementation</mva:VisualBasic.Settings>
<Sequence sad:XamlDebuggerXmlReader.FileName="D:\Vs 2010\RC\Workflow Foundation\ErrorHandlingForNativeActivities\ErrorHandlingForNativeActivities\ParallelFlow.xaml" sap:VirtualizedContainerService.HintSize="309,330">
<sap:WorkflowViewStateService.ViewState>
<scg:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">True</x:Boolean>
</scg:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<ParallelForEach x:TypeArguments="x:Char" DisplayName="ParallelForEach<Char>" sap:VirtualizedContainerService.HintSize="287,206" Values="[vSentence]">
<ActivityAction x:TypeArguments="x:Char">
<ActivityAction.Argument>
<DelegateInArgument x:TypeArguments="x:Char" Name="ltr" />
</ActivityAction.Argument>
<local:LetterCalculaterActivity sap:VirtualizedContainerService.HintSize="257,100" Letter="[ltr]" />
</ActivityAction>
</ParallelForEach>
</Sequence>
</Activity></pre>
<p>Tasarım zamanından da görüleceği üzere, <strong>ParallelFlow.xaml</strong> içerisinde <strong>ParallelForEach<T> </strong>aktivite bileşeni yer almaktadır. <strong>ParallelForEach<T></strong>, <strong>char </strong>tipi ile çalışacak şekilde ayarlanmıştır ve <strong>Workflow </strong>için <strong>vSentence </strong>isimli argümanın değerini alıp, söz konusu cümledeki her bir harfi, içerdiği <strong>LetterCalculaterActivity </strong>bileşenine göndermektedir. Bu akıştan çalışma zamanındaki beklentimiz, söz konusu cümledeki harflerin paralel thread' lerin ele alacağı şekilde yorumlaması ve kullanılmasıdır. Bu arada unutmadan, <strong>Main </strong>metodunun içeriğinin aşağıdaki gibi olduğunu düşünelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
namespace ErrorHandlingForNativeActivities
{
class Program
{
static void Main(string[] args)
{
ParallelFlow pFlow = new ParallelFlow();
WorkflowInvoker.Invoke(pFlow);
Console.WriteLine("İşlemler tamamlandı");
Console.ReadLine();
}
}
}</pre>
<p>ve buna göre çalışma zamanı sonuçlarına kısaca bir bakalım.</p>
<p><img src="/pics/2010%2f2%2fblg155_FirstRuntime.gif" alt="" /></p>
<p>Uppsss!!! <img title="Sealed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-sealed.gif" alt="Sealed" border="0" /> Enteresan bir durum söz konusu.<strong> "Bu gün çok güzel bir gündü" </strong>cümlesi ters sırada işlenmiştir. Dahası tüm işlemler <strong>1</strong> numaralı <strong>ThreadId</strong>' ye bağlı olarak gerçekleştirilmektedir. Bir başka deyişle <strong>ParallelForEach<T></strong> aktivitesi istediğimiz/beklediğimiz şekilde <span style="text-decoration: underline;">çalışmamıştır</span>. Sorun ne olabilir acaba?<img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> Aslında sorundan ziyade yanlış bir çözüm yolu izlediğimizi ifade edebiliriz. Esasında <strong>ParallelForEach<T> </strong>bileşeninin bu senaryoda işe yarayabilmesi için içerisinde yer alan <strong>CodeActivity </strong>türevli bileşenin de paralel çalışmaya destek vermesi bir başka deyişle asenkron olarak yürütülebiliyor olması gerekmektedir. Ahaaa!! <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> İşte şimdi çözümü bulduk. Buna göre <strong>LetterCalculaterActivity </strong>bileşeninin <strong>CodeActivity </strong>yerine <strong>AsyncCodeActivity </strong>tipinden türetilmesi ve kodlanması yeterlidir. O halde söz konusu bileşenimizi aşağıdaki şekilde değiştirelim.</p>
<p><img src="/pics/2010%2f2%2fblg155_ClassDia2.gif" alt="" /></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
using System.Threading;
namespace ErrorHandlingForNativeActivities
{
public sealed class LetterCalculaterActivity
: AsyncCodeActivity
{
public InArgument<char> Letter { get; set; }
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
Func<char, bool> dlg = c =>
{
Thread.Sleep(1000);
Console.WriteLine("{0} için hesaplamalar| Current Thread Id : {1}", c, Thread.CurrentThread.ManagedThreadId.ToString());
return true;
};
context.UserState = dlg;
return dlg.BeginInvoke(Letter.Get(context), callback, state);
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
bool r = ((Func<char, bool>)context.UserState).EndInvoke(result);
Console.WriteLine("\t{0}", r);
}
}
}</pre>
<p>Kod parçasına göre, <strong>temsilcilerin(Delegates) BeginInvoke </strong>ve <strong>EndInvoke </strong>metodlarından yararlanılarak aktivite içerisinde asenkron bir işin yürütülmesinin sağlandığını özetleyebiliriz.</p>
<blockquote>
<p>AsyncCodeActivity türevli bileşenlerin nasıl geliştirileceğini daha önceden <a class="postheader taggedlink" href="https://buraksenyurt.com/post/Workflow-Foundation-40-Custom-Async-Activity">Workflow Foundation 4.0 - Custom Async Activity Geliştirmek [Beta 2] </a>isimli yazımızda değerlendirmiştik.</p>
</blockquote>
<p>Buna göre program kodumuzu yeniden test edersek, çalışma zamanında aşağıdakine benzer sonuçlar ile karşılaştığımızı görebiliriz.</p>
<p><img src="/pics/2010%2f2%2fblg155_LastRuntime.gif" alt="" /></p>
<p>Çalışma sırası tam olarak şöyledir ; <strong>"Bu gnü ç kogz eülbir günüd"</strong> . Sakın bu cümleyi okumaya çalışmayın.<img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /></p>
<p>Görüldüğü üzere <strong>farklı yönetimli Thread Id </strong>değerleri üretilmiş, üstelik<strong> "Bu gün çok güzel bir gündü"</strong> cümlesi aynı harf sırasına göre ele alınmamıştır. Bir başka deyişle paralel çalışma sağlanmıştır. Tabi çalışma zamanı ve çevresel donanım şartlarına göre bu sıralama her seferinde farklı sonuçlanabilir veya aynı sonuçlar tekrar tekrar elde edilebilir. Aslında bütün mesele de budur zaten. <strong>"Paralel olmak ya da olmamak"</strong>. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2010%2f2%2fToBeOrNotToBe_RC.rar">ToBeOrNotToBe_RC.rar (48,75 kb)</a><strong> [Örnek uygulama Visual Studio 2010 Ultimate RC Sürümü Üzerinde Geliştirilmiştir ve Test Edilmiştir]</strong></p>2010-03-16T02:15:00+00:00wfwf 4.0parallel programming.net framework 4.0bsenyurtGeçtiğimiz günlerde Workflow Foundation 4.0 içerisinde NativeActivity türevli bileşenlerde hata yönetiminin nasıl yapılabileceğini incelerken, ne olduysa kendimi ParallelForEach<T> aktivitesini çalıştırmaya uğraşırken buldum. Bir türlü istediğim gibi ayrı Thread parçaları oluşturulmuyor dolayısıyla aktivite içerisine aldığım işler paralel olarak yürütülmüyordu.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=5250d1cd-28fc-45e0-adb8-2e85b5efa6aa0https://buraksenyurt.com/trackback.axd?id=5250d1cd-28fc-45e0-adb8-2e85b5efa6aahttps://buraksenyurt.com/post/Workflow-Foundation-40-Paralel-Olmak-ya-da-Olmamak#commenthttps://buraksenyurt.com/syndication.axd?post=5250d1cd-28fc-45e0-adb8-2e85b5efa6aahttps://buraksenyurt.com/post/Screencast-Workflow-Foundation-40-Switch-Aktivite-Bileseni-RCScreencast - Workflow Foundation 4.0 Switch Aktivite Bileşeni [RC]2010-03-01T00:35:00+00:00bsenyurt<p><img style="float: left;" src="http://www.buraksenyurt.com/pics/2010%2f2%2fblg158_VideoLink2.gif" alt="" width="250" height="186" />Merhaba Arkadaşlar,</p>
<p>Bildiğiniz üzere bir süre önce<strong> .Net Framework 4.0 RC</strong> sürümü yayınlandı. Bu da <strong>RTM </strong>ve <strong>Release </strong>sürüme çok yaklaştığımızı göstermekte. <strong>RC(Release Candidate) </strong>sürümünün önceki <strong>Beta </strong>sürümlerine göre daha tutarlı olduğunu söyleyebiliriz. Ancak yine de bu görsel dersimizde anlatacaklarımız ile ilişkili olarak <strong>Bug Fix</strong>' ler veya farklı güncelleştirmeler söz konusu olacaktır. Peki ya biz bu görsel dersimizde neyi ele almaktayız? <img title="Wink" src="http://www.buraksenyurt.com/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" border="0" alt="Wink" /></p>
<p><strong>Workflow Foundation 4.0</strong> içerisinde yer alan<strong> Built-In Activity</strong> bileşenleri arasında bir programlama dilinin temel özelliklerinin de çoğu yer almakta aslında. Söz gelimi <strong>ForEach<T>, While, If, DoWhile, Assign, InvokeMethod, WriteLine </strong>ve benzerleri gibi aktiviteler göz önüne alındığında, değişken ataması, metod çağırılması, döngü kurulması veya koşullu kontrollerin yapılması son derece kolay. Bu anlamda, <strong>WF 4.0 </strong>içerisinde yer alan aktivite bileşenlerinden bir tanesi de <strong>Switch</strong>.<strong> C#</strong> dilinden aşina olduğumuz bu koşul ifadesinin mantığını, <strong>Workflow </strong>tiplerinde de kullanabilmekteyiz. <a title="NedirTv?" href="http://www.nedirtv.com">NedirTv?</a> katkılarıyla gerçekleştirdiğimiz bu görsel dersimizde <strong>Switch </strong>aktivite bileşeninin özel<strong> .Net</strong> tipleri için nasıl değerlendirilebileceğini incelemeye çalışmaktayız. Hepinize keyifli seyirler dilerim.</p>
<p><strong>[Görsel derste yer alan örneğimiz Visual Studio 2010 Ultimate Beta 2 sürümünde geliştirilmiş ve test edilmiştir.]</strong></p>
<p><strong>Dosya Boyutu :</strong> 24.5 Mb</p>
<p><strong>Süre : </strong>13:43</p>
<p><a title="Workflow Foundation 4.0 - Switch Aktivite Bileşeni [RC]" href="http://www.nedirtv.com/video/Screencast---Workflow-Foundation-40-Switch-Aktivite-Bileseni-RC.aspx" target="_blank"><strong>İzlemek veya Download etmek için</strong></a></p>
<p><a href="http://www.buraksenyurt.com/pics/2010%2f2%2fUsingSwitch.rar">UsingSwitch.rar (57,95 kb)</a></p>2010-03-01T00:35:00+00:00screencastwf 4.0wfbsenyurthttps://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=fd08c99a-e6a3-41b4-839e-54a39e13da182https://buraksenyurt.com/trackback.axd?id=fd08c99a-e6a3-41b4-839e-54a39e13da18https://buraksenyurt.com/post/Screencast-Workflow-Foundation-40-Switch-Aktivite-Bileseni-RC#commenthttps://buraksenyurt.com/syndication.axd?post=fd08c99a-e6a3-41b4-839e-54a39e13da18https://buraksenyurt.com/post/WF-40-BookmarksWF 4.0 - Bookmarks [RC]2010-02-19T05:04:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2010%2f2%2fblg154_Giris.jpg" alt="" />Merhaba Arkadaşlar,</p>
<p>Çalışmakta olduğum yazılım şirketinin çok yakınında kocaman bir alışveriş merkezi bulunmakta. Bazen öğle yemekleri için alışveriş merkezinin tahsis ettiği servisler ile oraya gidiyoruz. Alışveriş merkezi olduğu için tehlikeli bir yer olduğunu da söyleyebiliriz. <img title="Sealed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-sealed.gif" alt="Sealed" border="0" /> Nitekim çok büyük bir yer ve A' dan Z'ye herşey bulunabilmekte. Arkadaşlarım ile sık uğradığım mekanlardan birisi de D&R kitap evi. Çoğunlukla aylık dergilerimi almak için uğramaktayım <em>(Aslında Türkiye' de Amazon gibi bir kitap dağıtım evi olmadığı için çok şanslı olduğumu düşünüyorum. Her halde öyle bir yer açılsa kazancımın çok büyük bir kısmı meslek kitaplarına gider)</em></p>
<p>Geçen gün yine Bilim Teknik, NTV Bilim ve NG dergilerimi almak üzere oradaydım. Sırada beklerken kasada ücretsiz olarak verilen kitap ayraçlarını farkettim. Hep görürdüm ama bu gün biraz daha anlamlı geliyorlardı. Üzelerinde çeşitli reklamlar veya faydalı bilgiler bulunan bu ayraçlar yardımıyla<em>(ki <strong>Bookmark </strong>diyebilir miyiz acaba? <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" />)</em>, okuduğumuz kitabın neresinde kaldığımızı kolayca hatırlayabildiğimizi düşünmeye başladım. Derken evde uzun süredir el değdirip kaldığım yerden devam edemediğim kitaplarım aklıma geldi. Hüzünlendim...<img title="Tongue out" src="/editors/tiny_mce3/plugins/emotions/img/smiley-tongue-out.gif" alt="Tongue out" border="0" /> Tesadüfe bakın ki bu kitapları okumak baya uzun sürmüştü. Zamanın neresinde okumaya başladığımı pek hatırlamamakla birlikte, neresinde kaldığımı da hatırlamadığım bir kaç kitap...Tesadüfe bakın ki bu uzun sürecin benzeri Workflow Uygulamalarında da söz konusu olabilmekteydi. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /></p>
<p>Aslında<strong> .Net Framework 3.5</strong> sürümünde <strong>Uzun Süreli İşemlerin(Long Running Process) </strong>için <strong>ExternalDataExchangeService </strong>veya <strong>WorkflowQueue</strong> tiplerinden yararlanılmaktadır. Ne varki <strong>Workflow Foundation 4.0</strong> sürümünde, geliştiricilerin kulağına daha hoş gelen <strong>Bookmark </strong>kavramı ile karşılaşmaktayız. Peki <strong>Bookmark </strong>nedir? Ne işe yaramaktadır? Nasıl kullanılmaktadır? Konuyu anlamanın belki de en kolay yolu her zaman ki gibi basit bir örnek üzerinden ilerlemekle olacaktır. Bu nedenle Bookmark kavramının tanımlamasını yazımızın sonunda yapmaya çalışacağız.</p>
<p><strong>Bookmark </strong>kullanımında önemli olan noktalardan birisi, geçici olarak duraksatılabilecek(Pause) <strong>Activity </strong>bileşeninin <strong>Workflow' </strong>un çalışma zamanı içeriğine ulaşabiliyor olmasıdır. Bu nedenle en uygun aktivite bileşenleri, <strong>NativeActivity(veya NativeActivity<T>) </strong>türevli olanlardır. Bunu ilk gereksinimimiz olarak düşünebiliriz. Aşağıdaki diagramda<strong> .Net Framework 4.0 RC </strong>sürümü içerisinde yer alan <strong>NativeActivity </strong>tipleri ve üyeleri görülmektedir.</p>
<p><img src="/pics/2010%2f2%2fblg154_ClassDiagram.gif" alt="" /></p>
<p>Şimdi bu türetmeyi kullanarak aşağıdaki kod parçasında görülen aktivite bileşenini geliştirdiğimizi düşünelim. İlgili örneğin bir <strong>Workflow Console Application </strong>üzerinden geliştirebiliriz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
namespace HelloBookmarks
{
public sealed class ResizeImageActivity
: NativeActivity
{
protected override bool CanInduceIdle
{
get
{
return true;
}
}
protected override void Execute(NativeActivityContext context)
{
Console.WriteLine("Resize Image bir takım işlemler yapıyor");
// Bazı işlemler
// İkinci parametre BookmarkCallback temsilcisi tarafından işaret edilen bir fonksiyondur.
context.CreateBookmark("ResizeImageBookmark",
(nac, b, obj) =>
{
Console.WriteLine("Resume edilen bookmark adı {0}",b.Name);
}
);
}
}
}</pre>
<p><strong>Bookmark </strong>işlemleri <strong>Idle </strong>konuma düşebilen <strong>Workflow </strong>aktivitelerinde işe yarayacak bir teknik olarak düşünülmelidir. Nitekim bir aktivite içerisinde herhangibir zamanda <strong>Pause </strong>etme ve sonraki bir anda <strong>Resume </strong>etme söz operasyonları konusudur. Bu sebepten <strong>CanIncludeIdle </strong>özelliğinin <strong>override </strong>edilmesi ve geriye <strong>true </strong>değer döndürmesi söz konusudur. Aksi durumda çalışma zamanında aşağıda görülen <strong>InvalidOperationException </strong>hata mesajı alınacaktır.</p>
<p><img src="/pics/2010%2f2%2fblg154_Exception.gif" alt="" /></p>
<p><strong>CreateBookmark </strong>metodunun ikinci parametresi <strong>BookmarkCallback </strong>tipinden bir<strong> temsilcidir(Delegate)</strong>. Bu temsilcinin yapısı ise aşağıdaki gibidir.</p>
<p><strong>public delegate void BookmarkCallback(System.Activities.NativeActivityContext context, System.Activities.Bookmark bookmark, object value)</strong></p>
<p>Buna göre örneğimizde yer alan<strong> isimsiz metodun(Anonymous Method)</strong> ilk parametresi ile <strong>Activity</strong>' nin çalışma zamanındaki çevresel içeriğine, ikinci parametre ilede <strong>Bookmark </strong>örneğine erişilebilir. Bu temsilci aslında bir <strong>geri bildirim metodunu(Callback Method)</strong> işaret etmektedir. Bir başka deyişle, <strong>Idle </strong>konumda kalan <strong>Activity </strong>örneğinin tekrar <strong>Resume </strong>edilmesi halinde devreye girecek olan metod olarak düşünülebilir. Dolayısıyla geri bildirim metodu içerisinde <strong>CreateBookmark </strong>tarafında saklanan bazı varlıkların tekrardan yüklenmesi, hazırlanması gibi operasyonlar ele alınabilir. <strong>CreateBookmark</strong> metodunun aslında 8 <strong>aşırı yüklenmiş(Overload)</strong> versiyonu bulunmaktadır.</p>
<p>Diğer versiyonlar göz önüne alındığında dikkat çeken parametrelerden birisi <strong>BookmarkOptions Enum </strong>sabitidir. Bu enum sabiti <strong>MultipleResume, NonBlocking </strong>ve<strong> None </strong>değerlerinden birisini almaktadır. Varsayılan değer <strong>None' </strong>dır. <strong>MultipleResume </strong>olması halinde bir den fazla <strong>Resume </strong>işlemi yapılabileceği belirtilir. <strong>NonBlocking </strong>değerine göre ilgili aktivite bileşeni <strong>Resume </strong>edilmemiş olsa dahi <strong>WF' </strong>in çalışacağını belirtilir. Nitekim normal şartlar altında bir aktivite içerisinde oluşturulan <strong>Bookmark'</strong> ların tamamı <strong>Resume </strong>edilmediği sürece <strong>WF</strong>' in tamamlanması söz konusu değildir. Dilerseniz <strong>MultipleResume </strong>ve <strong>NonBlocking </strong>değerlerini bir arada kullanabilirsiniz. Gelelim aktivitenin nasıl kullanılacağına. Örneğimizdeki amacımız sadece <strong>Bookmark </strong>kullanımını görmek olduğundan aşağıdaki şekilde görülen <strong>Workflow Activity</strong> içeriğini değerlendirebiliriz.</p>
<p><img src="/pics/2010%2f2%2fblg154_Workflow1.gif" alt="" /></p>
<p><strong>Bookmark </strong>kullanımı yazımızın başında da belirttiğimiz üzere <strong>uzun süreli işlemler(Long Running Process)</strong> için anlamlıdır. Bu sebepten <strong>WorkflowApplication </strong>tipinin kullanılması gerekmektedir. <strong>Workflow Console Application</strong> tipinden olan uygulamamızda, çalışma zamanındaki <strong>Idle </strong>durumları irdelememiz aslında son derece kolaydır.<strong> Console.ReadLine</strong> metodu burada çok işe yarayacaktır. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> İşte kod içeriğimiz;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
using System.Threading;
namespace HelloBookmarks
{
class Program
{
static void Main(string[] args)
{
AutoResetEvent rE = new AutoResetEvent(false);
// Workflow örneği oluşturlur
Workflow1 wf1 = new Workflow1();
// Workflow Application örneği oluşturulur
WorkflowApplication wfApp = new WorkflowApplication(wf1);
// Workflow' un tamamlanması sonrası devreye girecek Completed olay metodu
wfApp.Completed = (e) => { rE.Set(); }; // işlemlerin bittiğine dair bilgilendirme için AutoResetEvent örneğinin Set metodu çağırılır.
// Workflow çalışma zamanı başlatılır dolayısıyla Workflow1 örneği yürütülür
wfApp.Run();
Console.WriteLine("Bir süre bekleyin...");
Console.ReadLine(); // Bu noktada Workflow1 örneğinin Idle konuma geçmesi söz konusudur.
/* Kullanıcı devam etmek istediğinde Bookmark' lanan Workflow1 örneğine tekrardan hayata geçirilir. ResumeBookmark metodunun ilk parametresi dikkat edileceği üzere ResizeImageActivity içerisinde kullanılan Bookmark adıdır. Bu adın aslında aktivite bileşeni içerisinden çalışma zamanı ortamına verilmesi(örneğin bir OutArgument) ile faydalı olabilir. İkinci parametre ise hangi Workflow örneğinin Resume edileceğidir. Buna göre Workflow1 içerisinde ResizeImageBookmark isimli Bookmark' ın yer aldığı aktivite bileşeninin Resume edilmesi söz konusudur. */
BookmarkResumptionResult result = wfApp.ResumeBookmark("ResizeImageBookmark", wf1);
// ResumeBookmark metodunun sonucu olan Enum sabitinin değerine göre bir işlem yapılabilir
switch (result)
{
case BookmarkResumptionResult.NotFound:
Console.WriteLine("Not Found");
break;
case BookmarkResumptionResult.NotReady:
Console.WriteLine("Not Ready");
break;
case BookmarkResumptionResult.Success:
Console.WriteLine("Success");
break;
default:
break;
}
// Eğer Workflow Application' ın beklediği çalışan örnekler var ise bunların tamamlanması beklenir
rE.WaitOne();
}
}
}</pre>
<p>Aslında örnek kodumuz <strong>Workflow1 </strong>tipinden bir nesne örneğini çalıştırmakta ve yaşamı içerisinde kullanıcından belirli süreliğine tuşa basmasını beklemektedir. Tuşa basmayı beklediği sırada ise <strong>Idle </strong>olabilen bileşenlerin bu konuma geçmesi söz konusudur. <strong>ResumeBookmark </strong>çağrısından sonra ise <strong>Bookmark </strong>ile Pause konumda duran aktivitenin ilgili geri bildirim metodunun çağırılması ve dolayısıyla yürütülmeye devam edilmesi sağlanır. İşte örnek program kodumuzun çalışma zamanı çıktısı.</p>
<p><img src="/pics/2010%2f2%2fblg154_Runtime.gif" alt="" /></p>
<p>Bu arada çalışma zamanında aktif olan <strong>Bookmark </strong>listesini de <strong>WorkflowApplication </strong>nesne örneğine ait <strong>GetBookmarks </strong>metodu üzerinden alabileceğinizi belirtmek isterim. Aşağıdaki kod parçasında bu durum örneklenmektedir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
using System.Threading;
using System.Activities.Hosting;
namespace HelloBookmarks
{
class Program
{
static void Main(string[] args)
{
AutoResetEvent rE = new AutoResetEvent(false);
Workflow1 wf1 = new Workflow1();
WorkflowApplication wfApp = new WorkflowApplication(wf1);
wfApp.Completed = (e) => { rE.Set(); }; // işlemlerin bittiğine dair bilgilendirme için AutoResetEvent örneğinin Set metodu çağırılır.
wfApp.Run();
Console.WriteLine("Bir süre bekleyin...");
Console.ReadLine();
foreach (BookmarkInfo bm in wfApp.GetBookmarks())
{
Console.WriteLine(bm.BookmarkName);
}
...</pre>
<p>Şimdi örneğimizi biraz daha ilginç bir hale getirelim. Öncelikli olarak aşağıdaki kod içeriğine sahip<strong> Custom Activity</strong> sınıfını oluşturarak projemize ilave edelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
namespace HelloBookmarks
{
public sealed class SendImageActivity
: NativeActivity
{
protected override bool CanInduceIdle
{
get
{
return true;
}
}
protected override void Execute(NativeActivityContext context)
{
Console.WriteLine("Send Image bir takım işlemler yapıyor");
context.CreateBookmark("SendImageBookmark",
(nac, b, obj) =>
{
Console.WriteLine("Resume edilen bookmark adı {0}",b.Name);
}
);
}
}
}</pre>
<p><strong>ResizeImageActivity </strong>tipinin tıpkısının aynısı olan bu bileşeni de ele alarak <strong>Workflow1 </strong>içeriğini aşağıdaki şekilde görüldüğü gibi değiştirelim.</p>
<p><img src="/pics/2010%2f2%2fblg154_Workflow1Last.gif" alt="" /></p>
<p>Bu sefer aynı anda birden fazla aktivitenin çalıştırılmasına izin veren <strong>Parallel </strong>bileşeninden yararlanmaktayız. İncelemek istediğimiz nokta ise şu; her iki aktivite de <strong>Execute </strong>metodları içerisinde birer <strong>Bookmark</strong> oluşturmaktadır. Buna göre program kodumuzda birden fazla <strong>Bookmark</strong>' ın nasıl ele alınacağına bakmak istiyoruz. Söz konusu vakayı analiz etmek için, <strong>Main </strong>metoduna ait kod içeriğini aşağıdaki gibi değiştirmemiz yeterli olacaktır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Activities;
using System.Threading;
using System.Activities.Hosting;
namespace HelloBookmarks
{
class Program
{
static void Main(string[] args)
{
AutoResetEvent rE = new AutoResetEvent(false);
Workflow1 wf1 = new Workflow1();
WorkflowApplication wfApp = new WorkflowApplication(wf1);
wfApp.Completed = (e) => { rE.Set(); };
wfApp.Run();
Console.WriteLine("Bir süre bekleyin...");
Console.ReadLine();
Console.WriteLine("***Etkin Bookmark Listesi***");
foreach (BookmarkInfo bm in wfApp.GetBookmarks())
{
Console.WriteLine("Bookmark Name:{0}, Owner:{1}",bm.BookmarkName,bm.OwnerDisplayName.ToString());
}
Console.WriteLine();
BookmarkResumptionResult result1 = wfApp.ResumeBookmark("ResizeImageBookmark", wf1);
BookmarkResumptionResult result2 = wfApp.ResumeBookmark("SendImageBookmark", wf1);
Console.WriteLine("ResizeImageBookmark için Resume Result : {0}",result1.ToString());
Console.WriteLine("SendImageBookmark için Resume Result : {0}", result2.ToString());
rE.WaitOne();
Console.ReadLine();
}
}
}</pre>
<p>Ve işte çalışma zamanı sonuçları;</p>
<p><img src="/pics/2010%2f2%2fblg154_Runtime2.gif" alt="" /></p>
<p>Çıktımıza göre her iki akitivite bileşeni, eş zamanlı olarak <strong>Execute </strong>metodlarını icra etmiş ve birer <strong>Bookmark </strong>oluşturmuştur. Sonrasında kullanıcının tuşa basması ile devam eden süreçte ilk olarak yüklü olan <strong>Bookmark</strong>' lar listelenmiş ve ardından <strong>ResumeBookmark </strong>çağrıları nedeniyle <strong>Pause </strong>edilmiş olan aktivitelerin geri bildirim operasyonları devreye girmiştir. Her iki <strong>Bookmark</strong>' ında <strong>Resume </strong>edilmesinin sonucu olarak <strong>Workflow1 </strong>örneğinin işlemlerini tamamladığı anlaşılmaktadır. Program kodu da buna göre sonlanır.</p>
<p>Görüldüğü gibi bir aktivitenin <strong>Bookmark</strong>' lanması aslında isimlendirilmiş duraksama noktalarına(Named Pause Points) sahip olması anlamına gelmektedir. Öyleki, <strong>ResumeBookmark </strong>metodu sayesinde <strong>Pause </strong>edilen noktadan tekrar yürütülmeleri sağlanabilir. Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2010%2f2%2fHelloBookmarks.rar">HelloBookmarks.rar (54,52 kb)</a><strong> [Örnek Visual Studio 2010 Ultimate RC sürümü üzerinde geliştirilmiş ve test edilmiştir]</strong></p>2010-02-19T05:04:00+00:00workflow foundationwf 4.0wfbsenyurtÇalışmakta olduğum yazılım şirketinin çok yakınında kocaman bir alışveriş merkezi bulunmakta. Bazen öğle yemekleri için alışveriş merkezinin tahsis ettiği servisler ile oraya gidiyoruz. Alışveriş merkezi olduğu için tehlikeli bir yer olduğunu da söyleyebiliriz.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=b7ed662e-997e-4474-8def-6bd3cb380c4c0https://buraksenyurt.com/trackback.axd?id=b7ed662e-997e-4474-8def-6bd3cb380c4chttps://buraksenyurt.com/post/WF-40-Bookmarks#commenthttps://buraksenyurt.com/syndication.axd?post=b7ed662e-997e-4474-8def-6bd3cb380c4c