Refactor static IServiceProvider initialization
Refactor static IServiceProvider initialization to use a thread-safe Lazy<IServiceProvider>, 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.
This commit is contained in:
0
docs/ReC.Client.xwiki.md
Normal file
0
docs/ReC.Client.xwiki.md
Normal file
@@ -85,19 +85,28 @@ namespace ReC.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Static
|
#region Static
|
||||||
private static readonly IServiceCollection Services = new ServiceCollection();
|
|
||||||
|
|
||||||
#if NET8_0_OR_GREATER
|
#if NET8_0_OR_GREATER
|
||||||
private static IServiceProvider? Provider = null;
|
private static Action<IServiceCollection>? _staticConfigure = null;
|
||||||
#else
|
#else
|
||||||
private static IServiceProvider Provider = null;
|
private static Action<IServiceCollection> _staticConfigure = null;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private static readonly Lazy<IServiceProvider> LazyProvider = new Lazy<IServiceProvider>(() =>
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures and builds the static <see cref="IServiceProvider"/> for creating <see cref="ReCClient"/> instances.
|
/// Configures and builds the static <see cref="IServiceProvider"/> for creating <see cref="ReCClient"/> instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This method should only be called once during application startup.
|
/// This method should only be called once during application startup.
|
||||||
|
/// The underlying <see cref="IServiceProvider"/> is created lazily and thread-safely on first access via <see cref="Create"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="apiUri">The base URI of the ReC API.</param>
|
/// <param name="apiUri">The base URI of the ReC API.</param>
|
||||||
/// <param name="configureOptions">An optional callback to configure <see cref="ReCClientOptions"/>.</param>
|
/// <param name="configureOptions">An optional callback to configure <see cref="ReCClientOptions"/>.</param>
|
||||||
@@ -109,11 +118,9 @@ namespace ReC.Client
|
|||||||
public static void BuildStaticClient(string apiUri, Action<ReCClientOptions>? configureOptions = null)
|
public static void BuildStaticClient(string apiUri, Action<ReCClientOptions>? configureOptions = null)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if(Provider != null)
|
Action<IServiceCollection> configure = services => services.AddRecClient(apiUri, configureOptions);
|
||||||
|
if (System.Threading.Interlocked.CompareExchange(ref _staticConfigure, configure, null) != null)
|
||||||
throw new InvalidOperationException("Static Provider is already built.");
|
throw new InvalidOperationException("Static Provider is already built.");
|
||||||
|
|
||||||
Services.AddRecClient(apiUri, configureOptions);
|
|
||||||
Provider = Services.BuildServiceProvider();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -121,6 +128,7 @@ namespace ReC.Client
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This method should only be called once during application startup.
|
/// This method should only be called once during application startup.
|
||||||
|
/// The underlying <see cref="IServiceProvider"/> is created lazily and thread-safely on first access via <see cref="Create"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="configureClient">An action to configure the <see cref="HttpClient"/>.</param>
|
/// <param name="configureClient">An action to configure the <see cref="HttpClient"/>.</param>
|
||||||
/// <param name="configureOptions">An optional callback to configure <see cref="ReCClientOptions"/>.</param>
|
/// <param name="configureOptions">An optional callback to configure <see cref="ReCClientOptions"/>.</param>
|
||||||
@@ -132,25 +140,20 @@ namespace ReC.Client
|
|||||||
public static void BuildStaticClient(Action<HttpClient> configureClient, Action<ReCClientOptions>? configureOptions = null)
|
public static void BuildStaticClient(Action<HttpClient> configureClient, Action<ReCClientOptions>? configureOptions = null)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (Provider != null)
|
Action<IServiceCollection> configure = services => services.AddRecClient(configureClient, configureOptions);
|
||||||
|
if (System.Threading.Interlocked.CompareExchange(ref _staticConfigure, configure, null) != null)
|
||||||
throw new InvalidOperationException("Static Provider is already built.");
|
throw new InvalidOperationException("Static Provider is already built.");
|
||||||
|
|
||||||
Services.AddRecClient(configureClient, configureOptions);
|
|
||||||
Provider = Services.BuildServiceProvider();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="ReCClient"/> instance using the statically configured provider.
|
/// Creates a new <see cref="ReCClient"/> instance using the statically configured provider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A new instance of the <see cref="ReCClient"/>.</returns>
|
/// <returns>A new instance of the <see cref="ReCClient"/>.</returns>
|
||||||
/// <exception cref="InvalidOperationException">Thrown if <see cref="BuildStaticClient(string)"/> has not been called yet.</exception>
|
/// <exception cref="InvalidOperationException">Thrown if <see cref="BuildStaticClient(string, Action{ReCClientOptions})"/> has not been called yet.</exception>
|
||||||
[Obsolete("Use a local service collection instead of the static provider.")]
|
[Obsolete("Use a local service collection instead of the static provider.")]
|
||||||
public static ReCClient Create()
|
public static ReCClient Create()
|
||||||
{
|
{
|
||||||
if (Provider == null)
|
return LazyProvider.Value.GetRequiredService<ReCClient>();
|
||||||
throw new InvalidOperationException("Static Provider is not built. Call BuildStaticClient first.");
|
|
||||||
|
|
||||||
return Provider.GetRequiredService<ReCClient>();
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user