diff --git a/src/Trax.Effect.Data.InMemory/Extensions/ServiceExtensions.cs b/src/Trax.Effect.Data.InMemory/Extensions/ServiceExtensions.cs index 1157905..eb82130 100644 --- a/src/Trax.Effect.Data.InMemory/Extensions/ServiceExtensions.cs +++ b/src/Trax.Effect.Data.InMemory/Extensions/ServiceExtensions.cs @@ -1,7 +1,7 @@ -using Trax.Effect.Configuration.TraxEffectBuilder; using Trax.Effect.Data.InMemory.Services.InMemoryContextFactory; using Trax.Effect.Data.Services.IDataContextFactory; using Trax.Effect.Extensions; +using TraxEffectBuilder = Trax.Effect.Configuration.TraxEffectBuilder.TraxEffectBuilder; namespace Trax.Effect.Data.InMemory.Extensions; @@ -43,16 +43,14 @@ public static class ServiceExtensions /// /// Example usage: /// ```csharp - /// services.AddTraxEffects(options => options.AddInMemoryEffect()); + /// services.AddTrax(trax => trax.AddEffects(effects => effects.UseInMemory())); /// ``` /// /// Note that data stored in the in-memory database is lost when the application stops, /// so this implementation is not suitable for production scenarios where data persistence /// is required. /// - public static TraxEffectConfigurationBuilder AddInMemoryEffect( - this TraxEffectConfigurationBuilder configurationBuilder - ) => + public static TraxEffectBuilder UseInMemory(this TraxEffectBuilder configurationBuilder) => configurationBuilder.AddEffect( toggleable: false ); diff --git a/src/Trax.Effect.Data.InMemory/Services/InMemoryContext/InMemoryContext.cs b/src/Trax.Effect.Data.InMemory/Services/InMemoryContext/InMemoryContext.cs index 3d187b1..ceac874 100644 --- a/src/Trax.Effect.Data.InMemory/Services/InMemoryContext/InMemoryContext.cs +++ b/src/Trax.Effect.Data.InMemory/Services/InMemoryContext/InMemoryContext.cs @@ -25,7 +25,7 @@ namespace Trax.Effect.Data.InMemory.Services.InMemoryContext; /// /// Example usage: /// ```csharp -/// services.AddTraxEffects(options => options.AddInMemoryEffect()); +/// services.AddTrax(trax => trax.AddEffects(effects => effects.UseInMemory())); /// ``` /// /// Note that data stored in the in-memory database is lost when the application stops, diff --git a/src/Trax.Effect.Data.InMemory/Services/InMemoryContextFactory/InMemoryContexFactory.cs b/src/Trax.Effect.Data.InMemory/Services/InMemoryContextFactory/InMemoryContexFactory.cs index 79b1e11..6852a90 100644 --- a/src/Trax.Effect.Data.InMemory/Services/InMemoryContextFactory/InMemoryContexFactory.cs +++ b/src/Trax.Effect.Data.InMemory/Services/InMemoryContextFactory/InMemoryContexFactory.cs @@ -29,7 +29,7 @@ namespace Trax.Effect.Data.InMemory.Services.InMemoryContextFactory; /// /// Example usage: /// ```csharp -/// services.AddTraxEffects(options => options.AddInMemoryEffect()); +/// services.AddTrax(trax => trax.AddEffects(effects => effects.UseInMemory())); /// ``` /// public class InMemoryContextProviderFactory : IDataContextProviderFactory diff --git a/src/Trax.Effect.Data.Postgres/Extensions/ServiceExtensions.cs b/src/Trax.Effect.Data.Postgres/Extensions/ServiceExtensions.cs index 21abbf2..3e7cd9d 100644 --- a/src/Trax.Effect.Data.Postgres/Extensions/ServiceExtensions.cs +++ b/src/Trax.Effect.Data.Postgres/Extensions/ServiceExtensions.cs @@ -15,6 +15,7 @@ using Trax.Effect.Enums; using Trax.Effect.Extensions; using Trax.Effect.Models; +using TraxEffectBuilder = Trax.Effect.Configuration.TraxEffectBuilder.TraxEffectBuilder; namespace Trax.Effect.Data.Postgres.Extensions; @@ -56,13 +57,13 @@ public static class ServiceExtensions /// /// Example usage: /// ```csharp - /// services.AddTraxEffects(options => - /// options.AddPostgresEffect("Host=localhost;Database=trax;Username=postgres;Password=password") + /// services.AddTrax(trax => trax + /// .AddEffects(effects => effects.UsePostgres("Host=localhost;Database=trax;Username=postgres;Password=password")) /// ); /// ``` /// - public static TraxEffectConfigurationBuilder AddPostgresEffect( - this TraxEffectConfigurationBuilder configurationBuilder, + public static TraxEffectBuilder UsePostgres( + this TraxEffectBuilder configurationBuilder, string connectionString ) { diff --git a/src/Trax.Effect.Data.Postgres/Services/PostgresContext/PostgresContext.cs b/src/Trax.Effect.Data.Postgres/Services/PostgresContext/PostgresContext.cs index f08c7e7..1556358 100644 --- a/src/Trax.Effect.Data.Postgres/Services/PostgresContext/PostgresContext.cs +++ b/src/Trax.Effect.Data.Postgres/Services/PostgresContext/PostgresContext.cs @@ -29,8 +29,8 @@ namespace Trax.Effect.Data.Postgres.Services.PostgresContext; /// /// Example usage: /// ```csharp -/// services.AddTraxEffects(options => -/// options.AddPostgresEffect("Host=localhost;Database=trax;Username=postgres;Password=password") +/// services.AddTrax(trax => trax +/// .AddEffects(effects => effects.UsePostgres("Host=localhost;Database=trax;Username=postgres;Password=password")) /// ); /// ``` /// diff --git a/src/Trax.Effect.Data.Postgres/Services/PostgresContextFactory/PostgresContextProviderFactory.cs b/src/Trax.Effect.Data.Postgres/Services/PostgresContextFactory/PostgresContextProviderFactory.cs index 4cf803f..5868c00 100644 --- a/src/Trax.Effect.Data.Postgres/Services/PostgresContextFactory/PostgresContextProviderFactory.cs +++ b/src/Trax.Effect.Data.Postgres/Services/PostgresContextFactory/PostgresContextProviderFactory.cs @@ -29,8 +29,8 @@ namespace Trax.Effect.Data.Postgres.Services.PostgresContextFactory; /// /// Example usage: /// ```csharp -/// services.AddTraxEffects(options => -/// options.AddPostgresEffect("Host=localhost;Database=trax;Username=postgres;Password=password") +/// services.AddTrax(trax => trax +/// .AddEffects(effects => effects.UsePostgres("Host=localhost;Database=trax;Username=postgres;Password=password")) /// ); /// ``` /// diff --git a/src/Trax.Effect.Data/Extensions/ServiceExtensions.cs b/src/Trax.Effect.Data/Extensions/ServiceExtensions.cs index 30a5626..56bcd19 100644 --- a/src/Trax.Effect.Data/Extensions/ServiceExtensions.cs +++ b/src/Trax.Effect.Data/Extensions/ServiceExtensions.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Trax.Effect.Configuration.TraxEffectBuilder; using Trax.Effect.Data.Services.DataContextLoggingProvider; +using TraxEffectBuilder = Trax.Effect.Configuration.TraxEffectBuilder.TraxEffectBuilder; namespace Trax.Effect.Data.Extensions; @@ -48,18 +48,19 @@ public static class ServiceExtensions /// /// Example usage: /// ```csharp - /// services.AddTraxEffects(options => - /// options - /// .AddPostgresEffect(connectionString) - /// .AddEffectDataContextLogging( + /// services.AddTrax(trax => trax + /// .AddEffects(effects => effects + /// .UsePostgres(connectionString) + /// .AddDataContextLogging( /// minimumLogLevel: LogLevel.Information, /// blacklist: ["Microsoft.EntityFrameworkCore.*"] /// ) + /// ) /// ); /// ``` /// - public static TraxEffectConfigurationBuilder AddEffectDataContextLogging( - this TraxEffectConfigurationBuilder configurationBuilder, + public static TraxEffectBuilder AddDataContextLogging( + this TraxEffectBuilder configurationBuilder, LogLevel? minimumLogLevel = null, List? blacklist = null ) @@ -67,7 +68,7 @@ public static TraxEffectConfigurationBuilder AddEffectDataContextLogging( // Verify that data context logging is enabled if (configurationBuilder.DataContextLoggingEffectEnabled == false) throw new Exception( - "Data Context Logging effect is not enabled in Trax.Core. Ensure a Data Effect has been added to TraxEffects (before calling AddEffectDataContextLogging). e.g. .AddTraxEffects(x => x.AddPostgresEffect(connectionString).AddDataContextEffectLogging())" + "Data Context Logging effect is not enabled in Trax.Core. Ensure a Data Effect has been added to TraxEffects (before calling AddDataContextLogging). e.g. .AddTrax(trax => trax.AddEffects(effects => effects.UsePostgres(connectionString).AddDataContextLogging()))" ); // Create and register the logging configuration diff --git a/src/Trax.Effect.Provider.Json/Extensions/ServiceExtensions.cs b/src/Trax.Effect.Provider.Json/Extensions/ServiceExtensions.cs index a316756..e267081 100644 --- a/src/Trax.Effect.Provider.Json/Extensions/ServiceExtensions.cs +++ b/src/Trax.Effect.Provider.Json/Extensions/ServiceExtensions.cs @@ -1,9 +1,9 @@ using Microsoft.Extensions.DependencyInjection; -using Trax.Effect.Configuration.TraxEffectBuilder; using Trax.Effect.Extensions; using Trax.Effect.Provider.Json.Services.JsonEffect; using Trax.Effect.Provider.Json.Services.JsonEffectFactory; using Trax.Effect.Services.EffectProviderFactory; +using TraxEffectBuilder = Trax.Effect.Configuration.TraxEffectBuilder.TraxEffectBuilder; namespace Trax.Effect.Provider.Json.Extensions; @@ -41,14 +41,12 @@ public static class ServiceExtensions /// /// Example usage: /// ```csharp - /// services.AddTraxEffects(options => - /// options.AddJsonEffect() + /// services.AddTrax(trax => trax + /// .AddEffects(effects => effects.AddJson()) /// ); /// ``` /// - public static TraxEffectConfigurationBuilder AddJsonEffect( - this TraxEffectConfigurationBuilder configurationBuilder - ) + public static TraxEffectBuilder AddJson(this TraxEffectBuilder configurationBuilder) { configurationBuilder.ServiceCollection.AddTransient< IJsonEffectProvider, diff --git a/src/Trax.Effect.Provider.Parameter/Extensions/ServiceExtensions.cs b/src/Trax.Effect.Provider.Parameter/Extensions/ServiceExtensions.cs index 7d3aa2d..a86cc7c 100644 --- a/src/Trax.Effect.Provider.Parameter/Extensions/ServiceExtensions.cs +++ b/src/Trax.Effect.Provider.Parameter/Extensions/ServiceExtensions.cs @@ -1,11 +1,11 @@ using System.Text.Json; using Microsoft.Extensions.DependencyInjection; -using Trax.Effect.Configuration.TraxEffectBuilder; using Trax.Effect.Extensions; using Trax.Effect.Provider.Parameter.Configuration; using Trax.Effect.Provider.Parameter.Services.ParameterEffectProviderFactory; using Trax.Effect.Services.EffectProviderFactory; using Trax.Effect.Utils; +using TraxEffectBuilder = Trax.Effect.Configuration.TraxEffectBuilder.TraxEffectBuilder; namespace Trax.Effect.Provider.Parameter.Extensions; @@ -45,8 +45,8 @@ public static class ServiceExtensions /// /// Example usage: /// ```csharp - /// services.AddTraxEffects(options => - /// options.SaveTrainParameters() + /// services.AddTrax(trax => trax + /// .AddEffects(effects => effects.SaveTrainParameters()) /// ); /// ``` /// @@ -58,24 +58,24 @@ public static class ServiceExtensions /// WriteIndented = true /// }; /// - /// services.AddTraxEffects(options => - /// options.SaveTrainParameters(jsonOptions) + /// services.AddTrax(trax => trax + /// .AddEffects(effects => effects.SaveTrainParameters(jsonOptions)) /// ); /// ``` /// /// Or with parameter configuration to control which parameters are saved: /// ```csharp - /// services.AddTraxEffects(options => - /// options.SaveTrainParameters(configure: cfg => + /// services.AddTrax(trax => trax + /// .AddEffects(effects => effects.SaveTrainParameters(configure: cfg => /// { /// cfg.SaveInputs = true; /// cfg.SaveOutputs = false; - /// }) + /// })) /// ); /// ``` /// - public static TraxEffectConfigurationBuilder SaveTrainParameters( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder SaveTrainParameters( + this TraxEffectBuilder builder, JsonSerializerOptions? jsonSerializerOptions = null, Action? configure = null ) diff --git a/src/Trax.Effect.StepProvider.Logging/Extensions/ServiceExtensions.cs b/src/Trax.Effect.StepProvider.Logging/Extensions/ServiceExtensions.cs index e3a259a..5081bd4 100644 --- a/src/Trax.Effect.StepProvider.Logging/Extensions/ServiceExtensions.cs +++ b/src/Trax.Effect.StepProvider.Logging/Extensions/ServiceExtensions.cs @@ -1,15 +1,15 @@ using Microsoft.Extensions.DependencyInjection; -using Trax.Effect.Configuration.TraxEffectBuilder; using Trax.Effect.Extensions; using Trax.Effect.StepProvider.Logging.Services.StepLoggerFactory; using Trax.Effect.StepProvider.Logging.Services.StepLoggerProvider; +using TraxEffectBuilder = Trax.Effect.Configuration.TraxEffectBuilder.TraxEffectBuilder; namespace Trax.Effect.StepProvider.Logging.Extensions; public static class ServiceExtensions { - public static TraxEffectConfigurationBuilder AddStepLogger( - this TraxEffectConfigurationBuilder configurationBuilder, + public static TraxEffectBuilder AddStepLogger( + this TraxEffectBuilder configurationBuilder, bool serializeStepData = false ) { diff --git a/src/Trax.Effect.StepProvider.Progress/Extensions/ServiceExtensions.cs b/src/Trax.Effect.StepProvider.Progress/Extensions/ServiceExtensions.cs index f75bb25..df1c212 100644 --- a/src/Trax.Effect.StepProvider.Progress/Extensions/ServiceExtensions.cs +++ b/src/Trax.Effect.StepProvider.Progress/Extensions/ServiceExtensions.cs @@ -1,18 +1,16 @@ using Microsoft.Extensions.DependencyInjection; -using Trax.Effect.Configuration.TraxEffectBuilder; using Trax.Effect.Extensions; using Trax.Effect.StepProvider.Progress.Services.CancellationCheckFactory; using Trax.Effect.StepProvider.Progress.Services.CancellationCheckProvider; using Trax.Effect.StepProvider.Progress.Services.StepProgressFactory; using Trax.Effect.StepProvider.Progress.Services.StepProgressProvider; +using TraxEffectBuilder = Trax.Effect.Configuration.TraxEffectBuilder.TraxEffectBuilder; namespace Trax.Effect.StepProvider.Progress.Extensions; public static class ServiceExtensions { - public static TraxEffectConfigurationBuilder AddStepProgress( - this TraxEffectConfigurationBuilder configurationBuilder - ) + public static TraxEffectBuilder AddStepProgress(this TraxEffectBuilder configurationBuilder) { configurationBuilder.ServiceCollection.AddTransient< ICancellationCheckProvider, diff --git a/src/Trax.Effect/Configuration/TraxBuilder/TraxBuilder.cs b/src/Trax.Effect/Configuration/TraxBuilder/TraxBuilder.cs new file mode 100644 index 0000000..cd76564 --- /dev/null +++ b/src/Trax.Effect/Configuration/TraxBuilder/TraxBuilder.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.DependencyInjection; +using Trax.Effect.Configuration.TraxEffectConfiguration; +using Trax.Effect.Services.EffectRegistry; + +namespace Trax.Effect.Configuration.TraxBuilder; + +/// +/// Root builder for configuring the Trax system. +/// +/// +/// Each subsystem (effects, mediator, scheduler) has its own scoped builder, +/// accessible via extension methods on this type: +/// +/// services.AddTrax(trax => trax +/// .AddEffects(effects => effects +/// .UsePostgres(connectionString) +/// .AddJson() +/// .SaveTrainParameters() +/// ) +/// .AddMediator(typeof(Program).Assembly) +/// .AddScheduler(scheduler => scheduler +/// .UseLocalWorkers() +/// .Schedule<IMyTrain>(...) +/// ) +/// ); +/// +/// +public class TraxBuilder(IServiceCollection services, IEffectRegistry registry) +{ + /// + /// Gets the service collection for registering services. + /// + public IServiceCollection ServiceCollection => services; + + /// + /// Gets the effect registry for registering effect providers. + /// + internal IEffectRegistry EffectRegistry => registry; + + /// + /// Gets or sets the effect configuration, populated by AddEffects(). + /// + internal TraxEffectConfiguration.TraxEffectConfiguration? EffectConfiguration { get; set; } +} diff --git a/src/Trax.Effect/Configuration/TraxBuilder/TraxBuilderWithEffects.cs b/src/Trax.Effect/Configuration/TraxBuilder/TraxBuilderWithEffects.cs new file mode 100644 index 0000000..e3eba54 --- /dev/null +++ b/src/Trax.Effect/Configuration/TraxBuilder/TraxBuilderWithEffects.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Trax.Effect.Configuration.TraxBuilder; + +/// +/// Builder state after AddEffects() has been called. +/// Extension methods for AddMediator() target this type, +/// enforcing that effects are configured before the mediator. +/// +public class TraxBuilderWithEffects +{ + /// + /// The root builder that holds accumulated configuration state. + /// + public TraxBuilder Root { get; } + + public TraxBuilderWithEffects(TraxBuilder root) + { + Root = root; + } + + /// + /// Gets the service collection for registering services. + /// + public IServiceCollection ServiceCollection => Root.ServiceCollection; +} diff --git a/src/Trax.Effect/Configuration/TraxBuilder/TraxMarker.cs b/src/Trax.Effect/Configuration/TraxBuilder/TraxMarker.cs new file mode 100644 index 0000000..da0c9f6 --- /dev/null +++ b/src/Trax.Effect/Configuration/TraxBuilder/TraxMarker.cs @@ -0,0 +1,7 @@ +namespace Trax.Effect.Configuration.TraxBuilder; + +/// +/// Marker service registered by AddTrax(). Used by AddTraxDashboard() +/// and AddTraxGraphQL() to verify that AddTrax() was called first. +/// +public sealed class TraxMarker; diff --git a/src/Trax.Effect/Configuration/TraxEffectBuilder/TraxEffectConfigurationBuilder.cs b/src/Trax.Effect/Configuration/TraxEffectBuilder/TraxEffectBuilder.cs similarity index 68% rename from src/Trax.Effect/Configuration/TraxEffectBuilder/TraxEffectConfigurationBuilder.cs rename to src/Trax.Effect/Configuration/TraxEffectBuilder/TraxEffectBuilder.cs index df168b6..a50ecc0 100644 --- a/src/Trax.Effect/Configuration/TraxEffectBuilder/TraxEffectConfigurationBuilder.cs +++ b/src/Trax.Effect/Configuration/TraxEffectBuilder/TraxEffectBuilder.cs @@ -2,19 +2,27 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; +using Trax.Effect.Configuration.TraxBuilder; using Trax.Effect.Services.EffectRegistry; using Trax.Effect.Utils; namespace Trax.Effect.Configuration.TraxEffectBuilder; -public class TraxEffectConfigurationBuilder( - IServiceCollection serviceCollection, - IEffectRegistry? effectRegistry = null -) +/// +/// Builder for configuring the Trax effect system (data providers, step providers, lifecycle hooks). +/// +public class TraxEffectBuilder { - public IServiceCollection ServiceCollection => serviceCollection; + private readonly TraxBuilder.TraxBuilder _parent; - public IEffectRegistry? EffectRegistry => effectRegistry; + internal TraxEffectBuilder(TraxBuilder.TraxBuilder parent) + { + _parent = parent; + } + + public IServiceCollection ServiceCollection => _parent.ServiceCollection; + + public IEffectRegistry? EffectRegistry => _parent.EffectRegistry; public bool DataContextLoggingEffectEnabled { get; set; } = false; @@ -28,7 +36,7 @@ public class TraxEffectConfigurationBuilder( public JsonSerializerSettings NewtonsoftJsonSerializerSettings { get; set; } = TraxJsonSerializationOptions.NewtonsoftDefault; - protected internal TraxEffectConfiguration.TraxEffectConfiguration Build() + internal TraxEffectConfiguration.TraxEffectConfiguration Build() { var configuration = new TraxEffectConfiguration.TraxEffectConfiguration { diff --git a/src/Trax.Effect/Extensions/FunctionalExtensions.cs b/src/Trax.Effect/Extensions/FunctionalExtensions.cs index d9baac3..d7bf2d2 100644 --- a/src/Trax.Effect/Extensions/FunctionalExtensions.cs +++ b/src/Trax.Effect/Extensions/FunctionalExtensions.cs @@ -21,7 +21,7 @@ value is EffectRunner || value is IStepEffectRunner ) throw new InvalidOperationException( - $"{valueExpr} has not been loaded. Ensure services.AddTraxEffects() is being added to your Dependency Injection Container" + $"{valueExpr} has not been loaded. Ensure services.AddTrax() is being added to your Dependency Injection Container" ); if (value is IServiceProvider) diff --git a/src/Trax.Effect/Extensions/ServiceExtensions.cs b/src/Trax.Effect/Extensions/ServiceExtensions.cs index 3c038f9..8cac866 100644 --- a/src/Trax.Effect/Extensions/ServiceExtensions.cs +++ b/src/Trax.Effect/Extensions/ServiceExtensions.cs @@ -1,6 +1,7 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Trax.Effect.Attributes; +using Trax.Effect.Configuration.TraxBuilder; using Trax.Effect.Configuration.TraxEffectBuilder; using Trax.Effect.Configuration.TraxEffectConfiguration; using Trax.Effect.Services.EffectProviderFactory; @@ -17,37 +18,66 @@ public static class ServiceExtensions { #region Configuration - public static IServiceCollection AddTraxEffects( - this IServiceCollection serviceCollection, - Action? options = null + /// + /// Registers the Trax system with the dependency injection container. + /// + /// + /// This is the root entry point for all Trax configuration. Each subsystem + /// (effects, mediator, scheduler) has its own scoped builder: + /// + /// services.AddTrax(trax => trax + /// .AddEffects(effects => effects + /// .UsePostgres(connectionString) + /// .AddJson() + /// .SaveTrainParameters() + /// ) + /// .AddMediator(typeof(Program).Assembly) + /// .AddScheduler(scheduler => scheduler + /// .UseLocalWorkers() + /// .Schedule<IMyTrain>(...) + /// ) + /// ); + /// + /// + public static IServiceCollection AddTrax( + this IServiceCollection services, + Action configure ) { - // Create the registry eagerly so AddEffect calls during configuration can register types var registry = new EffectRegistry(); + var builder = new TraxBuilder(services, registry); + + configure(builder); - var configuration = BuildConfiguration(serviceCollection, options, registry); + // Use effect configuration from AddEffects(), or defaults if not called + var effectConfig = + builder.EffectConfiguration + ?? new Trax.Effect.Configuration.TraxEffectConfiguration.TraxEffectConfiguration(); - return serviceCollection + // Marker so AddTraxDashboard() / AddTraxGraphQL() can verify AddTrax() was called + services.AddSingleton(); + + return services .AddSingleton(registry) - .AddSingleton(configuration) + .AddSingleton(effectConfig) .AddTransient() .AddTransient() .AddTransient(); } - private static TraxEffectConfiguration BuildConfiguration( - IServiceCollection serviceCollection, - Action? options, - IEffectRegistry registry + /// + /// Configures the Trax effect system (data providers, step providers, lifecycle hooks). + /// + /// A that enables chaining AddMediator(). + public static TraxBuilderWithEffects AddEffects( + this TraxBuilder builder, + Action configure ) { - // Create Builder to be used after Options are invoked - var builder = new TraxEffectConfigurationBuilder(serviceCollection, registry); - - // Options able to be null since all values have defaults - options?.Invoke(builder); - - return builder.Build(); + var effectBuilder = new TraxEffectBuilder(builder); + configure(effectBuilder); + builder.EffectConfiguration = effectBuilder.Build(); + return new TraxBuilderWithEffects(builder); } public static void InjectProperties(this IServiceProvider serviceProvider, object instance) @@ -91,11 +121,8 @@ public static void InjectProperties(this IServiceProvider serviceProvider, objec #region Effect - public static TraxEffectConfigurationBuilder AddEffect< - TIEffectProviderFactory, - TEffectProviderFactory - >( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder AddEffect( + this TraxEffectBuilder builder, TEffectProviderFactory factory, bool toggleable = true ) @@ -116,8 +143,8 @@ public static TraxEffectConfigurationBuilder AddEffect< return builder; } - public static TraxEffectConfigurationBuilder AddEffect( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder AddEffect( + this TraxEffectBuilder builder, bool toggleable = true ) where TEffectProviderFactory : class, IEffectProviderFactory @@ -133,10 +160,10 @@ public static TraxEffectConfigurationBuilder AddEffect( return builder; } - public static TraxEffectConfigurationBuilder AddEffect< - TIEffectProviderFactory, - TEffectProviderFactory - >(this TraxEffectConfigurationBuilder builder, bool toggleable = true) + public static TraxEffectBuilder AddEffect( + this TraxEffectBuilder builder, + bool toggleable = true + ) where TIEffectProviderFactory : class, IEffectProviderFactory where TEffectProviderFactory : class, TIEffectProviderFactory { @@ -154,8 +181,8 @@ public static TraxEffectConfigurationBuilder AddEffect< return builder; } - public static TraxEffectConfigurationBuilder AddEffect( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder AddEffect( + this TraxEffectBuilder builder, TEffectProviderFactory factory, bool toggleable = true ) @@ -172,14 +199,10 @@ public static TraxEffectConfigurationBuilder AddEffect( #region StepEffect - public static TraxEffectConfigurationBuilder AddStepEffect< + public static TraxEffectBuilder AddStepEffect< TIStepEffectProviderFactory, TStepEffectProviderFactory - >( - this TraxEffectConfigurationBuilder builder, - TStepEffectProviderFactory factory, - bool toggleable = true - ) + >(this TraxEffectBuilder builder, TStepEffectProviderFactory factory, bool toggleable = true) where TIStepEffectProviderFactory : class, IStepEffectProviderFactory where TStepEffectProviderFactory : class, TIStepEffectProviderFactory { @@ -200,8 +223,8 @@ public static TraxEffectConfigurationBuilder AddStepEffect< return builder; } - public static TraxEffectConfigurationBuilder AddStepEffect( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder AddStepEffect( + this TraxEffectBuilder builder, bool toggleable = true ) where TStepEffectProviderFactory : class, IStepEffectProviderFactory @@ -220,8 +243,8 @@ public static TraxEffectConfigurationBuilder AddStepEffect( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder AddStepEffect( + this TraxEffectBuilder builder, TStepEffectProviderFactory factory, bool toggleable = true ) @@ -241,11 +264,8 @@ public static TraxEffectConfigurationBuilder AddStepEffect( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder AddLifecycleHook( + this TraxEffectBuilder builder, TLifecycleHookFactory factory, bool toggleable = true ) @@ -266,8 +286,8 @@ public static TraxEffectConfigurationBuilder AddLifecycleHook< return builder; } - public static TraxEffectConfigurationBuilder AddLifecycleHook( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder AddLifecycleHook( + this TraxEffectBuilder builder, bool toggleable = true ) where TLifecycleHookFactory : class, ITrainLifecycleHookFactory @@ -283,8 +303,8 @@ public static TraxEffectConfigurationBuilder AddLifecycleHook( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder AddLifecycleHook( + this TraxEffectBuilder builder, TLifecycleHookFactory factory, bool toggleable = true ) @@ -305,55 +325,40 @@ public static IServiceCollection AddScopedTraxStep( this IServiceCollection services ) where TService : class - where TImplementation : class, TService - // Nothing inherently different about the injection. Overload for posterity. - => + where TImplementation : class, TService => services.AddScopedTraxRoute(); public static IServiceCollection AddScopedTraxStep( this IServiceCollection services, Type serviceInterface, Type serviceImplementation - ) - // Nothing inherently different about the injection. Overload for posterity. - => - services.AddScopedTraxRoute(serviceInterface, serviceImplementation); + ) => services.AddScopedTraxRoute(serviceInterface, serviceImplementation); public static IServiceCollection AddTransientTraxStep( this IServiceCollection services ) where TService : class - where TImplementation : class, TService - // Nothing inherently different about the injection. Overload for posterity. - => + where TImplementation : class, TService => services.AddTransientTraxRoute(); public static IServiceCollection AddTransientTraxStep( this IServiceCollection services, Type serviceInterface, Type serviceImplementation - ) - // Nothing inherently different about the injection. Overload for posterity. - => - services.AddTransientTraxRoute(serviceInterface, serviceImplementation); + ) => services.AddTransientTraxRoute(serviceInterface, serviceImplementation); public static IServiceCollection AddSingletonTraxStep( this IServiceCollection services ) where TService : class - where TImplementation : class, TService - // Nothing inherently different about the injection. Overload for posterity. - => + where TImplementation : class, TService => services.AddSingletonTraxRoute(); public static IServiceCollection AddSingletonTraxStep( this IServiceCollection services, Type serviceInterface, Type serviceImplementation - ) - // Nothing inherently different about the injection. Overload for posterity. - => - services.AddSingletonTraxRoute(serviceInterface, serviceImplementation); + ) => services.AddSingletonTraxRoute(serviceInterface, serviceImplementation); #endregion diff --git a/src/Trax.Effect/Extensions/TraxEffectConfigurationBuilderExtensions.cs b/src/Trax.Effect/Extensions/TraxEffectConfigurationBuilderExtensions.cs index 896a085..87b1900 100644 --- a/src/Trax.Effect/Extensions/TraxEffectConfigurationBuilderExtensions.cs +++ b/src/Trax.Effect/Extensions/TraxEffectConfigurationBuilderExtensions.cs @@ -3,10 +3,10 @@ namespace Trax.Effect.Extensions; -public static class TraxEffectConfigurationBuilderExtensions +public static class TraxEffectBuilderExtensions { - public static TraxEffectConfigurationBuilder SetEffectLogLevel( - this TraxEffectConfigurationBuilder builder, + public static TraxEffectBuilder SetEffectLogLevel( + this TraxEffectBuilder builder, LogLevel logLevel ) { diff --git a/tests/Trax.Effect.Tests.Benchmarks/Benchmarks/ScalingBenchmarks.cs b/tests/Trax.Effect.Tests.Benchmarks/Benchmarks/ScalingBenchmarks.cs index 18ad300..592497a 100644 --- a/tests/Trax.Effect.Tests.Benchmarks/Benchmarks/ScalingBenchmarks.cs +++ b/tests/Trax.Effect.Tests.Benchmarks/Benchmarks/ScalingBenchmarks.cs @@ -23,7 +23,7 @@ public class ScalingBenchmarks public void Setup() { var services = new ServiceCollection(); - services.AddTraxEffects(); + services.AddTrax(trax => trax.AddEffects(_ => { })); services.AddScopedTraxRoute(); services.AddScopedTraxRoute(); services.AddScopedTraxRoute(); diff --git a/tests/Trax.Effect.Tests.Benchmarks/Benchmarks/TrainOverheadBenchmarks.cs b/tests/Trax.Effect.Tests.Benchmarks/Benchmarks/TrainOverheadBenchmarks.cs index 8daa144..480c4b3 100644 --- a/tests/Trax.Effect.Tests.Benchmarks/Benchmarks/TrainOverheadBenchmarks.cs +++ b/tests/Trax.Effect.Tests.Benchmarks/Benchmarks/TrainOverheadBenchmarks.cs @@ -26,7 +26,7 @@ public void Setup() { // EffectTrain with no effect providers var noEffectsServices = new ServiceCollection(); - noEffectsServices.AddTraxEffects(); + noEffectsServices.AddTrax(trax => trax.AddEffects(_ => { })); noEffectsServices.AddScopedTraxRoute(); noEffectsServices.AddScopedTraxRoute(); noEffectsServices.AddScopedTraxRoute(); @@ -35,7 +35,7 @@ public void Setup() // EffectTrain with InMemory effect var inMemoryServices = new ServiceCollection(); - inMemoryServices.AddTraxEffects(options => options.AddInMemoryEffect()); + inMemoryServices.AddTrax(trax => trax.AddEffects(effects => effects.UseInMemory())); inMemoryServices.AddScopedTraxRoute(); inMemoryServices.AddScopedTraxRoute(); inMemoryServices.AddScopedTraxRoute(); diff --git a/tests/Trax.Effect.Tests.Data.InMemory.Integration/TestSetup.cs b/tests/Trax.Effect.Tests.Data.InMemory.Integration/TestSetup.cs index 0d6c53e..27f56ee 100644 --- a/tests/Trax.Effect.Tests.Data.InMemory.Integration/TestSetup.cs +++ b/tests/Trax.Effect.Tests.Data.InMemory.Integration/TestSetup.cs @@ -18,10 +18,12 @@ public async Task RunBeforeAnyTests() { ServiceCollection = new ServiceCollection(); - ServiceCollection.AddTraxEffects(options => - options - .SetEffectLogLevel(logLevel: Microsoft.Extensions.Logging.LogLevel.Debug) - .AddInMemoryEffect() + ServiceCollection.AddTrax(trax => + trax.AddEffects(effects => + effects + .SetEffectLogLevel(logLevel: Microsoft.Extensions.Logging.LogLevel.Debug) + .UseInMemory() + ) ); ServiceProvider = ConfigureServices(ServiceCollection); diff --git a/tests/Trax.Effect.Tests.Integration/UnitTests/Configuration/TraxEffectConfigurationBuilderTests.cs b/tests/Trax.Effect.Tests.Integration/UnitTests/Configuration/TraxEffectConfigurationBuilderTests.cs index f7cf99a..27ad4ae 100644 --- a/tests/Trax.Effect.Tests.Integration/UnitTests/Configuration/TraxEffectConfigurationBuilderTests.cs +++ b/tests/Trax.Effect.Tests.Integration/UnitTests/Configuration/TraxEffectConfigurationBuilderTests.cs @@ -1,71 +1,61 @@ using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Trax.Effect.Configuration.TraxEffectBuilder; +using Trax.Effect.Configuration.TraxEffectConfiguration; +using Trax.Effect.Extensions; +using Trax.Effect.Services.EffectRegistry; namespace Trax.Effect.Tests.Integration.UnitTests.Configuration; [TestFixture] -public class TraxEffectConfigurationBuilderTests +public class TraxEffectBuilderTests { [Test] - public void Constructor_DefaultValues_AreCorrect() - { - // Arrange & Act - var builder = new TraxEffectConfigurationBuilder(new ServiceCollection()); - - // Assert - builder.DataContextLoggingEffectEnabled.Should().BeFalse(); - builder.SerializeStepData.Should().BeFalse(); - builder.LogLevel.Should().Be(LogLevel.Debug); - } - - [Test] - public void ServiceCollection_ExposedFromConstructor() + public void AddTrax_WithDefaults_RegistersEffectConfiguration() { // Arrange var services = new ServiceCollection(); // Act - var builder = new TraxEffectConfigurationBuilder(services); + services.AddTrax(_ => { }); // Assert - builder.ServiceCollection.Should().BeSameAs(services); + var provider = services.BuildServiceProvider(); + var config = provider.GetRequiredService(); + config.Should().NotBeNull(); + config.LogLevel.Should().Be(LogLevel.Debug); + config.SerializeStepData.Should().BeFalse(); } [Test] - public void SetEffectLogLevel_UpdatesLogLevel() + public void AddTrax_WithEffects_RegistersEffectConfiguration() { // Arrange - var builder = new TraxEffectConfigurationBuilder(new ServiceCollection()); + var services = new ServiceCollection(); // Act - builder.LogLevel = LogLevel.Trace; + services.AddTrax(trax => + trax.AddEffects(effects => effects.SetEffectLogLevel(LogLevel.Trace)) + ); // Assert - builder.LogLevel.Should().Be(LogLevel.Trace); + var provider = services.BuildServiceProvider(); + var config = provider.GetRequiredService(); + config.LogLevel.Should().Be(LogLevel.Trace); } [Test] - public void SerializeStepData_SetTrue_IsReflected() + public void AddTrax_RegistersEffectRegistry() { // Arrange - var builder = new TraxEffectConfigurationBuilder(new ServiceCollection()); + var services = new ServiceCollection(); // Act - builder.SerializeStepData = true; - - // Assert - builder.SerializeStepData.Should().BeTrue(); - } - - [Test] - public void TrainParameterJsonSerializerOptions_DefaultIsNotNull() - { - // Arrange & Act - var builder = new TraxEffectConfigurationBuilder(new ServiceCollection()); + services.AddTrax(_ => { }); // Assert - builder.TrainParameterJsonSerializerOptions.Should().NotBeNull(); + var provider = services.BuildServiceProvider(); + var registry = provider.GetRequiredService(); + registry.Should().NotBeNull(); } } diff --git a/tests/Trax.Effect.Tests.Integration/UnitTests/Extensions/ServiceExtensionsRegistryTests.cs b/tests/Trax.Effect.Tests.Integration/UnitTests/Extensions/ServiceExtensionsRegistryTests.cs index 166a3be..58f08e9 100644 --- a/tests/Trax.Effect.Tests.Integration/UnitTests/Extensions/ServiceExtensionsRegistryTests.cs +++ b/tests/Trax.Effect.Tests.Integration/UnitTests/Extensions/ServiceExtensionsRegistryTests.cs @@ -13,13 +13,13 @@ namespace Trax.Effect.Tests.Integration.UnitTests.Extensions; public class ServiceExtensionsRegistryTests { [Test] - public void AddTraxEffects_RegistersIEffectRegistryAsSingleton() + public void AddTrax_RegistersIEffectRegistryAsSingleton() { // Arrange var services = new ServiceCollection(); // Act - services.AddTraxEffects(); + services.AddTrax(trax => trax.AddEffects(_ => { })); using var provider = services.BuildServiceProvider(); // Assert @@ -38,8 +38,8 @@ public void AddEffect_DefaultToggleable_RegistersInRegistry() var services = new ServiceCollection(); services.AddLogging(); - // Act - AddJsonEffect calls AddEffect() with default toggleable=true - services.AddTraxEffects(options => options.AddJsonEffect()); + // Act - AddJson calls AddEffect() with default toggleable=true + services.AddTrax(trax => trax.AddEffects(effects => effects.AddJson())); using var provider = services.BuildServiceProvider(); // Assert @@ -58,7 +58,7 @@ public void AddStepEffect_DefaultToggleable_RegistersInRegistry() services.AddLogging(); // Act - AddStepLogger calls AddStepEffect() with default toggleable=true - services.AddTraxEffects(options => options.AddStepLogger()); + services.AddTrax(trax => trax.AddEffects(effects => effects.AddStepLogger())); using var provider = services.BuildServiceProvider(); // Assert @@ -70,13 +70,13 @@ public void AddStepEffect_DefaultToggleable_RegistersInRegistry() } [Test] - public void AddTraxEffects_NoEffects_RegistryIsEmpty() + public void AddTrax_NoEffects_RegistryIsEmpty() { // Arrange var services = new ServiceCollection(); // Act - services.AddTraxEffects(); + services.AddTrax(trax => trax.AddEffects(_ => { })); using var provider = services.BuildServiceProvider(); // Assert @@ -92,7 +92,7 @@ public void AddEffect_Toggleable_AppearsInGetToggleable() services.AddLogging(); // Act - services.AddTraxEffects(options => options.AddJsonEffect()); + services.AddTrax(trax => trax.AddEffects(effects => effects.AddJson())); using var provider = services.BuildServiceProvider(); // Assert @@ -103,14 +103,14 @@ public void AddEffect_Toggleable_AppearsInGetToggleable() } [Test] - public void AddTraxEffects_MultipleEffects_AllRegistered() + public void AddTrax_MultipleEffects_AllRegistered() { // Arrange var services = new ServiceCollection(); services.AddLogging(); // Act - services.AddTraxEffects(options => options.AddJsonEffect().AddStepLogger()); + services.AddTrax(trax => trax.AddEffects(effects => effects.AddJson().AddStepLogger())); using var provider = services.BuildServiceProvider(); // Assert diff --git a/tests/Trax.Effect.Tests.Integration/UnitTests/Services/AddLifecycleHookTests.cs b/tests/Trax.Effect.Tests.Integration/UnitTests/Services/AddLifecycleHookTests.cs index 2c7776a..29a8acf 100644 --- a/tests/Trax.Effect.Tests.Integration/UnitTests/Services/AddLifecycleHookTests.cs +++ b/tests/Trax.Effect.Tests.Integration/UnitTests/Services/AddLifecycleHookTests.cs @@ -18,7 +18,9 @@ public void AddLifecycleHook_TypeOnly_RegistersFactoryAsSingleton() { var services = new ServiceCollection(); services.AddLogging(); - services.AddTraxEffects(options => options.AddLifecycleHook()); + services.AddTrax(trax => + trax.AddEffects(effects => effects.AddLifecycleHook()) + ); using var provider = services.BuildServiceProvider(); var factories = provider.GetServices().ToList(); @@ -31,7 +33,9 @@ public void AddLifecycleHook_TypeOnly_FactoryResolvableByConcreteType() { var services = new ServiceCollection(); services.AddLogging(); - services.AddTraxEffects(options => options.AddLifecycleHook()); + services.AddTrax(trax => + trax.AddEffects(effects => effects.AddLifecycleHook()) + ); using var provider = services.BuildServiceProvider(); var factory = provider.GetService(); @@ -44,7 +48,9 @@ public void AddLifecycleHook_TypeOnly_RegistersInEffectRegistry() { var services = new ServiceCollection(); services.AddLogging(); - services.AddTraxEffects(options => options.AddLifecycleHook()); + services.AddTrax(trax => + trax.AddEffects(effects => effects.AddLifecycleHook()) + ); using var provider = services.BuildServiceProvider(); var registry = provider.GetRequiredService(); @@ -58,8 +64,8 @@ public void AddLifecycleHook_NonToggleable_RegisteredAsNonToggleable() { var services = new ServiceCollection(); services.AddLogging(); - services.AddTraxEffects(options => - options.AddLifecycleHook(toggleable: false) + services.AddTrax(trax => + trax.AddEffects(effects => effects.AddLifecycleHook(toggleable: false)) ); using var provider = services.BuildServiceProvider(); @@ -78,7 +84,7 @@ public void AddLifecycleHook_Instance_RegistersProvidedFactory() var instance = new StubHookFactory(); var services = new ServiceCollection(); services.AddLogging(); - services.AddTraxEffects(options => options.AddLifecycleHook(instance)); + services.AddTrax(trax => trax.AddEffects(effects => effects.AddLifecycleHook(instance))); using var provider = services.BuildServiceProvider(); var factories = provider.GetServices().ToList(); @@ -95,7 +101,9 @@ public void LifecycleHookRunner_ResolvedFromDI_IncludesRegisteredHooks() { var services = new ServiceCollection(); services.AddLogging(); - services.AddTraxEffects(options => options.AddLifecycleHook()); + services.AddTrax(trax => + trax.AddEffects(effects => effects.AddLifecycleHook()) + ); using var provider = services.BuildServiceProvider(); var runner = provider.GetService(); @@ -108,7 +116,7 @@ public void LifecycleHookRunner_NoHooksRegistered_StillResolvable() { var services = new ServiceCollection(); services.AddLogging(); - services.AddTraxEffects(_ => { }); + services.AddTrax(trax => trax.AddEffects(_ => { })); using var provider = services.BuildServiceProvider(); var runner = provider.GetService(); @@ -125,8 +133,12 @@ public void AddLifecycleHook_Multiple_AllRegistered() { var services = new ServiceCollection(); services.AddLogging(); - services.AddTraxEffects(options => - options.AddLifecycleHook().AddLifecycleHook() + services.AddTrax(trax => + trax.AddEffects(effects => + effects + .AddLifecycleHook() + .AddLifecycleHook() + ) ); using var provider = services.BuildServiceProvider(); diff --git a/tests/Trax.Effect.Tests.Json.Integration/IntegrationTests/JsonEffectToggleTests.cs b/tests/Trax.Effect.Tests.Json.Integration/IntegrationTests/JsonEffectToggleTests.cs index 5071385..519516c 100644 --- a/tests/Trax.Effect.Tests.Json.Integration/IntegrationTests/JsonEffectToggleTests.cs +++ b/tests/Trax.Effect.Tests.Json.Integration/IntegrationTests/JsonEffectToggleTests.cs @@ -31,11 +31,13 @@ public void RunBeforeAnyTests() .AddLogging(x => x.AddConsole().AddProvider(arrayProvider).SetMinimumLevel(LogLevel.Debug) ) - .AddTraxEffects(options => - options - .SetEffectLogLevel(LogLevel.Information) - .AddJsonEffect() - .AddStepLogger(serializeStepData: true) + .AddTrax(trax => + trax.AddEffects(effects => + effects + .SetEffectLogLevel(LogLevel.Information) + .AddJson() + .AddStepLogger(serializeStepData: true) + ) ) .AddTransientTraxRoute(); diff --git a/tests/Trax.Effect.Tests.Json.Integration/TestSetup.cs b/tests/Trax.Effect.Tests.Json.Integration/TestSetup.cs index c17ea59..984d06f 100644 --- a/tests/Trax.Effect.Tests.Json.Integration/TestSetup.cs +++ b/tests/Trax.Effect.Tests.Json.Integration/TestSetup.cs @@ -27,11 +27,13 @@ public async Task RunBeforeAnyTests() .AddLogging(x => x.AddConsole().AddProvider(arrayProvider).SetMinimumLevel(LogLevel.Debug) ) - .AddTraxEffects(options => - options - .SetEffectLogLevel(LogLevel.Information) - .AddJsonEffect() - .AddStepLogger(serializeStepData: true) + .AddTrax(trax => + trax.AddEffects(effects => + effects + .SetEffectLogLevel(LogLevel.Information) + .AddJson() + .AddStepLogger(serializeStepData: true) + ) ); ServiceProvider = ConfigureServices(ServiceCollection);