Skip to content


WPF RichTextbox Parçalı Yazı Rengi Değiştirmek

WPF ile ilgili bilgim son derece sınırlı olmakla birlikte, şuan üzerinde çalıştığım proje de WPF kullanmam gerekiyor. Uygulamanın analizinde belirli bir textboxt içerisinde, belirli uzunlukta metin alınacağı ve bu belirli uzunluktan sonra girilen metnin farklı bir renkte boyanarak  silineceği görsel bilgisinin kullanıcıya verilmesi gerekiyor.

Bir örnekle açıklarsak, metin kutusuna girilen 25 karakterden ilk 10 karakteri kırmızı, geri kalan 15 karakterin siyah olması ve tamam düğmesine basıldığında bu 10 karakterin işlenmesi gerekiyor.

Normalde rahatlıkla yapılabilecek bu isteği, WPF’in bileşenlerinin biraz yetersiz ve farklı, ve benim bu konudaki bilgimin az oluşu nedeniyle yarım gün boyunca araştırmam gerekti. Fakat neyseki mutlu son ile bitti ve aşağıdaki birkaç satır kod ile bu işi kotardım.

Öncelikle formumuza koyduğumuz bir RichTextBox nesnesinin KeyUp olayının içerisine aşağıdaki satırları yazıyoruz.

private void TextInput_KeyUp(object sender, KeyEventArgs e)
{

// mevcut metindeki butun renklendirmeleri kaldir
TextRange documentRange = new TextRange(TextInput.Document.ContentStart, TextInput.Document.ContentEnd);
documentRange.ClearAllProperties();
// 10 karakterden fazla bir text girilmisse
if (documentRange.Text.Trim().Length >= 10)
{
Color c = Colors.Red;
SolidColorBrush brush = new SolidColorBrush(c);

// 10. karakterin pointer bilgisini al. (text in sonunda \r\n karakterleri oldugundan +2)
var rightPointer = TextInput.Document.ContentStart.GetPositionAtOffset(10 + 2, LogicalDirection.Forward);
// ilk 10 karakteri sec
TextRange tr = new TextRange(TextInput.Document.ContentStart, rightPointer);

// yazi rengini degistir
tr.ApplyPropertyValue(TextElement.ForegroundProperty, brush);
}
}

WPF RichTextBox Output

WPF RichTextBox Coloring Output

WPF in normal TextBox bileşeni bu tarz renklendirmeyi desteklemediği için RichTextBox kullanmamız gerekti.

Ayrıca, RichTextBox’un textchanged olayına bu kodları yazarsanız metnin rengini değiştirdiğiniz anda tekrar tekrar textchange olayının tetiklenmesine sebep olacağından hata ile karşılaşırsınız.

Posted in WPF.

Tagged with , , , , .


Workflow Foundation ve Transaction Kullanımı

Bugün Workflow Foundation ile transaction işlemleri nasıl yapılır diye bir inceleyim dedim. Öncelikle Framework 3.5 ile gelen Transaction Scope Activity’nin derdime çözüm olacağını düşündüm fakat biraz inceleyince pek uygun olmadığını anladım. Zira bu aktivitenin yaptığı sadece içerisindeki aktivite bloklarını atomik hale getirmekten ibaretti.

Benim yapmak istediğim ise, bir iş akışı başlatmak ve bu akışın herhangi bir aşamasında bir problem olduğu durumda rollback yapmak. Bu bağlamda (file veya bir listeyi de manipüle edebiliyor olabileceğim olasılığı ile) sql veritabanına birşeyler yazdığımı varsaydım.

Bu süreci gerçeklemek için SqlTransaction sınıfını kullandım. Şöyle ki; bir init aktivitesi içinde bağlantı bilgilerini hazırladıktan sonra, ilk aktivitede bağlantı açıyorum. ikinci aktivitede SqlTransaction başlatıyorum, üçüncü aktivitede iki adet kayıt giriyorum (ikinci kayıtta hata var). Sonraki aktivitede ise eğer kayıt yapıldıysa transaction’ı commit ediyorum. Son olarak da bağlantıyı kapatıyorum.

İkinci kayıtta soyadı alanını null geçtiğim ve veritabanı modelinin buna izin vermemesi nedeniyle transaction başarısız olacağından, ilk kayıt da geri alınacak ve veritabanına iki kayıt da yazılmayacak.

