首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WF 4.0 四種自訂活動基類完整解析:CodeActivity、AsyncCodeActivity、Activity、NativeActivity

     編輯:關於.NET

WF 4.0 活動採樹狀結構,開發自訂活動可繼承四大基類,各有適用場景與能力邊界。本文系統化解析四類別差異,並以 HttpGet (葉子活動) 與 FlowChartActivity、MyWhile (複合/控制流活動) 為例完整示範。

四大基類能力對照表

基類適用場景核心方法非同步支援存取運行時服務排程子活動建立書籤自訂追蹤/持久化
CodeActivity簡單同步葉子活動Execute❌✅ (Context)❌❌❌
AsyncCodeActivity非同步葉子活動 (APM 模式)BeginExecute/EndExecute✅ (APM)✅❌❌❌
Activity組合現有活動為新活動 (宣告式)Implementation (Func<Activity>)✅ (透過子活動)✅✅ (宣告式)❌❌
NativeActivity完整控制流、書籤、持久化、追蹤Execute/CacheMetadata✅ (完整)✅ (NativeActivityContext)✅ (ScheduleActivity)✅ (CreateBookmark)✅

1. CodeActivity:最簡單的同步葉子活動


public sealed class HttpGet : CodeActivity
{
    public InArgument Uri { get; set; }

    protected override string Execute(CodeActivityContext context)
    {
        var request = HttpWebRequest.Create(Uri.Get(context));
        using (var response = request.GetResponse())
        using (var stream = response.GetResponseStream())
        using (var reader = new StreamReader(stream))
        {
            return reader.ReadToEnd(); // 同步阻塞直到完成
        }
    }
}

使用方式


var fetch = new HttpGet { Uri = "https://www.msn.com" };
string content = WorkflowInvoker.Invoke(fetch);
Console.WriteLine(content);
💡 InArgument<T> 取值需透過 .Get(context) 或 context.GetValue(arg),CodeActivityContext 提供運行時服務存取 (追蹤、變數、屬性)。

2. AsyncCodeActivity:APM 模式非同步葉子活動


public sealed class HttpGet : AsyncCodeActivity
{
    public InArgument Uri { get; set; }

    protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {
        var request = HttpWebRequest.Create(Uri.Get(context));
        context.UserState = request; // 傳遞狀態至 EndExecute
        return request.BeginGetResponse(callback, state);
    }

    protected override string EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
    {
        var request = (WebRequest)context.UserState;
        using (var response = request.EndGetResponse(result))
        using (var stream = response.GetResponseStream())
        using (var reader = new StreamReader(stream))
        {
            return reader.ReadToEnd();
        }
    }
}
💡 BeginExecute 發起非同步操作立即返回 IAsyncResult,**不阻塞工作流執行緒**;操作完成觸發 EndExecute 取得結果。適用於 I/O 密集型操作 (Web Request、DB、檔案)。

3. Activity:宣告式組合活動

以 FlowChart 為例,建構促銷折扣計算邏輯:


public sealed class FlowChartActivity : Activity
{
    public string PromoCode { get; set; }
    public int NumKids { get; set; }

    public FlowChartActivity(string promoCode, int numKids)
    {
        PromoCode = promoCode; NumKids = numKids;
        Implementation = new Func(CreateBody); // 關鍵:指定建構活動樹的工廠方法
    }

