Skip to main content

Fonksiyon

Akışın belirli bir noktasında C# kodu çalıştıran nesnedir. Akış bu düğüme ulaştığında, sizin yazdığınız kod bloğu çalışır: form alanlarını okur, akış değişkenlerine değer atar, onaycı pozisyonlarını belirler ya da bir servis çağırırsınız. Kod, düğümün kendi fnc_<ad>_Execute olayına yazılır.

Sınıf olarak FlowScript adını taşır ve BaseErrorManagedApiStep<FlowScriptProperties> tabanından türer; bu yüzden hata yönetimi özellikleri (ResumeOnError, ErrorOptions, ErrorDescriptionObjectName) bu nesnede de bulunur.

Ne zaman kullanılır?

İş kuralını koda dökmeniz gerektiğinde kullanın:

  • Formdaki bir tutara göre yönlendirme değişkeni belirlemek (ör. V_gorus.Value = "5").
  • Bir Pozisyon ya da Pozisyon Grubu nesnesine onaycı atamak.
  • Form kontrollerini okuyup hesaplama yapmak, doküman alanlarını güncellemek.
  • Akış içinden bir servis (datasource sorgusu, doküman, HR vb.) çağırmak.

Sadece veriyi bir kaynaktan bir hedefe kopyalayacaksanız ve kod yazmanız gerekmiyorsa Atama gibi hazır nesneler daha pratiktir; iş mantığı koşullu ve hesaplamalıysa Fonksiyon kullanın.

Değer tipi

Fonksiyon nesnesinin Value (Object) adında kendi bir değeri vardır; ancak bu değer akışı dallandırmak için kullanılmaz. Yönlendirmeyi ayrı bir Değişken nesnesi (V_gorus.Value = "...") üzerinden yapın. FlowScript.Value doğrulanmış örneklerde routing amacıyla set edilmez.

Ayarlar

Fonksiyon nesnesinde tasarımcıda düzenlenen başlıklar, hata yönetimiyle ilgilidir:

AyarTipAçıklama
ResumeOnErrorboolKod hata fırlatırsa akışın durmak yerine devam edip etmeyeceği.
ErrorOptionsIFlowErrorOptionsHata durumunda uygulanacak zengin hata yapılandırması (tasarımcıda ayarlanır).
ErrorDescriptionObjectNamestringHata açıklamasının yazılacağı nesnenin adı.

Bu üç özellik BaseErrorManagedApiStep<T> tabanından gelir.

Akıştaki yeri

Fonksiyon, akışın ortasında bir işlem noktasıdır: önceki adım tamamlanınca kod bloğu çalışır, iş bittiğinde akış bir sonraki adıma geçer. Bekleme yapmaz; onay beklenmez, kod ne kadar sürerse o kadar çalışır ve döner. Çoğu zaman bir Pozisyon ya da Karşılaştırma adımından hemen önce konumlandırılır: önce burada onaycıyı ya da yönlendirme değişkenini hazırlar, sonra bir sonraki nesne bu değeri kullanır.

Kod örnekleri

Kod, düğümün fnc_<ad>_Execute olay imzasının içine yazılır. Sunucu (akış) kodu turuncu çerçevelidir.

İşleyici (handler) iskeleti

public void fnc_SektorBaskaniAtama_Execute(object sender, OnExecuteEventArguments args)
{
try
{
// ... pozisyon ata, değişken set et, kontrol oku ...
V_gorus.Value = "5"; // alt taraftaki dallanma için yönlendirme değişkeni
}
catch (Exception ex)
{
// hata yönet / yeniden fırlat; throw new Exception(...) motora yansır
throw new Exception("Atama yapılamadı: " + ex.Message);
}
}

OnExecuteEventArguments nesnesi, üzerinden işlem bağlamına ulaşabileceğiniz birkaç üye taşır: args.Context (Context), args.ProcessId (Int64), args.IsSessionStarterObject (bool), args.Step (StepArguments).

Nesne ve servis çözme (doğrulanmış idiom)

Akış nesnelerine (doküman, pozisyon, değişken, grup) erişmenin doğrulanmış yolu, tasarımcının ürettiği lazy property üzerinden nesneyi adıyla doğrudan kullanmaktır. Document1, p_mudur, V_gorus gibi adlar Flow1.Designer.cs içinde sizin için üretilir; siz Flow1.cs tarafında bunları doğrudan yazarsınız.

// Üretilmiş erişimcileri DOĞRUDAN kullan; ek çözümleme gerekmez
string tutar = Document1.Controls["TUTAR"].Value?.ToString();
long mudurId = p_mudur.GetUserInfo().Id;
V_gorus.Value = "5";

Bu erişimcilerin arkasındaki üretilmiş desen şöyledir (siz yazmazsınız, Flow1.Designer.cs üretir):

// Flow1.Designer.cs (ÜRETİLMİŞ — elle düzenlenmez)
private FlowDocument _document1;
private FlowDocument Document1 => _document1 ??= new FlowDocument("Document1", _workflowData, this);

private FlowPosition _p_mudur;
private FlowPosition p_mudur => _p_mudur ??= new FlowPosition("p_mudur", _workflowData, this);

private Variable _v_gorus;
private Variable V_gorus => _v_gorus ??= new Variable("V_gorus", _workflowData, this);

Bir platform servisini çağırmak için, bağlamdan kimlik bilgisi kurup bir ServiceAPI örneği oluşturmak doğrulanmış yoldur. Tipik kullanım, bir proje datasource sorgusunu DataSourceManager.ExecuteQuery<T> ile çalıştırmaktır:

// Kimlik bilgisi bağlamdan kurulur
protected LoginWithTokenAuthenticationParameters Credentials => new()
{
EncryptedData = _workflowData.Context.EncryptedData,
Language = _workflowData.Context.Language,
Token = _workflowData.Context.Token
};

private ServiceAPI _serviceApi;
protected ServiceAPI ServiceApi => _serviceApi ??= new ServiceAPI(Credentials, WebInterfaceUrl);

// Proje datasource sorgusu çalıştır (örnekler .Result ile bloke eder)
var satirlar = ServiceApi.DataSourceManager
.ExecuteQuery<OnayciRow>("DV_SAT", "GET_ONAYCI", new { SICIL = sicil }).Result;
Yönlendirmeyi değişkenle yapın

Akışı dallandırmak için Fonksiyon düğümünün kendi Value özelliğini değil, ayrı bir Değişken nesnesini (V_gorus.Value = "...") set edin. Doğrulanmış örnekler routing'i bu şekilde yürütür.

Form kontrolü okuma ve yazma

Form alanlarına Document1.Controls["AD"] indekslemesi üzerinden ulaşılır. Dönen kontrolün .Value (object) ve .Text (string) üyeleri vardır. Doğrulanmış örneklerde okuma .Value?.ToString(), yazma ise çoğu zaman hem .Value hem .Text set edilerek yapılır (veri + görüntü).

// Oku
string satNo = Document1.Controls["SATNO"].Value?.ToString();
string aktaran = Document1.Controls["GORAKTAR"]?.Text?.ToString();
string byd = Convert.ToString(Document1.Controls["BELGE_SICIL"].Value);

// Yaz: hem Value hem Text set etmek yaygın pratik
Document1.Controls["DURUM"].Value = "1";
Document1.Controls["GORAKTAR"].Value = new List<object>(); // çoklu seçim listesini sıfırla
Document1.Controls["GORAKTAR"].Text = "";

Akışı kullanıcıya mesajla durdurma

Bir betikten kullanıcıya görünen bir mesajla akışı durdurmak için WorkflowCode tabanının StopWithError / StopWithWarning / StopWithInfo / StopWith(StopMessageType, ...) yardımcıları vardır. Her birinin son argümanı bir Context'tir; _workflowData.Context tam olarak bu tipi döner. throw new Exception(...) de örneklerle doğrulanmış bir durdurma yoludur, ancak çerçevenin kullanıcıya yönelik niyetli yolu StopWith* ailesidir.

// Zorunlu alan boşsa uyarı verip durdur
if (string.IsNullOrEmpty(Document1.Controls["KONTROLEDEN"].Value?.ToString()))
StopWithWarning("Uyarı", "Kontrol Eden seçilmelidir.", _workflowData.Context);

// Bir değeri kullanıcıya gösteren hızlı debug noktası
StopWithInfo("debug", JsonConvert.SerializeObject(Document1.Controls["dtp_zaman"]), _workflowData.Context);

// Alternatif: istisna fırlatarak durdurma (mesaj motora yansır)
throw new Exception("Görüşe aktarılacak kullanıcı seçimi yapınız.");

StopWith* yardımcılarının Dictionary<String,String> alan çok dilli aşırı yüklemeleri de vardır. StopMessageType enum'ı Error, Warning, Info değerlerini taşır.

