diff --git a/Elsa.sln.DotSettings b/Elsa.sln.DotSettings index 53631d115..50be8157a 100644 --- a/Elsa.sln.DotSettings +++ b/Elsa.sln.DotSettings @@ -1,5 +1,6 @@  True + True True True True diff --git a/src/core/Elsa.Core/Options/ElsaOptionsConfigurator.cs b/src/core/Elsa.Core/Options/ElsaOptionsConfigurator.cs index 2fbb6b1d1..2355a9ef4 100644 --- a/src/core/Elsa.Core/Options/ElsaOptionsConfigurator.cs +++ b/src/core/Elsa.Core/Options/ElsaOptionsConfigurator.cs @@ -19,11 +19,13 @@ public class ElsaOptionsConfigurator public IServiceCollection Services { get; } - public T Configure(Action? configure = default) where T : class, IConfigurator, new() + public T Configure(Action? configure = default) where T : class, IConfigurator, new() => Configure(() => new T(), configure); + + public T Configure(Func factory, Action? configure = default) where T : class, IConfigurator { if (_configurators.FirstOrDefault(x => x is T) is not T configurator) { - configurator = new T(); + configurator = factory(); _configurators.Add(configurator); } diff --git a/src/core/Elsa.Persistence.Abstractions/Extensions/ServiceCollectionExtensions.cs b/src/core/Elsa.Persistence.Abstractions/Extensions/ServiceCollectionExtensions.cs index cb46809ab..81e43c07a 100644 --- a/src/core/Elsa.Persistence.Abstractions/Extensions/ServiceCollectionExtensions.cs +++ b/src/core/Elsa.Persistence.Abstractions/Extensions/ServiceCollectionExtensions.cs @@ -1,11 +1,13 @@ -using Microsoft.Extensions.DependencyInjection; +using Elsa.Options; +using Elsa.Persistence.Options; namespace Elsa.Persistence.Extensions; public static class ServiceCollectionExtensions { - public static IServiceCollection AddPersistenceServices(this IServiceCollection services) + public static ElsaOptionsConfigurator UsePersistence(this ElsaOptionsConfigurator configurator, Action? configure = default) { - return services; + configurator.Configure(() => new PersistenceOptions(configurator), configure); + return configurator; } } \ No newline at end of file diff --git a/src/core/Elsa.Persistence.Abstractions/Options/PersistenceOptions.cs b/src/core/Elsa.Persistence.Abstractions/Options/PersistenceOptions.cs index 988b574ab..3174c5e01 100644 --- a/src/core/Elsa.Persistence.Abstractions/Options/PersistenceOptions.cs +++ b/src/core/Elsa.Persistence.Abstractions/Options/PersistenceOptions.cs @@ -1,3 +1,4 @@ +using Elsa.Options; using Elsa.Persistence.Implementations; using Elsa.Persistence.Services; using Elsa.Services; @@ -7,6 +8,13 @@ namespace Elsa.Persistence.Options; public class PersistenceOptions : IConfigurator { + public ElsaOptionsConfigurator ElsaOptionsConfigurator { get; } + + public PersistenceOptions(ElsaOptionsConfigurator elsaOptionsConfigurator) + { + ElsaOptionsConfigurator = elsaOptionsConfigurator; + } + public Func WorkflowDefinitionStore { get; set; } = _ => new NullWorkflowDefinitionStore(); public Func WorkflowInstanceStore { get; set; } = _ => new NullWorkflowInstanceStore(); public Func WorkflowBookmarkStore { get; set; } = _ => new NullWorkflowBookmarkStore(); diff --git a/src/core/Elsa/Extensions/ServiceCollectionExtensions.cs b/src/core/Elsa/Extensions/ServiceCollectionExtensions.cs index 2566e6691..83640617f 100644 --- a/src/core/Elsa/Extensions/ServiceCollectionExtensions.cs +++ b/src/core/Elsa/Extensions/ServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using Elsa.Management.Extensions; using Elsa.Mediator.Extensions; using Elsa.Modules.Activities.Extensions; using Elsa.Options; +using Elsa.Persistence.Extensions; using Elsa.Persistence.InMemory.Extensions; using Elsa.Runtime.Extensions; using Microsoft.Extensions.DependencyInjection; @@ -18,8 +19,8 @@ public static class ServiceCollectionExtensions return services .AddElsaCore(elsa => { - elsa.UseInMemoryPersistence(); - elsa.AddActivityServices(); + elsa.UsePersistence(persistence => persistence.UseInMemoryProvider()); + elsa.UseActivityServices(); elsa.AddElsaRuntime(); elsa.AddElsaManagement(); configure?.Invoke(elsa); diff --git a/src/modules/Elsa.Modules.Activities/Extensions/ServiceCollectionExtensions.cs b/src/modules/Elsa.Modules.Activities/Extensions/ServiceCollectionExtensions.cs index e05bf890f..7cdca6151 100644 --- a/src/modules/Elsa.Modules.Activities/Extensions/ServiceCollectionExtensions.cs +++ b/src/modules/Elsa.Modules.Activities/Extensions/ServiceCollectionExtensions.cs @@ -8,7 +8,7 @@ public static class ServiceCollectionExtensions /// /// Registers required services for activities provided by this package. /// - public static ActivityOptions AddActivityServices(this ElsaOptionsConfigurator configurator) + public static ActivityOptions UseActivityServices(this ElsaOptionsConfigurator configurator) { return configurator.Configure(); } diff --git a/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore.Sqlite/DbContextOptionsBuilderExtensions.cs b/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore.Sqlite/DbContextOptionsBuilderExtensions.cs index 881118201..56275a7cc 100644 --- a/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore.Sqlite/DbContextOptionsBuilderExtensions.cs +++ b/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore.Sqlite/DbContextOptionsBuilderExtensions.cs @@ -1,11 +1,17 @@ -using Microsoft.EntityFrameworkCore; +using Elsa.Persistence.EntityFrameworkCore.Options; +using Microsoft.EntityFrameworkCore; namespace Elsa.Persistence.EntityFrameworkCore.Sqlite { public static class DbContextOptionsBuilderExtensions { - public static DbContextOptionsBuilder UseSqlite(this DbContextOptionsBuilder builder, string connectionString = "Data Source=elsa.sqlite.db;Cache=Shared;") => builder.UseSqlite(connectionString, db => db - .MigrationsAssembly(typeof(SqliteElsaContextFactory).Assembly.GetName().Name) - .MigrationsHistoryTable(ElsaDbContext.MigrationsHistoryTable, ElsaDbContext.ElsaSchema)); + public static EFCorePersistenceOptions UseSqlite(this EFCorePersistenceOptions builder, string connectionString = "Data Source=elsa.sqlite.db;Cache=Shared;") + { + builder.ConfigureDbContextOptions((_, x) => x.UseSqlite(connectionString, db => db + .MigrationsAssembly(typeof(SqliteElsaContextFactory).Assembly.GetName().Name) + .MigrationsHistoryTable(ElsaDbContext.MigrationsHistoryTable, ElsaDbContext.ElsaSchema))); + + return builder; + } } } \ No newline at end of file diff --git a/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore/Extensions/ServiceCollectionExtensions.cs b/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore/Extensions/ServiceCollectionExtensions.cs index fb14fe436..a06c1b749 100644 --- a/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore/Extensions/ServiceCollectionExtensions.cs +++ b/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore/Extensions/ServiceCollectionExtensions.cs @@ -1,57 +1,20 @@ -using Elsa.Persistence.Entities; -using Elsa.Persistence.EntityFrameworkCore.Handlers; using Elsa.Persistence.EntityFrameworkCore.HostedServices; -using Elsa.Persistence.EntityFrameworkCore.Implementations; -using Elsa.Persistence.EntityFrameworkCore.Services; -using Elsa.Persistence.Services; -using Microsoft.EntityFrameworkCore; +using Elsa.Persistence.EntityFrameworkCore.Options; +using Elsa.Persistence.Options; using Microsoft.Extensions.DependencyInjection; namespace Elsa.Persistence.EntityFrameworkCore.Extensions; public static class ServiceCollectionExtensions { - public static IServiceCollection AddEntityFrameworkCorePersistence( - this IServiceCollection services, - Action configure, - bool useContextPooling = true) + public static PersistenceOptions UseEntityFrameworkCoreProvider(this PersistenceOptions configurator, Action configure) { - services.AddElsaDbContextFactory(configure, useContextPooling); - - services - .AddSingleton, EFCoreStore>() - .AddSingleton, EFCoreStore>() - .AddSingleton, EFCoreStore>() - .AddSingleton, EFCoreStore>() - .AddSingleton, EFCoreStore>() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton, WorkflowDefinitionSerializer>() - .AddSingleton, WorkflowInstanceSerializer>() - .AddSingleton, WorkflowExecutionLogRecordSerializer>() - ; - - return services; + configurator.ElsaOptionsConfigurator.Configure(() => new EFCorePersistenceOptions(configurator), configure); + return configurator; } public static IServiceCollection AutoRunMigrations(this IServiceCollection services) { return services.AddHostedService(); } - - private static IServiceCollection AddElsaDbContextFactory(this IServiceCollection services, - Action configure, - bool useContextPooling, - ServiceLifetime serviceLifetime = ServiceLifetime.Singleton) - { - if (useContextPooling) - services.AddPooledDbContextFactory(configure); - else - services.AddDbContextFactory(configure, serviceLifetime); - - return services; - } } \ No newline at end of file diff --git a/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore/Options/EFCorePersistenceOptions.cs b/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore/Options/EFCorePersistenceOptions.cs new file mode 100644 index 000000000..a396c6759 --- /dev/null +++ b/src/persistence/efcore/Elsa.Persistence.EntityFrameworkCore/Options/EFCorePersistenceOptions.cs @@ -0,0 +1,67 @@ +using Elsa.Persistence.Entities; +using Elsa.Persistence.EntityFrameworkCore.Handlers; +using Elsa.Persistence.EntityFrameworkCore.Implementations; +using Elsa.Persistence.EntityFrameworkCore.Services; +using Elsa.Persistence.Options; +using Elsa.Services; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.Persistence.EntityFrameworkCore.Options; + +public class EFCorePersistenceOptions : IConfigurator +{ + public EFCorePersistenceOptions(PersistenceOptions persistenceOptions) + { + PersistenceOptions = persistenceOptions; + + persistenceOptions + .WithWorkflowDefinitionStore(sp => sp.GetRequiredService()) + .WithWorkflowInstanceStore(sp => sp.GetRequiredService()) + .WithWorkflowBookmarkStore(sp => sp.GetRequiredService()) + .WithWorkflowTriggerStore(sp => sp.GetRequiredService()) + .WithWorkflowExecutionLogStore(sp => sp.GetRequiredService()) + ; + } + + public PersistenceOptions PersistenceOptions { get; } + public bool ContextPoolingIsEnabled { get; set; } + public ServiceLifetime DbContextFactoryLifetime { get; set; } = ServiceLifetime.Singleton; + public Action DbContextOptionsBuilderAction = (_, _) => { }; + + public EFCorePersistenceOptions WithContextPooling(bool enabled = true) + { + ContextPoolingIsEnabled = enabled; + return this; + } + + public EFCorePersistenceOptions ConfigureDbContextOptions(Action configure) + { + DbContextOptionsBuilderAction = configure; + return this; + } + + public void ConfigureServices(IServiceCollection services) + { + if (ContextPoolingIsEnabled) + services.AddPooledDbContextFactory(DbContextOptionsBuilderAction); + else + services.AddDbContextFactory(DbContextOptionsBuilderAction, DbContextFactoryLifetime); + + services + .AddSingleton, EFCoreStore>() + .AddSingleton, EFCoreStore>() + .AddSingleton, EFCoreStore>() + .AddSingleton, EFCoreStore>() + .AddSingleton, EFCoreStore>() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton, WorkflowDefinitionSerializer>() + .AddSingleton, WorkflowInstanceSerializer>() + .AddSingleton, WorkflowExecutionLogRecordSerializer>() + ; + } +} \ No newline at end of file diff --git a/src/persistence/memory/Elsa.Persistence.InMemory/Extensions/ServiceCollectionExtensions.cs b/src/persistence/memory/Elsa.Persistence.InMemory/Extensions/ServiceCollectionExtensions.cs index 269a2f68d..92e2a99de 100644 --- a/src/persistence/memory/Elsa.Persistence.InMemory/Extensions/ServiceCollectionExtensions.cs +++ b/src/persistence/memory/Elsa.Persistence.InMemory/Extensions/ServiceCollectionExtensions.cs @@ -10,9 +10,9 @@ namespace Elsa.Persistence.InMemory.Extensions; public static class ServiceCollectionExtensions { - public static PersistenceOptions UseInMemoryPersistence(this ElsaOptionsConfigurator configurator) + public static PersistenceOptions UseInMemoryProvider(this PersistenceOptions configurator) { - var services = configurator.Services; + var services = configurator.ElsaOptionsConfigurator.Services; services .AddSingleton>() @@ -27,12 +27,12 @@ public static class ServiceCollectionExtensions .AddSingleton() ; - return configurator.Configure() + return configurator.ElsaOptionsConfigurator.Configure(() => new PersistenceOptions(configurator.ElsaOptionsConfigurator), o => o .WithWorkflowDefinitionStore(sp => sp.GetRequiredService()) .WithWorkflowInstanceStore(sp => sp.GetRequiredService()) .WithWorkflowBookmarkStore(sp => sp.GetRequiredService()) .WithWorkflowTriggerStore(sp => sp.GetRequiredService()) - .WithWorkflowExecutionLogStore(sp => sp.GetRequiredService()) + .WithWorkflowExecutionLogStore(sp => sp.GetRequiredService())) ; } } \ No newline at end of file diff --git a/src/samples/aspnet/Elsa.Samples.Web1/Program.cs b/src/samples/aspnet/Elsa.Samples.Web1/Program.cs index ba4783d0f..6b1c4f593 100644 --- a/src/samples/aspnet/Elsa.Samples.Web1/Program.cs +++ b/src/samples/aspnet/Elsa.Samples.Web1/Program.cs @@ -16,6 +16,7 @@ using Elsa.Modules.Scheduling.Extensions; using Elsa.Modules.WorkflowContexts.Extensions; using Elsa.Persistence.EntityFrameworkCore.Extensions; using Elsa.Persistence.EntityFrameworkCore.Sqlite; +using Elsa.Persistence.Extensions; using Elsa.Pipelines.WorkflowExecution.Components; using Elsa.Runtime.Extensions; using Elsa.Samples.Web1.Activities; @@ -40,9 +41,8 @@ var sqlServerConnectionString = configuration.GetConnectionString("SqlServer"); // Add services. services .AutoRunMigrations() - .AddElsa() + .AddElsa(elsa => elsa.UsePersistence(p => p.UseEntityFrameworkCoreProvider(ef => ef.UseSqlite()))) //.AddProtoActorWorkflowHost() - .AddEntityFrameworkCorePersistence((_, ef) => ef.UseSqlite()) .AddJobServices(new QuartzJobSchedulerProvider(), new HangfireJobQueueProvider()) .AddSchedulingServices() .AddHttpActivityServices() diff --git a/src/samples/console/Elsa.Samples.Console1/Program.cs b/src/samples/console/Elsa.Samples.Console1/Program.cs index 7db35e22c..50168570e 100644 --- a/src/samples/console/Elsa.Samples.Console1/Program.cs +++ b/src/samples/console/Elsa.Samples.Console1/Program.cs @@ -94,7 +94,8 @@ class Program var services = new ServiceCollection(); services - .AddElsa(elsa => elsa.Configure().WithStandardOutStreamProvider(sp => new CustomOutStreamProvider(Console.Out))) + .AddElsa(elsa => elsa.Configure() + .WithStandardOutStreamProvider(sp => new CustomOutStreamProvider(Console.Out))) .AddLogging(logging => logging.AddConsole().SetMinimumLevel(LogLevel.Warning)); return services.BuildServiceProvider();