    Activity CreateBody()
    {
        // 變數宣告
        var promo = new Variable { Default = PromoCode };
        var numberOfKids = new Variable { Default = NumKids };
        var discount = new Variable();

        // FlowStep: 折扣未套用
        var discountNotApplied = new FlowStep
        {
            Action = new WriteLine { DisplayName = "Discount not applied", Text = "Discount not applied" },
            Next = null
        };

        // FlowStep: 折扣已套用
        var discountApplied = new FlowStep
        {
            Action = new WriteLine { DisplayName = "Discount applied", Text = "Discount applied" },
            Next = null
        };

        // FlowDecision: 判斷折扣 > 0
        var flowDecision = new FlowDecision
        {
            Condition = ExpressionServices.Convert(ctx => discount.Get(ctx) > 0),
            True = discountApplied,
            False = discountNotApplied
        };

        // 各促銷代碼對應步驟 (Single, MNK, MWK, Default)
        // ... 此處省略單步驟建構代碼 (Assign, TryCatch, Sequence 等)

        // FlowSwitch 依 PromoCode 分派
        var promoCodeSwitch = new FlowSwitch
        {
            Expression = promo,
            Cases = { { "Single", singleStep }, { "MNK", mnkStep }, { "MWK", mwkStep } },
            Default = discountDefault
        };

        // 組裝 Flowchart
        return new Flowchart
        {
            DisplayName = "Promotional Discount Calculation",
            Variables = { discount, promo, numberOfKids },
            StartNode = promoCodeSwitch,
            Nodes = { promoCodeSwitch, singleStep, mnkStep, mwkStep, discountDefault, flowDecision, discountApplied, discountNotApplied }
        };
    }
}

調用


WorkflowInvoker.Invoke(new FlowChartActivity("MWK", 2));
💡 Activity 透過 Implementation = new Func<Activity>(CreateBody) **宣告式組合** 內建活動,**不撰寫命令式 Execute 邏輯**,WF 運行時負責排程執行活動樹。

4. NativeActivity:功能最強大的控制流活動基類

內建 Sequence、While、If、Parallel 皆繼承此類。以自訂 MyWhile 示範:


public sealed class MyWhile : NativeActivity
{
    public Collection Variables { get; } = new Collection();
    public Activity Condition { get; set; }
    public Activity Body { get; set; }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        base.CacheMetadata(metadata); // 註冊 Variables、Condition、Body 至中繼資料
        if (Condition == null)
            metadata.AddValidationError($"While {DisplayName} requires a Condition");
    }

    protected override void Execute(NativeActivityContext context)
    {
        InternalExecute(context, null);
    }

    void InternalExecute(NativeActivityContext context, ActivityInstance instance)
    {
        // 排程 Condition 評估,完成後回呼 OnEvaluateConditionCompleted
        context.ScheduleActivity(Condition, new CompletionCallback(OnEvaluateConditionCompleted));
    }

    void OnEvaluateConditionCompleted(NativeActivityContext context, ActivityInstance instance, bool result)
    {
        if (result && Body != null)
        {
            // Condition 為 true 且有 Body → 排程 Body 執行,完成後再次回呼 InternalExecute (形成迴圈)
            context.ScheduleActivity(Body, InternalExecute);
        }
        // result == false 或 Body == null → 迴圈結束,不再排程
    }
}

關鍵能力解析

  • CacheMetadata:驗證必要引數、註冊變數/子活動/書籤至運行時中繼資料,**驗證失敗加入 ValidationError 可阻止工作流啟動**。
  • ScheduleActivity:**排程子活動執行**,支援完成回呼 (CompletionCallback),實現複雜控制流 (迴圈、分支、平行、錯誤處理)。
  • CreateBookmark:建立書籤,支援 **長時間等待外部事件** (人工審核、訊息到達) 並持久化工作流實例。
  • NativeActivityContext:提供完整運行時服務存取 (變數、屬性、追蹤、持久化、計時器、書籤管理)。

選擇指南:我該繼承哪一個?

  1. **同步運算、無子活動排程需求** → CodeActivity<TResult>
  2. **非同步 I/O (APM/TAP)、無子活動排程需求** → AsyncCodeActivity<TResult>
  3. **組合現有活動 (Sequence/Flowchart/StateMachine)、宣告式邏輯** → Activity
  4. **需要書籤、自訂持久化/追蹤、複雜控制流 (迴圈、平行、錯誤邊界)、動態排程子活動** → NativeActivity

總結

WF 4.0 四大活動基類形成 **能力階梯**:CodeActivity ⊂ AsyncCodeActivity ⊂ Activity ⊂ NativeActivity。**原則:選擇滿足需求的最簡單基類**,避免過度使用 NativeActivity 導致複雜度暴增。掌握 CacheMetadata 驗證、ScheduleActivity 排程、Bookmark 等核心概念,即可開發出健壯、可重用、效能優異的自訂活動庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved