From 7547708603744c9458983d77d2408007b199cd84 Mon Sep 17 00:00:00 2001 From: jeanbaptistedalle Date: Sat, 7 Oct 2023 23:24:56 +0200 Subject: [PATCH] Feature/postgresql efcore (#4500) * Create the extension to enable efcore for postgresql with workflow-runtime * Create a efcore postgresql samples to check extensions --------- Co-authored-by: Jean-Baptiste Dalle --- Elsa.sln | 7 +++ src/bundles/Elsa.AllInOne.Web/Program.cs | 9 +-- .../Modules/Runtime/Extensions.cs | 17 ++++++ .../Controllers/RunWorkflowController.cs | 26 ++++++++ ...Net.EntityFrameworkCore.PostgresSql.csproj | 16 +++++ .../Program.cs | 61 +++++++++++++++++++ .../Properties/launchSettings.json | 25 ++++++++ .../Workflows/HelloWorldHttpWorkflow.cs | 28 +++++++++ .../appsettings.json | 12 ++++ .../Properties/launchSettings.json | 12 ++++ 10 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 src/modules/Elsa.EntityFrameworkCore.PostgreSql/Modules/Runtime/Extensions.cs create mode 100644 src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Controllers/RunWorkflowController.cs create mode 100644 src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql.csproj create mode 100644 src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Program.cs create mode 100644 src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Properties/launchSettings.json create mode 100644 src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Workflows/HelloWorldHttpWorkflow.cs create mode 100644 src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/appsettings.json create mode 100644 src/samples/aspnet/Elsa.Samples.AspNet.HelloWorld/Properties/launchSettings.json diff --git a/Elsa.sln b/Elsa.sln index 84801bffa..bbce11dd9 100644 --- a/Elsa.sln +++ b/Elsa.sln @@ -112,6 +112,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.ConsoleApp.Wor EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.AspNet.MyBackendApi", "src\samples\aspnet\Elsa.Samples.AspNet.MyBackendApi\Elsa.Samples.AspNet.MyBackendApi.csproj", "{1A37795B-EBAB-4A9F-8CF0-373DA3D4C64A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql", "src\samples\aspnet\Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql\Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql.csproj", "{F363BE0D-7DD0-4613-BB90-3245E23F35F9}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.AspNet.WorkflowServer", "src\samples\aspnet\Elsa.Samples.AspNet.WorkflowServer\Elsa.Samples.AspNet.WorkflowServer.csproj", "{89157FB8-A25B-42EC-A91F-37DFEE274C8C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.AspNet.WorkflowDesigner", "src\samples\aspnet\Elsa.Samples.AspNet.WorkflowDesigner\Elsa.Samples.AspNet.WorkflowDesigner.csproj", "{812B3B34-D2DD-4A3B-BA2D-3D3C52E0C062}" @@ -415,6 +417,10 @@ Global {1A37795B-EBAB-4A9F-8CF0-373DA3D4C64A}.Debug|Any CPU.Build.0 = Debug|Any CPU {1A37795B-EBAB-4A9F-8CF0-373DA3D4C64A}.Release|Any CPU.ActiveCfg = Release|Any CPU {1A37795B-EBAB-4A9F-8CF0-373DA3D4C64A}.Release|Any CPU.Build.0 = Release|Any CPU + {F363BE0D-7DD0-4613-BB90-3245E23F35F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F363BE0D-7DD0-4613-BB90-3245E23F35F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F363BE0D-7DD0-4613-BB90-3245E23F35F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F363BE0D-7DD0-4613-BB90-3245E23F35F9}.Release|Any CPU.Build.0 = Release|Any CPU {89157FB8-A25B-42EC-A91F-37DFEE274C8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {89157FB8-A25B-42EC-A91F-37DFEE274C8C}.Debug|Any CPU.Build.0 = Debug|Any CPU {89157FB8-A25B-42EC-A91F-37DFEE274C8C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -671,6 +677,7 @@ Global {AD8C4BB0-C78F-496C-B326-1D82C02C7568} = {C6658DE0-2B2F-47F0-BB61-2CA66D435C09} {4782CA82-83B0-437E-8C97-636BB8B402EA} = {873BFC3E-63C2-4495-A503-5EC05DCD84E4} {1A37795B-EBAB-4A9F-8CF0-373DA3D4C64A} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5} + {F363BE0D-7DD0-4613-BB90-3245E23F35F9} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5} {89157FB8-A25B-42EC-A91F-37DFEE274C8C} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5} {812B3B34-D2DD-4A3B-BA2D-3D3C52E0C062} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5} {34FBB2D3-4E2B-4411-95F2-C6B56899826A} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5} diff --git a/src/bundles/Elsa.AllInOne.Web/Program.cs b/src/bundles/Elsa.AllInOne.Web/Program.cs index 34bb996b9..7337ef6d8 100644 --- a/src/bundles/Elsa.AllInOne.Web/Program.cs +++ b/src/bundles/Elsa.AllInOne.Web/Program.cs @@ -1,8 +1,8 @@ using Elsa.AllInOne.Web.Extensions; using Elsa.EntityFrameworkCore.Extensions; -using Elsa.Extensions; using Elsa.EntityFrameworkCore.Modules.Management; using Elsa.EntityFrameworkCore.Modules.Runtime; +using Elsa.Extensions; using Elsa.Webhooks.Extensions; using Microsoft.AspNetCore.Mvc; @@ -28,10 +28,7 @@ services }) .UseDefaultAuthentication() .UseWorkflowManagement(management => management.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString))) - .UseWorkflowRuntime(runtime => - { - runtime.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString)); - }) + .UseWorkflowRuntime(runtime => runtime.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString))) .UseScheduling() .UseJavaScript() .UseLiquid() @@ -71,4 +68,4 @@ app.UseAuthorization(); app.UseWorkflowsApi(); app.UseWorkflows(); app.MapRazorPages(); -app.Run(); \ No newline at end of file +app.Run(); diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Modules/Runtime/Extensions.cs b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Modules/Runtime/Extensions.cs new file mode 100644 index 000000000..9ddfc09d1 --- /dev/null +++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Modules/Runtime/Extensions.cs @@ -0,0 +1,17 @@ +using Elsa.EntityFrameworkCore.Common; +using Elsa.EntityFrameworkCore.Modules.Runtime; + +// ReSharper disable once CheckNamespace +namespace Elsa.EntityFrameworkCore.Extensions; + +public static partial class Extensions +{ + /// + /// Configures the to use PostgreSql. + /// + public static EFCoreWorkflowRuntimePersistenceFeature UsePostgreSql(this EFCoreWorkflowRuntimePersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default) + { + feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(connectionString, options); + return feature; + } +} diff --git a/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Controllers/RunWorkflowController.cs b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Controllers/RunWorkflowController.cs new file mode 100644 index 000000000..f47da60fb --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Controllers/RunWorkflowController.cs @@ -0,0 +1,26 @@ +using Elsa.Http; +using Elsa.Workflows.Core.Contracts; +using Microsoft.AspNetCore.Mvc; + +namespace Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql.Controllers; + +[ApiController] +[Route("run-workflow")] +public class RunWorkflowController : ControllerBase +{ + private readonly IWorkflowRunner _workflowRunner; + + public RunWorkflowController(IWorkflowRunner workflowRunner) + { + _workflowRunner = workflowRunner; + } + + [HttpGet] + public async Task Post() + { + await _workflowRunner.RunAsync(new WriteHttpResponse + { + Content = new("Hello ASP.NET world!") + }); + } +} \ No newline at end of file diff --git a/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql.csproj b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql.csproj new file mode 100644 index 000000000..c48b992fa --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql.csproj @@ -0,0 +1,16 @@ + + + + net7.0 + enable + enable + + + + + + + + + + diff --git a/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Program.cs b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Program.cs new file mode 100644 index 000000000..5e78b14e3 --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Program.cs @@ -0,0 +1,61 @@ +using Elsa.EntityFrameworkCore.Common; +using Elsa.EntityFrameworkCore.Extensions; +using Elsa.EntityFrameworkCore.Modules.Management; +using Elsa.EntityFrameworkCore.Modules.Runtime; +using Elsa.Extensions; +using FastEndpoints.Swagger; + +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); +ConfigurationManager configuration = builder.Configuration; + +// Add services to the container. +builder.Services.AddControllers(); +builder.Services.AddElsa(elsa => +{ + var dbContextOptions = new ElsaDbContextOptions(); + string postgresConnectionString = configuration.GetConnectionString("Postgres")!; + string schema = configuration.GetConnectionString("Schema")!; + + if (!string.IsNullOrEmpty(schema)) + { + dbContextOptions.SchemaName = schema; + dbContextOptions.MigrationsAssemblyName = typeof(Program).Assembly.GetName().Name; + } + + elsa.UseWorkflowManagement(management => management.UseEntityFrameworkCore(ef => ef.UsePostgreSql(postgresConnectionString, dbContextOptions))); + elsa.UseWorkflowRuntime(runtime => runtime.UseEntityFrameworkCore(ef => ef.UsePostgreSql(postgresConnectionString, dbContextOptions))); + + elsa + .UseHttp() + .AddFastEndpointsAssembly() + .UseWorkflowsApi(); + + elsa.AddWorkflowsFrom(); +}); + +builder.Services.SwaggerDocument(options => +{ + options.DocumentSettings = documentSetting => + { + documentSetting.Title = "Elsa API"; + documentSetting.Version = "v1"; + }; +}); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +app.UseHttpsRedirection(); +app.UseAuthorization(); +app.MapControllers(); +app.UseWorkflows(); +app.UseWorkflowsApi(); + +if (!app.Environment.IsProduction()) +{ + app.UseOpenApi(); + app.UseSwaggerUi3(); + app.UseReDoc(); +} + +app.Run(); diff --git a/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Properties/launchSettings.json b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Properties/launchSettings.json new file mode 100644 index 000000000..01ac0b6cb --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Properties/launchSettings.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5284", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7285;http://localhost:5284", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Workflows/HelloWorldHttpWorkflow.cs b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Workflows/HelloWorldHttpWorkflow.cs new file mode 100644 index 000000000..4ab32a312 --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Workflows/HelloWorldHttpWorkflow.cs @@ -0,0 +1,28 @@ +using Elsa.Http; +using Elsa.Workflows.Core; +using Elsa.Workflows.Core.Activities; +using Elsa.Workflows.Core.Contracts; + +namespace Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql.Workflows; + +public class HelloWorldHttpWorkflow : WorkflowBase +{ + protected override void Build(IWorkflowBuilder builder) + { + builder.Root = new Sequence + { + Activities = + { + new HttpEndpoint + { + Path = new("/hello-world"), + CanStartWorkflow = true + }, + new WriteHttpResponse + { + Content = new("Hello world of HTTP workflows!") + } + } + }; + } +} \ No newline at end of file diff --git a/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/appsettings.json b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/appsettings.json new file mode 100644 index 000000000..944aa8fae --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "Postgres": "Host=localhost;Database=elsa_efcore;Username=elsa;Password=password;Pooling=true;" + } +} diff --git a/src/samples/aspnet/Elsa.Samples.AspNet.HelloWorld/Properties/launchSettings.json b/src/samples/aspnet/Elsa.Samples.AspNet.HelloWorld/Properties/launchSettings.json new file mode 100644 index 000000000..6d7506177 --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.AspNet.HelloWorld/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Elsa.Samples.AspNet.HelloWorld": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58521;http://localhost:58522" + } + } +} \ No newline at end of file