using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders.Physical; using Microsoft.Extensions.Hosting; using System.Collections.ObjectModel; using System.Text.Json; using static System.Collections.Specialized.BitVector32; namespace Toolkit.Foundation; public static class IHostBuilderExtension { public static IHostBuilder AddConfiguration(this IHostBuilder builder, string section) where TConfiguration : class, new() => builder.AddConfiguration(section, "Settings.json", null); public static IHostBuilder AddConfiguration(this IHostBuilder services) where TConfiguration : class, new() => services.AddConfiguration(typeof(TConfiguration).Name, "Settings.json", null); public static IHostBuilder AddConfiguration(this IHostBuilder builder, Action configurationDelegate) where TConfiguration : class, new() { TConfiguration configuration = new(); configurationDelegate.Invoke(configuration); return builder.AddConfiguration(typeof(TConfiguration).Name, "Settings.json", configuration); } public static IHostBuilder AddConfiguration(this IHostBuilder builder, Action configurationDelegate, string section) where TConfiguration : class, new() { TConfiguration configuration = new(); configurationDelegate.Invoke(configuration); return builder.AddConfiguration(section, "Settings.json", configuration); } public static IHostBuilder AddConfiguration(this IHostBuilder builder, TConfiguration configuration) where TConfiguration : class, new() => builder.AddConfiguration(configuration.GetType().Name, "Settings.json", configuration); public static IHostBuilder AddConfiguration(this IHostBuilder builder, object configuration) where TConfiguration : class, new() => builder.AddConfiguration(configuration.GetType().Name, "Settings.json", (TConfiguration?)configuration); public static IHostBuilder AddConfiguration(this IHostBuilder builder, string section, string path = "Settings.json", TConfiguration? defaultConfiguration = null, Action? serializerDelegate = null) where TConfiguration : class, new() { builder.ConfigureServices((context, services) => { HashSet sections = []; if (section.EndsWith(":*")) { section = section[..^1]; if (context.Configuration is ConfigurationRoot root) { foreach (KeyValuePair configuration in root.AsEnumerable()) { string[] segments = configuration.Key.Split(':'); if (segments.Length > 2) { string keyPrefix = string.Join(':', segments.Take(2)); if (keyPrefix.StartsWith(section) && !keyPrefix.EndsWith(":*")) { sections.Add(keyPrefix); } } } } } else { if (context.Configuration is ConfigurationRoot root) { sections.Add(section); } } foreach (string section in sections) { if (context.Properties.TryGetValue(section, out object? value)) { if (value is List configurations) { if (configurations.Contains(typeof(TConfiguration))) { return; } else { configurations.Add(typeof(TConfiguration)); } } } else { context.Properties.Add(section, new List { typeof(TConfiguration) }); } services.TryAddSingleton>(provider => { IFileInfo? fileInfo = null; if (provider.GetService() is IHostEnvironment hostEnvironment) { IFileProvider fileProvider = hostEnvironment.ContentRootFileProvider; fileInfo = fileProvider.GetFileInfo(path); } fileInfo ??= new PhysicalFileInfo(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path))); return new ConfigurationFile(fileInfo); }); services.TryAddKeyedTransient>(section, (provider, key) => { JsonSerializerOptions? defaultSerializer = null; if (serializerDelegate is not null) { defaultSerializer = new JsonSerializerOptions(); serializerDelegate.Invoke(defaultSerializer); } return new ConfigurationSource(provider.GetRequiredService>(), section, defaultSerializer); }); //services.AddHostedService>(); services.TryAddKeyedTransient>(section, (provider, key) => new ConfigurationReader(provider.GetRequiredKeyedService>(key), provider.GetRequiredKeyedService>(key))); services.TryAddKeyedTransient>(section, (provider, key) => new ConfigurationWriter(provider.GetRequiredKeyedService>(key), provider.GetRequiredKeyedService>(key))); services.TryAddKeyedTransient>(section, (provider, key) => new ConfigurationFactory(() => defaultConfiguration ?? provider.GetRequiredKeyedService(key))); services.AddTransient>(provider => new ConfigurationInitializer(provider.GetRequiredKeyedService>(section), provider.GetRequiredKeyedService>(section), provider.GetRequiredKeyedService>(section), provider.GetRequiredService())); services.AddTransient, ConfigurationInitializer>(provider => provider.GetRequiredService().Create>(section)); services.TryAddKeyedTransient>(section, (provider, key) => new WritableConfiguration(provider.GetRequiredKeyedService>(key))); services.TryAddTransient>(provider => new WritableConfiguration(provider.GetRequiredKeyedService>(section))); services.TryAddKeyedTransient>(section, (provider, key) => new ConfigurationDescriptor(section, provider.GetRequiredKeyedService>(key))); services.AddTransient(provider => provider.GetRequiredKeyedService>(section)); services.AddTransient(provider => provider.GetRequiredKeyedService>(section).Value); } }); return builder; } }