Loglama: LogExtension.Log

Akış kodundan sunucu loguna yazmak için LogExtension.Log(mesaj, context) kullanılır. Sondaki satır/metot/dosya parametreleri caller-info olduğundan pratikte sadece mesaj ve bağlam verilir.

LogExtension.Log("p_mudur atandı: " + mudurId, _workflowData.Context);
LogExtension.Log(JsonConvert.SerializeObject(satirlar), _workflowData.Context);

// Bir olay işleyicisinin içindeyseniz args.Context da geçerli bir bağlam kaynağıdır.

Gerçek kullanım senaryoları

1. Kontrol oku → hesapla → değişken set et

Form tutarına göre bir yönlendirme kodu belirleyip aşağıdaki Karşılaştırma adımının okuyacağı değişkene yazar.

public void fnc_TutarKademe_Execute(object sender, OnExecuteEventArguments args)
{
try
{
decimal tutar = Convert.ToDecimal(Document1.Controls["TUTAR"].Value ?? "0");

if (tutar <= 1000m) V_gorus.Value = "1"; // sadece müdür onayı
else if (tutar <= 50000m) V_gorus.Value = "2"; // müdür + direktör
else V_gorus.Value = "3"; // komite

LogExtension.Log("Kademe seçildi: " + V_gorus.Value, _workflowData.Context);
}
catch (Exception ex)
{
StopWithError("Hata", "Kademe hesaplanamadı: " + ex.Message, _workflowData.Context);
}
}

2. Kontroldeki değerden onaycı çözüp pozisyona ata

Formda seçilen sicili bir datasource sorgusuyla CSP kullanıcı kimliğine çevirip Pozisyon nesnesine atar.

public void fnc_KontrolEdenAta_Execute(object sender, OnExecuteEventArguments args)
{
try
{
string sicil = Document1.Controls["KONTROLEDEN_SICIL"].Value?.ToString();
if (string.IsNullOrEmpty(sicil))
StopWithWarning("Uyarı", "Kontrol Eden sicili boş olamaz.", _workflowData.Context);

var satirlar = ServiceApi.DataSourceManager
.ExecuteQuery<OnayciRow>("DV_SAT", "SICIL_TO_USERID", new { SICIL = sicil }).Result;

if (satirlar == null || satirlar.Count == 0)
StopWithError("Hata", "Sicil için kullanıcı bulunamadı: " + sicil, _workflowData.Context);

p_kontrolEden.SetFromUser(Convert.ToInt64(satirlar[0].USERID));
}
catch (Exception ex)
{
throw new Exception("Kontrol Eden atanamadı: " + ex.Message);
}
}

3. Gridden toplam hesaplayıp forma geri yaz

Bir DataGrid'in satırlarını GridData.FromControl ile gezip bir sütunu toplar ve sonucu başka bir alana yazar.

public void fnc_ToplamHesapla_Execute(object sender, OnExecuteEventArguments args)
{
try
{
Control kontrol = Document1.Controls["DT_MALZEME"];
GridData grid = GridData.FromControl(kontrol);

decimal toplam = 0m;
foreach (GridDataRow satir in grid.Rows)
{
string tutarMetni = satir.Cells
.FirstOrDefault(c => c.Name == "TUTAR")?.Value?.ToString();
if (decimal.TryParse(tutarMetni, out decimal t)) toplam += t;
}

// Hesabı forma geri yaz (hem veri hem görüntü)
Document1.Controls["GENELTOPLAM"].Value = toplam;
Document1.Controls["GENELTOPLAM"].Text = toplam.ToString("N2");
Document1.SaveDocument();
}
catch (Exception ex)
{
StopWithError("Hata", "Toplam hesaplanamadı: " + ex.Message, _workflowData.Context);
}
}

4. Bağlam ve süreç kimliğini kullanma

Akışı başlatanın kendisine geri yönlendirilmesini engellemek için aktif kullanıcının kimliğini (_workflowData.Context.UserId) ve çalışan talep kimliğini (_workflowData.General.ProcessId) okur.

