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

WF4 進階:使用 WorkflowHostingEndpoint 承載無服務工作流(No-Service Workflow Hosting)

     編輯:關於.NET

標準工作流服務透過 Receive 活動接收訊息,由 WorkflowServiceHost 承載。但當工作流不包含任何訊息活動(純邏輯流程、批次處理、長時間執行作業),卻仍需透過服務端點建立執行個體、恢復書籤時,WorkflowHostingEndpoint 就是關鍵解決方案。

架構角色對比

特性WorkflowServiceHost + ReceiveWorkflowHostingEndpoint
適用場景訊息驅動工作流無訊息活動的工作流
建立執行個體自動 (Receive 啟動)透過端點明確呼叫 Create
書籤恢復Receive 隱含處理需實作 OnResolveBookmark
服務合約從活動推導開發者自訂介面

完整實作範例:自訂建立與書籤恢復端點

1. 定義服務合約

[ServiceContract(Name = "IWorkflowCreation")]
public interface IWorkflowCreation
{
    [OperationContract(Name = "Create")]
    Guid Create(IDictionary<string, object> inputs);

    [OperationContract(Name = "CreateWithInstanceId", IsOneWay = true)]
    void CreateWithInstanceId(Guid instanceId, IDictionary<string, object> inputs);

    [OperationContract(Name = "ResumeBookmark", IsOneWay = true)]
    void ResumeBookmark(Guid instanceId, string bookmarkName, string message);
}

2. 實作 WorkflowHostingEndpoint 核心邏輯

public class ResumeBookmarkEndpoint : WorkflowHostingEndpoint
{
    public ResumeBookmarkEndpoint(Binding binding, EndpointAddress address)
        : base(typeof(IWorkflowCreation), binding, address) { }

    // 決定執行個體 ID:Create 回傳新 GUID,其他使用傳入 ID
    protected override Guid OnGetInstanceId(object[] inputs, OperationContext operationContext)
    {
        string action = operationContext.IncomingMessageHeaders.Action;
        if (action.EndsWith("Create")) return Guid.Empty;
        if (action.EndsWith("CreateWithInstanceId") || action.EndsWith("ResumeBookmark"))
            return (Guid)inputs[0];
        throw new InvalidOperationException("Invalid Action: " + action);
    }

    // 建立工作流建立內容:傳遞輸入參數
    protected override WorkflowCreationContext OnGetCreationContext(
        object[] inputs, OperationContext operationContext, 
        Guid instanceId, WorkflowHostingResponseContext responseContext)
    {
        var context = new WorkflowCreationContext();
        string action = operationContext.IncomingMessageHeaders.Action;
        
        if (action.EndsWith("Create") || action.EndsWith("CreateWithInstanceId"))
        {
            var args = (Dictionary<string, object>)inputs[0];
            if (args != null)
                foreach (var kvp in args) context.WorkflowArguments.Add(kvp.Key, kvp.Value);
            
            if (action.EndsWith("Create")) 
                responseContext.SendResponse(instanceId, null); // 同步回傳 InstanceId
        }
        else throw new InvalidOperationException("Invalid Action: " + action);
        
        return context;
    }

    // 解析書籤:ResumeBookmark 對應書籤名稱與載荷
    protected override Bookmark OnResolveBookmark(
        object[] inputs, OperationContext operationContext, 
        WorkflowHostingResponseContext responseContext, out object value)
    {
        if (operationContext.IncomingMessageHeaders.Action.EndsWith("ResumeBookmark"))
        {
            value = inputs[2];  // message 參數
            return new Bookmark((string)inputs[1]);  // bookmarkName 參數
        }
        throw new NotImplementedException();
    }
}

3. 自訂書籤活動(NativeActivity)

public sealed class CaryActivity<T> : NativeActivity<T>
{
    public string BookmarkName { get; set; }

    protected override bool CanInduceIdle { get { return true; } }

    protected override void Execute(NativeActivityContext context)
    {
        // 建立書籤等待外部恢復
        context.CreateBookmark(BookmarkName, OnBookmarkCallback);
    }

    void OnBookmarkCallback(NativeActivityContext context, Bookmark bookmark, object state)
    {
        Result.Set(context, (T)state);  // 書籤恢復時設定活動結果
    }
}

4. 工作流設計

序列:

  1. CaryActivity<string> (BookmarkName="cary") - 等待外部訊息
  2. WriteLine - 輸出書籤恢復的訊息內容

5. 服務端承載程式

static void Main(string[] args)
{
    WorkflowServiceHost host = null;
    try
    {
        host = new WorkflowServiceHost(new Workflow1(), new Uri("https://localhost"));
        
        var endpoint = new ResumeBookmarkEndpoint(
            new BasicHttpBinding(),
            new EndpointAddress(new Uri("https://localhost/CaryService1.xaml")));
            
        host.AddServiceEndpoint(endpoint);
        host.Open();
        
        Console.WriteLine("Host Started: " + endpoint.Address);
        Console.ReadLine();
    }
    finally { host?.Close(); }
}

6. 客戶端呼叫測試

static void Main(string[] args)
{
    var endpoint = new ResumeBookmarkEndpoint(
        new BasicHttpBinding(),
        new EndpointAddress(new Uri("https://localhost/CaryService1.xaml")));
        
    var client = new ChannelFactory<IWorkflowCreation>(endpoint.Binding, endpoint.Address).CreateChannel();
    
    Guid id = client.Create(null);
    Console.WriteLine("WorkflowApplication {0} Created", id);
    
    client.ResumeBookmark(id, "cary", "Hello World!");
}

7. 執行結果

Host Started: https://localhost/CaryService1.xaml
WorkflowApplication {GUID} Created
// 服務端主控台輸出: Hello World!

核心設計模式總結

  • 命令查詢分離 (CQS):Create 回傳 ID (查詢),CreateWithInstanceId/ResumeBookmark 為單向命令
  • 關聯性管理:OnGetInstanceId 根據 Action 決定新建或關聯既有執行個體
  • 書籤為核心同步點:工作流在 CreateBookmark 閒置,外部透過 ResumeBookmark 注入資料繼續執行
  • 非同步回應:responseContext.SendResponse 僅在同步 Create 時使用

此模式適用於:長時間執行的業務流程、人工審核等待、批次作業外部觸發、混合人機協作流程等無訊息活動工作流承載場景。

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