Skip to content

Commit

Permalink
Add LifeCycle to FluxorOptions and use in registration (#287)
Browse files Browse the repository at this point in the history
* Add LifeCycle (Scoped/Singleton) to FluxorOptions and use the life cycle value when registering Fluxor components.
  • Loading branch information
bradtwurst authored Apr 11, 2022
1 parent cb318ff commit fa8763e
Show file tree
Hide file tree
Showing 15 changed files with 290 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Fluxor.Blazor.Web.ReduxDevTools;
using Fluxor.DependencyInjection;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;

Expand All @@ -21,10 +22,12 @@ public static FluxorOptions UseReduxDevTools(
updateReduxOptions?.Invoke(reduxOptions);

options.AddMiddleware<ReduxDevToolsMiddleware>();
options.Services.AddScoped<ReduxDevToolsInterop>();
options.Services.AddScoped(_ => reduxOptions);
options.Services.Add<ReduxDevToolsInterop>(options);
options.Services.Add(_ => reduxOptions, options);
options.UseRouting();
return options;
}

}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Fluxor.Blazor.Web.ReduxDevTools.Serialization;
using Fluxor.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Fluxor.Extensions;
using Newtonsoft.Json;
using System;
using System.Text.Json;
Expand Down Expand Up @@ -63,7 +63,7 @@ public ReduxDevToolsMiddlewareOptions(FluxorOptions fluxorOptions)
#endif
public ReduxDevToolsMiddlewareOptions EnableStackTrace(
int limit = 0,
string stackTraceFilterExpression =
string stackTraceFilterExpression =
@"^(?:(?!\b" +
@"System" +
@"|Microsoft" +
Expand Down Expand Up @@ -91,7 +91,7 @@ public ReduxDevToolsMiddlewareOptions UseNewtonsoftJson(
JsonSerializerSettings settings = getSettings?.Invoke(sp);
return new NewtonsoftJsonAdapter(settings);
});
FluxorOptions.Services.AddScoped<IJsonSerialization, NewtonsoftJsonAdapter>(implementationFactory);
FluxorOptions.Services.Add<IJsonSerialization, NewtonsoftJsonAdapter>(implementationFactory, FluxorOptions);
return this;
}

Expand All @@ -108,7 +108,7 @@ public ReduxDevToolsMiddlewareOptions UseSystemTextJson(
JsonSerializerOptions jsonOptions = getOptions?.Invoke(sp);
return new SystemTextJsonAdapter(jsonOptions);
});
FluxorOptions.Services.AddScoped<IJsonSerialization, SystemTextJsonAdapter>(implementationFactory);
FluxorOptions.Services.Add<IJsonSerialization, SystemTextJsonAdapter>(implementationFactory, FluxorOptions);
return this;
}
}
Expand Down
36 changes: 34 additions & 2 deletions Source/Fluxor/DependencyInjection/FluxorOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -14,6 +15,8 @@ public class FluxorOptions
internal AssemblyScanSettings[] AssembliesToScan { get; private set; } = Array.Empty<AssemblyScanSettings>();
internal Type[] TypesToScan { get; private set; } = Array.Empty<Type>();
internal Type[] MiddlewareTypes = Array.Empty<Type>();
internal StoreLifetime StoreLifetime { get; set; } = StoreLifetime.Scoped;

/// <summary>
/// Service collection for registering services
/// </summary>
Expand Down Expand Up @@ -53,6 +56,35 @@ public FluxorOptions ScanTypes(
return this;
}

/// <summary>
/// The Store Lifetime that should be used when registering Fluxor features/reducers/effects/middleware
/// </summary>
/// <param name="lifecycle">the lifecycle to use</param>
/// <returns>Options</returns>
/// <remarks>
/// <list type="bullet">
/// <item>
/// <term>LifecycleEnum.Scoped</term>
/// <description>(default) Create a new instance for each new request</description>
/// </item>
/// <item>
/// <term>LifecycleEnum.Singleton</term>
/// <description>Create a new instance on first request and reuse for rest of application lifetime</description>
/// <para>
/// 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
/// </para>
/// <para>
/// This value should only be set once during the configuration of Fluxor
/// </para>
/// </remarks>
public FluxorOptions WithLifetime(StoreLifetime lifecycle)
{
StoreLifetime = lifecycle;
return this;
}

