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

WF 實作會簽業務流程:從流程設計到 WCF 服務化的完整架構

     編輯:關於.NET

WF 雖非專為企業業務流程(BPM)設計,但其核心優勢在於「流程執行引擎」。企業級 BPM 最複雜的核心正是流程邏輯,因此用 WF 構建 BPM 平台是順勢而為。本文以經典「會簽」流程為例,示範 WF + WCF + WPF 的端到端實作,涵蓋持久化、狀態追蹤、服務化宿主與客戶端呼叫。

會簽業務場景

發起人發起申請 → 多位會簽人並行/串行審核 → 所有會簽人通過 → 流程結束。任一會簽人駁回 → 流程終止/退回。

會簽流程業務場景圖

業務規則說明

系統架構

系統架構圖:WPF Client ↔ WCF Service ↔ WF Runtime ↔ SQL Persistence

核心組件

  • WF 流程定義:Flowchart/Sequence 建模會簽邏輯
  • 自訂活動:封裝業務原語(發起、指派、審核、通知)
  • WCF 服務宿主:WorkflowServiceHost 暴露啟動/處理操作
  • SQL 持久化:SqlWorkflowInstanceStore 確保流程狀態不丟失
  • WPF 客戶端:呼叫 WCF 服務發起/處理任務
  • 狀態追蹤表:自定義資料表記錄流程實例、節點、處理人、意見

資料庫設計

流程主表

會簽任務明細表

流程實例狀態表

WF 流程設計

會簽 Flowchart 設計圖

關鍵流程邏輯

  1. 啟動階段:建立流程實例,寫入主表,根據會簽名單生成並行任務分支
  2. 並行會簽:使用 Parallel 活動,每個分支執行「指派任務 → 等待處理 → 記錄結果」
  3. 結果聚合:所有分支完成後,FlowDecision 判斷是否全數通過
  4. 異常處理:外層 TryCatch 捕獲異常,記錄錯誤狀態,確保持久化一致性

自訂業務活動

// 指派會簽任務活動
public sealed class AssignCountersignTaskActivity : NativeActivity {
    [RequiredArgument] public InArgument<Guid> InstanceId { get; set; }
    [RequiredArgument] public InArgument<List<string>> Assignees { get; set; }
    public OutArgument<List<Guid>> TaskIds { get; set; }

    protected override void Execute(NativeActivityContext context) {
        var instanceId = InstanceId.Get(context);
        var assignees = Assignees.Get(context);
        var taskIds = new List<Guid>();
        
        using (var db = new BpmContext()) {
            foreach (var user in assignees) {
                var task = new CountersignTask {
                    Id = Guid.NewGuid(), InstanceId = instanceId, Assignee = user,
                    Status = TaskStatus.Pending, CreatedAt = DateTime.Now
                };
                db.Tasks.Add(task);
                taskIds.Add(task.Id);
            }
            db.SaveChanges();
        }
        TaskIds.Set(context, taskIds);
    }
}

// 等待會簽處理活動(Bookmark 機制)
public sealed class WaitCountersignActivity : NativeActivity {
    [RequiredArgument] public InArgument<Guid> TaskId { get; set; }
    public OutArgument<bool> IsApproved { get; set; }
    public OutArgument<string> Comment { get; set; }

    protected override bool CanInduceIdle => true;

    protected override void Execute(NativeActivityContext context) {
        var taskId = TaskId.Get(context);
        var bookmark = context.CreateBookmark($"Countersign_{taskId}", OnTaskCompleted);
        // 此處不阻塞,等待外部 WCF 呼叫 ResumeBookmark
    }

    void OnTaskCompleted(NativeActivityContext context, Bookmark bookmark, object value) {
        var result = (CountersignResult)value;
        IsApproved.Set(context, result.IsApproved);
        Comment.Set(context, result.Comment);
    }
}

WCF 服務契約與實作

[ServiceContract]
public interface ICountersignService {
    [OperationContract] Guid StartProcess(StartProcessRequest request);
    [OperationContract] void ProcessTask(ProcessTaskRequest request);
    [OperationContract] ProcessStatus GetStatus(Guid instanceId);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class CountersignService : ICountersignService {
    public Guid StartProcess(StartProcessRequest request) {
        var app = new WorkflowApplication(new CountersignFlowchart());
        // 設定持久化、追蹤、Extensions...
        var instanceId = Guid.NewGuid();
        app.Extensions.Add(new BpmContext());
        app.Run(instanceId); // 啟動並持久化
        return instanceId;
    }

    public void ProcessTask(ProcessTaskRequest request) {
        // 載入流程實例,ResumeBookmark 繼續執行
        var store = new SqlWorkflowInstanceStore(connectionString);
        var instance = WorkflowApplication.GetInstance(request.InstanceId, store);
        var app = new WorkflowApplication(new CountersignFlowchart(), instance.DefinitionIdentity);
        app.Extensions.Add(new BpmContext());
        app.Load(instance);
        app.ResumeBookmark($"Countersign_{request.TaskId}", new CountersignResult { 
            IsApproved = request.IsApproved, Comment = request.Comment 
        });
        app.Unload(); // 觸發持久化
    }
}

WPF 客戶端介面

WPF 客戶端加入服務參考

WPF 客戶端 UI 設計

private void btnStart_Click(object sender, RoutedEventArgs e) {
    var client = new CountersignServiceClient();
    var request = new StartProcessRequest {
        Title = txtTitle.Text,
        Content = txtContent.Text,
        Assignees = lstAssignees.Items.Cast<string>().ToList()
    };
    var instanceId = client.StartProcess(request);
    MessageBox.Show($"流程已啟動,InstanceId: {instanceId}");
}

private void btnProcess_Click(object sender, RoutedEventArgs e) {
    var client = new CountersignServiceClient();
    client.ProcessTask(new ProcessTaskRequest {
        InstanceId = Guid.Parse(txtInstanceId.Text),
        TaskId = Guid.Parse(txtTaskId.Text),
        IsApproved = chkApproved.IsChecked.Value,
        Comment = txtComment.Text
    });
    MessageBox.Show("處理完成");
}

執行效果驗證

啟動流程成功

並行會簽任務生成

會簽處理結果

同時啟動兩個流程實例

流程實例列表

處理會簽業務

查看流程結果

會簽詳細記錄

關鍵技術總結

技術點實現方式核心價值
長流程持久化SqlWorkflowInstanceStore + WorkflowApplication應用程式重啟流程不中斷
外部事件驅動Bookmark + WCF ResumeBookmark人工任務無縫整合自動化流程
並行會簽建模Parallel 活動 + 動態分支生成天然支援 N 位會簽人並行處理
狀態可視化自定義追蹤參與者寫入狀態表即時監控、審計追溯、報表分析
服務化解耦WCF 契約隔離 WF 實現細節多種客戶端(Web/Win/WPF/Mobile)統一介面

源碼下載

https://files.cnblogs.com/foundation/countersignature.rar

註:本範例專注於 WF 核心流程引擎應用,未包含組織架構、權限系統等 BPM 平台基礎設施,實際專案需補充這些模組。

WF 的價值在於將「流程邏輯」從業務代碼中剝離,成為可視化、可版本化、可持久化、可服務化的獨立資產。會簽只是冰山一角——掌握這套模式,即可應對任意複雜度的長時間業務流程。

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