diff --git a/src/activities/webhooks/Elsa.Webhooks.Persistence.EntityFramework.Core/EntityFrameworkWebhookStartupBase.cs b/src/activities/webhooks/Elsa.Webhooks.Persistence.EntityFramework.Core/EntityFrameworkWebhookStartupBase.cs index af5e3f21c..d5aa71dd8 100644 --- a/src/activities/webhooks/Elsa.Webhooks.Persistence.EntityFramework.Core/EntityFrameworkWebhookStartupBase.cs +++ b/src/activities/webhooks/Elsa.Webhooks.Persistence.EntityFramework.Core/EntityFrameworkWebhookStartupBase.cs @@ -16,7 +16,7 @@ namespace Elsa.Webhooks.Persistence.EntityFramework.Core public override void ConfigureElsa(ElsaOptionsBuilder elsa, IConfiguration configuration) { var services = elsa.Services; - var section = configuration.GetSection($"Elsa:Persistence:{ProviderName}"); + var section = configuration.GetSection($"Elsa:Features:Webhooks:Persistence:EntityFrameworkCore:{ProviderName}"); var connectionStringName = section.GetValue("ConnectionStringName"); var connectionString = section.GetValue("ConnectionString"); diff --git a/src/activities/webhooks/Elsa.Webhooks.Persistence.MongoDb/Startup.cs b/src/activities/webhooks/Elsa.Webhooks.Persistence.MongoDb/Startup.cs index c8295b9dd..98a249f44 100644 --- a/src/activities/webhooks/Elsa.Webhooks.Persistence.MongoDb/Startup.cs +++ b/src/activities/webhooks/Elsa.Webhooks.Persistence.MongoDb/Startup.cs @@ -1,7 +1,6 @@ using Elsa.Activities.Webhooks; using Elsa.Activities.Webhooks.Persistence.Decorators; using Elsa.Attributes; -using Elsa.Persistence.MongoDb.Options; using Elsa.Services.Startup; using Elsa.Webhooks.Persistence.MongoDb.Extensions; using Microsoft.Extensions.Configuration; @@ -15,7 +14,7 @@ namespace Elsa.Webhooks.Persistence.MongoDb public override void ConfigureElsa(ElsaOptionsBuilder elsa, IConfiguration configuration) { var services = elsa.Services; - var section = configuration.GetSection($"Elsa:Persistence:MongoDb"); + var section = configuration.GetSection($"Elsa:Features:Webhooks:Persistence:MongoDb"); var connectionStringName = section.GetValue("ConnectionStringName"); var connectionString = section.GetValue("ConnectionString"); diff --git a/src/activities/webhooks/Elsa.Webhooks.Persistence.YesSql/Startups.cs b/src/activities/webhooks/Elsa.Webhooks.Persistence.YesSql/Startups.cs index 51081f3cf..b605ee7bb 100644 --- a/src/activities/webhooks/Elsa.Webhooks.Persistence.YesSql/Startups.cs +++ b/src/activities/webhooks/Elsa.Webhooks.Persistence.YesSql/Startups.cs @@ -49,7 +49,7 @@ namespace Elsa.Webhooks.Persistence.YesSql public override void ConfigureElsa(ElsaOptionsBuilder elsa, IConfiguration configuration) { var services = elsa.Services; - var section = configuration.GetSection($"Elsa:Persistence:{ProviderName}"); + var section = configuration.GetSection($"Elsa:Features:Webhooks:Persistence:YesSql:{ProviderName}"); var connectionStringName = section.GetValue("ConnectionStringName"); var connectionString = section.GetValue("ConnectionString"); diff --git a/src/core/Elsa.Core/ElsaOptionsBuilder.cs b/src/core/Elsa.Core/ElsaOptionsBuilder.cs index 9b5261b8a..68ac903fb 100644 --- a/src/core/Elsa.Core/ElsaOptionsBuilder.cs +++ b/src/core/Elsa.Core/ElsaOptionsBuilder.cs @@ -4,10 +4,12 @@ using System.Linq; using System.Reflection; using Elsa.Builders; using Elsa.Caching; +using Elsa.Models; using Elsa.Persistence; using Elsa.Providers.WorkflowStorage; using Elsa.Services; using Elsa.Services.Messaging; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Rebus.DataBus.InMem; diff --git a/src/core/Elsa.Core/Extensions/ElsaOptionBuilderExtensions.cs b/src/core/Elsa.Core/Extensions/ElsaOptionBuilderExtensions.cs index 3c033f2cb..081375ee9 100644 --- a/src/core/Elsa.Core/Extensions/ElsaOptionBuilderExtensions.cs +++ b/src/core/Elsa.Core/Extensions/ElsaOptionBuilderExtensions.cs @@ -10,14 +10,16 @@ namespace Elsa { public static class ElsaOptionBuilderExtensions { - public static ElsaOptionsBuilder AddFeatures(this ElsaOptionsBuilder builder, IEnumerable assemblyMarkerTypes, IConfiguration configuration, IEnumerable features) => AddFeatures(builder, GetAssemblies(assemblyMarkerTypes), configuration, features); + public static ElsaOptionsBuilder AddFeatures(this ElsaOptionsBuilder builder, IEnumerable assemblyMarkerTypes, IConfiguration configuration) => AddFeatures(builder, GetAssemblies(assemblyMarkerTypes), configuration); - public static ElsaOptionsBuilder AddFeatures(this ElsaOptionsBuilder builder, IEnumerable assemblies, IConfiguration configuration, IEnumerable features) + public static ElsaOptionsBuilder AddFeatures(this ElsaOptionsBuilder builder, IEnumerable assemblies, IConfiguration configuration) { - if (features == null!) // Null when configuration binding finds an empty array. + var enabledFeatures = ParseFeatures(configuration); + + if (enabledFeatures == null!) // Null when configuration binding finds an empty array. return builder; - - var enabledFeatures = features.ToHashSet(); + + enabledFeatures = enabledFeatures.ToHashSet(); var startupTypesQuery = from assembly in assemblies from type in assembly.GetExportedTypes() @@ -37,7 +39,36 @@ namespace Elsa return builder; } - + + private static IEnumerable ParseFeatures(IConfiguration configuration) + { + var elsaFeaturesSection = "Elsa:Features"; + var features = configuration.GetSection(elsaFeaturesSection).AsEnumerable(); + + return + from feature in features + let isEnabled = ParseFeatureFlag(configuration, feature.Key) + where isEnabled + select feature.Key.Replace($"{elsaFeaturesSection}:", string.Empty); + } + + private static bool ParseFeatureFlag(IConfiguration configuration, string feature) + { + if (configuration.GetSection($"{feature}:Enabled").Exists()) + { + bool.TryParse(configuration.GetValue($"{feature}:Enabled"), out var enabled); + return enabled; + } + + if (!feature.EndsWith(":Enabled")) + { + bool.TryParse(configuration.GetValue($"{feature}"), out var enabled); + return enabled; + } + + return false; + } + private static IEnumerable GetAssemblies(IEnumerable assemblyMarkerTypes) => assemblyMarkerTypes.Select(x => x.Assembly).Distinct(); } } \ No newline at end of file diff --git a/src/persistence/Elsa.Persistence.EntityFramework/Elsa.Persistence.EntityFramework.Core/EntityFrameworkCoreStartupBase.cs b/src/persistence/Elsa.Persistence.EntityFramework/Elsa.Persistence.EntityFramework.Core/EntityFrameworkCoreStartupBase.cs index 25026ca10..6cf381516 100644 --- a/src/persistence/Elsa.Persistence.EntityFramework/Elsa.Persistence.EntityFramework.Core/EntityFrameworkCoreStartupBase.cs +++ b/src/persistence/Elsa.Persistence.EntityFramework/Elsa.Persistence.EntityFramework.Core/EntityFrameworkCoreStartupBase.cs @@ -12,7 +12,7 @@ namespace Elsa.Persistence.EntityFramework.Core public override void ConfigureElsa(ElsaOptionsBuilder elsa, IConfiguration configuration) { - var section = configuration.GetSection($"Elsa:Persistence:{ProviderName}"); + var section = configuration.GetSection($"Elsa:Features:Persistence:EntityFrameworkCore:{ProviderName}"); var connectionStringName = section.GetValue("ConnectionStringName"); var connectionString = section.GetValue("ConnectionString"); diff --git a/src/persistence/Elsa.Persistence.MongoDb/Startup.cs b/src/persistence/Elsa.Persistence.MongoDb/Startup.cs index 20c55c9c5..38eaf73ca 100644 --- a/src/persistence/Elsa.Persistence.MongoDb/Startup.cs +++ b/src/persistence/Elsa.Persistence.MongoDb/Startup.cs @@ -9,7 +9,7 @@ namespace Elsa.Persistence.MongoDb { public override void ConfigureElsa(ElsaOptionsBuilder elsa, IConfiguration configuration) { - var section = configuration.GetSection($"Elsa:Persistence:MongoDb"); + var section = configuration.GetSection($"Elsa:Features:Persistence:MongoDb"); var connectionStringName = section.GetValue("ConnectionStringName"); var connectionString = section.GetValue("ConnectionString"); diff --git a/src/persistence/Elsa.Persistence.YesSql/Startups.cs b/src/persistence/Elsa.Persistence.YesSql/Startups.cs index c1d608981..ffcce94d6 100644 --- a/src/persistence/Elsa.Persistence.YesSql/Startups.cs +++ b/src/persistence/Elsa.Persistence.YesSql/Startups.cs @@ -44,7 +44,7 @@ namespace Elsa.Persistence.YesSql public override void ConfigureElsa(ElsaOptionsBuilder elsa, IConfiguration configuration) { - var section = configuration.GetSection($"Elsa:Persistence:{ProviderName}"); + var section = configuration.GetSection($"Elsa:Features:Persistence:YesSql:{ProviderName}"); var connectionStringName = section.GetValue("ConnectionStringName"); var connectionString = section.GetValue("ConnectionString"); diff --git a/src/samples/dashboard/aspnetcore/ElsaDashboard.Samples.AspNetCore.Monolith/Startup.cs b/src/samples/dashboard/aspnetcore/ElsaDashboard.Samples.AspNetCore.Monolith/Startup.cs index 0941b4024..1dfd52ca0 100644 --- a/src/samples/dashboard/aspnetcore/ElsaDashboard.Samples.AspNetCore.Monolith/Startup.cs +++ b/src/samples/dashboard/aspnetcore/ElsaDashboard.Samples.AspNetCore.Monolith/Startup.cs @@ -36,7 +36,7 @@ namespace ElsaDashboard.Samples.AspNetCore.Monolith .AddQuartzTemporalActivities() .AddJavaScriptActivities() .AddActivitiesFrom() - .AddFeatures(new[] { typeof(Startup) }, Configuration, elsaSection.GetSection("Features").Get>()) + .AddFeatures(new[] { typeof(Startup) }, Configuration) ); services diff --git a/src/samples/server/Elsa.Samples.Server.Host/README.md b/src/samples/server/Elsa.Samples.Server.Host/README.md index ea7b451d1..07879a189 100644 --- a/src/samples/server/Elsa.Samples.Server.Host/README.md +++ b/src/samples/server/Elsa.Samples.Server.Host/README.md @@ -1,93 +1,104 @@ -### Configure persistence in appsettings.json +### Configure persistence for Elsa Core in the appsettings.json + +It is required to specify the persistence, it's enabled status and connection string name in Features EF Sqlite ``` "Elsa": { -"Features": [ - "Persistence:EntityFrameworkCore:Sqlite", + "Features": { + "Persistence:EntityFrameworkCore:Sqlite": { + "Enabled": true, + "ConnectionStringName": "Sqlite" + }, ... - ], -} ``` EF MySQL ``` "Elsa": { -"Features": [ - "Persistence:EntityFrameworkCore:MySql", + "Features": { + "Persistence:EntityFrameworkCore:MySql": { + "Enabled": true, + "ConnectionStringName": "MySql" + }, ... - ], -} ``` EF SQL Server ``` "Elsa": { -"Features": [ - "Persistence:EntityFrameworkCore:SqlServer", - ... - ], -} + "Features": { + "Persistence:EntityFrameworkCore:SqlServer": { + "Enabled": true, + "ConnectionStringName": "SqlServer" + }, + ... ``` EF Postgre ``` "Elsa": { -"Features": [ - "Persistence:EntityFrameworkCore:PostgreSql", + "Features": { + "Persistence:EntityFrameworkCore:PostgreSql": { + "Enabled": "true", + "ConnectionStringName": "PostgreSql" + }, ... - ], -} ``` EF MongoDB ``` "Elsa": { -"Features": [ - "Persistence:MongoDb", + "Features": { + "Persistence:MongoDb": { + "Enabled": true, + "ConnectionStringName": "MongoDb" + }, ... - ], -} ``` YesSql Sqlite ``` "Elsa": { -"Features": [ - "Persistence:YesSql:Sqlite", + "Features": { + "Persistence:YesSql:Sqlite": { + "Enabled": true, + "ConnectionStringName": "Sqlite" + }, ... - ], -} ``` YesSql MySQL ``` "Elsa": { -"Features": [ - "Persistence:YesSql:MySql", + "Features": { + "Persistence:YesSql:MySql": { + "Enabled": true, + "ConnectionStringName": "MySql" + }, ... - ], -} ``` YesSql SQL Server ``` "Elsa": { -"Features": [ - "Persistence:YesSql:SqlServer", + "Features": { + "Persistence:YesSql:SqlServer": { + "Enabled": true, + "ConnectionStringName": "SqlServer" + }, ... - ], -} ``` YesSql Postgre ``` "Elsa": { -"Features": [ - "Persistence:YesSql:PostgreSql", + "Features": { + "Persistence:YesSql:PostgreSql": { + "Enabled": true, + "ConnectionStringName": "PostgreSql" + }, ... - ], -} ``` ### Configure modular activity providers such as Webhooks @@ -98,25 +109,35 @@ Two examples below are given to set up Elsa Core and Webhooks persistence as fol EF Sqlite ``` "Elsa": { -"Features": [ - "Persistence:EntityFrameworkCore:Sqlite", - "Webhooks" - "Webhooks:Persistence:EntityFrameworkCore:Sqlite", + "Features": { + "Persistence:EntityFrameworkCore:Sqlite": { + "Enabled": true, + "ConnectionStringName": "Sqlite" + }, + "Webhooks": true + }, + "Webhooks:Persistence:EntityFrameworkCore:Sqlite": { + "Enabled": true, + "ConnectionStringName": "Sqlite" + } ... - ], -} ``` EF MongoDB ``` "Elsa": { -"Features": [ - "Persistence:MongoDb", - "Webhooks" - "Webhooks:Persistence:MongoDb", + "Features": { + "Persistence:MongoDb": { + "Enabled": true, + "ConnectionStringName": "MongoDb" + }, + "Webhooks": true + }, + "Webhooks:Persistence:MongoDb": { + "Enabled": true, + "ConnectionStringName": "MongoDb" + } ... - ], -} ``` ### Configure connection strings for each persistence diff --git a/src/samples/server/Elsa.Samples.Server.Host/Startup.cs b/src/samples/server/Elsa.Samples.Server.Host/Startup.cs index 0aac4f73a..ddfbed3f1 100644 --- a/src/samples/server/Elsa.Samples.Server.Host/Startup.cs +++ b/src/samples/server/Elsa.Samples.Server.Host/Startup.cs @@ -66,7 +66,7 @@ namespace Elsa.Samples.Server.Host .AddElsa(elsa => elsa .AddActivitiesFrom() .AddWorkflowsFrom() - .AddFeatures(startups, Configuration, elsaSection.GetSection("Features").Get>()) + .AddFeatures(startups, Configuration) .ConfigureWorkflowChannels(options => elsaSection.GetSection("WorkflowChannels").Bind(options)) ); diff --git a/src/samples/server/Elsa.Samples.Server.Host/appsettings.json b/src/samples/server/Elsa.Samples.Server.Host/appsettings.json index 4a9984de6..0b93db473 100644 --- a/src/samples/server/Elsa.Samples.Server.Host/appsettings.json +++ b/src/samples/server/Elsa.Samples.Server.Host/appsettings.json @@ -18,34 +18,25 @@ "PostgreSql": "Server=127.0.0.1;Port=5432;Database=elsa;User Id=postgres;Password=password;" }, "Elsa": { - "Features": [ - "Persistence:EntityFrameworkCore:Sqlite", - "Dispatcher:Hangfire", - "Console", - "Http", - "Email", - "Temporal:Quartz", - "JavaScript:Activities", - "UserTask", - "Conductor", - "Telnyx", - "Webhooks", - "Webhooks:Persistence:EntityFrameworkCore:Sqlite" - ], - "Persistence:MySql": { - "ConnectionStringName": "MySql" - }, - "Persistence:SqlServer": { - "ConnectionStringName": "SqlServer" - }, - "Persistence:Sqlite": { - "ConnectionStringName": "Sqlite" - }, - "Persistence:MongoDb": { - "ConnectionStringName": "MongoDb" - }, - "Persistence:PostgreSql": { - "ConnectionStringName": "PostgreSql" + "Features": { + "Persistence:EntityFrameworkCore:Sqlite": { + "Enabled": true, + "ConnectionStringName": "Sqlite" + }, + "Dispatcher:Hangfire": true, + "Console": true, + "Http": true, + "Email": true, + "Temporal:Quartz": true, + "JavaScript:Activities": true, + "UserTask": true, + "Conductor": true, + "Telnyx": true, + "Webhooks": true, + "Webhooks:Persistence:EntityFrameworkCore:Sqlite": { + "Enabled": true, + "ConnectionStringName": "Sqlite" + } }, "WorkflowChannels": { "Channels": [