• elsa-core:3.elsa 服务


    在本快速入门中,我们将介绍一个用于设置Elsa Server的最小ASP.NET Core应用程序。我们还将安装一些更常用的activities(活动),如Timer、Cron和sendmail,以能够实现简单的重复工作流。

    此应用程序的目的是作为工作流服务。这意味着它将承载和执行工作流,但不会承载dashboard(仪表板) UI。当然,也可以将工作流主机与承载dashboard UI的web应用程序相结合,将在随后的文章中展示。


    我们将:

    • 创建ASP.NET Core应用程序。
    • 使用EF Core和SQLite提供配置持久性。
    • 注册各种activities (活动)以在工作流中使用。
    • 使用workflow Builder API创建简单的工作流。
    • 公开Elsa API Endpoints供外部应用程序(包括Elsa Dashboard)使用。
    • 使用Postman验证Elsa API Endpoints。

    项目:

    创建一个新的空ASP.NET核心项目,名为ElsaQuickstarts.Server.apidemps:

    dotnet new web -n "ElsaQuickstarts.Server.ApiEndpoints"

    CD 到创建的项目文件夹中:

    cd ElsaQuickstarts.Server.ApiEndpoints
    cd ElsaQuickstarts.Server.ApiEndpoints

    添加以下包:

    dotnet add package Elsa
    dotnet add package Elsa.Activities.Http
    dotnet add package Elsa.Activities.Temporal.Quartz
    dotnet add package Elsa.Persistence.EntityFramework.Sqlite
    dotnet add package Elsa.Server.Api

     Heartbeat(心跳)工作流

    仅出于演示目的,我们将创建一个简单的“心跳”工作流,它会定期将当前时间写入标准。这将展示以下内容:

    • Elsa 支持程序化和动态工作流(例如,使用 Elsa Dashboard 可视化创建)。
    • 如果我们有 Elsa Dashboard 设置,我们可以直观地查看这个 Heartbeat 工作流程,即使我们要在这以编程方式创建它。
    • 我们可以使用 Postman 与 Elsa API endpoints交互并查询 Heartbeat 工作流生成的工作流实例。

    继续创建一个名为 HeartbeatWorkflow.cs 的新文件并添加以下代码:

    using Elsa.Activities.Console;
    using Elsa.Activities.Temporal;
    using Elsa.Builders;
    using NodaTime;
    
    namespace ElsaQuickstarts.Server.ApiEndpoints
    {
        public class HeartbeatWorkflow : IWorkflow
        {
            private readonly IClock _clock;
            public HeartbeatWorkflow(IClock clock) => _clock = clock;
    
            public void Build(IWorkflowBuilder builder) =>
                builder
                    .Timer(Duration.FromSeconds(10))
                    .WriteLine(context => $"Heartbeat at {_clock.GetCurrentInstant()}");
        }
    }

    上述工作流有两个活动。第一个活动 Timer 将导致此工作流每 10 秒执行一次。第二个活动 WriteLine 将当前时间写入标准输出。请注意它采用字符串委托的重载。这会允许在运行时提供动态的属性值。类似与在Elsa 1工作流中使用 JavaScript 和 Liquid 表达式。当然,不同之处在于您现在可以在使用 Workflow Builder API 编写工作流时使用普通的旧 C# 语法。

    另请注意,HeartbeatWorkflow 类可以接受构造函数注入的服务,就像向 DI 系统注册的任何其他类型一样。

    IClock :它是由 NodaTime 提供的抽象,它是 .NET 的替代日期和时间的 API。

     Startup

    接下来,打开 Startup.cs 并将其内容替换为以下内容:

    using Elsa;
    using Elsa.Persistence.EntityFramework.Core.Extensions;
    using Elsa.Persistence.EntityFramework.Sqlite;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    
    namespace ElsaQuickstarts.Server.ApiEndpoints
    {
        public class Startup
        {
            public Startup(IWebHostEnvironment environment, IConfiguration configuration)
            {
                Environment = environment;
                Configuration = configuration;
            }
    
            private IWebHostEnvironment Environment { get; }
            private IConfiguration Configuration { get; }
    
            public void ConfigureServices(IServiceCollection services)
            {
                var elsaSection = Configuration.GetSection("Elsa");
    
                // Elsa services.
                services
                    .AddElsa(elsa => elsa
                        .UseEntityFrameworkPersistence(ef => ef.UseSqlite())
                        .AddConsoleActivities()
                        .AddHttpActivities(elsaSection.GetSection("Server").Bind)
                        .AddQuartzTemporalActivities()
                        .AddJavaScriptActivities()
                        .AddWorkflowsFrom<Startup>()
                    );
    
                // Elsa API endpoints.
                services.AddElsaApiEndpoints();
    
                // Allow arbitrary client browser apps to access the API.
                // In a production environment, make sure to allow only origins you trust.
                services.AddCors(cors => cors.AddDefaultPolicy(policy => policy
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowAnyOrigin()
                    .WithExposedHeaders("Content-Disposition"))
                );
            }
    
            public void Configure(IApplicationBuilder app)
            {
                if (Environment.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app
                    .UseCors()
                    .UseHttpActivities()
                    .UseRouting()
                    .UseEndpoints(endpoints =>
                    {
                        // Elsa API Endpoints are implemented as regular ASP.NET Core API controllers.
                        endpoints.MapControllers();
                    });
            }
        }
    }

    使用 Entity Framework Core 时,Elsa 将默认使用合并数据库上下文,并将自动为您运行迁移。如果您不想使用池化数据库上下文,请改用 UseNonPooledEntityFrameworkPersistence 方法。如果您更喜欢自己运行迁移,请确保在使用 UseEntityFrameworkPersistence 方法时传递 autoRunMigrations: false (它是一个默认设置为 true 的可选参数)。

    请注意,我们正在访问名为“Elsa”的配置部分。然后我们使用此部分来检索名为“Http”和“Smtp”的子部分。接下来让我们用这些部分更新 appsettings.json:


     Appsettings.json

    打开 appsettings.json 并添加以下部分:

    {
      "Elsa": {
        "Http": {
          "BaseUrl": "https://localhost:5001"
        }
      }
    }

    我们设置“BaseUrl”的原因是 HTTP 活动库提供了一个绝对 URL 提供程序,可供活动和工作流表达式使用。由于这个绝对 URL 提供者可以在实际 HTTP 请求的上下文之外使用(例如,当一个计时器事件发生时),我们不能依赖例如IHttpContextAccessor,因为不会有任何 HTTP 上下文。


     运行

    运行程序并等待,直到看到以下输出:

    Now listening on: http://localhost:5000
    Now listening on: https://localhost:5001
    Application started. Press Ctrl+C to shut down.

    等待大约 10 秒后,可以看到以下输出:

    info: Elsa.Bookmarks.BookmarkIndexer[0]
          Indexed 0 bookmarks in 00:00:00.0077348
    Heartbeat at 2021-05-07T19:43:47Z
    info: Elsa.Bookmarks.BookmarkIndexer[0]
          Indexing bookmarks

    Postman

    启动 Postman 或任何其他HTTP 请求的工具。接下来将尝试一些公开的 API。

    列出工作流蓝图

    首先,让我们查询工作流注册表:

    GET /v1/workflow-registry
    Host: localhost:5001

    JSON 响应将包含所有已注册工作流的“summary(摘要)”视图(目前只有一个):

    {
        "items": [
            {
                "id": "HeartbeatWorkflow",
                "name": "HeartbeatWorkflow",
                "displayName": "HeartbeatWorkflow",
                "description": null,
                "version": 1,
                "tenantId": null,
                "isSingleton": false,
                "isEnabled": false,
                "isPublished": true,
                "isLatest": true
            }
        ],
        "page": null,
        "pageSize": null,
        "totalCount": 1
    }

    获取单一工作流蓝图

    要获取完整的工作流蓝图定义,请发出以下 HTTP 请求:

    GET /v1/workflow-registry/HeartbeatWorkflow
    Host: localhost:5001

    响应将包括更多详细信息,包括activities (活动)和connections(联系):

    {
        "$id": "1",
        "version": 1,
        "isSingleton": false,
        "isEnabled": false,
        "isPublished": true,
        "isLatest": true,
        "variables": {
            "$id": "2",
            "data": {}
        },
        "persistenceBehavior": "WorkflowBurst",
        "deleteCompletedInstances": false,
        "customAttributes": {
            "$id": "3",
            "data": {}
        },
        "activities": [
            {
                "$id": "4",
                "id": "activity-1",
                "type": "Timer",
                "parentId": "HeartbeatWorkflow",
                "persistWorkflow": false,
                "loadWorkflowContext": false,
                "saveWorkflowContext": false,
                "properties": {
                    "$id": "5",
                    "data": {
                        "Timeout": "0:00:10"
                    }
                }
            },
            {
                "$id": "6",
                "id": "activity-2",
                "type": "WriteLine",
                "parentId": "HeartbeatWorkflow",
                "persistWorkflow": false,
                "loadWorkflowContext": false,
                "saveWorkflowContext": false,
                "properties": {
                    "$id": "7",
                    "data": {
                        "Text": "Heartbeat at 2021-05-07T19:58:22Z"
                    }
                }
            }
        ],
        "connections": [
            {
                "$id": "8",
                "sourceActivityId": "activity-1",
                "targetActivityId": "activity-2",
                "outcome": "Done"
            }
        ],
        "id": "HeartbeatWorkflow",
        "name": "HeartbeatWorkflow",
        "displayName": "HeartbeatWorkflow",
        "type": "HeartbeatWorkflow",
        "parentId": "HeartbeatWorkflow",
        "persistWorkflow": true,
        "loadWorkflowContext": false,
        "saveWorkflowContext": false,
        "properties": {
            "$id": "9",
            "data": {}
        }
    }

    列出工作流实例

    随着 HeartbeatWorkflow 的执行,每 10 秒将创建一个新的工作流实例。要获取工作流实例列表,请发出以下请求:

    GET /v1/workflow-instances?workflow=HeartbeatWorkflow&page=0&pageSize=2
    Host: localhost:5001

    响应应类似于以下内容:

    {
        "items": [
            {
                "id": "e380d0a7fd4a4b6ba236fbdc0adf0ddb",
                "definitionId": "HeartbeatWorkflow",
                "tenantId": null,
                "version": 1,
                "workflowStatus": "Finished",
                "correlationId": null,
                "contextType": null,
                "contextId": null,
                "name": null,
                "createdAt": "2021-05-07T19:43:46.4198083Z",
                "lastExecutedAt": "2021-05-07T19:43:47.4602325Z",
                "finishedAt": "2021-05-07T19:43:47.4626325Z",
                "cancelledAt": null,
                "faultedAt": null
            },
            {
                "id": "418d0b535a89413e9ca2014a3b476b93",
                "definitionId": "HeartbeatWorkflow",
                "tenantId": null,
                "version": 1,
                "workflowStatus": "Finished",
                "correlationId": null,
                "contextType": null,
                "contextId": null,
                "name": null,
                "createdAt": "2021-05-07T19:43:56.175008Z",
                "lastExecutedAt": "2021-05-07T19:43:56.3284055Z",
                "finishedAt": "2021-05-07T19:43:56.3285439Z",
                "cancelledAt": null,
                "faultedAt": null
            }
        ],
        "page": 0,
        "pageSize": 2,
        "totalCount": 110
    }

    列出活动

    要获取可用活动的完整列表,您可以发出以下 HTTP 请求:

    GET /v1/activities
    Host: localhost:5001

    以下是部分响应,让您了解它的样子

    [
        {
            "type": "ReadLine",
            "displayName": "Read Line",
            "description": "Read text from standard in.",
            "category": "Console",
            "traits": 1,
            "outcomes": [
                "Done"
            ],
            "properties": []
        },
        {
            "type": "WriteLine",
            "displayName": "Write Line",
            "description": "Write text to standard out.",
            "category": "Console",
            "traits": 1,
            "outcomes": [
                "Done"
            ],
            "properties": [
                {
                    "name": "Text",
                    "type": "System.String",
                    "uiHint": "single-line",
                    "label": "Text",
                    "hint": "The text to write.",
                    "supportedSyntaxes": [
                        "JavaScript",
                        "Liquid"
                    ]
                }
            ]
        },
        {
            "type": "HttpEndpoint",
            "displayName": "HTTP Endpoint",
            "description": "Handle an incoming HTTP request.",
            "category": "HTTP",
            "traits": 2,
            "outcomes": [
                "Done"
            ],
            "properties": [
                {
                    "name": "Path",
                    "type": "Microsoft.AspNetCore.Http.PathString",
                    "uiHint": "single-line",
                    "label": "Path",
                    "hint": "The relative path that triggers this activity.",
                    "supportedSyntaxes": [
                        "JavaScript",
                        "Liquid"
                    ]
                },
                {
                    "name": "Methods",
                    "type": "System.Collections.Generic.HashSet`1[System.String]",
                    "uiHint": "check-list",
                    "label": "Methods",
                    "hint": "The HTTP methods that trigger this activity.",
                    "options": [
                        "GET",
                        "POST",
                        "PUT",
                        "DELETE",
                        "PATCH",
                        "OPTIONS",
                        "HEAD"
                    ],
                    "defaultValue": [
                        "GET"
                    ],
                    "defaultSyntax": "Json",
                    "supportedSyntaxes": [
                        "Json",
                        "JavaScript",
                        "Liquid"
                    ]
                },
                {
                    "name": "ReadContent",
                    "type": "System.Boolean",
                    "uiHint": "checkbox",
                    "label": "Read Content",
                    "hint": "A value indicating whether the HTTP request content body should be read and stored as part of the HTTP request model. The stored format depends on the content-type header.",
                    "supportedSyntaxes": [
                        "Literal",
                        "JavaScript",
                        "Liquid"
                    ]
                },
                {
                    "name": "TargetType",
                    "type": "System.Type",
                    "uiHint": "single-line",
                    "label": "Target Type",
                    "category": "Advanced",
                    "supportedSyntaxes": []
                }
            ]
        }
    ]:
    如果觉得不错,可以推荐收藏一下,让我也更有动力。
  • 相关阅读:
    day01的那些事
    Activity活动
    开始认真学习Android了
    《知其所以然》读书笔记
    网络编程——完成端口
    开发服务器端——工程配置
    完善自己的学习方法
    WSAAsyncSelect模型
    双缓冲绘图
    ListControl常用操作汇总
  • 原文地址:https://www.cnblogs.com/jingboweilan/p/15223408.html
Copyright © 2020-2023  润新知