From 0dd319f56a58bc4d172aabc0b9c110120fa3782f Mon Sep 17 00:00:00 2001 From: JBradt Date: Wed, 6 Apr 2022 16:32:54 -0400 Subject: [PATCH 1/4] Add LifeCycle (scoped/singleton) to FluxorOptions and use the life cycle value when registering fluxor components --- .../OptionsReduxDevToolsExtensions.cs | 37 ++++++- .../ReduxDevToolsMiddlewareOptions.cs | 7 +- .../DependencyInjection/FluxorOptions.cs | 30 +++++- .../DependencyInjection/LifecycleEnum.cs | 8 ++ .../ServiceCollectionExtensions.cs | 53 +++++++++- .../EffectClassRegistration.cs | 5 +- .../EffectMethodRegistration.cs | 5 +- .../FeatureRegistration.cs | 26 +++-- .../ReducerClassRegistration.cs | 5 +- .../ReducerMethodRegistration.cs | 5 +- .../ServiceRegistration/StoreRegistration.cs | 22 +++-- .../IsolationTests/LifeCycleTests.cs | 99 +++++++++++++++++++ .../SupportFiles/IsolatedTests.cs | 2 +- 13 files changed, 266 insertions(+), 38 deletions(-) create mode 100644 Source/Fluxor/DependencyInjection/LifecycleEnum.cs create mode 100644 Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs diff --git a/Source/Fluxor.Blazor.Web.ReduxDevTools/OptionsReduxDevToolsExtensions.cs b/Source/Fluxor.Blazor.Web.ReduxDevTools/OptionsReduxDevToolsExtensions.cs index 37f95001..b06a6ac3 100644 --- a/Source/Fluxor.Blazor.Web.ReduxDevTools/OptionsReduxDevToolsExtensions.cs +++ b/Source/Fluxor.Blazor.Web.ReduxDevTools/OptionsReduxDevToolsExtensions.cs @@ -21,10 +21,43 @@ public static FluxorOptions UseReduxDevTools( updateReduxOptions?.Invoke(reduxOptions); options.AddMiddleware(); - options.Services.AddScoped(); - options.Services.AddScoped(_ => reduxOptions); + options.Services.AddRegistration(options); + options.Services.AddRegistration(_ => reduxOptions, options); options.UseRouting(); return options; } + + private static IServiceCollection AddRegistration(this IServiceCollection services, FluxorOptions options) + where TService : class + { + return options.RegistrationLifecycle switch { + LifecycleEnum.Scoped => services.AddScoped(), + LifecycleEnum.Singleton => services.AddSingleton(), + _ => services + }; + } + + private static IServiceCollection AddRegistration(this IServiceCollection services, Func implementationFactory, FluxorOptions options) + where TService : class + { + return options.RegistrationLifecycle switch { + LifecycleEnum.Scoped => services.AddScoped(implementationFactory), + LifecycleEnum.Singleton => services.AddSingleton(implementationFactory), + _ => services + }; + } + + internal static IServiceCollection AddRegistration(this IServiceCollection services, Func implementationFactory, FluxorOptions options) + where TService : class + where TImplementation : class, TService + { + return options.RegistrationLifecycle switch { + LifecycleEnum.Scoped => services.AddScoped(implementationFactory), + LifecycleEnum.Singleton => services.AddSingleton(implementationFactory), + _ => services + }; + } } + + } diff --git a/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddlewareOptions.cs b/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddlewareOptions.cs index a3acbf89..5761e75b 100644 --- a/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddlewareOptions.cs +++ b/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddlewareOptions.cs @@ -1,6 +1,5 @@ using Fluxor.Blazor.Web.ReduxDevTools.Serialization; using Fluxor.DependencyInjection; -using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using System; using System.Text.Json; @@ -63,7 +62,7 @@ public ReduxDevToolsMiddlewareOptions(FluxorOptions fluxorOptions) #endif public ReduxDevToolsMiddlewareOptions EnableStackTrace( int limit = 0, - string stackTraceFilterExpression = + string stackTraceFilterExpression = @"^(?:(?!\b" + @"System" + @"|Microsoft" + @@ -91,7 +90,7 @@ public ReduxDevToolsMiddlewareOptions UseNewtonsoftJson( JsonSerializerSettings settings = getSettings?.Invoke(sp); return new NewtonsoftJsonAdapter(settings); }); - FluxorOptions.Services.AddScoped(implementationFactory); + FluxorOptions.Services.AddRegistration(implementationFactory, FluxorOptions); return this; } @@ -108,7 +107,7 @@ public ReduxDevToolsMiddlewareOptions UseSystemTextJson( JsonSerializerOptions jsonOptions = getOptions?.Invoke(sp); return new SystemTextJsonAdapter(jsonOptions); }); - FluxorOptions.Services.AddScoped(implementationFactory); + FluxorOptions.Services.AddRegistration(implementationFactory, FluxorOptions); return this; } } diff --git a/Source/Fluxor/DependencyInjection/FluxorOptions.cs b/Source/Fluxor/DependencyInjection/FluxorOptions.cs index a6cf00cf..3161105d 100644 --- a/Source/Fluxor/DependencyInjection/FluxorOptions.cs +++ b/Source/Fluxor/DependencyInjection/FluxorOptions.cs @@ -14,6 +14,17 @@ public class FluxorOptions internal AssemblyScanSettings[] AssembliesToScan { get; private set; } = Array.Empty(); internal Type[] TypesToScan { get; private set; } = Array.Empty(); internal Type[] MiddlewareTypes = Array.Empty(); + /// + /// The Lifecycle that should be used when registering Fluxor features/reducers/effects/middleware
+ /// (default) LifecycleEnum.Scoped = Create a new instance for each new request
+ /// LifecycleEnum.Singleton = Create a new instance on first request and reuse for rest of application lifetime
+ ///
+ /// NOTE: indicating Singleton should be done only for exceptional cases. + /// For example, in MAUI/Blazor hybrid applications, the main MAUI application is a different scope then each BlazorWebView component + /// and state needs to be shared across all scopes of the application + ///
+ public LifecycleEnum RegistrationLifecycle { get; private set; } = LifecycleEnum.Scoped; + /// /// Service collection for registering services /// @@ -53,6 +64,23 @@ public FluxorOptions ScanTypes( return this; } + /// + /// The Lifecycle that should be used when registering Fluxor features/reducers/effects/middleware
+ /// (default) LifecycleEnum.Scoped = Create a new instance for each new request
+ /// LifecycleEnum.Singleton = Create a new instance on first request and reuse for rest of application lifetime
+ ///
+ /// NOTE: indicating Singleton should be done only for exceptional cases. + /// For example, in MAUI/Blazor hybrid applications, the main MAUI application is a different scope then each BlazorWebView component + /// and state needs to be shared across all scopes of the application
+ ///
+ /// This value should only be set once during the configuration of Fluxor + ///
+ public FluxorOptions SetRegistrationLifecycle(LifecycleEnum lifecycle) + { + RegistrationLifecycle = lifecycle; + return this; + } + /// /// Enables automatic discovery of features/effects/reducers /// @@ -89,7 +117,7 @@ public FluxorOptions AddMiddleware() if (Array.IndexOf(MiddlewareTypes, typeof(TMiddleware)) > -1) return this; - Services.AddScoped(typeof(TMiddleware)); + Services.AddRegistration(typeof(TMiddleware), this); Assembly assembly = typeof(TMiddleware).Assembly; string @namespace = typeof(TMiddleware).Namespace; diff --git a/Source/Fluxor/DependencyInjection/LifecycleEnum.cs b/Source/Fluxor/DependencyInjection/LifecycleEnum.cs new file mode 100644 index 00000000..0c68cdbb --- /dev/null +++ b/Source/Fluxor/DependencyInjection/LifecycleEnum.cs @@ -0,0 +1,8 @@ +namespace Fluxor +{ + public enum LifecycleEnum + { + Scoped, + Singleton + } +} diff --git a/Source/Fluxor/DependencyInjection/ServiceCollectionExtensions.cs b/Source/Fluxor/DependencyInjection/ServiceCollectionExtensions.cs index 318cbe8c..ed014fb0 100644 --- a/Source/Fluxor/DependencyInjection/ServiceCollectionExtensions.cs +++ b/Source/Fluxor/DependencyInjection/ServiceCollectionExtensions.cs @@ -31,7 +31,7 @@ public static IServiceCollection AddFluxor( // Register all middleware types with dependency injection foreach (Type middlewareType in options.MiddlewareTypes) - services.AddScoped(middlewareType); + services.AddRegistration(middlewareType, options); IEnumerable scanIncludeList = options.MiddlewareTypes .Select(t => new AssemblyScanSettings(t.Assembly, t.Namespace)); @@ -42,10 +42,59 @@ public static IServiceCollection AddFluxor( assembliesToScan: options.AssembliesToScan, typesToScan: options.TypesToScan, scanIncludeList: scanIncludeList); - services.AddScoped(typeof(IState<>), typeof(State<>)); + services.AddRegistration(typeof(IState<>), typeof(State<>), options); services.AddTransient(typeof(IStateSelection<,>), typeof(StateSelection<,>)); return services; } + + internal static IServiceCollection AddRegistration(this IServiceCollection services, Type serviceType, FluxorOptions options) + { + return options.RegistrationLifecycle switch { + LifecycleEnum.Scoped => services.AddScoped(serviceType), + LifecycleEnum.Singleton => services.AddSingleton(serviceType), + _ => services + }; + } + + internal static IServiceCollection AddRegistration(this IServiceCollection services, Type serviceType, Type implementationType, FluxorOptions options) + { + return options.RegistrationLifecycle switch { + LifecycleEnum.Scoped => services.AddScoped(serviceType, implementationType), + LifecycleEnum.Singleton => services.AddSingleton(serviceType, implementationType), + _ => services + }; + } + + internal static IServiceCollection AddRegistration(this IServiceCollection services, Type serviceType, Func implementationFactory, FluxorOptions options) + { + return options.RegistrationLifecycle switch { + LifecycleEnum.Scoped => services.AddScoped(serviceType, implementationFactory), + LifecycleEnum.Singleton => services.AddSingleton(serviceType, implementationFactory), + _ => services + }; + } + + internal static IServiceCollection AddRegistration(this IServiceCollection services, FluxorOptions options) + where TService : class + where TImplementation : class, TService + { + return options.RegistrationLifecycle switch { + LifecycleEnum.Scoped => services.AddScoped(), + LifecycleEnum.Singleton => services.AddSingleton(), + _ => services + }; + } + + internal static IServiceCollection AddRegistration(this IServiceCollection services, Func implementationFactory, FluxorOptions options) + where TService : class + { + return options.RegistrationLifecycle switch { + LifecycleEnum.Scoped => services.AddScoped(implementationFactory), + LifecycleEnum.Singleton => services.AddSingleton(implementationFactory), + _ => services + }; + } + } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectClassRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectClassRegistration.cs index 4697c260..773d2cef 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectClassRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectClassRegistration.cs @@ -7,10 +7,11 @@ internal static class EffectClassRegistration { public static void Register( IServiceCollection services, - IEnumerable effectClassInfos) + IEnumerable effectClassInfos, + FluxorOptions options) { foreach (EffectClassInfo effectClassInfo in effectClassInfos) - services.AddScoped(effectClassInfo.ImplementingType); + services.AddRegistration(effectClassInfo.ImplementingType, options); } } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectMethodRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectMethodRegistration.cs index eef47eb5..db06e66e 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectMethodRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectMethodRegistration.cs @@ -9,7 +9,8 @@ internal static class EffectMethodRegistration { public static void Register( IServiceCollection services, - EffectMethodInfo[] effectMethodInfos) + EffectMethodInfo[] effectMethodInfos, + FluxorOptions options) { IEnumerable hostClassTypes = effectMethodInfos @@ -18,7 +19,7 @@ public static void Register( .Distinct(); foreach (Type hostClassType in hostClassTypes) - services.AddScoped(hostClassType); + services.AddRegistration(hostClassType, options); } } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/FeatureRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/FeatureRegistration.cs index 2306015d..a716c647 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/FeatureRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/FeatureRegistration.cs @@ -14,7 +14,8 @@ public static void Register( FeatureClassInfo[] featureClassInfos, FeatureStateInfo[] featureStateInfos, ReducerClassInfo[] reducerClassInfos, - ReducerMethodInfo[] reducerMethodInfos) + ReducerMethodInfo[] reducerMethodInfos, + FluxorOptions options) { Dictionary> reducerClassInfoByStateType = reducerClassInfos @@ -30,16 +31,18 @@ public static void Register( services, featureClassInfos, reducerClassInfoByStateType, - reducerMethodInfoByStateType); + reducerMethodInfoByStateType, + options); RegisterStateInfos( services, featureStateInfos, reducerClassInfoByStateType, - reducerMethodInfoByStateType); + reducerMethodInfoByStateType, + options); } - private static void RegisterFeatureClassInfos(IServiceCollection services, FeatureClassInfo[] featureClassInfos, Dictionary> reducerClassInfoByStateType, Dictionary> reducerMethodInfoByStateType) + private static void RegisterFeatureClassInfos(IServiceCollection services, FeatureClassInfo[] featureClassInfos, Dictionary> reducerClassInfoByStateType, Dictionary> reducerMethodInfoByStateType, FluxorOptions options) { foreach (FeatureClassInfo info in featureClassInfos) { @@ -52,10 +55,10 @@ private static void RegisterFeatureClassInfos(IServiceCollection services, Featu out IGrouping reducerMethodInfosForStateType); // Register the implementing type so we can get an instance from the service provider - services.AddScoped(info.ImplementingType); + services.AddRegistration(info.ImplementingType, options); // Register a factory for the feature's interface - services.AddScoped(info.FeatureInterfaceGenericType, serviceProvider => + services.AddRegistration(info.FeatureInterfaceGenericType, serviceProvider => { // Create an instance of the implementing type var featureInstance = @@ -68,7 +71,8 @@ private static void RegisterFeatureClassInfos(IServiceCollection services, Featu reducerMethodInfosForStateType); return featureInstance; - }); + }, + options); } } @@ -85,7 +89,8 @@ private static void RegisterStateInfos( IServiceCollection services, FeatureStateInfo[] featureStateInfos, Dictionary> reducerClassInfoByStateType, - Dictionary> reducerMethodInfoByStateType) + Dictionary> reducerMethodInfoByStateType, + FluxorOptions options) { foreach (FeatureStateInfo info in featureStateInfos) { @@ -98,7 +103,7 @@ private static void RegisterStateInfos( out IGrouping reducerMethodInfosForStateType); // Register a factory for the feature's interface - services.AddScoped(info.FeatureInterfaceGenericType, serviceProvider => + services.AddRegistration(info.FeatureInterfaceGenericType, serviceProvider => { // Create an instance of the implementing type ConstructorInfo featureConstructor = @@ -115,7 +120,8 @@ private static void RegisterStateInfos( reducerMethodInfosForStateType); return featureInstance; - }); + }, + options); } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerClassRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerClassRegistration.cs index 57214f18..f1debbb8 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerClassRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerClassRegistration.cs @@ -6,10 +6,11 @@ internal static class ReducerClassRegistration { public static void Register( IServiceCollection services, - ReducerClassInfo[] reducerClassInfos) + ReducerClassInfo[] reducerClassInfos, + FluxorOptions options) { foreach (ReducerClassInfo reducerClassInfo in reducerClassInfos) - services.AddScoped(serviceType: reducerClassInfo.ImplementingType); + services.AddRegistration(serviceType: reducerClassInfo.ImplementingType, options: options); } } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerMethodRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerMethodRegistration.cs index 918be49b..f8c6dfca 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerMethodRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerMethodRegistration.cs @@ -9,7 +9,8 @@ internal static class ReducerMethodRegistration { public static void Register( IServiceCollection services, - ReducerMethodInfo[] reducerMethodInfos) + ReducerMethodInfo[] reducerMethodInfos, + FluxorOptions options) { IEnumerable hostClassTypes = reducerMethodInfos @@ -18,7 +19,7 @@ public static void Register( .Distinct(); foreach (Type hostClassType in hostClassTypes) - services.AddScoped(hostClassType); + services.AddRegistration(hostClassType, options); } } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/StoreRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/StoreRegistration.cs index d30a884c..af87a5e0 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/StoreRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/StoreRegistration.cs @@ -23,20 +23,21 @@ public static void Register( featureClassInfos, featureStateInfos, reducerClassInfos, - reducerMethodInfos); ; - ReducerClassRegistration.Register(services, reducerClassInfos); - ReducerMethodRegistration.Register(services, reducerMethodInfos); - EffectClassRegistration.Register(services, effectClassInfos); - EffectMethodRegistration.Register(services, effectMethodInfos); + reducerMethodInfos, + options); ; + ReducerClassRegistration.Register(services, reducerClassInfos, options); + ReducerMethodRegistration.Register(services, reducerMethodInfos, options); + EffectClassRegistration.Register(services, effectClassInfos, options); + EffectMethodRegistration.Register(services, effectMethodInfos, options); - services.AddScoped(); + services.AddRegistration(options); // Register IActionSubscriber as an alias to Store - services.AddScoped(serviceProvider => serviceProvider.GetService()); + services.AddRegistration(serviceProvider => serviceProvider.GetService(), options); // Register IStore as an alias to Store - services.AddScoped(serviceProvider => serviceProvider.GetService()); + services.AddRegistration(serviceProvider => serviceProvider.GetService(), options); // Register a custom factory for building IStore that will inject all effects - services.AddScoped(typeof(Store), serviceProvider => + services.AddRegistration(typeof(Store), serviceProvider => { var dispatcher = serviceProvider.GetService(); var store = new Store(dispatcher); @@ -71,7 +72,8 @@ public static void Register( } return store; - }); + }, + options); } } diff --git a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs new file mode 100644 index 00000000..e8c45428 --- /dev/null +++ b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs @@ -0,0 +1,99 @@ +using Fluxor.UnitTests.DependencyInjectionTests.IsolationTests.SupportFiles; +using Microsoft.Extensions.DependencyInjection; +using System; +using Xunit; + +namespace Fluxor.UnitTests.DependencyInjectionTests.IsolationTests +{ + public class LifeCycleTests + { + [Fact] + public void WhenStoreIsCreatedWithScopedLifecycle_ItIsUniqueToDependencyInjectionScope() + { + IServiceProvider serviceProvider = SetupServiceProvider(LifecycleEnum.Scoped); + + (IServiceScope scope1, IStore store1, IDispatcher dispatcher1, IState state1) = CreateStore(serviceProvider); + (IServiceScope scope2, IStore store2, IDispatcher dispatcher2, IState state2) = CreateStore(serviceProvider); + + IncrementCounterAction action = new IncrementCounterAction(); + + Assert.NotEqual(scope1, scope2); + Assert.NotEqual(store1, store2); + Assert.NotEqual(dispatcher1, dispatcher2); + Assert.NotEqual(state1, state2); + + Assert.Equal(0, state1.Value.Counter); + Assert.Equal(0, state2.Value.Counter); + + dispatcher1.Dispatch(action); + Assert.Equal(1, state1.Value.Counter); + Assert.Equal(0, state2.Value.Counter); + + dispatcher2.Dispatch(action); + Assert.Equal(1, state1.Value.Counter); + Assert.Equal(1, state2.Value.Counter); + + dispatcher2.Dispatch(action); + Assert.Equal(1, state1.Value.Counter); + Assert.Equal(2, state2.Value.Counter); + + scope1.Dispose(); + scope2.Dispose(); + } + + [Fact] + public void WhenStoreIsCreatedWithSingletonLifecycle_ItIsNotUniqueToDependencyInjectionScope() + { + IServiceProvider serviceProvider = SetupServiceProvider(LifecycleEnum.Singleton); + + (IServiceScope scope1, IStore store1, IDispatcher dispatcher1, IState state1) = CreateStore(serviceProvider); + (IServiceScope scope2, IStore store2, IDispatcher dispatcher2, IState state2) = CreateStore(serviceProvider); + + IncrementCounterAction action = new IncrementCounterAction(); + + Assert.NotEqual(scope1, scope2); + Assert.Equal(store1, store2); + Assert.Equal(dispatcher1, dispatcher2); + Assert.Equal(state1, state2); + + Assert.Equal(0, state1.Value.Counter); + Assert.Equal(0, state2.Value.Counter); + + dispatcher1.Dispatch(action); + Assert.Equal(1, state1.Value.Counter); + Assert.Equal(1, state2.Value.Counter); + + dispatcher2.Dispatch(action); + Assert.Equal(2, state1.Value.Counter); + Assert.Equal(2, state2.Value.Counter); + + dispatcher2.Dispatch(action); + Assert.Equal(3, state1.Value.Counter); + Assert.Equal(3, state2.Value.Counter); + } + + private static IServiceProvider SetupServiceProvider(LifecycleEnum lifecycle) + { + ServiceCollection services = new ServiceCollection(); + services.AddFluxor(x => x + .SetRegistrationLifecycle(lifecycle) + .AddMiddleware() + .ScanAssemblies(typeof(IsolatedTests).Assembly)); + IServiceProvider serviceProvider = services.BuildServiceProvider(); + return serviceProvider; + } + + private static (IServiceScope, IStore, IDispatcher, IState) CreateStore(IServiceProvider serviceProvider) + { + IServiceScope serviceScope = serviceProvider.CreateScope(); + IServiceProvider serviceScopeProvider = serviceScope.ServiceProvider; + + IStore store = serviceScopeProvider.GetRequiredService(); + store.InitializeAsync().Wait(); + IDispatcher dispatcher = serviceScopeProvider.GetRequiredService(); + IState state = serviceScopeProvider.GetRequiredService>(); + + return (serviceScope, store, dispatcher, state); + } + } +} diff --git a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/SupportFiles/IsolatedTests.cs b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/SupportFiles/IsolatedTests.cs index 936b254a..a5a34b8e 100644 --- a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/SupportFiles/IsolatedTests.cs +++ b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/SupportFiles/IsolatedTests.cs @@ -2,5 +2,5 @@ { public class IsolatedTests : Middleware { - } + } } From 796f8aefe1c7dcbe450f32d11f08c9fd458d8741 Mon Sep 17 00:00:00 2001 From: JBradt Date: Sun, 10 Apr 2022 10:40:22 -0400 Subject: [PATCH 2/4] requested changes to PR * AddRegistration renamed to Add * consolidated Add extension methods into IServiceCollectionExtensions.cs * rename RegistrationLifecycle to StoreLifetime and made a public property * currently left the SetStoreLifetime method in Options -- awaiting feedback in PR discussion * rename LifecycleEnum to StoreLifetime * improve XmlDoc comments for StoreLifetime --- .../OptionsReduxDevToolsExtensions.cs | 36 +-------- .../ReduxDevToolsMiddlewareOptions.cs | 5 +- .../DependencyInjection/FluxorOptions.cs | 43 +++++----- .../DependencyInjection/LifecycleEnum.cs | 2 +- .../ServiceCollectionExtensions.cs | 53 +----------- .../EffectClassRegistration.cs | 5 +- .../EffectMethodRegistration.cs | 5 +- .../FeatureRegistration.cs | 7 +- .../ReducerClassRegistration.cs | 5 +- .../ReducerMethodRegistration.cs | 5 +- .../ServiceRegistration/StoreRegistration.cs | 9 ++- .../IServiceCollectionExtensions.cs | 80 +++++++++++++++++++ .../IsolationTests/LifeCycleTests.cs | 8 +- .../StateActionsReducersTutorial/Program.cs | 7 +- 14 files changed, 144 insertions(+), 126 deletions(-) create mode 100644 Source/Fluxor/Extensions/IServiceCollectionExtensions.cs diff --git a/Source/Fluxor.Blazor.Web.ReduxDevTools/OptionsReduxDevToolsExtensions.cs b/Source/Fluxor.Blazor.Web.ReduxDevTools/OptionsReduxDevToolsExtensions.cs index b06a6ac3..fc6ca23b 100644 --- a/Source/Fluxor.Blazor.Web.ReduxDevTools/OptionsReduxDevToolsExtensions.cs +++ b/Source/Fluxor.Blazor.Web.ReduxDevTools/OptionsReduxDevToolsExtensions.cs @@ -1,5 +1,6 @@ using Fluxor.Blazor.Web.ReduxDevTools; using Fluxor.DependencyInjection; +using Fluxor.Extensions; using Microsoft.Extensions.DependencyInjection; using System; @@ -21,43 +22,12 @@ public static FluxorOptions UseReduxDevTools( updateReduxOptions?.Invoke(reduxOptions); options.AddMiddleware(); - options.Services.AddRegistration(options); - options.Services.AddRegistration(_ => reduxOptions, options); + options.Services.Add(options); + options.Services.Add(_ => reduxOptions, options); options.UseRouting(); return options; } - private static IServiceCollection AddRegistration(this IServiceCollection services, FluxorOptions options) - where TService : class - { - return options.RegistrationLifecycle switch { - LifecycleEnum.Scoped => services.AddScoped(), - LifecycleEnum.Singleton => services.AddSingleton(), - _ => services - }; - } - - private static IServiceCollection AddRegistration(this IServiceCollection services, Func implementationFactory, FluxorOptions options) - where TService : class - { - return options.RegistrationLifecycle switch { - LifecycleEnum.Scoped => services.AddScoped(implementationFactory), - LifecycleEnum.Singleton => services.AddSingleton(implementationFactory), - _ => services - }; - } - - internal static IServiceCollection AddRegistration(this IServiceCollection services, Func implementationFactory, FluxorOptions options) - where TService : class - where TImplementation : class, TService - { - return options.RegistrationLifecycle switch { - LifecycleEnum.Scoped => services.AddScoped(implementationFactory), - LifecycleEnum.Singleton => services.AddSingleton(implementationFactory), - _ => services - }; - } } - } diff --git a/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddlewareOptions.cs b/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddlewareOptions.cs index 5761e75b..b2e307f9 100644 --- a/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddlewareOptions.cs +++ b/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddlewareOptions.cs @@ -1,5 +1,6 @@ using Fluxor.Blazor.Web.ReduxDevTools.Serialization; using Fluxor.DependencyInjection; +using Fluxor.Extensions; using Newtonsoft.Json; using System; using System.Text.Json; @@ -90,7 +91,7 @@ public ReduxDevToolsMiddlewareOptions UseNewtonsoftJson( JsonSerializerSettings settings = getSettings?.Invoke(sp); return new NewtonsoftJsonAdapter(settings); }); - FluxorOptions.Services.AddRegistration(implementationFactory, FluxorOptions); + FluxorOptions.Services.Add(implementationFactory, FluxorOptions); return this; } @@ -107,7 +108,7 @@ public ReduxDevToolsMiddlewareOptions UseSystemTextJson( JsonSerializerOptions jsonOptions = getOptions?.Invoke(sp); return new SystemTextJsonAdapter(jsonOptions); }); - FluxorOptions.Services.AddRegistration(implementationFactory, FluxorOptions); + FluxorOptions.Services.Add(implementationFactory, FluxorOptions); return this; } } diff --git a/Source/Fluxor/DependencyInjection/FluxorOptions.cs b/Source/Fluxor/DependencyInjection/FluxorOptions.cs index 3161105d..ba33fc0a 100644 --- a/Source/Fluxor/DependencyInjection/FluxorOptions.cs +++ b/Source/Fluxor/DependencyInjection/FluxorOptions.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Fluxor.Extensions; +using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; @@ -15,15 +16,25 @@ public class FluxorOptions internal Type[] TypesToScan { get; private set; } = Array.Empty(); internal Type[] MiddlewareTypes = Array.Empty(); /// - /// The Lifecycle that should be used when registering Fluxor features/reducers/effects/middleware
- /// (default) LifecycleEnum.Scoped = Create a new instance for each new request
- /// LifecycleEnum.Singleton = Create a new instance on first request and reuse for rest of application lifetime
- ///
+ /// The Store Lifetime that should be used when registering Fluxor features/reducers/effects/middleware + ///
+ /// + /// + /// + /// LifecycleEnum.Scoped + /// (default) Create a new instance for each new request + /// + /// + /// LifecycleEnum.Singleton + /// Create a new instance on first request and reuse for rest of application lifetime + /// /// NOTE: indicating Singleton should be done only for exceptional cases. /// For example, in MAUI/Blazor hybrid applications, the main MAUI application is a different scope then each BlazorWebView component /// and state needs to be shared across all scopes of the application - /// - public LifecycleEnum RegistrationLifecycle { get; private set; } = LifecycleEnum.Scoped; + /// + /// This value should only be set once during the configuration of Fluxor + /// + public StoreLifetime StoreLifetime { get; set; } = StoreLifetime.Scoped; /// /// Service collection for registering services @@ -65,19 +76,13 @@ public FluxorOptions ScanTypes( } /// - /// The Lifecycle that should be used when registering Fluxor features/reducers/effects/middleware
- /// (default) LifecycleEnum.Scoped = Create a new instance for each new request
- /// LifecycleEnum.Singleton = Create a new instance on first request and reuse for rest of application lifetime
- ///
- /// NOTE: indicating Singleton should be done only for exceptional cases. - /// For example, in MAUI/Blazor hybrid applications, the main MAUI application is a different scope then each BlazorWebView component - /// and state needs to be shared across all scopes of the application
- ///
- /// This value should only be set once during the configuration of Fluxor + /// Sets the Lifecycle that should be used when registering Fluxor features/reducers/effects/middleware ///
- public FluxorOptions SetRegistrationLifecycle(LifecycleEnum lifecycle) + /// the lifecycle to use + /// Options + public FluxorOptions SetStoreLifetime(StoreLifetime lifecycle) { - RegistrationLifecycle = lifecycle; + StoreLifetime = lifecycle; return this; } @@ -117,7 +122,7 @@ public FluxorOptions AddMiddleware() if (Array.IndexOf(MiddlewareTypes, typeof(TMiddleware)) > -1) return this; - Services.AddRegistration(typeof(TMiddleware), this); + Services.Add(typeof(TMiddleware), this); Assembly assembly = typeof(TMiddleware).Assembly; string @namespace = typeof(TMiddleware).Namespace; diff --git a/Source/Fluxor/DependencyInjection/LifecycleEnum.cs b/Source/Fluxor/DependencyInjection/LifecycleEnum.cs index 0c68cdbb..21d1f0eb 100644 --- a/Source/Fluxor/DependencyInjection/LifecycleEnum.cs +++ b/Source/Fluxor/DependencyInjection/LifecycleEnum.cs @@ -1,6 +1,6 @@ namespace Fluxor { - public enum LifecycleEnum + public enum StoreLifetime { Scoped, Singleton diff --git a/Source/Fluxor/DependencyInjection/ServiceCollectionExtensions.cs b/Source/Fluxor/DependencyInjection/ServiceCollectionExtensions.cs index ed014fb0..0855dd13 100644 --- a/Source/Fluxor/DependencyInjection/ServiceCollectionExtensions.cs +++ b/Source/Fluxor/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using Fluxor.DependencyInjection; +using Fluxor.Extensions; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; @@ -31,7 +32,7 @@ public static IServiceCollection AddFluxor( // Register all middleware types with dependency injection foreach (Type middlewareType in options.MiddlewareTypes) - services.AddRegistration(middlewareType, options); + services.Add(middlewareType, options); IEnumerable scanIncludeList = options.MiddlewareTypes .Select(t => new AssemblyScanSettings(t.Assembly, t.Namespace)); @@ -42,59 +43,11 @@ public static IServiceCollection AddFluxor( assembliesToScan: options.AssembliesToScan, typesToScan: options.TypesToScan, scanIncludeList: scanIncludeList); - services.AddRegistration(typeof(IState<>), typeof(State<>), options); + services.Add(typeof(IState<>), typeof(State<>), options); services.AddTransient(typeof(IStateSelection<,>), typeof(StateSelection<,>)); return services; } - internal static IServiceCollection AddRegistration(this IServiceCollection services, Type serviceType, FluxorOptions options) - { - return options.RegistrationLifecycle switch { - LifecycleEnum.Scoped => services.AddScoped(serviceType), - LifecycleEnum.Singleton => services.AddSingleton(serviceType), - _ => services - }; - } - - internal static IServiceCollection AddRegistration(this IServiceCollection services, Type serviceType, Type implementationType, FluxorOptions options) - { - return options.RegistrationLifecycle switch { - LifecycleEnum.Scoped => services.AddScoped(serviceType, implementationType), - LifecycleEnum.Singleton => services.AddSingleton(serviceType, implementationType), - _ => services - }; - } - - internal static IServiceCollection AddRegistration(this IServiceCollection services, Type serviceType, Func implementationFactory, FluxorOptions options) - { - return options.RegistrationLifecycle switch { - LifecycleEnum.Scoped => services.AddScoped(serviceType, implementationFactory), - LifecycleEnum.Singleton => services.AddSingleton(serviceType, implementationFactory), - _ => services - }; - } - - internal static IServiceCollection AddRegistration(this IServiceCollection services, FluxorOptions options) - where TService : class - where TImplementation : class, TService - { - return options.RegistrationLifecycle switch { - LifecycleEnum.Scoped => services.AddScoped(), - LifecycleEnum.Singleton => services.AddSingleton(), - _ => services - }; - } - - internal static IServiceCollection AddRegistration(this IServiceCollection services, Func implementationFactory, FluxorOptions options) - where TService : class - { - return options.RegistrationLifecycle switch { - LifecycleEnum.Scoped => services.AddScoped(implementationFactory), - LifecycleEnum.Singleton => services.AddSingleton(implementationFactory), - _ => services - }; - } - } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectClassRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectClassRegistration.cs index 773d2cef..0304bd00 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectClassRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectClassRegistration.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Fluxor.Extensions; +using Microsoft.Extensions.DependencyInjection; using System.Collections.Generic; namespace Fluxor.DependencyInjection.ServiceRegistration @@ -11,7 +12,7 @@ public static void Register( FluxorOptions options) { foreach (EffectClassInfo effectClassInfo in effectClassInfos) - services.AddRegistration(effectClassInfo.ImplementingType, options); + services.Add(effectClassInfo.ImplementingType, options); } } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectMethodRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectMethodRegistration.cs index db06e66e..6d808e88 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectMethodRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/EffectMethodRegistration.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Fluxor.Extensions; +using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; @@ -19,7 +20,7 @@ public static void Register( .Distinct(); foreach (Type hostClassType in hostClassTypes) - services.AddRegistration(hostClassType, options); + services.Add(hostClassType, options); } } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/FeatureRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/FeatureRegistration.cs index a716c647..94ae011c 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/FeatureRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/FeatureRegistration.cs @@ -1,4 +1,5 @@ using Fluxor.DependencyInjection.WrapperFactories; +using Fluxor.Extensions; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; @@ -55,10 +56,10 @@ private static void RegisterFeatureClassInfos(IServiceCollection services, Featu out IGrouping reducerMethodInfosForStateType); // Register the implementing type so we can get an instance from the service provider - services.AddRegistration(info.ImplementingType, options); + services.Add(info.ImplementingType, options); // Register a factory for the feature's interface - services.AddRegistration(info.FeatureInterfaceGenericType, serviceProvider => + services.Add(info.FeatureInterfaceGenericType, serviceProvider => { // Create an instance of the implementing type var featureInstance = @@ -103,7 +104,7 @@ private static void RegisterStateInfos( out IGrouping reducerMethodInfosForStateType); // Register a factory for the feature's interface - services.AddRegistration(info.FeatureInterfaceGenericType, serviceProvider => + services.Add(info.FeatureInterfaceGenericType, serviceProvider => { // Create an instance of the implementing type ConstructorInfo featureConstructor = diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerClassRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerClassRegistration.cs index f1debbb8..82e2b7fb 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerClassRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerClassRegistration.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Fluxor.Extensions; +using Microsoft.Extensions.DependencyInjection; namespace Fluxor.DependencyInjection.ServiceRegistration { @@ -10,7 +11,7 @@ public static void Register( FluxorOptions options) { foreach (ReducerClassInfo reducerClassInfo in reducerClassInfos) - services.AddRegistration(serviceType: reducerClassInfo.ImplementingType, options: options); + services.Add(serviceType: reducerClassInfo.ImplementingType, options: options); } } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerMethodRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerMethodRegistration.cs index f8c6dfca..79190cd6 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerMethodRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/ReducerMethodRegistration.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Fluxor.Extensions; +using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; @@ -19,7 +20,7 @@ public static void Register( .Distinct(); foreach (Type hostClassType in hostClassTypes) - services.AddRegistration(hostClassType, options); + services.Add(hostClassType, options); } } } diff --git a/Source/Fluxor/DependencyInjection/ServiceRegistration/StoreRegistration.cs b/Source/Fluxor/DependencyInjection/ServiceRegistration/StoreRegistration.cs index af87a5e0..50929e2d 100644 --- a/Source/Fluxor/DependencyInjection/ServiceRegistration/StoreRegistration.cs +++ b/Source/Fluxor/DependencyInjection/ServiceRegistration/StoreRegistration.cs @@ -1,4 +1,5 @@ using Fluxor.DependencyInjection.WrapperFactories; +using Fluxor.Extensions; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; @@ -30,14 +31,14 @@ public static void Register( EffectClassRegistration.Register(services, effectClassInfos, options); EffectMethodRegistration.Register(services, effectMethodInfos, options); - services.AddRegistration(options); + services.Add(options); // Register IActionSubscriber as an alias to Store - services.AddRegistration(serviceProvider => serviceProvider.GetService(), options); + services.Add(serviceProvider => serviceProvider.GetService(), options); // Register IStore as an alias to Store - services.AddRegistration(serviceProvider => serviceProvider.GetService(), options); + services.Add(serviceProvider => serviceProvider.GetService(), options); // Register a custom factory for building IStore that will inject all effects - services.AddRegistration(typeof(Store), serviceProvider => + services.Add(typeof(Store), serviceProvider => { var dispatcher = serviceProvider.GetService(); var store = new Store(dispatcher); diff --git a/Source/Fluxor/Extensions/IServiceCollectionExtensions.cs b/Source/Fluxor/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 00000000..03a8ef2a --- /dev/null +++ b/Source/Fluxor/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,80 @@ +using Fluxor.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using System; + +namespace Fluxor.Extensions +{ + public static class IServiceCollectionExtensions + { + public static IServiceCollection Add + (this IServiceCollection services, Type serviceType, FluxorOptions options) + { + return options.StoreLifetime switch { + StoreLifetime.Scoped => services.AddScoped(serviceType), + StoreLifetime.Singleton => services.AddSingleton(serviceType), + _ => services + }; + } + + public static IServiceCollection Add(this IServiceCollection services, Type serviceType, Type implementationType, FluxorOptions options) + { + return options.StoreLifetime switch { + StoreLifetime.Scoped => services.AddScoped(serviceType, implementationType), + StoreLifetime.Singleton => services.AddSingleton(serviceType, implementationType), + _ => services + }; + } + + public static IServiceCollection Add(this IServiceCollection services, Type serviceType, Func implementationFactory, FluxorOptions options) + { + return options.StoreLifetime switch { + StoreLifetime.Scoped => services.AddScoped(serviceType, implementationFactory), + StoreLifetime.Singleton => services.AddSingleton(serviceType, implementationFactory), + _ => services + }; + } + + public static IServiceCollection Add(this IServiceCollection services, FluxorOptions options) + where TService : class + where TImplementation : class, TService + { + return options.StoreLifetime switch { + StoreLifetime.Scoped => services.AddScoped(), + StoreLifetime.Singleton => services.AddSingleton(), + _ => services + }; + } + + public static IServiceCollection Add(this IServiceCollection services, Func implementationFactory, FluxorOptions options) + where TService : class + { + return options.StoreLifetime switch { + StoreLifetime.Scoped => services.AddScoped(implementationFactory), + StoreLifetime.Singleton => services.AddSingleton(implementationFactory), + _ => services + }; + } + + public static IServiceCollection Add(this IServiceCollection services, FluxorOptions options) + where TService : class + { + return options.StoreLifetime switch { + StoreLifetime.Scoped => services.AddScoped(), + StoreLifetime.Singleton => services.AddSingleton(), + _ => services + }; + } + + public static IServiceCollection Add(this IServiceCollection services, Func implementationFactory, FluxorOptions options) + where TService : class + where TImplementation : class, TService + { + return options.StoreLifetime switch { + StoreLifetime.Scoped => services.AddScoped(implementationFactory), + StoreLifetime.Singleton => services.AddSingleton(implementationFactory), + _ => services + }; + } + + } +} diff --git a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs index e8c45428..5e4d8a37 100644 --- a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs +++ b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs @@ -10,7 +10,7 @@ public class LifeCycleTests [Fact] public void WhenStoreIsCreatedWithScopedLifecycle_ItIsUniqueToDependencyInjectionScope() { - IServiceProvider serviceProvider = SetupServiceProvider(LifecycleEnum.Scoped); + IServiceProvider serviceProvider = SetupServiceProvider(StoreLifetime.Scoped); (IServiceScope scope1, IStore store1, IDispatcher dispatcher1, IState state1) = CreateStore(serviceProvider); (IServiceScope scope2, IStore store2, IDispatcher dispatcher2, IState state2) = CreateStore(serviceProvider); @@ -44,7 +44,7 @@ public void WhenStoreIsCreatedWithScopedLifecycle_ItIsUniqueToDependencyInjectio [Fact] public void WhenStoreIsCreatedWithSingletonLifecycle_ItIsNotUniqueToDependencyInjectionScope() { - IServiceProvider serviceProvider = SetupServiceProvider(LifecycleEnum.Singleton); + IServiceProvider serviceProvider = SetupServiceProvider(StoreLifetime.Singleton); (IServiceScope scope1, IStore store1, IDispatcher dispatcher1, IState state1) = CreateStore(serviceProvider); (IServiceScope scope2, IStore store2, IDispatcher dispatcher2, IState state2) = CreateStore(serviceProvider); @@ -72,11 +72,11 @@ public void WhenStoreIsCreatedWithSingletonLifecycle_ItIsNotUniqueToDependencyIn Assert.Equal(3, state2.Value.Counter); } - private static IServiceProvider SetupServiceProvider(LifecycleEnum lifecycle) + private static IServiceProvider SetupServiceProvider(StoreLifetime lifecycle) { ServiceCollection services = new ServiceCollection(); services.AddFluxor(x => x - .SetRegistrationLifecycle(lifecycle) + .SetStoreLifetime(lifecycle) .AddMiddleware() .ScanAssemblies(typeof(IsolatedTests).Assembly)); IServiceProvider serviceProvider = services.BuildServiceProvider(); diff --git a/Tutorials/01-BasicConcepts/01A-StateActionsReducersTutorial/StateActionsReducersTutorial/Program.cs b/Tutorials/01-BasicConcepts/01A-StateActionsReducersTutorial/StateActionsReducersTutorial/Program.cs index 2592fc13..2e48ca33 100644 --- a/Tutorials/01-BasicConcepts/01A-StateActionsReducersTutorial/StateActionsReducersTutorial/Program.cs +++ b/Tutorials/01-BasicConcepts/01A-StateActionsReducersTutorial/StateActionsReducersTutorial/Program.cs @@ -10,8 +10,11 @@ static void Main(string[] args) { var services = new ServiceCollection(); services.AddScoped(); - services.AddFluxor(o => o - .ScanAssemblies(typeof(Program).Assembly)); + services.AddFluxor(o => + { + o.StoreLifetime = StoreLifetime.Scoped; + o.ScanAssemblies(typeof(Program).Assembly); + }); IServiceProvider serviceProvider = services.BuildServiceProvider(); From 05488952621bb200302849db4f21c7160b9e78bf Mon Sep 17 00:00:00 2001 From: JBradt Date: Mon, 11 Apr 2022 12:40:56 -0400 Subject: [PATCH 3/4] requested changes to PR * renamed SetStoreLifetime() to WithServiceLifetime() * change StoreLifetime prop to internal --- .../DependencyInjection/FluxorOptions.cs | 43 +++++++++---------- .../IsolationTests/LifeCycleTests.cs | 2 +- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Source/Fluxor/DependencyInjection/FluxorOptions.cs b/Source/Fluxor/DependencyInjection/FluxorOptions.cs index ba33fc0a..d1b6509b 100644 --- a/Source/Fluxor/DependencyInjection/FluxorOptions.cs +++ b/Source/Fluxor/DependencyInjection/FluxorOptions.cs @@ -15,26 +15,7 @@ public class FluxorOptions internal AssemblyScanSettings[] AssembliesToScan { get; private set; } = Array.Empty(); internal Type[] TypesToScan { get; private set; } = Array.Empty(); internal Type[] MiddlewareTypes = Array.Empty(); - /// - /// The Store Lifetime that should be used when registering Fluxor features/reducers/effects/middleware - /// - /// - /// - /// - /// LifecycleEnum.Scoped - /// (default) Create a new instance for each new request - /// - /// - /// LifecycleEnum.Singleton - /// Create a new instance on first request and reuse for rest of application lifetime - /// - /// NOTE: indicating Singleton should be done only for exceptional cases. - /// For example, in MAUI/Blazor hybrid applications, the main MAUI application is a different scope then each BlazorWebView component - /// and state needs to be shared across all scopes of the application - /// - /// This value should only be set once during the configuration of Fluxor - /// - public StoreLifetime StoreLifetime { get; set; } = StoreLifetime.Scoped; + internal StoreLifetime StoreLifetime { get; set; } = StoreLifetime.Scoped; /// /// Service collection for registering services @@ -76,11 +57,29 @@ public FluxorOptions ScanTypes( } /// - /// Sets the Lifecycle that should be used when registering Fluxor features/reducers/effects/middleware + /// The Store Lifetime that should be used when registering Fluxor features/reducers/effects/middleware /// /// the lifecycle to use /// Options - public FluxorOptions SetStoreLifetime(StoreLifetime lifecycle) + /// + /// + /// + /// LifecycleEnum.Scoped + /// (default) Create a new instance for each new request + /// + /// + /// LifecycleEnum.Singleton + /// Create a new instance on first request and reuse for rest of application lifetime + /// + /// NOTE: indicating Singleton should be done only for exceptional cases. + /// For example, in MAUI/Blazor hybrid applications, the main MAUI application is a different scope then each BlazorWebView component + /// and state needs to be shared across all scopes of the application + /// + /// + /// This value should only be set once during the configuration of Fluxor + /// + /// + public FluxorOptions WithServiceLifetime(StoreLifetime lifecycle) { StoreLifetime = lifecycle; return this; diff --git a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs index 5e4d8a37..7a858a9e 100644 --- a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs +++ b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs @@ -76,7 +76,7 @@ private static IServiceProvider SetupServiceProvider(StoreLifetime lifecycle) { ServiceCollection services = new ServiceCollection(); services.AddFluxor(x => x - .SetStoreLifetime(lifecycle) + .WithServiceLifetime(lifecycle) .AddMiddleware() .ScanAssemblies(typeof(IsolatedTests).Assembly)); IServiceProvider serviceProvider = services.BuildServiceProvider(); From 12896e5a726d6fbf9cef24914b175e9960399460 Mon Sep 17 00:00:00 2001 From: JBradt Date: Mon, 11 Apr 2022 15:11:08 -0400 Subject: [PATCH 4/4] requested changes to PR renamed WithServiceLifetime() to WithLifetime() --- Source/Fluxor/DependencyInjection/FluxorOptions.cs | 2 +- .../DependencyInjectionTests/IsolationTests/LifeCycleTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Fluxor/DependencyInjection/FluxorOptions.cs b/Source/Fluxor/DependencyInjection/FluxorOptions.cs index d1b6509b..d0c0e848 100644 --- a/Source/Fluxor/DependencyInjection/FluxorOptions.cs +++ b/Source/Fluxor/DependencyInjection/FluxorOptions.cs @@ -79,7 +79,7 @@ public FluxorOptions ScanTypes( /// This value should only be set once during the configuration of Fluxor /// /// - public FluxorOptions WithServiceLifetime(StoreLifetime lifecycle) + public FluxorOptions WithLifetime(StoreLifetime lifecycle) { StoreLifetime = lifecycle; return this; diff --git a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs index 7a858a9e..effbeab9 100644 --- a/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs +++ b/Tests/Fluxor.UnitTests/DependencyInjectionTests/IsolationTests/LifeCycleTests.cs @@ -76,7 +76,7 @@ private static IServiceProvider SetupServiceProvider(StoreLifetime lifecycle) { ServiceCollection services = new ServiceCollection(); services.AddFluxor(x => x - .WithServiceLifetime(lifecycle) + .WithLifetime(lifecycle) .AddMiddleware() .ScanAssemblies(typeof(IsolatedTests).Assembly)); IServiceProvider serviceProvider = services.BuildServiceProvider();