/// <summary>
/// Enables automatic discovery of features/effects/reducers
/// </summary>
Expand Down Expand Up @@ -89,7 +121,7 @@ public FluxorOptions AddMiddleware<TMiddleware>()
if (Array.IndexOf(MiddlewareTypes, typeof(TMiddleware)) > -1)
return this;

Services.AddScoped(typeof(TMiddleware));
Services.Add(typeof(TMiddleware), this);
Assembly assembly = typeof(TMiddleware).Assembly;
string @namespace = typeof(TMiddleware).Namespace;

Expand Down
8 changes: 8 additions & 0 deletions Source/Fluxor/DependencyInjection/LifecycleEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Fluxor
{
public enum StoreLifetime
{
Scoped,
Singleton
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Fluxor.DependencyInjection;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -31,7 +32,7 @@ public static IServiceCollection AddFluxor(

// Register all middleware types with dependency injection
foreach (Type middlewareType in options.MiddlewareTypes)
services.AddScoped(middlewareType);
services.Add(middlewareType, options);

IEnumerable<AssemblyScanSettings> scanIncludeList = options.MiddlewareTypes
.Select(t => new AssemblyScanSettings(t.Assembly, t.Namespace));
Expand All @@ -42,10 +43,11 @@ public static IServiceCollection AddFluxor(
assembliesToScan: options.AssembliesToScan,
typesToScan: options.TypesToScan,
scanIncludeList: scanIncludeList);
services.AddScoped(typeof(IState<>), typeof(State<>));
services.Add(typeof(IState<>), typeof(State<>), options);
services.AddTransient(typeof(IStateSelection<,>), typeof(StateSelection<,>));

return services;
}

}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;

namespace Fluxor.DependencyInjection.ServiceRegistration
Expand All @@ -7,10 +8,11 @@ internal static class EffectClassRegistration
{
public static void Register(
IServiceCollection services,
IEnumerable<EffectClassInfo> effectClassInfos)
IEnumerable<EffectClassInfo> effectClassInfos,
FluxorOptions options)
{
foreach (EffectClassInfo effectClassInfo in effectClassInfos)
services.AddScoped(effectClassInfo.ImplementingType);
services.Add(effectClassInfo.ImplementingType, options);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -9,7 +10,8 @@ internal static class EffectMethodRegistration
{
public static void Register(
IServiceCollection services,
EffectMethodInfo[] effectMethodInfos)
EffectMethodInfo[] effectMethodInfos,
FluxorOptions options)
{
IEnumerable<Type> hostClassTypes =
effectMethodInfos
Expand All @@ -18,7 +20,7 @@ public static void Register(
.Distinct();

foreach (Type hostClassType in hostClassTypes)
services.AddScoped(hostClassType);
services.Add(hostClassType, options);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Fluxor.DependencyInjection.WrapperFactories;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
Expand All @@ -14,7 +15,8 @@ public static void Register(
FeatureClassInfo[] featureClassInfos,
FeatureStateInfo[] featureStateInfos,
ReducerClassInfo[] reducerClassInfos,
ReducerMethodInfo[] reducerMethodInfos)
ReducerMethodInfo[] reducerMethodInfos,
FluxorOptions options)
{
Dictionary<Type, IGrouping<Type, ReducerClassInfo>> reducerClassInfoByStateType =
reducerClassInfos
Expand All @@ -30,16 +32,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<Type, IGrouping<Type, ReducerClassInfo>> reducerClassInfoByStateType, Dictionary<Type, IGrouping<Type, ReducerMethodInfo>> reducerMethodInfoByStateType)
private static void RegisterFeatureClassInfos(IServiceCollection services, FeatureClassInfo[] featureClassInfos, Dictionary<Type, IGrouping<Type, ReducerClassInfo>> reducerClassInfoByStateType, Dictionary<Type, IGrouping<Type, ReducerMethodInfo>> reducerMethodInfoByStateType, FluxorOptions options)
{
foreach (FeatureClassInfo info in featureClassInfos)
{
Expand All @@ -52,10 +56,10 @@ private static void RegisterFeatureClassInfos(IServiceCollection services, Featu
out IGrouping<Type, ReducerMethodInfo> reducerMethodInfosForStateType);

// Register the implementing type so we can get an instance from the service provider
services.AddScoped(info.ImplementingType);
services.Add(info.ImplementingType, options);

// Register a factory for the feature's interface
services.AddScoped(info.FeatureInterfaceGenericType, serviceProvider =>
services.Add(info.FeatureInterfaceGenericType, serviceProvider =>
{
// Create an instance of the implementing type
var featureInstance =
Expand All @@ -68,7 +72,8 @@ private static void RegisterFeatureClassInfos(IServiceCollection services, Featu
reducerMethodInfosForStateType);

return featureInstance;
});
},
options);
}
}

Expand All @@ -85,7 +90,8 @@ private static void RegisterStateInfos(
IServiceCollection services,
FeatureStateInfo[] featureStateInfos,
Dictionary<Type, IGrouping<Type, ReducerClassInfo>> reducerClassInfoByStateType,
Dictionary<Type, IGrouping<Type, ReducerMethodInfo>> reducerMethodInfoByStateType)
Dictionary<Type, IGrouping<Type, ReducerMethodInfo>> reducerMethodInfoByStateType,
FluxorOptions options)
{
foreach (FeatureStateInfo info in featureStateInfos)
{
Expand All @@ -98,7 +104,7 @@ private static void RegisterStateInfos(
out IGrouping<Type, ReducerMethodInfo> reducerMethodInfosForStateType);

// Register a factory for the feature's interface
services.AddScoped(info.FeatureInterfaceGenericType, serviceProvider =>
services.Add(info.FeatureInterfaceGenericType, serviceProvider =>
{
// Create an instance of the implementing type
ConstructorInfo featureConstructor =
Expand All @@ -115,7 +121,8 @@ private static void RegisterStateInfos(
reducerMethodInfosForStateType);

return featureInstance;
});
},
options);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;

namespace Fluxor.DependencyInjection.ServiceRegistration
{
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.Add(serviceType: reducerClassInfo.ImplementingType, options: options);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -9,7 +10,8 @@ internal static class ReducerMethodRegistration
{
public static void Register(
IServiceCollection services,
ReducerMethodInfo[] reducerMethodInfos)
ReducerMethodInfo[] reducerMethodInfos,
FluxorOptions options)
{
IEnumerable<Type> hostClassTypes =
reducerMethodInfos
Expand All @@ -18,7 +20,7 @@ public static void Register(
.Distinct();

foreach (Type hostClassType in hostClassTypes)
services.AddScoped(hostClassType);
services.Add(hostClassType, options);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Fluxor.DependencyInjection.WrapperFactories;
using Fluxor.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
Expand All @@ -23,20 +24,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<IDispatcher, Dispatcher>();
services.Add<IDispatcher, Dispatcher>(options);
// Register IActionSubscriber as an alias to Store
services.AddScoped<IActionSubscriber>(serviceProvider => serviceProvider.GetService<Store>());
services.Add<IActionSubscriber>(serviceProvider => serviceProvider.GetService<Store>(), options);
// Register IStore as an alias to Store
services.AddScoped<IStore>(serviceProvider => serviceProvider.GetService<Store>());
services.Add<IStore>(serviceProvider => serviceProvider.GetService<Store>(), options);

// Register a custom factory for building IStore that will inject all effects
services.AddScoped(typeof(Store), serviceProvider =>
services.Add(typeof(Store), serviceProvider =>
{
var dispatcher = serviceProvider.GetService<IDispatcher>();
var store = new Store(dispatcher);
Expand Down Expand Up @@ -71,7 +73,8 @@ public static void Register(
}

return store;
});
},
options);

}
}
Expand Down
Loading

0 comments on commit fa8763e

Please sign in to comment.