From 09c0a5f3cfcc791b1ae0f68d9e84b79cc9abfeeb Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 20 May 2026 16:43:47 +0200 Subject: [PATCH] Refactor static IServiceProvider initialization Refactor static IServiceProvider initialization to use a thread-safe Lazy, ensuring lazy creation and improved efficiency. Replace `Services` and `Provider` fields with `_staticConfigure` delegate for dynamic service collection configuration. Update `BuildStaticClient` methods to use `Interlocked.CompareExchange` for safe initialization of `_staticConfigure`. Modify `Create` method to retrieve the provider via `LazyProvider`. Mark `BuildStaticClient` and `Create` methods as obsolete, encouraging the use of local service collections. Adjust exception messages and documentation to reflect these changes. --- docs/ReC.Client.xwiki.md | 0 src/ReC.Client/ReCClient.cs | 37 ++++++++++++++++++++----------------- 2 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 docs/ReC.Client.xwiki.md diff --git a/docs/ReC.Client.xwiki.md b/docs/ReC.Client.xwiki.md new file mode 100644 index 0000000..e69de29 diff --git a/src/ReC.Client/ReCClient.cs b/src/ReC.Client/ReCClient.cs index b67ae34..51aa917 100644 --- a/src/ReC.Client/ReCClient.cs +++ b/src/ReC.Client/ReCClient.cs @@ -85,19 +85,28 @@ namespace ReC.Client } #region Static - private static readonly IServiceCollection Services = new ServiceCollection(); - #if NET8_0_OR_GREATER - private static IServiceProvider? Provider = null; + private static Action? _staticConfigure = null; #else - private static IServiceProvider Provider = null; + private static Action _staticConfigure = null; #endif + private static readonly Lazy LazyProvider = new Lazy(() => + { + var configure = _staticConfigure + ?? throw new InvalidOperationException("Static Provider is not built. Call BuildStaticClient first."); + + var services = new ServiceCollection(); + configure(services); + return services.BuildServiceProvider(); + }, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication); + /// /// Configures and builds the static for creating instances. /// /// /// This method should only be called once during application startup. + /// The underlying is created lazily and thread-safely on first access via . /// /// The base URI of the ReC API. /// An optional callback to configure . @@ -109,11 +118,9 @@ namespace ReC.Client public static void BuildStaticClient(string apiUri, Action? configureOptions = null) #endif { - if(Provider != null) + Action configure = services => services.AddRecClient(apiUri, configureOptions); + if (System.Threading.Interlocked.CompareExchange(ref _staticConfigure, configure, null) != null) throw new InvalidOperationException("Static Provider is already built."); - - Services.AddRecClient(apiUri, configureOptions); - Provider = Services.BuildServiceProvider(); } /// @@ -121,6 +128,7 @@ namespace ReC.Client /// /// /// This method should only be called once during application startup. + /// The underlying is created lazily and thread-safely on first access via . /// /// An action to configure the . /// An optional callback to configure . @@ -132,25 +140,20 @@ namespace ReC.Client public static void BuildStaticClient(Action configureClient, Action? configureOptions = null) #endif { - if (Provider != null) + Action configure = services => services.AddRecClient(configureClient, configureOptions); + if (System.Threading.Interlocked.CompareExchange(ref _staticConfigure, configure, null) != null) throw new InvalidOperationException("Static Provider is already built."); - - Services.AddRecClient(configureClient, configureOptions); - Provider = Services.BuildServiceProvider(); } /// /// Creates a new instance using the statically configured provider. /// /// A new instance of the . - /// Thrown if has not been called yet. + /// Thrown if has not been called yet. [Obsolete("Use a local service collection instead of the static provider.")] public static ReCClient Create() { - if (Provider == null) - throw new InvalidOperationException("Static Provider is not built. Call BuildStaticClient first."); - - return Provider.GetRequiredService(); + return LazyProvider.Value.GetRequiredService(); } #endregion }