public void fnc_TeslimEdenAta_Execute(object sender, OnExecuteEventArguments args)
{
try
{
string cspId = Document1.Controls["TESLIMEDEN_USERID"].Value?.ToString();

// Talebi açan kişiyi onaycı yapma (kendi kendine yönlendirme olmasın)
if (cspId != _workflowData.Context.UserId.ToString())
pg_teslimEden.AddConstantUser(Convert.ToInt64(cspId));

LogExtension.Log(
"ProcessId=" + _workflowData.General.ProcessId + " teslim eden atandı.",
_workflowData.Context);
}
catch (Exception ex)
{
throw new Exception("Teslim eden atanamadı: " + ex.Message);
}
}

İpuçları

  • İşleyici adı düğümün adına bağlıdır: fnc_<düğüm adı>_Execute. Düğümü yeniden adlandırırsanız imza da değişir.
  • Akış nesnelerine erişmenin doğrulanmış yolu üretilmiş erişimcilerdir: Document1, p_mudur, V_gorus adlarını doğrudan yazın. GetWorkflowObject<T>(...) / GetServiceAPI<T>() derlenir ama çalışma zamanı doğrulanmamıştır; yalnızca üretilmiş bir erişimci yoksa başvurun.
  • Kodu her zaman try/catch ile sarın. Akışı kullanıcıya görünen bir mesajla durdurmak için StopWithError / StopWithWarning / StopWithInfo yardımcılarını kullanın; throw new Exception("...") de mesajı motora yansıtır.
  • ResumeOnError açıksa kod hata fırlatsa bile akış durmaz, devam eder. Hatanın akışı durdurması gerekiyorsa bu seçeneği kapalı bırakın.
  • Form kontrolü okurken .Value?.ToString(), yazarken çoğu zaman hem .Value hem .Text set edin (veri + görüntü tutarlı kalsın).
  • Onaycıyı koşula göre atamak için, atamayı bu Fonksiyon adımında yapıp hemen ardından Pozisyon nesnesini yerleştirin.
  • _workflowData.Context (UserId, Token, Language, EncryptedData) servis çağrıları ve loglama için; _workflowData.General.ProcessId ise çalışan talep kimliği için kullanılır.
Doğrulanmış kod arayüzü (FlowScript)

Sınıf: Bimser.CSP.Workflow.Api.Steps.FlowScript : BaseErrorManagedApiStep<FlowScriptProperties>

İşleyici imzası: public void fnc_<ad>_Execute(object sender, OnExecuteEventArguments args)

Nesne özellikleri: Value (Object), ErrorOptions (IFlowErrorOptions), ResumeOnError (bool), ErrorDescriptionObjectName (string) — son üçü BaseErrorManagedApiStep<T> tabanından. Ayrıca taban üyeleri: Caption, Key, Name, TypeCode, CachedDMObjects, WorkflowCodeInstance.

Metotlar: ToLiquid(), Initialize().

Üretilmiş erişimci deseni (Flow1.Designer.cs): new FlowScript("fnc_ad", _workflowData, this); aynı şekilde new FlowDocument("Document1", _workflowData, this), new FlowPosition("p_mudur", _workflowData, this), new Variable("V_gorus", _workflowData, this). [example-confirmed]

WorkflowCode tabanı yardımcıları: StopWithError/StopWithWarning/StopWithInfo/StopWith(StopMessageType, title, message, Context) (çok dilli Dictionary<String,String> aşırı yüklemeleriyle); GetWorkflowObject<T>(name) ve GetServiceAPI<T>() [dump-only: derlenir, çalışma zamanı doğrulanmamış — üretilmiş erişimci yoksa kullanın].

Bağlam: _workflowData.Context (Context: UserId, Username, Token, EncryptedData, Language, Positions ...), _workflowData.General.ProcessId (çalışan talep kimliği) [example-confirmed].

Servis: new ServiceAPI(Credentials, WebInterfaceUrl)DataSourceManager.ExecuteQuery<T>(project, query, params) ve diğer manager'lar (DocumentManagement, FormManager, HumanResources ...) [example-confirmed].

Loglama: LogExtension.Log(message, _workflowData.Context) (ayrıca Error, Warning, ShowMessage) [example-confirmed].

note

ResumeOnError, ErrorOptions ve ErrorDescriptionObjectName BaseErrorManagedApiStep<T> tabanından gelir; derlenir ancak çalışma zamanı davranışı dump'tan doğrulanmamıştır.

Kaynak: synergy-csp references/flow-code-basics.md (üretilmiş lazy erişimciler, _workflowData, StopWith*, ServiceAPI/DataSourceManager, LogExtension — örneklerle doğrulanmış) + references/flow-objects.md (FlowScript) + Bimser.CSP.Workflow.Api.api.txt.