開源的.Net 工作流引擎Elsa初試——創建工作流伺服器和圖形化工作流配置管理應用

微軟的Workflow Foundation基於.Net Framework,並且沒有向.Net Core遷移的計劃。我們的很多項目使用了工作流引擎,這些項目向.Net Core以及更高版本遷移時遇到了不少問題,一直在尋找/開發適合的工作流引擎。找到一些開源的項目,可以解決一些問題,還有些項目不是基於.Net生態的,但我希望能有一個長期穩定的基於.Net生態的項目,能夠滿足多種場景,可以替換原來的Workflow Foundation。希望的特性包括:1、同時支援編程工作流定義和配置工作流定義,最好有圖形化的管理工具。2、支援長期工作流。3、支援有限狀態機類型的工作流定義。4、工作流引擎可以集成在應用中,也可以獨立部署為工作流伺服器,採用Web Api的方式調用。在我們跟蹤的工作流相關項目中,Elsa一直在穩步發展,最新的版本(2.9)已經基本可以滿足我們的上述要求了,在以後的版本也會增加對有限狀態機的支援。這裡簡單介紹一下如何創建工作流伺服器和圖形化的工作流配置管理應用。

首先,使用Visual Studio 2022創建一個空的Asp.Net Core Web應用,名稱為MyElsaServer。項目創建完成後,使用NuGet包管理器,安裝如下程式包:
Install-Package Elsa
Install-Package Elsa.Activities.Http
Install-Package Elsa.Persistence.EntityFramework.Sqlite
Install-Package Elsa.Server.Api
然後,修改項目的Properties/launchSettings.json,去掉通過IIS Express啟動的選項:

{
  "profiles": {
    "MyElsaServer": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "//localhost:5298",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

最後,修改Program.cs:

using Elsa.Persistence.EntityFramework.Core.Extensions;
using Elsa.Persistence.EntityFramework.Sqlite;

var builder = WebApplication.CreateBuilder(args);


var elsaSection = builder.Configuration.GetSection("Elsa");

// Elsa services.
builder.Services
    .AddElsa(elsa => elsa
        .UseEntityFrameworkPersistence(ef => ef.UseSqlite())
        .AddConsoleActivities()
        .AddHttpActivities(elsaSection.GetSection("Server").Bind)
        .AddJavaScriptActivities()
    );

// Elsa API endpoints.
builder.Services.AddElsaApiEndpoints();

// Allow arbitrary client browser apps to access the API.
// In a production environment, make sure to allow only origins you trust.
builder.Services.AddCors(cors => cors.AddDefaultPolicy(policy => policy
    .AllowAnyHeader()
    .AllowAnyMethod()
    .AllowAnyOrigin()
    .WithExposedHeaders("Content-Disposition"))
);

var app = builder.Build();

app
    .UseCors()
    .UseHttpActivities()
    .UseRouting()
    .UseEndpoints(endpoints =>
     {
       // Elsa API Endpoints are implemented as regular ASP.NET Core API controllers.
       endpoints.MapControllers();
     })
    .UseWelcomePage();
app.Run();

最後,在appSettings.json中增加伺服器地址的定義:

  "Elsa": {
    "Http": {
      "BaseUrl": "//localhost:5298"
    }
  }

啟動項目,會出現歡迎介面:

伺服器可以運行了,但還沒有定義工作流,現在我們創建圖形化的工作流定義和管理應用,向工作流伺服器發布工作流,並查看工作流的執行情況。
在解決方案中增加一個新的Asp.Net Core Web空項目,命名為MyElsaDashboard,修改Properties/launchSettings.json,將項目改為自啟動:

{
  "profiles": {
    "MyElsaDashboard": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "//localhost:5060",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

在項目中添加如下程式包:

Install-Package Elsa.Designer.Components.Web

修改Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapFallbackToPage("/_Host"); });

app.Run();

然後在項目中創建Pages文件夾,在文件夾中添加兩個Razepage頁面,名稱為_ViewImports.cshtml和_Host.cshtml,_ViewImports的內容如下:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

_Host.cshtml的內容如下:

@page "/"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Elsa Workflows</title>
    <link rel="icon" type="image/png" sizes="32x32" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/images/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/images/favicon-16x16.png">
    <link rel="stylesheet" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/fonts/inter/inter.css">
    <link rel="stylesheet" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/elsa-workflows-studio.css">
    <script src="/_content/Elsa.Designer.Components.Web/monaco-editor/min/vs/loader.js"></script>
    <script type="module" src="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/elsa-workflows-studio.esm.js"></script>
</head>
<body>
<elsa-studio-root server-url="//localhost:5298" monaco-lib-path="_content/Elsa.Designer.Components.Web/monaco-editor/min">
    <elsa-studio-dashboard></elsa-studio-dashboard>
</elsa-studio-root>
</body>
</html>

請注意上面的server-url屬性,這裡指向我們前面創建的Elsa伺服器地址。
現在我們修改解決方案的啟動項目,設置為兩個項目同時啟動:

在Visual Studio中執行啟動,管理介面如下:

選擇Workflow Definitions進入流程定義管理介面,點擊「Create Workflow」創建新的流程:

點擊Start,然後選擇Http->Http EndPoint,定義流程的入口url:

設置完成後按Save保存,可以看到多個一個環節,在這個環節下點擊「+」圖標可以繼續添加環節,這裡選擇HttpResponse:

在Advanced選擇卡中,選擇Status Code為Ok,添加完成後,流程如下:

流程定義完成了,點擊Publish發布流程到流程伺服器。
流程發布後,可以在流程伺服器執行流程。我們在瀏覽器訪問//localhost:5298/hello-world,可以看到流程執行的結果:

回到流程管理應用,選擇Workflow Instances,可以看到剛剛執行完成的流程實例:

點擊流程Id,可以查看流程執行的詳細過程:

到此,我們完成了工作流服務和管理應用的創建,上述示例程式碼可以從github下載://github.com/zhenl/MyElsa