Şimdi bu senaryonu gerçekleyelim. Öncelikle veritabanımızı oluşturup, bir adet personel tablosu oluşturuyoruz. Benim kullandığım Personel tablosunun script’i aşağıdaki gibidir.

USE [TestDB]
GO

/****** Object:  Table [dbo].[Personel]    Script Date: 01/22/2010 15:06:50 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[Personel](
[PersonelID] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [varchar](50) NULL,
[LastName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Personel] PRIMARY KEY CLUSTERED
(
[PersonelID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

Bundan sonra, Visual Studio içerisinden projemizi oluşturuyoruz. Uygulama son derece basit bir state machine console application. Bir adet workflow içeriyor ve aşağıdaki gibi aktivitelere sahip.

Bundan sonra, StateActivity2 içerisinde yukarıda bahsettiğim akışı tasarlıyoruz. bunun için de en basitinden olsun diye adım adım CodeActity kullandım. 

Öncelikle initActivity ile workflow içerisinde kullanılacak connection, transaction ve command nesnelerinin tanımlıyoruz.

Bundan sonraki aktivitelerde ise aşağıda görebileceğiniz üzere; bağlantı açma, transaction başlatma, kayıt, transaction kapatma ve bağlantı sonlandırma işlemleri yapılıyor.

Bir sonraki çalışmam bunun entity framework ile kullanımı üzerine olacak.

Posted in Asp.NET, C#, SQL Server, Workflow Foundation.

Tagged with , , , .


Server 2008 ve IIS 7′li sistemde WebDeploymentPack 1603 hatası

Mevcut projemizde test sunucumuz Windows 2008 yüklü IIS 7 kullanan bir sisteme sahipti. Web tabanlı uygulamayı test sunucusuna deploy etmeye kalktığımda Kurulum Sihirbazı, “The installer was interrupted before <uygulamanın adı> could be installed. You need to restart the installer to try again’” şeklinde bir mesaj ile kurulumu iptal ediyordu. Event log’a baktığımda “…. Installation success or error status: 1603.” şeklinde bir hata aldığımızı gördüm. Öncelikle sorunun başka birşey olduğunu düşündüm  ve deployment pack’i tekrar tekrar oluşturdum. Her seferinde aynı hatayı verince google’a danışayım dedim. Nitiative, Inc adlı bir blogda bu sorunun aynısının yaşandığını ve bizim test sunucumuzdaki bir eksik konfigürasyon nedeniyle bu hatayı aldığımızı öğrendim.

Server Manager üzerinden IIS 7 servis rollerine “IIS 6 Metabase Compatibility” rolünü ekledikten sonra kurulum başarı ile başladı.

Posted in Deployment, IIS 7.

Tagged with , .


Workflow Persistence Service

Geliştirdiğimiz workflowların başlatıldığı anda bitmesinin gerekmediği durumlar olabilir. Yani, düğmeye bastığınızda yapılacak olan iş başka birilierinin onayına ihtiyaç duyuyor olabilir, başka kaynaklardan bilgi alması gerekiyor olabilir ya da buna benzer dış etkenlere bağlı workflow geliştiriyor olabilirsiniz.

Bu noktada workflowun bir noktada saklanması ve belirli şartlar olgunlaştığında veya istendiği takdirde yeniden çağrılması için Workflow Persistence Service kullanılır. .NET WF kütüphaneleri, SQL Server ile entegre bir biçimde bunu gerçekleştirmektedir.

Dolayısı ile uygulamalarınızda WF Persistence Service kullanmak için sadece gerekli ayarları yapıp servisi doğru parametre ile çağırmanız yeterlidir.

01-wfSQLScripts

Öncelikle SQL Server üzerinde workflowların kaydedileceği şemanın yaratılması gerekmektedir. .NET Framework 3.0 ile birlikte SQL Server üzerinde gerekli yapıyı oluşturacak SQL Scriptleri mevcuttur. Bunlara “c:\Windows\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN”  klasöründen erişebilirsiniz. Burada bulunan dosyalardan sırası ile şunları çalıştırıyoruz.

  1. SqlPersistenceService_Schema.sql
  2. SqlPersistenceService_Logic.sql
03-wfDBScheme Bu hazır olduktan sonra işin kod kısmına geliyoruz. Bu makale için geliştirdiğim örnek, bir Delay Activity içeriyor. Delay Activity, workflow’umuzu belirli bir süre bekleten bir aktivitedir. Örneğimizde bu bekletme işini workflow’un idle olması için kullanacağız.

Senaryomuza bakacak olursak; öncelikle wfApplication workflow’u çalışacak,, ardından 30 saniyelik bir bekleme sürecine girecek. Bizim Persistence servisimiz ise 15 sn aktivite göstermeyen bir workflow var ise bunu idle olacak şekilde belirleyecek. Bu, workflow’un

saklanmasına ve unload edilmesine yol açacak. Sonrasında belirli aralıklar ile kayıtlı workflowları toplayan servisimiz idle durumdaki bu worklowu bulup yeniden yükleyecek. Bu süreç içinde delay zamanı timeout olduğundan, yani aşıldığından, workflow’umuz sonlanacak.

Senaryomuzu tanıdıktan sonra yavaş yavaş kütüphanemizi ve kod bloğumuzu tanıyalım.

Worklow’u çalıştırmak için bir adet worklow runtime oluşturuyoruz ve buna event handler metodlar ekliyoruz. Böylece worklow’un idle veya unload gibi durumlarında mesaj verebiliyoruz.

Olayları tanımladıktan sonra Persistence servisini tanımlıyoruz. Bunun için kullanacağımız obje “SqlWorkflowPersistenceService”. Bu objeyi oluştururken belirli parametreler veriyoruz. Örnek tanımlama ve bu parametrelerin anlamları aşağıdaki gibidir.

SqlWorkflowPersistenceService wfPersistenceService = new SqlWorkflowPersistenceService([ConnectionString], [UnloadOnIdle] , [TimeForOwnership], [TimeForRespawn]);

ConnectionString : Veritabanına bağlantı cümlesi

UnloadOnIdle : Workflow idle duruma düştüğünde otomatik olarak veritabanına saklanıp hafızadan atılsın mı.

TimeForOwnership : Workflow ne kadar süre için bu uygulamanın kontrolünde olacak

TimeForRespawn : Veritabanına, kayıtlı worklowları yüklemek amacıyla hangi sıklıkla bakılacak.

Bir adet PersistenceService sınıfı tanımladıktan sonra bunu workflow runtime ‘a AddService metodunu kullanarak ekliyoruz.

Sonuç olarak, ana programımızda ortaya çıkan kodumuz şu şekilde olacaktır :

wfCode

Uygulamamızın çıktısı ise aşağıdaki gibi olacaktır.

console-output

Örnek uygulamaya ait kaynak kodu buradan indirebilirsiniz.

Posted in C#, SQL Server, Workflow Foundation.


Workflow Foundation – State Machine

Uygulamalarımızda planladığımız iş süreçleri herzaman düz bir akış içermeyebilir. Bunun yerine, daha çok belirli durumlarda belirli işlerin yapılmasını gerektiriyor olabilir. Bu makalede buna benzer durumlarda kullanabileceğimiz “State Machine Workflow” ile ilgili bir örnek yapacağız.

Örneğimiz hepimizin bildiği müzik kutularını simule edecek son derece basit bir uygulama. Kullanıcıya hangi şarkıyı dinlemek istediği liste halinde sunulacak, kullanıcı bir şarkı seçecek ve dinleyecek, sonrasında yeniden başa dönecek.

Öncelikle yeni bir uygulama açıyoruz (File/New/Project, State machine workflow console application). Visual studio bize default olarak bir şablon oluşturmuş olacak, kendisinin oluşturduğu “Workflow1” isimli dosyayı silip, proje üzerinde sağ tuşa tıklayıp “Add/State machine worklow” seçiyoruz, isim olarak “wfMusicBox” yazıp onaylıyoruz.

State machine workflow oluşturduğumuzda boş bir kutu içeren bir tasarım penceresi ile karşılaşacağız. Burada bilmemiz gereken birkaç husus var.

Workflow tasarım penceresi üzerinde boş bir yere tıklayıp özellikler penceresine baktığınızda, workflowa ait birkaç özelliğin bulunduğunu göreceksiniz. En önemli iki özellik; “Initial State Name” ve “Completed State Name” dir. bunlar sırasıyla başlangıç ve bitiş durumlarını ifade eder. Dizayn penceresinde öncelikle durumları (state) belirler, o durumların içinde de bu state e bağlı olarak yapılması gerekenleri belirlersiniz. Örneğin şarkı bittikten sonra yeni bir şarkı çalınıp çalınmayacağı kararı sonrası ya çıkış, ya da listeleme moduna geri dönülmesi için yapılan işlemler mevcut duruma bağlı olarak yapılması gereken aktivitelerdir.

Workflow üzerinde başlangıç ve bitiş statelerini belirledikten sonra, belirlediğiniz statelerin başlık kısmında bunu belirtir ufak birer simge olduğunu göreceksiniz. Ek olarak bitiş stateinin içerisinin boş olması gerektiğini unutmamak gerekir.

State ler ile ilgili olarak içerilerinde kullanabileceğiniz aktiviteler sınırlıdır. Buraya koyduğunuz aktiviteler bir nevi konteyner görevi görecektir, dolayısı ile bunların içerisinde normal bir aktivite akış tasarımı yapacağız.

Bu kadar girişten sonra şekildeki gibi state lerimizi tasarlıyoruz. state ler arası çizgilerin çıkmayışını dert etmeyin, onları elle çizmiyorsunuz. Aksine, SetStateActivity kullandığınızda otomatik olarak çiziliyor.

1_states

Her bir state içerisinde birer adet “StateInitializationActivity” mevcut. Init aktivitesinin içerisindeki akışımız ve özellikler aşağıdaki gibidir.

2_init 

Kullandığımı CodeActivity belirli bir init mesajı vermek içindir. Sonrasında da “SetStateActivity” kullanarak akışı, “stateListMode” isimli liste durumuna geçiriyoruz.

Liste modundan devam eden akış da benzer bir yapıya sahiptir. CodeActivity kullanarak kullanıcıya bir seçenek sunulmasını sağlıyoruz. Kullanıcı seçimini yaptıktan sonra ise SetStateActivity kullanarak çalma moduna, “statePlayMode” state’ine geçiyoruz.

3_list

Bu örnekteki listeleme ve çalma işlemi tamamen temsilidir. Maksat süreci ve bileşenlerin kullanımını göstermektir. Dolayısı ile gerçekten bir şarkı çaldığımız yok :) Sadece belirli bir süre (bu örnekte 2sn) akışı bekletiyoruz.

Play modu da buna benzer bir yapı kullanmakla birlikte, FadeOut modu (bu modda şarkının bitiime yakın  olduğunu varsayıyoruz.)

4_fadeout

Fadeout modunda bir karar mekanizması var. buradaki yapı sadece if-else yapısı olduğundan, sadece ilk if brunch’’ında condition bulunmakta ve bu declarative değil, yani genel bir property den değer almıyor da direkt bir metod sonucunda geri dönüş değerine bağlı. Dolayısı ile içeride istediğimiz işlemi yapıp sonrasında berlili bir sonuç geri döndürebiliyoruz.

Duruma göre SetStateActivity’ler ile ya akışı bitiriyoruz ve “stateShutDownMode” durumuna atlıyoruz, ya da “stateListMode” durumuna atlayarak yeniden başlıyoruz.

Gördüğünüz üzere, herhangi bir state den devam edip çeşitli şekillerde akışı kontrol edebiliriz.

Örnek uygulamayı indirmek için aşağıdaki linke tıklayın.

smWorkflowConsole.rar

Posted in Asp.NET, C#, Workflow Foundation.

Tagged with , , , .


"SQL Server Startup Issue related to TDSSNIClient error 0×7e status 0×60" Hatası

Bugün ilginç bir hata ile karşılaştım.

Lokal SQL Server’ı çalıştırdığımda “named pipes” ile ilgili bir hata veriyordu. SQL Server configuration manager üzerinden baktığımda da named pipe ların enable olduğunu görüyordum. Kontrol panelindeki services kısmında manuel sql server servisini start etmeye kalktığımda otomatik tekrar duruyordu.

Sorunun kaynağını anlamak için event viewer kullandım, peşpeşe 4 farklı hata vardı. En üstteki hataya baktığımda portların kapandığı durumda aldığımız mesaja benzer bir hata olduğunu görüp makineye kurulu antivirüs uygulamasını kontrol ettim. Burada bir sıkıntı yoktu, antivirüs kapatmıyordu ama telnet ile de ulaşamıyordum.

En alttaki hataya baktığımda ise daha sorunun kaynağı daha anlaşılır oldu. Problem configuration manager üzerinde “VIA”protokolünün de açık olmasından kaynaklanıyordu. Bunu “Disabled” duruma getirince sorun düzeldi.

Peşpeşe aldığım hatalar ise şöyle:

1. TDSSNIClient initialization failed with error 0×7e, status code 0×60.
2. TDSSNIClient initialization failed with error 0×7e, status code 0×1.
3. Could not start the network library because of an internal error in the network library. To determine the cause, review the errors immediately preceding this one in the error log.
4. SQL Server could not spawn FRunCM thread. Check the SQL Server error log and the Windows event logs for information about possible related problems.

Posted in SQL Server.

Tagged with .


Workflow Foundation – SequenceFlow

Bu makalede basit bir örnek uygulama yaparak Sequence türündeki workflowları anlatmaya çalışacağım.

Örnek uygulamamız basit bir bilgisayar toplama flow’u içeriyor. Bu workflowu inceleyerek şunları öğrenmiş olacaksınız :

  1. Bir sequence workflow oluşturmak
  2. Mevcut bir workflow’u çalıştırmak
  3. Çalıştıracağımız workflow’a parametre geçmek
  4. if-else-activity, codeActivity ve terminate aktiviteleri(bileşenleri)

Öncelikle uygulamayı anlatarak başlayayım. Uygulama belirli parça stoklarına sahip olacak ve kullanıcı istediği ve stoklar elverdiği müddetçe yeni bilgisayar toplayacak ve son olarak topladığı  bilgisayarda kullandığı parçaları stoktan düşecek.

İlk önce yeni bir proje açıyoruz. Soldaki listeden workflow grubunu, sağdaki listeden ise “sequential workflow console application” seçiyoruz.

newProject

Proje adını da “wfCompTechSample” olarak belirttikten sonra “Ok” düğmesine bastığımız anda visual studio bize gerekli solution ve dosyaları yaratıyor. Default yaratılan “workflow1.cs” dosyasını siliyoruz ve yerine kendi “Builder” worklowmuzu yaratıyoruz.

newSeqWorkflow

Yeni workflow yaratmak için projenin üzerinde sağ tuşa tıklayıp “Add->Sequential Workflow” seçiyoruz. Dosya adı olarak “Builder.cs” belirttikten sonra “Ok” diyoruz.

Sonrasında “Stock” adında yeni bir sınıf ekliyoruz. Bu sınıf bizim stok bilgilerimizi saklayacak.

public class Stock
{
public int Mainboard { get; set; }
public int Ram { get; set; }
public int GraphicCard { get; set; }
public int Chasis { get; set; }
public int CDRom { get; set; }
public int CPU { get; set; }
public int Fan { get; set; }
public int HDD { get; set; }

public void LoadDefaultStock()
{
Mainboard = 5;
Ram = 7;
GraphicCard = 3;
Chasis = 3;
CDRom = 3;
CPU = 3;
Fan = 2;
HDD = 3;
}

public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(String.Format(”Mainboards : {0}\n”, Mainboard));
sb.Append(String.Format(”Ram : {0}\n”, Ram));
sb.Append(String.Format(”GraphicCard : {0}\n”, GraphicCard));
sb.Append(String.Format(”Chasis : {0}\n”, Chasis));
sb.Append(String.Format(”CDRom : {0}\n”, CDRom));
sb.Append(String.Format(”CPU : {0}\n”, CPU));
sb.Append(String.Format(”Fan : {0}\n”, Fan));
sb.Append(String.Format(”HDD : {0}\n”, HDD));
return sb.ToString();
}
}

Sonrasında Builder workflowumuza dönüyoruz. Workflowun designer penceresinde bir yeşil ok ve bir kırmızı kare sembollü iki şekil göreceğiz. Bunlar akışın başlangıç ve bitişini gösteriyor. bunların arasına yerleştireceğimiz her aktivite, iş akışındaki bir görev veya adım anlamına gelmektedir.

Kullanacağımız aktiviteleri toolbar üzerinden görebilirsiniz. Öncelikle bir Code Activity bileşenini sürükleyip workflow’a bırakıyoruz. Bu bizim başlangıç aktivitemiz olacak, bunu koymaktaki amacaım amaç akışın başladığını kullanıcıya haber vermek. Code Activity eklediğimizde üzerinde bir kırmızı ünlem işareti belirecek. Bu henüz “ExecuteCode” özelliğinin belirtilmediği anlamına gelmektedir. Benzer şekilde, diğer bileşenlerin de temel gereksinim özelliklerini belirtmediğiniz sürece üzerlerinde bir “!” işareti göreceksiniz.

ExecuteCode özelliği bir metoda delege etmekte, dolayısı ile aynı ButtonClick olayı gibi buraya bir metod ismi belirtiyoruz. Ben “caInitActivity_ExecuteCode” yazdım. Sonra da kod arkasından aktivitenin başladığına dair bir mesaj yazdırdım.

ifaStockEnough_CreatingActivity

Ardından da if-else-activity ekliyoruz. Bu aktivite, belirli bir durumu kontrol edip buna bağlı olarak branch larındaki uygun akışı devam ettirir. Kod yazarken kullandığımız if-else yapısının görsel halidir diyebiliriz. İlk sürükleyip bıraktığımızda iki adet brunch otomatik eklenir, istersek daha fazla brunch ekleyebiliriz.

Sonrasında her bir branchın çalışma şartını belirliyoruz. Dalların çalışma şartı iki şekilde olabilir : “Code Condition” ve “Declarative Rule Condition”.

Code Condition, karşılaştırma işlemini kod arkasından yapmamızı sağlar. Belirteceğimiz metod karşılaştırma işlemini yapar ve result olarak true veya false değeri döner. false döner ise, bir sonraki brunch test edilir.

Declarative Rule Condition ise direkt belirtebileceğimiz bir script expression içerir. Örneğin workflow’a ait bir özellik veya bir başka aktivitenin sonucunu karşılaştırabiliriz.

ifbStockEnough_SettingConditionIf-else-activity, soldan sağa doğru her bir dalı kontrol eder. İlk bulduğu doğru değerdeki aktivite akışını tamamlar ve diğerlerini çalıştırmaz. Biz de ilk olarak soldaki aktivitede stok kontrolü yapıyoruz. Stok kontrolü geçilmediği durumda sağ taraftaki dal çalışacak (bunun için declarative rule contition a sadece “true” değerini yazıyoruz)

Ardından kod aktivitelerini aşağıdaki gibi ekleyip gerekli tanımlamaları yapıyoruz.

fullWorkflow

Burada kullandığımız “terminate-activity” (kırmızı “x” simgeli), hata oluştuğu için workflow u sonlandırmamızı sağlayacak. Fakat workflow sonlandırılırken bir hata mesajı verilmesini istiyoruz.errorActivity

Bunun için yeni bir property yaratıp “Error Message” adını vereceğiz. .NET bizim için gerekli kodları otomatik oluşturacaktır. Bu property’i oluştumuşken bizim parametre olarak göndereceğimiz “Stock” türündeki property’i de tanımlıyoruz.

Bundan sonra aktivitelerimizin arkasındaki kodları geliştiriyoruz. Böylece şartları ve süreci tamamlıyoruz. Builder sınıfının kodları aşağıdaki gibidir.

public sealed partial class Builder: SequentialWorkflowActivity
{
#region Property definitions

public Stock CurrentStock { get; set; }

public static DependencyProperty taNotEnoughStock_ErrorMessageProperty = DependencyProperty.Register(”taNotEnoughStock_ErrorMessage”, typeof(System.String), typeof(wfCompTechSample.Builder));

[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("Activity")]
public String taNotEnoughStock_ErrorMessage
{
get
{
return ((string)(base.GetValue(wfCompTechSample.Builder.taNotEnoughStock_ErrorMessageProperty)));
}
set
{
base.SetValue(wfCompTechSample.Builder.taNotEnoughStock_ErrorMessageProperty, value);
}
}
#endregion

public Builder()
{
InitializeComponent();
}

private void caInitActivity_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine(”builder started. with following stock.”);
Console.WriteLine(CurrentStock.ToString());
}

private void ifbStockEnough_CheckStock(object sender, ConditionalEventArgs e)
{
e.Result = (existEnough(CurrentStock.Mainboard) &&
existEnough(CurrentStock.Ram) &&
existEnough(CurrentStock.HDD) &&
existEnough(CurrentStock.GraphicCard) &&
existEnough(CurrentStock.Fan) &&
existEnough(CurrentStock.CPU) &&
existEnough(CurrentStock.Chasis) &&
existEnough(CurrentStock.CDRom));
}
private void caBuildComputer_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine(”building computer..”);
CurrentStock.Mainboard–;
CurrentStock.Ram–;
CurrentStock.HDD–;
CurrentStock.GraphicCard–;
CurrentStock.Fan–;
CurrentStock.CPU–;
CurrentStock.Chasis–;
CurrentStock.CDRom–;
}

private void caSetStockErrorMessage_ExecuteCode(object sender, EventArgs e)
{
taNotEnoughStock_ErrorMessage = “not enough stock to build a computer”;
}

private void caFinalActivity_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine(”successfully built..”);
}

private bool existEnough(int device)
{
return device – 1 >= 0;
}
}

Bütün bunları tamamladıktan sonra iş ana programdan workflow’u çağırmaya kaldı.

.NET zaten default olarak ana programa workflow’u çağırmak için gerekli temel kodları yerleştiriyor. Biz bu kodlara kullanıcı ile kuracağımız iletişim kodlarını ve parametrik workflow çağırımı için gerekli değişiklikleri ekleyeceğiz. Bu eklemeler sonrası tam kod aşağıdaki gibidir.

static void Main(string[] args)
{
string answer = “y”;
Stock currentStock = new Stock();
currentStock.LoadDefaultStock();
while (true)
{
Console.Write(”Do you want to build a computer [y/n]?”);
answer = Console.ReadLine();
if (answer.Equals(”n”, StringComparison.InvariantCultureIgnoreCase)) break;

using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); };
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
Dictionary<string, object> arguments = new Dictionary<string, object>() { { “CurrentStock”, currentStock } };

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(wfCompTechSample.Builder), arguments);
instance.Start();

waitHandle.WaitOne();
}
}
}

Son olarak uygulamamızı çalıştırıyoruz. Çıktısı aşağıdaki gibi olacaktır.

output

Örnek uygulamayı aşağıdaki linkten indirebilirsiniz

wfCompTechSample.zip

Posted in Asp.NET, C#, Workflow Foundation.


Workflow Foundation Önbilgiler

Windows Workflow Foundation ya da kısaca WF, çalışma zamanında iş akışları tasarlamayı ve çalıştırmayı sağlayan bir .NET Framework 3.0 ile gelmiş bir alt sistemdir. XAML tabanlı bir yapısı ve her Microsoft ürünü gibi, görsel bir tasarım arayüzü vardır.

WF’ye sadece if yapıları ve döngülerden oluşur demek biraz yazık olur çünkü bu ortaya koyduğu birçok yeniliği gözardı etmek olur.Bu makalede WF’i sadece tanımaya yönelik önbilgi bundan sonra yazacağım diğer makalelerde ise daha detaylı örnekler vereceğim.

WF komplex bir iş akışını, bir algoritmayı daha basit, görsel ve istenilen anda değiştirilip yenilenebilir bir seviyeye düşürmeyi sağlar. Ayrıca uygulamalara ve akışlara hiçbirşeye müdahale etmeden genişleyebilme imkanı da sunar.

WF üzerinde iki farklı iş akışı tanımlanabilir: Sequential (sıralı) ve State Machine (durum makinesi).

Sequential workflowlar belirli bir başlangıç ve bitiş noktası içerisinde hareket eder. Dışarıdan herhangi bir müdahale gerektirmeyen süreçlerde kullanılabilecek iş akışlarıdır.

State Machine Workflowlar ise bir duruma verilecek tepkilere göre tasarlanmıştır. Çeşitli durumlar tanımlar ve bazı şartlar olduğunda 1. state’e, diğer şartlar altında 2. state e geçilip o duruma özel işlemler yapılması sağlanılabilir.

Workflowlar XAML tabanlıdır ve görsel bir tasarım arayüzü vardır demiştik. İşte bu tasarım arayüzünde, aynen bir uygulama yazıyor gibi Visual Studio IDE’sinde Toolbox aracılığı ile dizayn penceresine çeşitli aktiviteler ekleyebilir, bunları yönetebilirsiniz. Workflowlar tasarlandıktan sonra, bir uygulama aracılığı ile tetiklenirler.

Son olarak Workflowlarda state saklamaktan da bahsedeyim.

Workflowlarınızı başlattığınız zaman o an bitene kadar beklemek zorunda değilsiniz. Herhangi bir anda workflowun o anki durumunu veritabanına saklayabilir ve istediğiniz herhangi bir anda bu workflowu geri yükleyip çalışmasına devam ettirebilirsiniz.

Önemli nokta şu ki, IDE aracılığı ile bir iş akışının nasıl olacağını tasarlıyorsunuz. Uygulama ise workflowu belirli bir duruma uyguluyor. Sizin sakladığınız şablon değil, şablonun uygulamasıdır.

Posted in Asp.NET, C#, Workflow Foundation.


Herşey "Object" ten Türemez!!

MSDN üzerindeki bir blogda okuduğum bir makale sayesinde çok önemli bir bilgiye sahip oldum. Genelde şöyle bir bilgi vardır “.NET üzerinde/C# da herşey object ten türemiştir”. Maalesef bütün genellemelerde olduğu gibi bu da yanlış.

Şöyle ki, .NET üzerinde birçok şey object nesnesinden türemiştir ve .NET dilleri (özellikle C#) çok güzel bir nesnesel programlama dilidir. Fakat herşey nesneden türemez. Örneğin pointer ve interface ‘ler nesneden türemedikleri gibi bu türleri hiyerarşik olarak genişletemezsiniz. Örneğin bir interface’den kalıtım alan başka bir interface tanımlayamazsınız!

Veya bir pointer nesneden türemediği gibi nesneye de dönüştürlemez.(bir değer türü gibi kullanmak istiyorsanız, önce IntPtr türüne dönüştürmeniz gerekir)

Yine aynı makalenin yorumlarında gördüğüm güzel bir çürütme sorusu vardı. “Peki neden ‘Typeof(ITestType)’ gibi bir kullanım ile tipini almaya kalktığımda bana nesne geri gönderiyor?”. Cevabı da gayet açık, TypeOf geriye bir tür gönderiyor, interface in kendisini değil.

Özetle, herşey nesne olmamakla birlikte, çeşitli dönüşüm yöntemleri ile farklı kullanımlara sahip olabilirler.

Bahsettiğim makaleye buradan ulaşabilirsiniz.

Posted in C#.

Tagged with , .


Asp.NET Membership’in Rolleri Saklama Problemi

Geliştirdiğimiz bir projede forms authenication kullanıyorduk. Performans, cache vs derken veritabanına mümkün olduğunca az gitmeye çalışıyorduk. Bununla birlikte portal üzerindeki bütün yetkilendirme işlemlerini aspnet membership üzerinden rollerle sağlıyorduk.

Bu noktada garip bir sorun ortaya çıktı, membership her sayfada veritabanına gidip kullanıcının rollerini tekrardan sorguluyordu. Biz performans konusuna bu kadar değiniyorken, herşeyi kısıp cache’lere yükleniyorken sürekli veritabanına sorgu atılması can sıkıcıydı tabii ki. Hele ki binlerce kullanıcının aynı anda bu portalı kullanacak olması sunuculara ciddi bir yük demekti.

Neyse ki sorunun kaynağı msdn de gizliydi. Varsayılan olarak .net maksimum 25 adet kullanıcı rolü saklıyor. Eğer bu sayıdan fazla rollere sahip bir kullanıcınız varsa veritabanına gidip her sayfa isteğinde rollerini tekrar çekiyor ve saklamıyor.

Çözüm ise gayet basit, web.Config içerisinde rol provider tanımında “maxCachedResults” özelliğinin minimum rol sayısından büyük olması gerekiyor.

Örneğin :
< roleManager defaultProvider=”myRoleProvider”
enabled=”true”
cacheRolesInCookie=”true”
cookieName=”.myPortalRoles”
cookiePath=”/”
cookieTimeout=”30″
cookieRequireSSL=”false”
cookieSlidingExpiration=”true”
cookieProtection=”All”
createPersistentCookie=”false”
maxCachedResults=”50″ >

ilgili msdn linki

Posted in Asp.NET, C#.

Tagged with , , .