diff --git a/shared-package.props b/shared-package.props index 610d149c10..29a1927bb4 100644 --- a/shared-package.props +++ b/shared-package.props @@ -53,14 +53,14 @@ + Condition="$(MSBuildProjectName.StartsWith('Steeltoe.Configuration')) Or $(MSBuildProjectName.StartsWith('Steeltoe.Management')) Or $(MSBuildProjectName.StartsWith('Steeltoe.Connectors')) Or $(MSBuildProjectName.StartsWith('Steeltoe.Logging')) Or $(MSBuildProjectName.StartsWith('Steeltoe.Bootstrap'))"> + Condition="!$(MSBuildProjectName.StartsWith('Steeltoe.Configuration')) And !$(MSBuildProjectName.StartsWith('Steeltoe.Management')) And !$(MSBuildProjectName.StartsWith('Steeltoe.Connectors')) And !$(MSBuildProjectName.StartsWith('Steeltoe.Logging')) And !$(MSBuildProjectName.StartsWith('Steeltoe.Bootstrap'))"> $(NoWarn);SA1401;S1168;S2360;S3900;S3956;S4004;S4023 diff --git a/src/Bootstrap/src/AutoConfiguration/AssemblyExtensions.cs b/src/Bootstrap/src/AutoConfiguration/AssemblyExtensions.cs deleted file mode 100644 index cdd7546e45..0000000000 --- a/src/Bootstrap/src/AutoConfiguration/AssemblyExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License. -// See the LICENSE file in the project root for more information. - -using System.Reflection; -using System.Text.RegularExpressions; -using Steeltoe.Common.Reflection; - -namespace Steeltoe.Bootstrap.AutoConfiguration; - -internal static class AssemblyExtensions -{ - private static readonly HashSet MissingAssemblies = new(); - - internal static IEnumerable ExcludedAssemblies { get; set; } - - internal static Assembly LoadAnyVersion(object sender, ResolveEventArgs args) - { - // Load whatever version available - strip out version and culture info - static string GetSimpleName(string assemblyName) - { - return new Regex(",.*").Replace(assemblyName, string.Empty); - } - - string name = GetSimpleName(args.Name); - - if (MissingAssemblies.Contains(name)) - { - return null; - } - - // AssemblyName.Equals() returns false when path and full name are identical, so the code below - // avoids a crash caused by inserting duplicate keys in dictionary. - Dictionary assemblies = AppDomain.CurrentDomain.GetAssemblies().GroupBy(asm => asm.GetName().Name) - .ToDictionary(grouping => grouping.Key, grouping => grouping.First()); - - if (assemblies.TryGetValue(name, out Assembly assembly)) - { - return assembly; - } - - if (args.Name.Contains(".resources", StringComparison.Ordinal)) - { - return args.RequestingAssembly; - } - - MissingAssemblies.Add(name); // throw it in there to prevent recursive attempts to resolve - assembly = Assembly.Load(name); - MissingAssemblies.Remove(name); - return assembly; - } - - internal static bool IsAssemblyLoaded(string assemblyName) - { - if (ExcludedAssemblies.Contains(assemblyName)) - { - return false; - } - - return ReflectionHelpers.IsAssemblyLoaded(assemblyName); - } - - internal static bool IsEitherAssemblyLoaded(string assemblyName1, string assemblyName2) - { - return IsAssemblyLoaded(assemblyName1) || IsAssemblyLoaded(assemblyName2); - } -} diff --git a/src/Bootstrap/src/AutoConfiguration/AssemblyLoader.cs b/src/Bootstrap/src/AutoConfiguration/AssemblyLoader.cs new file mode 100644 index 0000000000..6848112b21 --- /dev/null +++ b/src/Bootstrap/src/AutoConfiguration/AssemblyLoader.cs @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using System.Reflection; +using Steeltoe.Common; + +namespace Steeltoe.Bootstrap.AutoConfiguration; + +internal sealed class AssemblyLoader +{ + public IReadOnlySet AssemblyNamesToExclude { get; } + + static AssemblyLoader() + { + AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolver.LoadAnyVersion; + } + + public AssemblyLoader(IReadOnlySet assemblyNamesToExclude) + { + ArgumentGuard.NotNull(assemblyNamesToExclude); + ArgumentGuard.ElementsNotNullOrEmpty(assemblyNamesToExclude); + + // Take a copy to ensure comparisons are case insensitive. + AssemblyNamesToExclude = assemblyNamesToExclude.ToHashSet(StringComparer.OrdinalIgnoreCase); + } + + public bool IsAssemblyLoaded(string assemblyName) + { + ArgumentGuard.NotNullOrEmpty(assemblyName); + + if (AssemblyNamesToExclude.Contains(assemblyName)) + { + return false; + } + + return TryLoadAssembly(assemblyName); + } + + private static bool TryLoadAssembly(string assemblyName) + { + try + { + _ = Assembly.Load(assemblyName); + return true; + } + catch (Exception exception) when (exception is ArgumentException or IOException or BadImageFormatException) + { + return false; + } + } + + private static class AssemblyResolver + { + private static readonly HashSet FailedAssemblyNames = new(StringComparer.OrdinalIgnoreCase); + + public static Assembly? LoadAnyVersion(object? sender, ResolveEventArgs args) + { + // Workaround for Sonar bug at https://github.com/SonarSource/sonar-dotnet/issues/8371. + _ = sender; + + // Load whatever version is available (ignore Version, Culture and PublicKeyToken). + string assemblySimpleName = new AssemblyName(args.Name).Name!; + + if (FailedAssemblyNames.Contains(assemblySimpleName)) + { + return null; + } + + // AssemblyName.Equals() returns false when path and full name are identical, so the code below + // avoids a crash caused by inserting duplicate keys in the dictionary. + Dictionary assembliesBySimpleName = AppDomain.CurrentDomain.GetAssemblies().GroupBy(nextAssembly => nextAssembly.GetName().Name!) + .ToDictionary(grouping => grouping.Key, grouping => grouping.First(), StringComparer.OrdinalIgnoreCase); + + if (assembliesBySimpleName.TryGetValue(assemblySimpleName, out Assembly? assembly)) + { + return assembly; + } + + if (args.Name.Contains(".resources", StringComparison.Ordinal)) + { + return args.RequestingAssembly; + } + + // Prevent recursive attempts to resolve. + FailedAssemblyNames.Add(assemblySimpleName); + assembly = Assembly.Load(assemblySimpleName); + FailedAssemblyNames.Remove(assemblySimpleName); + + return assembly; + } + } +} diff --git a/src/Bootstrap/src/AutoConfiguration/BootstrapScanner.cs b/src/Bootstrap/src/AutoConfiguration/BootstrapScanner.cs new file mode 100644 index 0000000000..c06bdc8937 --- /dev/null +++ b/src/Bootstrap/src/AutoConfiguration/BootstrapScanner.cs @@ -0,0 +1,293 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Steeltoe.Common; +using Steeltoe.Common.DynamicTypeAccess; +using Steeltoe.Common.Hosting; +using Steeltoe.Configuration.CloudFoundry; +using Steeltoe.Configuration.ConfigServer; +using Steeltoe.Configuration.Kubernetes; +using Steeltoe.Configuration.Placeholder; +using Steeltoe.Configuration.RandomValue; +using Steeltoe.Connectors.CosmosDb; +using Steeltoe.Connectors.CosmosDb.DynamicTypeAccess; +using Steeltoe.Connectors.MongoDb; +using Steeltoe.Connectors.MongoDb.DynamicTypeAccess; +using Steeltoe.Connectors.MySql; +using Steeltoe.Connectors.MySql.DynamicTypeAccess; +using Steeltoe.Connectors.PostgreSql; +using Steeltoe.Connectors.PostgreSql.DynamicTypeAccess; +using Steeltoe.Connectors.RabbitMQ; +using Steeltoe.Connectors.RabbitMQ.DynamicTypeAccess; +using Steeltoe.Connectors.Redis; +using Steeltoe.Connectors.Redis.DynamicTypeAccess; +using Steeltoe.Connectors.SqlServer; +using Steeltoe.Connectors.SqlServer.RuntimeTypeAccess; +using Steeltoe.Discovery.Client; +using Steeltoe.Logging.DynamicSerilog; +using Steeltoe.Management.Endpoint; +using Steeltoe.Management.Kubernetes; +using Steeltoe.Management.Prometheus; +using Steeltoe.Management.Tracing; +using Steeltoe.Management.Wavefront; +using Steeltoe.Management.Wavefront.Exporters; +using Steeltoe.Security.Authentication.CloudFoundry; + +namespace Steeltoe.Bootstrap.AutoConfiguration; + +internal sealed class BootstrapScanner +{ + private readonly HostBuilderWrapper _wrapper; + private readonly AssemblyLoader _loader; + private readonly ILoggerFactory _loggerFactory; + private readonly ILogger _logger; + + public BootstrapScanner(HostBuilderWrapper wrapper, IReadOnlySet assemblyNamesToExclude, ILoggerFactory loggerFactory) + { + ArgumentGuard.NotNull(wrapper); + ArgumentGuard.NotNull(assemblyNamesToExclude); + ArgumentGuard.NotNull(loggerFactory); + + _wrapper = wrapper; + _loader = new AssemblyLoader(assemblyNamesToExclude); + _loggerFactory = loggerFactory; + _logger = loggerFactory.CreateLogger("Steeltoe.Bootstrap.AutoConfiguration"); + } + + public void ConfigureSteeltoe() + { + if (!WireIfLoaded(WireConfigServer, SteeltoeAssemblyNames.ConfigurationConfigServer)) + { + WireIfLoaded(WireCloudFoundryConfiguration, SteeltoeAssemblyNames.ConfigurationCloudFoundry); + } + + if (Platform.IsKubernetes && _loader.IsAssemblyLoaded(SteeltoeAssemblyNames.ConfigurationKubernetes)) + { + WireKubernetesConfiguration(); + } + + WireIfLoaded(WireRandomValueProvider, SteeltoeAssemblyNames.ConfigurationRandomValue); + WireIfLoaded(WirePlaceholderResolver, SteeltoeAssemblyNames.ConfigurationPlaceholder); + WireIfLoaded(WireConnectors, SteeltoeAssemblyNames.Connectors); + WireIfLoaded(WireDynamicSerilog, SteeltoeAssemblyNames.LoggingDynamicSerilog); + WireIfLoaded(WireDiscoveryClient, SteeltoeAssemblyNames.DiscoveryClient); + + if (_loader.IsAssemblyLoaded(SteeltoeAssemblyNames.ManagementKubernetes)) + { + WireIfLoaded(WireKubernetesActuators, SteeltoeAssemblyNames.ManagementKubernetes); + } + else + { + WireIfLoaded(WireAllActuators, SteeltoeAssemblyNames.ManagementEndpoint); + } + + WireIfLoaded(WirePrometheus, SteeltoeAssemblyNames.ManagementPrometheus); + WireIfLoaded(WireWavefrontMetrics, SteeltoeAssemblyNames.ManagementWavefront); + WireIfLoaded(WireDistributedTracing, SteeltoeAssemblyNames.ManagementTracing); + WireIfLoaded(WireCloudFoundryContainerIdentity, SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry); + } + + private void WireConfigServer() + { + _wrapper.ConfigureAppConfiguration((context, configurationBuilder) => configurationBuilder.AddConfigServer(context.HostEnvironment, _loggerFactory)); + _wrapper.ConfigureServices(services => services.AddConfigServerServices()); + + _logger.LogInformation("Configured Config Server configuration provider"); + } + + private void WireCloudFoundryConfiguration() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.AddCloudFoundry()); + + _logger.LogInformation("Configured Cloud Foundry configuration provider"); + } + + private void WireKubernetesConfiguration() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.AddKubernetes(_loggerFactory)); + _wrapper.ConfigureServices(services => services.AddKubernetesConfigurationServices()); + + _logger.LogInformation("Configured Kubernetes configuration provider"); + } + + private void WireRandomValueProvider() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.AddRandomValueSource(_loggerFactory)); + + _logger.LogInformation("Configured random value configuration provider"); + } + + private void WirePlaceholderResolver() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.AddPlaceholderResolver(_loggerFactory)); + + _logger.LogInformation("Configured placeholder configuration provider"); + } + + private void WireConnectors() + { + WireIfAnyLoaded(WireCosmosDbConnector, CosmosDbPackageResolver.Default); + WireIfAnyLoaded(WireMongoDbConnector, MongoDbPackageResolver.Default); + WireIfAnyLoaded(WireMySqlConnector, MySqlPackageResolver.Default); + WireIfAnyLoaded(WirePostgreSqlConnector, PostgreSqlPackageResolver.Default); + WireIfAnyLoaded(WireRabbitMQConnector, RabbitMQPackageResolver.Default); + WireIfAnyLoaded(WireRedisConnector, StackExchangeRedisPackageResolver.Default, MicrosoftRedisPackageResolver.Default); + WireIfAnyLoaded(WireSqlServerConnector, SqlServerPackageResolver.Default); + } + + private void WireCosmosDbConnector() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.ConfigureCosmosDb()); + _wrapper.ConfigureServices((host, services) => services.AddCosmosDb(host.Configuration)); + + _logger.LogInformation("Configured CosmosDB connector"); + } + + private void WireMongoDbConnector() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.ConfigureMongoDb()); + _wrapper.ConfigureServices((host, services) => services.AddMongoDb(host.Configuration)); + + _logger.LogInformation("Configured MongoDB connector"); + } + + private void WireMySqlConnector() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.ConfigureMySql()); + _wrapper.ConfigureServices((host, services) => services.AddMySql(host.Configuration)); + + _logger.LogInformation("Configured MySQL connector"); + } + + private void WirePostgreSqlConnector() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.ConfigurePostgreSql()); + _wrapper.ConfigureServices((host, services) => services.AddPostgreSql(host.Configuration)); + + _logger.LogInformation("Configured PostgreSQL connector"); + } + + private void WireRabbitMQConnector() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.ConfigureRabbitMQ()); + _wrapper.ConfigureServices((host, services) => services.AddRabbitMQ(host.Configuration)); + + _logger.LogInformation("Configured RabbitMQ connector"); + } + + private void WireRedisConnector() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.ConfigureRedis()); + _wrapper.ConfigureServices((host, services) => services.AddRedis(host.Configuration)); + + _logger.LogInformation("Configured StackExchange Redis connector"); + + // Intentionally ignoring excluded assemblies here. + if (MicrosoftRedisPackageResolver.Default.IsAvailable()) + { + _logger.LogInformation("Configured Redis distributed cache connector"); + } + } + + private void WireSqlServerConnector() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.ConfigureSqlServer()); + _wrapper.ConfigureServices((host, services) => services.AddSqlServer(host.Configuration)); + + _logger.LogInformation("Configured SQL Server connector"); + } + + private void WireDynamicSerilog() + { + _wrapper.AddDynamicSerilog(null, false); + + _logger.LogInformation("Configured dynamic console logger for Serilog"); + } + + private void WireDiscoveryClient() + { + _wrapper.ConfigureServices((context, services) => services.AddDiscoveryClient(context.Configuration)); + + _logger.LogInformation("Configured discovery client"); + } + + private void WireKubernetesActuators() + { + _wrapper.AddKubernetesActuators(null); + + _logger.LogInformation("Configured Kubernetes actuators"); + } + + private void WireAllActuators() + { + _wrapper.AddAllActuators(null, MediaTypeVersion.V2, null); + + _logger.LogInformation("Configured actuators"); + } + + private void WirePrometheus() + { + _wrapper.ConfigureServices(services => services.AddPrometheusActuator()); + + _logger.LogInformation("Configured Prometheus"); + } + + private void WireWavefrontMetrics() + { + _wrapper.ConfigureServices((context, services) => + { + if (HasWavefront(context.Configuration)) + { + services.AddWavefrontMetrics(); + _logger.LogInformation("Configured Wavefront metrics"); + } + }); + } + + private static bool HasWavefront(IConfiguration configuration) + { + var options = new WavefrontExporterOptions(); + + var configurer = new ConfigureWavefrontExporterOptions(configuration); + configurer.Configure(options); + + return !string.IsNullOrEmpty(options.Uri); + } + + private void WireDistributedTracing() + { + _wrapper.ConfigureServices(services => services.AddDistributedTracingAspNetCore()); + + _logger.LogInformation("Configured distributed tracing"); + } + + private void WireCloudFoundryContainerIdentity() + { + _wrapper.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.AddCloudFoundryContainerIdentity()); + _wrapper.ConfigureServices(services => services.AddCloudFoundryCertificateAuth()); + + _logger.LogInformation("Configured Cloud Foundry mTLS security"); + } + + private bool WireIfLoaded(Action wireAction, string assemblyName) + { + if (!_loader.IsAssemblyLoaded(assemblyName)) + { + return false; + } + + wireAction(); + return true; + } + + private void WireIfAnyLoaded(Action wireAction, params PackageResolver[] packageResolvers) + { + if (Array.Exists(packageResolvers, packageResolver => packageResolver.IsAvailable(_loader.AssemblyNamesToExclude))) + { + wireAction(); + } + } +} diff --git a/src/Bootstrap/src/AutoConfiguration/ConfigurationExtensions.cs b/src/Bootstrap/src/AutoConfiguration/ConfigurationExtensions.cs deleted file mode 100644 index 55bc4db0fc..0000000000 --- a/src/Bootstrap/src/AutoConfiguration/ConfigurationExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.Configuration; -using Steeltoe.Common; -using Steeltoe.Management.Wavefront.Exporters; - -namespace Steeltoe.Bootstrap.AutoConfiguration; - -internal static class ConfigurationExtensions -{ - public static bool HasWavefront(this IConfiguration configuration) - { - ArgumentGuard.NotNull(configuration); - - var options = new WavefrontExporterOptions(); - - var configurer = new ConfigureWavefrontExporterOptions(configuration); - configurer.Configure(options); - - return !string.IsNullOrEmpty(options.Uri); - } -} diff --git a/src/Bootstrap/src/AutoConfiguration/HostBuilderExtensions.cs b/src/Bootstrap/src/AutoConfiguration/HostBuilderExtensions.cs index 403ad11d82..fb9365b22d 100644 --- a/src/Bootstrap/src/AutoConfiguration/HostBuilderExtensions.cs +++ b/src/Bootstrap/src/AutoConfiguration/HostBuilderExtensions.cs @@ -2,355 +2,93 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System.Runtime.CompilerServices; +using System.Collections.Immutable; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Steeltoe.Common; -using Steeltoe.Common.DynamicTypeAccess; -using Steeltoe.Configuration.CloudFoundry; -using Steeltoe.Configuration.ConfigServer; -using Steeltoe.Configuration.Kubernetes; -using Steeltoe.Configuration.Placeholder; -using Steeltoe.Configuration.RandomValue; -using Steeltoe.Connectors.CosmosDb; -using Steeltoe.Connectors.CosmosDb.DynamicTypeAccess; -using Steeltoe.Connectors.MongoDb; -using Steeltoe.Connectors.MongoDb.DynamicTypeAccess; -using Steeltoe.Connectors.MySql; -using Steeltoe.Connectors.MySql.DynamicTypeAccess; -using Steeltoe.Connectors.PostgreSql; -using Steeltoe.Connectors.PostgreSql.DynamicTypeAccess; -using Steeltoe.Connectors.RabbitMQ; -using Steeltoe.Connectors.RabbitMQ.DynamicTypeAccess; -using Steeltoe.Connectors.Redis; -using Steeltoe.Connectors.Redis.DynamicTypeAccess; -using Steeltoe.Connectors.SqlServer; -using Steeltoe.Connectors.SqlServer.RuntimeTypeAccess; -using Steeltoe.Discovery.Client; -using Steeltoe.Logging.DynamicSerilog; -using Steeltoe.Management.Endpoint; -using Steeltoe.Management.Kubernetes; -using Steeltoe.Management.Prometheus; -using Steeltoe.Management.Tracing; -using Steeltoe.Management.Wavefront; -using Steeltoe.Security.Authentication.CloudFoundry; +using Steeltoe.Common.Hosting; namespace Steeltoe.Bootstrap.AutoConfiguration; public static class HostBuilderExtensions { - private const string LoggerName = "Steeltoe.AutoConfiguration"; - private static ILoggerFactory _loggerFactory; + private static readonly IReadOnlySet EmptySet = ImmutableHashSet.Empty; - static HostBuilderExtensions() + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddSteeltoe(this IHostBuilder builder) { - AppDomain currentDomain = AppDomain.CurrentDomain; - currentDomain.AssemblyResolve += AssemblyExtensions.LoadAnyVersion; + return AddSteeltoe(builder, EmptySet, NullLoggerFactory.Instance); } /// - /// Automatically configure Steeltoe packages that have been added as NuGet references. - /// - /// PLEASE NOTE: No extensions to IApplicationBuilder will be configured. + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. /// /// - /// Your . + /// The to configure. /// - /// - /// A list of assemblies to exclude from auto-configuration. For ease of use, select from . + /// + /// The set of assembly names to exclude from auto-configuration. For ease of use, select from the constants in . /// - /// - /// For logging within auto-configuration. - /// - public static IHostBuilder AddSteeltoe(this IHostBuilder builder, IEnumerable exclusions = null, ILoggerFactory loggerFactory = null) - { - AssemblyExtensions.ExcludedAssemblies = exclusions ?? new List(); - _loggerFactory = loggerFactory ?? NullLoggerFactory.Instance; - ILogger logger = _loggerFactory.CreateLogger(LoggerName); - builder.Properties[LoggerName] = logger; - - if (!builder.WireIfLoaded(WireConfigServer, SteeltoeAssemblyNames.ConfigurationConfigServer)) - { - builder.WireIfLoaded(WireCloudFoundryConfiguration, SteeltoeAssemblyNames.ConfigurationCloudFoundry); - } - - if (Platform.IsKubernetes && AssemblyExtensions.IsAssemblyLoaded(SteeltoeAssemblyNames.ConfigurationKubernetes)) - { - WireKubernetesConfiguration(builder); - } - - builder.WireIfLoaded(WireRandomValueProvider, SteeltoeAssemblyNames.ConfigurationRandomValue); - - builder.WireIfLoaded(WirePlaceholderResolver, SteeltoeAssemblyNames.ConfigurationPlaceholder); - - builder.WireIfLoaded(WireConnectors, SteeltoeAssemblyNames.Connectors); - - builder.WireIfLoaded(WireDynamicSerilog, SteeltoeAssemblyNames.LoggingDynamicSerilog); - builder.WireIfLoaded(WireDiscoveryClient, SteeltoeAssemblyNames.DiscoveryClient); - - if (AssemblyExtensions.IsAssemblyLoaded(SteeltoeAssemblyNames.ManagementKubernetes)) - { - builder.WireIfLoaded(WireKubernetesActuators, SteeltoeAssemblyNames.ManagementKubernetes); - } - else - { - builder.WireIfLoaded(WireAllActuators, SteeltoeAssemblyNames.ManagementEndpoint); - } - - builder.WireIfLoaded(WireSteeltoePrometheus, SteeltoeAssemblyNames.ManagementPrometheus); - - builder.WireIfLoaded(WireWavefrontMetrics, SteeltoeAssemblyNames.ManagementWavefront); - - builder.WireIfLoaded(WireDistributedTracing, SteeltoeAssemblyNames.ManagementTracing); - - builder.WireIfLoaded(WireCloudFoundryContainerIdentity, SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry); - return builder; - } - - private static bool WireIfLoaded(this IHostBuilder hostBuilder, Action action, params string[] assembly) - { - if (Array.TrueForAll(assembly, AssemblyExtensions.IsAssemblyLoaded)) - { - action(hostBuilder); - return true; - } - - return false; - } - - private static void WireIfAnyLoaded(this IHostBuilder hostBuilder, Action action, IReadOnlySet assemblyNamesToExclude, - params PackageResolver[] packageResolvers) - { - if (Array.Exists(packageResolvers, packageResolver => packageResolver.IsAvailable(assemblyNamesToExclude))) - { - action(hostBuilder); - } - } - - private static void Log(this IHostBuilder host, string message) - { - var logger = (ILogger)host.Properties[LoggerName]; - logger.LogInformation(message); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireConfigServer(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration((context, cfg) => cfg.AddConfigServer(context.HostingEnvironment, _loggerFactory)) - .ConfigureServices((_, services) => services.AddConfigServerServices()).Log(LogMessages.WireConfigServerConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCloudFoundryConfiguration(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddCloudFoundry()).Log(LogMessages.WireCloudFoundryConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireKubernetesConfiguration(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddKubernetes(_loggerFactory)) - .ConfigureServices(serviceCollection => serviceCollection.AddKubernetesConfigurationServices()).Log(LogMessages.WireKubernetesConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRandomValueProvider(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddRandomValueSource(_loggerFactory)).Log(LogMessages.WireRandomValueConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WirePlaceholderResolver(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddPlaceholderResolver(_loggerFactory)).Log(LogMessages.WirePlaceholderConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireConnectors(IHostBuilder builder) - { - var assemblyNamesToExclude = new HashSet(AssemblyExtensions.ExcludedAssemblies, StringComparer.OrdinalIgnoreCase); - - builder.WireIfAnyLoaded(WireCosmosDbConnector, assemblyNamesToExclude, CosmosDbPackageResolver.Default); - builder.WireIfAnyLoaded(WireMongoDbConnector, assemblyNamesToExclude, MongoDbPackageResolver.Default); - builder.WireIfAnyLoaded(WireMySqlConnector, assemblyNamesToExclude, MySqlPackageResolver.Default); - builder.WireIfAnyLoaded(WirePostgreSqlConnector, assemblyNamesToExclude, PostgreSqlPackageResolver.Default); - builder.WireIfAnyLoaded(WireRabbitMQConnector, assemblyNamesToExclude, RabbitMQPackageResolver.Default); - builder.WireIfAnyLoaded(WireRedisConnector, assemblyNamesToExclude, StackExchangeRedisPackageResolver.Default, MicrosoftRedisPackageResolver.Default); - builder.WireIfAnyLoaded(WireSqlServerConnector, assemblyNamesToExclude, SqlServerPackageResolver.Default); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireMySqlConnector(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureMySql(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddMySql(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireMySqlConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCosmosDbConnector(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureCosmosDb(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddCosmosDb(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireCosmosDbConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireMongoDbConnector(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureMongoDb(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddMongoDb(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireMongoDbConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WirePostgreSqlConnector(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigurePostgreSql(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddPostgreSql(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WirePostgreSqlConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRabbitMQConnector(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureRabbitMQ(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddRabbitMQ(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireRabbitMQConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRedisConnector(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureRedis(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddRedis(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireStackExchangeRedisConnector); - - // Intentionally ignoring excluded assemblies here. - if (MicrosoftRedisPackageResolver.Default.IsAvailable()) - { - hostBuilder.Log(LogMessages.WireDistributedCacheRedisConnector); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireSqlServerConnector(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureSqlServer(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddSqlServer(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireSqlServerConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDiscoveryClient(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureServices((host, svc) => svc.AddDiscoveryClient(host.Configuration)).Log(LogMessages.WireDiscoveryClient); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDistributedTracing(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureServices((_, svc) => svc.AddDistributedTracingAspNetCore()).Log(LogMessages.WireDistributedTracing); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireKubernetesActuators(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddSteeltoe(this IHostBuilder builder, IReadOnlySet assemblyNamesToExclude) { - hostBuilder.AddKubernetesActuators().Log(LogMessages.WireKubernetesActuators); + return AddSteeltoe(builder, assemblyNamesToExclude, NullLoggerFactory.Instance); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireAllActuators(this IHostBuilder hostBuilder) + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// Used for internal logging. Pass to disable logging. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddSteeltoe(this IHostBuilder builder, ILoggerFactory loggerFactory) { - hostBuilder.AddAllActuators().Log(LogMessages.WireAllActuators); + return AddSteeltoe(builder, EmptySet, loggerFactory); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireWavefrontMetrics(this IHostBuilder hostBuilder) + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// The set of assembly names to exclude from auto-configuration. For ease of use, select from the constants in . + /// + /// + /// Used for internal logging. Pass to disable logging. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddSteeltoe(this IHostBuilder builder, IReadOnlySet assemblyNamesToExclude, ILoggerFactory loggerFactory) { - hostBuilder.ConfigureServices((context, collection) => - { - if (context.Configuration.HasWavefront()) - { - collection.AddWavefrontMetrics(); - hostBuilder.Log(LogMessages.WireWavefrontMetrics); - } - }); - } + ArgumentGuard.NotNull(builder); + ArgumentGuard.NotNull(assemblyNamesToExclude); + ArgumentGuard.NotNull(loggerFactory); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireSteeltoePrometheus(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureServices((_, collection) => collection.AddPrometheusActuator()).Log(LogMessages.WirePrometheus); - } + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDynamicSerilog(this IHostBuilder hostBuilder) - { - hostBuilder.AddDynamicSerilog().Log(LogMessages.WireDynamicSerilog); - } + var scanner = new BootstrapScanner(wrapper, assemblyNamesToExclude, loggerFactory); + scanner.ConfigureSteeltoe(); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCloudFoundryContainerIdentity(this IHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddCloudFoundryContainerIdentity()).ConfigureServices((_, svc) => svc.AddCloudFoundryCertificateAuth()) - .Log(LogMessages.WireCloudFoundryContainerIdentity); + return builder; } } diff --git a/src/Bootstrap/src/AutoConfiguration/LogMessages.cs b/src/Bootstrap/src/AutoConfiguration/LogMessages.cs deleted file mode 100644 index b321f3c85e..0000000000 --- a/src/Bootstrap/src/AutoConfiguration/LogMessages.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License. -// See the LICENSE file in the project root for more information. - -namespace Steeltoe.Bootstrap.AutoConfiguration; - -internal static class LogMessages -{ - public const string WireAllActuators = "Configured actuators"; - public const string WireKubernetesActuators = "Configured Kubernetes actuators"; - - public const string WireCloudFoundryConfiguration = "Configured Cloud Foundry configuration provider"; - public const string WireKubernetesConfiguration = "Configured Kubernetes configuration provider"; - public const string WireConfigServerConfiguration = "Configured Config Server configuration provider"; - public const string WirePlaceholderConfiguration = "Configured placeholder configuration provider"; - public const string WireRandomValueConfiguration = "Configured random value configuration provider"; - - public const string WireCloudFoundryContainerIdentity = "Configured Cloud Foundry MTLs security"; - public const string WireDiscoveryClient = "Configured discovery client"; - public const string WireDistributedTracing = "Configured distributed tracing"; - public const string WireDynamicSerilog = "Configured dynamic console logger for Serilog"; - public const string WireWavefrontMetrics = "Configured Wavefront metrics"; - public const string WirePrometheus = "Configured Prometheus"; - - public const string WireCosmosDbConnector = "Configured CosmosDB connector"; - public const string WireMongoDbConnector = "Configured MongoDB connector"; - public const string WireMySqlConnector = "Configured MySQL connector"; - public const string WirePostgreSqlConnector = "Configured PostgreSQL connector"; - public const string WireRabbitMQConnector = "Configured RabbitMQ connector"; - public const string WireStackExchangeRedisConnector = "Configured StackExchange Redis connector"; - public const string WireDistributedCacheRedisConnector = "Configured Redis distributed cache connector"; - public const string WireSqlServerConnector = "Configured SQL Server connector"; -} diff --git a/src/Bootstrap/src/AutoConfiguration/PublicAPI.Shipped.txt b/src/Bootstrap/src/AutoConfiguration/PublicAPI.Shipped.txt new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/src/Bootstrap/src/AutoConfiguration/PublicAPI.Shipped.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/Bootstrap/src/AutoConfiguration/PublicAPI.Unshipped.txt b/src/Bootstrap/src/AutoConfiguration/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000..d16ec2189c --- /dev/null +++ b/src/Bootstrap/src/AutoConfiguration/PublicAPI.Unshipped.txt @@ -0,0 +1,31 @@ +#nullable enable +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ConfigurationCloudFoundry = "Steeltoe.Configuration.CloudFoundry" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ConfigurationConfigServer = "Steeltoe.Configuration.ConfigServer" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ConfigurationKubernetes = "Steeltoe.Configuration.Kubernetes" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ConfigurationPlaceholder = "Steeltoe.Configuration.Placeholder" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ConfigurationRandomValue = "Steeltoe.Configuration.RandomValue" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.Connectors = "Steeltoe.Connectors" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.DiscoveryClient = "Steeltoe.Discovery.Client" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.LoggingDynamicSerilog = "Steeltoe.Logging.DynamicSerilog" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ManagementEndpoint = "Steeltoe.Management.Endpoint" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ManagementKubernetes = "Steeltoe.Management.Kubernetes" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ManagementPrometheus = "Steeltoe.Management.Prometheus" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ManagementTracing = "Steeltoe.Management.Tracing" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.ManagementWavefront = "Steeltoe.Management.Wavefront" -> string! +const Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry = "Steeltoe.Security.Authentication.CloudFoundry" -> string! +static Steeltoe.Bootstrap.AutoConfiguration.HostBuilderExtensions.AddSteeltoe(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.HostBuilderExtensions.AddSteeltoe(this Microsoft.Extensions.Hosting.IHostBuilder! builder, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.HostBuilderExtensions.AddSteeltoe(this Microsoft.Extensions.Hosting.IHostBuilder! builder, System.Collections.Generic.IReadOnlySet! assemblyNamesToExclude) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.HostBuilderExtensions.AddSteeltoe(this Microsoft.Extensions.Hosting.IHostBuilder! builder, System.Collections.Generic.IReadOnlySet! assemblyNamesToExclude, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.WebApplicationBuilderExtensions.AddSteeltoe(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.WebApplicationBuilderExtensions.AddSteeltoe(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.WebApplicationBuilderExtensions.AddSteeltoe(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, System.Collections.Generic.IReadOnlySet! assemblyNamesToExclude) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.WebApplicationBuilderExtensions.AddSteeltoe(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, System.Collections.Generic.IReadOnlySet! assemblyNamesToExclude, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.WebHostBuilderExtensions.AddSteeltoe(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.WebHostBuilderExtensions.AddSteeltoe(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.WebHostBuilderExtensions.AddSteeltoe(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, System.Collections.Generic.IReadOnlySet! assemblyNamesToExclude) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Bootstrap.AutoConfiguration.WebHostBuilderExtensions.AddSteeltoe(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, System.Collections.Generic.IReadOnlySet! assemblyNamesToExclude, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +Steeltoe.Bootstrap.AutoConfiguration.HostBuilderExtensions +Steeltoe.Bootstrap.AutoConfiguration.SteeltoeAssemblyNames +Steeltoe.Bootstrap.AutoConfiguration.WebApplicationBuilderExtensions +Steeltoe.Bootstrap.AutoConfiguration.WebHostBuilderExtensions diff --git a/src/Bootstrap/src/AutoConfiguration/Steeltoe.Bootstrap.AutoConfiguration.csproj b/src/Bootstrap/src/AutoConfiguration/Steeltoe.Bootstrap.AutoConfiguration.csproj index 39eb33e85e..b1de6e9108 100644 --- a/src/Bootstrap/src/AutoConfiguration/Steeltoe.Bootstrap.AutoConfiguration.csproj +++ b/src/Bootstrap/src/AutoConfiguration/Steeltoe.Bootstrap.AutoConfiguration.csproj @@ -4,6 +4,7 @@ Package for automatically configuring Steeltoe packages that have separately been added to a project. Autoconfiguration;automatic configuration;application bootstrapping true + enable @@ -13,6 +14,7 @@ + diff --git a/src/Bootstrap/src/AutoConfiguration/SteeltoeAssemblyNames.cs b/src/Bootstrap/src/AutoConfiguration/SteeltoeAssemblyNames.cs index cd5c279b68..e34691d2d8 100644 --- a/src/Bootstrap/src/AutoConfiguration/SteeltoeAssemblyNames.cs +++ b/src/Bootstrap/src/AutoConfiguration/SteeltoeAssemblyNames.cs @@ -6,6 +6,9 @@ namespace Steeltoe.Bootstrap.AutoConfiguration; +/// +/// Lists the names of Steeltoe assemblies that are used in auto-configuration. +/// public static class SteeltoeAssemblyNames { public const string ConfigurationCloudFoundry = "Steeltoe.Configuration.CloudFoundry"; @@ -23,6 +26,14 @@ public static class SteeltoeAssemblyNames public const string ManagementWavefront = "Steeltoe.Management.Wavefront"; public const string SecurityAuthenticationCloudFoundry = "Steeltoe.Security.Authentication.CloudFoundry"; - internal static readonly IReadOnlyCollection All = typeof(SteeltoeAssemblyNames).GetFields().Where(field => field.FieldType == typeof(string)) - .Select(field => field.GetValue(null)).Cast().ToArray(); + internal static readonly IReadOnlySet All = typeof(SteeltoeAssemblyNames).GetFields().Where(field => field.FieldType == typeof(string)) + .Select(field => field.GetValue(null)).Cast().ToHashSet(); + + internal static IReadOnlySet Only(string assemblyName) + { + return All.Except(new[] + { + assemblyName + }).ToHashSet(); + } } diff --git a/src/Bootstrap/src/AutoConfiguration/WebApplicationBuilderExtensions.cs b/src/Bootstrap/src/AutoConfiguration/WebApplicationBuilderExtensions.cs index 4ae4fca40a..9abfd857d0 100644 --- a/src/Bootstrap/src/AutoConfiguration/WebApplicationBuilderExtensions.cs +++ b/src/Bootstrap/src/AutoConfiguration/WebApplicationBuilderExtensions.cs @@ -2,308 +2,94 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System.Runtime.CompilerServices; +using System.Collections.Immutable; using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Steeltoe.Common; -using Steeltoe.Common.DynamicTypeAccess; -using Steeltoe.Configuration.CloudFoundry; -using Steeltoe.Configuration.ConfigServer; -using Steeltoe.Configuration.Kubernetes; -using Steeltoe.Configuration.Placeholder; -using Steeltoe.Configuration.RandomValue; -using Steeltoe.Connectors.CosmosDb; -using Steeltoe.Connectors.CosmosDb.DynamicTypeAccess; -using Steeltoe.Connectors.MongoDb; -using Steeltoe.Connectors.MongoDb.DynamicTypeAccess; -using Steeltoe.Connectors.MySql; -using Steeltoe.Connectors.MySql.DynamicTypeAccess; -using Steeltoe.Connectors.PostgreSql; -using Steeltoe.Connectors.PostgreSql.DynamicTypeAccess; -using Steeltoe.Connectors.RabbitMQ; -using Steeltoe.Connectors.RabbitMQ.DynamicTypeAccess; -using Steeltoe.Connectors.Redis; -using Steeltoe.Connectors.Redis.DynamicTypeAccess; -using Steeltoe.Connectors.SqlServer; -using Steeltoe.Connectors.SqlServer.RuntimeTypeAccess; -using Steeltoe.Discovery.Client; -using Steeltoe.Logging.DynamicLogger; -using Steeltoe.Logging.DynamicSerilog; -using Steeltoe.Management.Endpoint; -using Steeltoe.Management.Kubernetes; -using Steeltoe.Management.Prometheus; -using Steeltoe.Management.Tracing; -using Steeltoe.Management.Wavefront; -using Steeltoe.Security.Authentication.CloudFoundry; +using Steeltoe.Common.Hosting; namespace Steeltoe.Bootstrap.AutoConfiguration; public static class WebApplicationBuilderExtensions { - private const string LoggerName = "Steeltoe.AutoConfiguration"; - private static ILoggerFactory _loggerFactory; - private static ILogger _logger; + private static readonly IReadOnlySet EmptySet = ImmutableHashSet.Empty; - static WebApplicationBuilderExtensions() + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddSteeltoe(this WebApplicationBuilder builder) { - AppDomain currentDomain = AppDomain.CurrentDomain; - currentDomain.AssemblyResolve += AssemblyExtensions.LoadAnyVersion; + return AddSteeltoe(builder, EmptySet, NullLoggerFactory.Instance); } /// - /// Automatically configure Steeltoe packages that have been added as NuGet references. - /// - /// PLEASE NOTE: No extensions to IApplicationBuilder will be configured. + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. /// /// - /// Your . + /// The to configure. /// - /// - /// A list of assemblies to exclude from auto-configuration. For ease of use, select from . + /// + /// The set of assembly names to exclude from auto-configuration. For ease of use, select from the constants in . /// - /// - /// For logging within auto-configuration. - /// - public static WebApplicationBuilder AddSteeltoe(this WebApplicationBuilder builder, IEnumerable exclusions = null, - ILoggerFactory loggerFactory = null) - { - AssemblyExtensions.ExcludedAssemblies = exclusions ?? new List(); - _loggerFactory = loggerFactory ?? NullLoggerFactory.Instance; - _logger = _loggerFactory.CreateLogger(LoggerName); - - if (!builder.WireIfLoaded(WireConfigServer, SteeltoeAssemblyNames.ConfigurationConfigServer)) - { - builder.WireIfLoaded(WireCloudFoundryConfiguration, SteeltoeAssemblyNames.ConfigurationCloudFoundry); - } - - if (Platform.IsKubernetes && AssemblyExtensions.IsAssemblyLoaded(SteeltoeAssemblyNames.ConfigurationKubernetes)) - { - WireKubernetesConfiguration(builder); - } - - builder.WireIfLoaded(WireRandomValueProvider, SteeltoeAssemblyNames.ConfigurationRandomValue); - - builder.WireIfLoaded(WirePlaceholderResolver, SteeltoeAssemblyNames.ConfigurationPlaceholder); - - builder.WireIfLoaded(WireConnectors, SteeltoeAssemblyNames.Connectors); - - builder.WireIfLoaded(WireDynamicSerilog, SteeltoeAssemblyNames.LoggingDynamicSerilog); - - builder.WireIfLoaded(WireDiscoveryClient, SteeltoeAssemblyNames.DiscoveryClient); - - if (AssemblyExtensions.IsAssemblyLoaded(SteeltoeAssemblyNames.ManagementKubernetes)) - { - builder.WireIfLoaded(WireKubernetesActuators, SteeltoeAssemblyNames.ManagementKubernetes); - } - else - { - builder.WireIfLoaded(WireAllActuators, SteeltoeAssemblyNames.ManagementEndpoint); - } - - builder.WireIfLoaded(WireSteeltoePrometheus, SteeltoeAssemblyNames.ManagementPrometheus); - - builder.WireIfLoaded(WireWavefrontMetrics, SteeltoeAssemblyNames.ManagementWavefront); - - builder.WireIfLoaded(WireDistributedTracing, SteeltoeAssemblyNames.ManagementTracing); - - builder.WireIfLoaded(WireCloudFoundryContainerIdentity, SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry); - return builder; - } - - private static bool WireIfLoaded(this WebApplicationBuilder webApplicationBuilder, Action action, params string[] assembly) - { - if (Array.TrueForAll(assembly, AssemblyExtensions.IsAssemblyLoaded)) - { - action(webApplicationBuilder); - return true; - } - - return false; - } - - private static void WireIfAnyLoaded(this WebApplicationBuilder builder, Action action, IReadOnlySet assemblyNamesToExclude, - params PackageResolver[] packageResolvers) - { - if (Array.Exists(packageResolvers, packageResolver => packageResolver.IsAvailable(assemblyNamesToExclude))) - { - action(builder); - } - } - - private static void Log(string message) - { - _logger.LogInformation(message); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireConfigServer(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Configuration.AddConfigServer(webApplicationBuilder.Environment.EnvironmentName, _loggerFactory); - webApplicationBuilder.Services.AddConfigServerServices(); - Log(LogMessages.WireConfigServerConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCloudFoundryConfiguration(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Configuration.AddCloudFoundry(); - Log(LogMessages.WireCloudFoundryConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireKubernetesConfiguration(this WebApplicationBuilder webApplicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddSteeltoe(this WebApplicationBuilder builder, IReadOnlySet assemblyNamesToExclude) { - webApplicationBuilder.Configuration.AddKubernetes(_loggerFactory); - webApplicationBuilder.Services.AddKubernetesConfigurationServices(); - Log(LogMessages.WireKubernetesConfiguration); + return AddSteeltoe(builder, assemblyNamesToExclude, NullLoggerFactory.Instance); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRandomValueProvider(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Configuration.AddRandomValueSource(_loggerFactory); - Log(LogMessages.WireRandomValueConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WirePlaceholderResolver(this WebApplicationBuilder webApplicationBuilder) - { - ((IConfigurationBuilder)webApplicationBuilder.Configuration).AddPlaceholderResolver(_loggerFactory); - Log(LogMessages.WirePlaceholderConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireConnectors(WebApplicationBuilder builder) - { - var assemblyNamesToExclude = new HashSet(AssemblyExtensions.ExcludedAssemblies, StringComparer.OrdinalIgnoreCase); - - builder.WireIfAnyLoaded(WireCosmosDbConnector, assemblyNamesToExclude, CosmosDbPackageResolver.Default); - builder.WireIfAnyLoaded(WireMongoDbConnector, assemblyNamesToExclude, MongoDbPackageResolver.Default); - builder.WireIfAnyLoaded(WireMySqlConnector, assemblyNamesToExclude, MySqlPackageResolver.Default); - builder.WireIfAnyLoaded(WirePostgreSqlConnector, assemblyNamesToExclude, PostgreSqlPackageResolver.Default); - builder.WireIfAnyLoaded(WireRabbitMQConnector, assemblyNamesToExclude, RabbitMQPackageResolver.Default); - builder.WireIfAnyLoaded(WireRedisConnector, assemblyNamesToExclude, StackExchangeRedisPackageResolver.Default, MicrosoftRedisPackageResolver.Default); - builder.WireIfAnyLoaded(WireSqlServerConnector, assemblyNamesToExclude, SqlServerPackageResolver.Default); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireMySqlConnector(this WebApplicationBuilder builder) - { - builder.AddMySql(); - Log(LogMessages.WireMySqlConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCosmosDbConnector(this WebApplicationBuilder builder) - { - builder.AddCosmosDb(); - Log(LogMessages.WireCosmosDbConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireMongoDbConnector(this WebApplicationBuilder builder) - { - builder.AddMongoDb(); - Log(LogMessages.WireMongoDbConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WirePostgreSqlConnector(this WebApplicationBuilder builder) - { - builder.AddPostgreSql(); - Log(LogMessages.WirePostgreSqlConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRabbitMQConnector(this WebApplicationBuilder builder) - { - builder.AddRabbitMQ(); - Log(LogMessages.WireRabbitMQConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRedisConnector(this WebApplicationBuilder builder) - { - builder.AddRedis(); - Log(LogMessages.WireStackExchangeRedisConnector); - - // Intentionally ignoring excluded assemblies here. - if (MicrosoftRedisPackageResolver.Default.IsAvailable()) - { - Log(LogMessages.WireDistributedCacheRedisConnector); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireSqlServerConnector(this WebApplicationBuilder builder) - { - builder.AddSqlServer(); - Log(LogMessages.WireSqlServerConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDiscoveryClient(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Services.AddDiscoveryClient(webApplicationBuilder.Configuration); - Log(LogMessages.WireDiscoveryClient); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDistributedTracing(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Services.AddDistributedTracingAspNetCore(); - Log(LogMessages.WireDistributedTracing); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireKubernetesActuators(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Logging.AddDynamicConsole(); - webApplicationBuilder.Services.AddKubernetesActuators(); - webApplicationBuilder.Services.ActivateActuatorEndpoints(); - Log(LogMessages.WireKubernetesActuators); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireAllActuators(this WebApplicationBuilder webApplicationBuilder) + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// Used for internal logging. Pass to disable logging. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddSteeltoe(this WebApplicationBuilder builder, ILoggerFactory loggerFactory) { - webApplicationBuilder.Logging.AddDynamicConsole(); - webApplicationBuilder.Services.AddAllActuators(); - webApplicationBuilder.Services.ActivateActuatorEndpoints(); - Log(LogMessages.WireAllActuators); + return AddSteeltoe(builder, EmptySet, loggerFactory); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireWavefrontMetrics(this WebApplicationBuilder webApplicationBuilder) + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// The set of assembly names to exclude from auto-configuration. For ease of use, select from the constants in . + /// + /// + /// Used for internal logging. Pass to disable logging. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddSteeltoe(this WebApplicationBuilder builder, IReadOnlySet assemblyNamesToExclude, + ILoggerFactory loggerFactory) { - if (webApplicationBuilder.Configuration.HasWavefront()) - { - webApplicationBuilder.AddWavefrontMetrics(); - Log(LogMessages.WireWavefrontMetrics); - } - } + ArgumentGuard.NotNull(builder); + ArgumentGuard.NotNull(assemblyNamesToExclude); + ArgumentGuard.NotNull(loggerFactory); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireSteeltoePrometheus(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Services.AddPrometheusActuator(); - Log(LogMessages.WirePrometheus); - } + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDynamicSerilog(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Logging.AddDynamicSerilog(); - Log(LogMessages.WireDynamicSerilog); - } + var scanner = new BootstrapScanner(wrapper, assemblyNamesToExclude, loggerFactory); + scanner.ConfigureSteeltoe(); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCloudFoundryContainerIdentity(this WebApplicationBuilder webApplicationBuilder) - { - webApplicationBuilder.Configuration.AddCloudFoundryContainerIdentity(); - webApplicationBuilder.Services.AddCloudFoundryCertificateAuth(); - Log(LogMessages.WireCloudFoundryContainerIdentity); + return builder; } } diff --git a/src/Bootstrap/src/AutoConfiguration/WebHostBuilderExtensions.cs b/src/Bootstrap/src/AutoConfiguration/WebHostBuilderExtensions.cs index 99d4cd949b..17196e3b2b 100644 --- a/src/Bootstrap/src/AutoConfiguration/WebHostBuilderExtensions.cs +++ b/src/Bootstrap/src/AutoConfiguration/WebHostBuilderExtensions.cs @@ -2,354 +2,93 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System.Runtime.CompilerServices; +using System.Collections.Immutable; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Steeltoe.Common; -using Steeltoe.Common.DynamicTypeAccess; -using Steeltoe.Configuration.CloudFoundry; -using Steeltoe.Configuration.ConfigServer; -using Steeltoe.Configuration.Kubernetes; -using Steeltoe.Configuration.Placeholder; -using Steeltoe.Configuration.RandomValue; -using Steeltoe.Connectors.CosmosDb; -using Steeltoe.Connectors.CosmosDb.DynamicTypeAccess; -using Steeltoe.Connectors.MongoDb; -using Steeltoe.Connectors.MongoDb.DynamicTypeAccess; -using Steeltoe.Connectors.MySql; -using Steeltoe.Connectors.MySql.DynamicTypeAccess; -using Steeltoe.Connectors.PostgreSql; -using Steeltoe.Connectors.PostgreSql.DynamicTypeAccess; -using Steeltoe.Connectors.RabbitMQ; -using Steeltoe.Connectors.RabbitMQ.DynamicTypeAccess; -using Steeltoe.Connectors.Redis; -using Steeltoe.Connectors.Redis.DynamicTypeAccess; -using Steeltoe.Connectors.SqlServer; -using Steeltoe.Connectors.SqlServer.RuntimeTypeAccess; -using Steeltoe.Discovery.Client; -using Steeltoe.Logging.DynamicSerilog; -using Steeltoe.Management.Endpoint; -using Steeltoe.Management.Kubernetes; -using Steeltoe.Management.Prometheus; -using Steeltoe.Management.Tracing; -using Steeltoe.Management.Wavefront; -using Steeltoe.Security.Authentication.CloudFoundry; +using Steeltoe.Common.Hosting; namespace Steeltoe.Bootstrap.AutoConfiguration; public static class WebHostBuilderExtensions { - private const string LoggerName = "Steeltoe.AutoConfiguration"; - private static ILoggerFactory _loggerFactory; - private static ILogger _logger; + private static readonly IReadOnlySet EmptySet = ImmutableHashSet.Empty; - static WebHostBuilderExtensions() + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddSteeltoe(this IWebHostBuilder builder) { - AppDomain currentDomain = AppDomain.CurrentDomain; - currentDomain.AssemblyResolve += AssemblyExtensions.LoadAnyVersion; + return AddSteeltoe(builder, EmptySet, NullLoggerFactory.Instance); } /// - /// Automatically configure Steeltoe packages that have been added as NuGet references. - /// - /// PLEASE NOTE: No extensions to IApplicationBuilder will be configured. + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. /// /// - /// Your . + /// The to configure. /// - /// - /// A list of assemblies to exclude from auto-configuration. For ease of use, select from . + /// + /// The set of assembly names to exclude from auto-configuration. For ease of use, select from the constants in . /// - /// - /// For logging within auto-configuration. - /// - public static IWebHostBuilder AddSteeltoe(this IWebHostBuilder builder, IEnumerable exclusions = null, ILoggerFactory loggerFactory = null) - { - AssemblyExtensions.ExcludedAssemblies = exclusions ?? new List(); - _loggerFactory = loggerFactory ?? NullLoggerFactory.Instance; - _logger = _loggerFactory.CreateLogger(LoggerName); - - if (!builder.WireIfLoaded(WireConfigServer, SteeltoeAssemblyNames.ConfigurationConfigServer)) - { - builder.WireIfLoaded(WireCloudFoundryConfiguration, SteeltoeAssemblyNames.ConfigurationCloudFoundry); - } - - if (Platform.IsKubernetes && AssemblyExtensions.IsAssemblyLoaded(SteeltoeAssemblyNames.ConfigurationKubernetes)) - { - WireKubernetesConfiguration(builder); - } - - builder.WireIfLoaded(WireRandomValueProvider, SteeltoeAssemblyNames.ConfigurationRandomValue); - - builder.WireIfLoaded(WirePlaceholderResolver, SteeltoeAssemblyNames.ConfigurationPlaceholder); - - builder.WireIfLoaded(WireConnectors, SteeltoeAssemblyNames.Connectors); - - builder.WireIfLoaded(WireDynamicSerilog, SteeltoeAssemblyNames.LoggingDynamicSerilog); - builder.WireIfLoaded(WireDiscoveryClient, SteeltoeAssemblyNames.DiscoveryClient); - - if (AssemblyExtensions.IsAssemblyLoaded(SteeltoeAssemblyNames.ManagementKubernetes)) - { - builder.WireIfLoaded(WireKubernetesActuators, SteeltoeAssemblyNames.ManagementKubernetes); - } - else - { - builder.WireIfLoaded(WireAllActuators, SteeltoeAssemblyNames.ManagementEndpoint); - } - - builder.WireIfLoaded(WireSteeltoePrometheus, SteeltoeAssemblyNames.ManagementPrometheus); - - builder.WireIfLoaded(WireWavefrontMetrics, SteeltoeAssemblyNames.ManagementWavefront); - - builder.WireIfLoaded(WireDistributedTracing, SteeltoeAssemblyNames.ManagementTracing); - - builder.WireIfLoaded(WireCloudFoundryContainerIdentity, SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry); - return builder; - } - - private static bool WireIfLoaded(this IWebHostBuilder hostBuilder, Action action, params string[] assembly) - { - if (Array.TrueForAll(assembly, AssemblyExtensions.IsAssemblyLoaded)) - { - action(hostBuilder); - return true; - } - - return false; - } - - private static void WireIfAnyLoaded(this IWebHostBuilder hostBuilder, Action action, IReadOnlySet assemblyNamesToExclude, - params PackageResolver[] packageResolvers) - { - if (Array.Exists(packageResolvers, packageResolver => packageResolver.IsAvailable(assemblyNamesToExclude))) - { - action(hostBuilder); - } - } - - private static void Log(this IWebHostBuilder host, string message) - { - _logger.LogInformation(message); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireConfigServer(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration((context, cfg) => cfg.AddConfigServer(context.HostingEnvironment, _loggerFactory)) - .ConfigureServices((_, services) => services.AddConfigServerServices()).Log(LogMessages.WireConfigServerConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCloudFoundryConfiguration(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddCloudFoundry()).Log(LogMessages.WireCloudFoundryConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireKubernetesConfiguration(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddKubernetes(_loggerFactory)) - .ConfigureServices(serviceCollection => serviceCollection.AddKubernetesConfigurationServices()).Log(LogMessages.WireKubernetesConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRandomValueProvider(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddRandomValueSource(_loggerFactory)).Log(LogMessages.WireRandomValueConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WirePlaceholderResolver(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddPlaceholderResolver(_loggerFactory)).Log(LogMessages.WirePlaceholderConfiguration); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireConnectors(IWebHostBuilder builder) - { - var assemblyNamesToExclude = new HashSet(AssemblyExtensions.ExcludedAssemblies, StringComparer.OrdinalIgnoreCase); - - builder.WireIfAnyLoaded(WireCosmosDbConnector, assemblyNamesToExclude, CosmosDbPackageResolver.Default); - builder.WireIfAnyLoaded(WireMongoDbConnector, assemblyNamesToExclude, MongoDbPackageResolver.Default); - builder.WireIfAnyLoaded(WireMySqlConnector, assemblyNamesToExclude, MySqlPackageResolver.Default); - builder.WireIfAnyLoaded(WirePostgreSqlConnector, assemblyNamesToExclude, PostgreSqlPackageResolver.Default); - builder.WireIfAnyLoaded(WireRabbitMQConnector, assemblyNamesToExclude, RabbitMQPackageResolver.Default); - builder.WireIfAnyLoaded(WireRedisConnector, assemblyNamesToExclude, StackExchangeRedisPackageResolver.Default, MicrosoftRedisPackageResolver.Default); - builder.WireIfAnyLoaded(WireSqlServerConnector, assemblyNamesToExclude, SqlServerPackageResolver.Default); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireMySqlConnector(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureMySql(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddMySql(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireMySqlConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCosmosDbConnector(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureCosmosDb(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddCosmosDb(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireCosmosDbConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireMongoDbConnector(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureMongoDb(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddMongoDb(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireMongoDbConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WirePostgreSqlConnector(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigurePostgreSql(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddPostgreSql(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WirePostgreSqlConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRabbitMQConnector(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureRabbitMQ(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddRabbitMQ(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireRabbitMQConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireRedisConnector(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureRedis(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddRedis(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireStackExchangeRedisConnector); - - // Intentionally ignoring excluded assemblies here. - if (MicrosoftRedisPackageResolver.Default.IsAvailable()) - { - hostBuilder.Log(LogMessages.WireDistributedCacheRedisConnector); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireSqlServerConnector(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(configurationBuilder => - { - configurationBuilder.ConfigureSqlServer(); - }); - - hostBuilder.ConfigureServices((host, services) => - { - services.AddSqlServer(host.Configuration); - }); - - hostBuilder.Log(LogMessages.WireSqlServerConnector); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDiscoveryClient(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureServices((_, svc) => svc.AddDiscoveryClient()).Log(LogMessages.WireDiscoveryClient); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDistributedTracing(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureServices((_, svc) => svc.AddDistributedTracingAspNetCore()).Log(LogMessages.WireDistributedTracing); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireKubernetesActuators(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddSteeltoe(this IWebHostBuilder builder, IReadOnlySet assemblyNamesToExclude) { - hostBuilder.AddKubernetesActuators().Log(LogMessages.WireKubernetesActuators); + return AddSteeltoe(builder, assemblyNamesToExclude, NullLoggerFactory.Instance); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireAllActuators(this IWebHostBuilder hostBuilder) + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// Used for internal logging. Pass to disable logging. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddSteeltoe(this IWebHostBuilder builder, ILoggerFactory loggerFactory) { - hostBuilder.AddAllActuators().Log(LogMessages.WireAllActuators); + return AddSteeltoe(builder, EmptySet, loggerFactory); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireWavefrontMetrics(this IWebHostBuilder hostBuilder) + /// + /// Automatically configures Steeltoe packages that have been added to your project as NuGet references. + /// + /// + /// The to configure. + /// + /// + /// The set of assembly names to exclude from auto-configuration. For ease of use, select from the constants in . + /// + /// + /// Used for internal logging. Pass to disable logging. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddSteeltoe(this IWebHostBuilder builder, IReadOnlySet assemblyNamesToExclude, ILoggerFactory loggerFactory) { - hostBuilder.ConfigureServices((context, collection) => - { - if (context.Configuration.HasWavefront()) - { - collection.AddWavefrontMetrics(); - hostBuilder.Log(LogMessages.WireWavefrontMetrics); - } - }); - } + ArgumentGuard.NotNull(builder); + ArgumentGuard.NotNull(assemblyNamesToExclude); + ArgumentGuard.NotNull(loggerFactory); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireSteeltoePrometheus(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureServices((_, collection) => collection.AddPrometheusActuator()).Log(LogMessages.WirePrometheus); - } + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireDynamicSerilog(this IWebHostBuilder hostBuilder) - { - hostBuilder.AddDynamicSerilog().Log(LogMessages.WireDynamicSerilog); - } + var scanner = new BootstrapScanner(wrapper, assemblyNamesToExclude, loggerFactory); + scanner.ConfigureSteeltoe(); - [MethodImpl(MethodImplOptions.NoInlining)] - private static void WireCloudFoundryContainerIdentity(this IWebHostBuilder hostBuilder) - { - hostBuilder.ConfigureAppConfiguration(cfg => cfg.AddCloudFoundryContainerIdentity()).ConfigureServices((_, svc) => svc.AddCloudFoundryCertificateAuth()) - .Log(LogMessages.WireCloudFoundryContainerIdentity); + return builder; } } diff --git a/src/Bootstrap/test/AutoConfiguration.Test/HostBuilderExtensionsTest.cs b/src/Bootstrap/test/AutoConfiguration.Test/HostBuilderExtensionsTest.cs index 1208707594..2ef9aa128d 100644 --- a/src/Bootstrap/test/AutoConfiguration.Test/HostBuilderExtensionsTest.cs +++ b/src/Bootstrap/test/AutoConfiguration.Test/HostBuilderExtensionsTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System.Net; using System.Reflection; using FluentAssertions; using Microsoft.AspNetCore.Authorization; @@ -56,133 +55,84 @@ namespace Steeltoe.Bootstrap.AutoConfiguration.Test; public sealed class HostBuilderExtensionsTest { - private readonly Action _testServerWithRouting = builder => - builder.UseTestServer().ConfigureServices(s => s.AddRouting().AddActionDescriptorCollectionProvider()).Configure(a => a.UseRouting()); - [Fact] public void ConfigServerConfiguration_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationConfigServer - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder().ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(TestHelpers.FastTestsConfiguration)); - - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ConfigurationConfigServer); var configuration = host.Services.GetRequiredService(); - Assert.NotNull(configuration.FindConfigurationProvider()); - Assert.NotNull(configuration.FindConfigurationProvider()); + configuration.FindConfigurationProvider().Should().NotBeNull(); + configuration.FindConfigurationProvider().Should().NotBeNull(); } [Fact] public void CloudFoundryConfiguration_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationCloudFoundry - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder(); - - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ConfigurationCloudFoundry); + var configuration = host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers.OfType()); + configuration.FindConfigurationProvider().Should().NotBeNull(); } - [Fact(Skip = "Requires Kubernetes")] + [Fact] public void KubernetesConfiguration_IsAutowired() { - using var scope = new EnvironmentVariableScope("KUBERNETES_SERVICE_HOST", "TEST"); - - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationKubernetes - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder(); + using var hostScope = new EnvironmentVariableScope("KUBERNETES_SERVICE_HOST", "TEST"); + using var testScope = new EnvironmentVariableScope("STEELTOE_USE_KUBERNETES_FAKE_CLIENT_FOR_TEST", "true"); - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ConfigurationKubernetes); var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); - Assert.Equal(2, configurationRoot.Providers.OfType().Count()); - Assert.Equal(2, configurationRoot.Providers.OfType().Count()); + configurationRoot.Providers.OfType().Should().HaveCount(2); + configurationRoot.Providers.OfType().Should().HaveCount(2); } [Fact] public void RandomValueConfiguration_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationRandomValue - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder(); - - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ConfigurationRandomValue); + var configuration = host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers.OfType()); + configuration.FindConfigurationProvider().Should().NotBeNull(); } [Fact] public void PlaceholderResolver_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationPlaceholder - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder(); - - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ConfigurationPlaceholder); var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers); - Assert.Single(configurationRoot.Providers.OfType()); + configurationRoot.Providers.OfType().Should().HaveCount(1); } [Fact] public void Connectors_AreAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.Connectors - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder(); - hostBuilder.AddSteeltoe(exclusions); - - IHost host = hostBuilder.Build(); - var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.Connectors); + var configuration = host.Services.GetRequiredService(); - configurationRoot.Providers.Should().ContainSingle(provider => provider is KubernetesServiceBindingConfigurationProvider); - configurationRoot.Providers.Should().ContainSingle(provider => provider is CloudFoundryServiceBindingConfigurationProvider); - - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); + configuration.FindConfigurationProvider().Should().NotBeNull(); + configuration.FindConfigurationProvider().Should().NotBeNull(); + + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); } [Fact] - public void SqlServerConnector_NotAutowiredIfExcluded() + public void SqlServerConnector_NotAutowiredIfDependenciesExcluded() { var exclusions = new HashSet(SteeltoeAssemblyNames.All); exclusions.Remove(SteeltoeAssemblyNames.Connectors); exclusions.Add("Microsoft.Data.SqlClient"); exclusions.Add("System.Data.SqlClient"); - IHostBuilder hostBuilder = new HostBuilder(); - hostBuilder.AddSteeltoe(exclusions); - - IHost host = hostBuilder.Build(); + using IHost host = GetHostExcluding(exclusions); host.Services.GetService>().Should().BeNull(); } @@ -190,171 +140,145 @@ public void SqlServerConnector_NotAutowiredIfExcluded() [Fact] public void DynamicSerilog_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.LoggingDynamicSerilog - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder(); - - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.LoggingDynamicSerilog); var loggerProvider = host.Services.GetRequiredService(); - Assert.IsType(loggerProvider); + loggerProvider.Should().BeOfType(); } [Fact] public void ServiceDiscovery_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.DiscoveryClient - }).ToArray(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.DiscoveryClient); + IDiscoveryClient[] discoveryClients = host.Services.GetServices().ToArray(); - IHostBuilder hostBuilder = new HostBuilder().ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(TestHelpers.FastTestsConfiguration)); + discoveryClients.Should().HaveCount(1); + discoveryClients[0].Should().BeOfType(); + } - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - IDiscoveryClient[] discoveryClients = host.Services.GetServices().ToArray(); + [Fact] + public void Prometheus_IsAutowired() + { + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ManagementPrometheus); - Assert.Single(discoveryClients); - Assert.IsType(discoveryClients[0]); + host.Services.GetService().Should().NotBeNull(); } [Fact] public void WavefrontMetricsExporter_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementWavefront - }).ToArray(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ManagementWavefront); - IHost host = new HostBuilder().ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(TestHelpers.WavefrontConfiguration)) - .AddSteeltoe(exclusions).Build(); - - var meterProvider = host.Services.GetRequiredService(); - Assert.NotNull(meterProvider); + host.Services.GetService().Should().NotBeNull(); } [Fact] public void WavefrontTraceExporter_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementTracing - }).ToArray(); - - IHost host = new HostBuilder().ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(TestHelpers.WavefrontConfiguration)) - .AddSteeltoe(exclusions).Build(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ManagementTracing); var tracerProvider = host.Services.GetRequiredService(); - Assert.NotNull(tracerProvider); - - PropertyInfo processorProperty = - tracerProvider.GetType().GetProperty("Processor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(processorProperty); + PropertyInfo? processorProperty = tracerProvider.GetType().GetProperty("Processor", BindingFlags.NonPublic | BindingFlags.Instance); + processorProperty.Should().NotBeNull(); - object processor = processorProperty.GetValue(tracerProvider); - Assert.NotNull(processor); + object? processor = processorProperty!.GetValue(tracerProvider); + processor.Should().NotBeNull(); - FieldInfo exporterField = processor.GetType().GetField("exporter", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(exporterField); + FieldInfo? exporterField = processor!.GetType().GetField("exporter", BindingFlags.NonPublic | BindingFlags.Instance); + exporterField.Should().NotBeNull(); - object exporter = exporterField.GetValue(processor); - Assert.NotNull(exporter); - Assert.IsType(exporter); + object? exporter = exporterField!.GetValue(processor); + exporter.Should().BeOfType(); } [Fact] public async Task KubernetesActuators_AreAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementKubernetes - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder().ConfigureWebHost(_testServerWithRouting); - - IHost host = await hostBuilder.AddSteeltoe(exclusions).StartAsync(); - HttpClient testClient = host.GetTestServer().CreateClient(); - - HttpResponseMessage response = await testClient.GetAsync(new Uri("/actuator", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await testClient.GetAsync(new Uri("/actuator/info", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await testClient.GetAsync(new Uri("/actuator/health", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await testClient.GetAsync(new Uri("/actuator/health/liveness", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("\"LivenessState\":\"CORRECT\"", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal); - response = await testClient.GetAsync(new Uri("/actuator/health/readiness", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("\"ReadinessState\":\"ACCEPTING_TRAFFIC\"", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ManagementKubernetes); + await host.StartAsync(); + + IActuatorEndpointHandler[] handlers = host.Services.GetServices().ToArray(); + handlers.Should().HaveCount(1); + + var filter = host.Services.GetRequiredService(); + filter.Should().BeOfType(); + + using HttpClient testClient = host.GetTestClient(); + await WebApplicationBuilderExtensionsTest.AssertActuatorEndpointsSucceedAsync(testClient); } [Fact] - public void AllActuators_AreAutowired() + public async Task AllActuators_AreAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementEndpoint - }).ToArray(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ManagementEndpoint); + await host.StartAsync(); - IHostBuilder hostBuilder = new HostBuilder(); - - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - IEnumerable handlers = host.Services.GetServices(); - Assert.Single(handlers); + IActuatorEndpointHandler[] handlers = host.Services.GetServices().ToArray(); + handlers.Should().HaveCount(1); var filter = host.Services.GetRequiredService(); - Assert.IsType(filter); + filter.Should().BeOfType(); + + using HttpClient testClient = host.GetTestClient(); + await WebApplicationBuilderExtensionsTest.AssertActuatorEndpointsSucceedAsync(testClient); } [Fact] public void Tracing_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementTracing - }).ToArray(); - - IHostBuilder hostBuilder = new HostBuilder(); - - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.ManagementTracing); var tracerProvider = host.Services.GetRequiredService(); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + + FieldInfo? instrumentationsField = tracerProvider.GetType().GetField("instrumentations", BindingFlags.NonPublic | BindingFlags.Instance); + instrumentationsField.Should().NotBeNull(); - // confirm instrumentation(s) were added as expected - FieldInfo instrumentationsField = tracerProvider.GetType().GetField("instrumentations", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(instrumentationsField); + var instrumentations = (List?)instrumentationsField!.GetValue(tracerProvider); - var instrumentations = (List)instrumentationsField.GetValue(tracerProvider); - Assert.NotNull(instrumentations); - Assert.Equal(2, instrumentations.Count); - Assert.Contains(instrumentations, obj => obj.GetType().Name.Contains("Http", StringComparison.Ordinal)); - Assert.Contains(instrumentations, obj => obj.GetType().Name.Contains("AspNetCore", StringComparison.Ordinal)); + instrumentations.Should().HaveCount(2); + instrumentations.Should().ContainSingle(instance => instance.GetType().Name == "HttpClientInstrumentation"); + instrumentations.Should().ContainSingle(instance => instance.GetType().Name == "AspNetCoreInstrumentation"); } [Fact] public void CloudFoundryContainerSecurity_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry - }).ToArray(); + using IHost host = GetHostForOnly(SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry); + var configuration = host.Services.GetRequiredService(); - IHostBuilder hostBuilder = new HostBuilder(); + configuration.FindConfigurationProvider().Should().NotBeNull(); - IHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + } + + private static IHost GetHostForOnly(string assemblyNameToInclude) + { + IReadOnlySet exclusions = SteeltoeAssemblyNames.Only(assemblyNameToInclude); + return GetHostExcluding(exclusions); + } + + private static IHost GetHostExcluding(IReadOnlySet assemblyNamesToExclude) + { + var hostBuilder = new HostBuilder(); + + hostBuilder.ConfigureWebHost(builder => + { + builder.UseDefaultServiceProvider(options => options.ValidateScopes = true); + builder.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.AddInMemoryCollection(TestHelpers.FastTestsConfiguration)); + builder.ConfigureServices(services => services.AddRouting().AddActionDescriptorCollectionProvider()); + builder.Configure(applicationBuilder => applicationBuilder.UseRouting()); + builder.UseTestServer(); + + builder.AddSteeltoe(assemblyNamesToExclude); + }); - Assert.Single(configurationRoot.Providers.OfType()); - Assert.NotNull(host.Services.GetRequiredService>()); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); + return hostBuilder.Build(); } } diff --git a/src/Bootstrap/test/AutoConfiguration.Test/Steeltoe.Bootstrap.AutoConfiguration.Test.csproj b/src/Bootstrap/test/AutoConfiguration.Test/Steeltoe.Bootstrap.AutoConfiguration.Test.csproj index 4e0baf6a63..20b2cc5b89 100644 --- a/src/Bootstrap/test/AutoConfiguration.Test/Steeltoe.Bootstrap.AutoConfiguration.Test.csproj +++ b/src/Bootstrap/test/AutoConfiguration.Test/Steeltoe.Bootstrap.AutoConfiguration.Test.csproj @@ -1,6 +1,7 @@ net8.0;net6.0 + enable diff --git a/src/Bootstrap/test/AutoConfiguration.Test/WebApplicationBuilderExtensionsTest.cs b/src/Bootstrap/test/AutoConfiguration.Test/WebApplicationBuilderExtensionsTest.cs index 6ec5d3beaa..4768de37e5 100644 --- a/src/Bootstrap/test/AutoConfiguration.Test/WebApplicationBuilderExtensionsTest.cs +++ b/src/Bootstrap/test/AutoConfiguration.Test/WebApplicationBuilderExtensionsTest.cs @@ -27,6 +27,7 @@ using Steeltoe.Common.Options; using Steeltoe.Common.Security; using Steeltoe.Common.TestResources; +using Steeltoe.Configuration; using Steeltoe.Configuration.CloudFoundry; using Steeltoe.Configuration.CloudFoundry.ServiceBinding; using Steeltoe.Configuration.ConfigServer; @@ -58,85 +59,81 @@ public sealed class WebApplicationBuilderExtensionsTest [Fact] public void ConfigServerConfiguration_IsAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.ConfigurationConfigServer); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ConfigurationConfigServer); + var configuration = host.Services.GetRequiredService(); - var configurationRoot = (IConfigurationRoot)(ConfigurationManager)host.Services.GetRequiredService(); - - Assert.Single(configurationRoot.Providers.OfType()); - Assert.Single(configurationRoot.Providers.OfType()); + configuration.FindConfigurationProvider().Should().NotBeNull(); + configuration.FindConfigurationProvider().Should().NotBeNull(); } [Fact] public void CloudFoundryConfiguration_IsAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.ConfigurationCloudFoundry); - var configurationRoot = (IConfigurationRoot)(ConfigurationManager)host.Services.GetRequiredService(); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ConfigurationCloudFoundry); + var configuration = host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers.OfType()); + configuration.FindConfigurationProvider().Should().NotBeNull(); } - [Fact(Skip = "Requires Kubernetes")] + [Fact] public void KubernetesConfiguration_IsAutowired() { - using var scope = new EnvironmentVariableScope("KUBERNETES_SERVICE_HOST", "TEST"); + using var hostScope = new EnvironmentVariableScope("KUBERNETES_SERVICE_HOST", "TEST"); + using var testScope = new EnvironmentVariableScope("STEELTOE_USE_KUBERNETES_FAKE_CLIENT_FOR_TEST", "true"); - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.ConfigurationKubernetes); - var configurationRoot = (IConfigurationRoot)(ConfigurationManager)host.Services.GetRequiredService(); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ConfigurationKubernetes); + var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); - Assert.Equal(2, configurationRoot.Providers.OfType().Count()); - Assert.Equal(2, configurationRoot.Providers.OfType().Count()); + configurationRoot.Providers.OfType().Should().HaveCount(2); + configurationRoot.Providers.OfType().Should().HaveCount(2); } [Fact] public void RandomValueConfiguration_IsAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.ConfigurationRandomValue); - var configurationRoot = (IConfigurationRoot)(ConfigurationManager)host.Services.GetRequiredService(); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ConfigurationRandomValue); + var configuration = host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers.OfType()); + configuration.FindConfigurationProvider().Should().NotBeNull(); } [Fact] public void PlaceholderResolver_IsAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.ConfigurationPlaceholder); - var configurationRoot = (IConfigurationRoot)(ConfigurationManager)host.Services.GetRequiredService(); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ConfigurationPlaceholder); + var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers.OfType()); + configurationRoot.Providers.OfType().Should().HaveCount(1); } [Fact] public void Connectors_AreAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.Connectors); - var configurationRoot = (IConfigurationRoot)(ConfigurationManager)host.Services.GetRequiredService(); - - configurationRoot.Providers.Should().ContainSingle(provider => provider is KubernetesServiceBindingConfigurationProvider); - configurationRoot.Providers.Should().ContainSingle(provider => provider is CloudFoundryServiceBindingConfigurationProvider); - - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.Connectors); + var configuration = host.Services.GetRequiredService(); + + configuration.FindConfigurationProvider().Should().NotBeNull(); + configuration.FindConfigurationProvider().Should().NotBeNull(); + + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); } [Fact] - public void SqlServerConnector_NotAutowiredIfExcluded() + public void SqlServerConnector_NotAutowiredIfDependenciesExcluded() { var exclusions = new HashSet(SteeltoeAssemblyNames.All); exclusions.Remove(SteeltoeAssemblyNames.Connectors); exclusions.Add("Microsoft.Data.SqlClient"); exclusions.Add("System.Data.SqlClient"); - WebApplicationBuilder webAppBuilder = WebApplication.CreateBuilder(); - webAppBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); - webAppBuilder.AddSteeltoe(exclusions); - webAppBuilder.WebHost.UseTestServer(); - WebApplication host = webAppBuilder.Build(); + using WebApplication host = GetWebApplicationExcluding(exclusions); host.Services.GetService>().Should().BeNull(); } @@ -144,174 +141,165 @@ public void SqlServerConnector_NotAutowiredIfExcluded() [Fact] public void DynamicSerilog_IsAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.LoggingDynamicSerilog); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.LoggingDynamicSerilog); var loggerProvider = host.Services.GetRequiredService(); - Assert.IsType(loggerProvider); + loggerProvider.Should().BeOfType(); } [Fact] public void ServiceDiscovery_IsAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.DiscoveryClient); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.DiscoveryClient); IDiscoveryClient[] discoveryClients = host.Services.GetServices().ToArray(); - Assert.Single(discoveryClients); - Assert.IsType(discoveryClients[0]); + discoveryClients.Should().HaveCount(1); + discoveryClients[0].Should().BeOfType(); } [Fact] - public async Task WavefrontMetricsExporter_IsAutowired() + public void Prometheus_IsAutowired() { - WebApplicationBuilder webAppBuilder = WebApplication.CreateBuilder(); - webAppBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); - webAppBuilder.Configuration.AddInMemoryCollection(TestHelpers.WavefrontConfiguration); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ManagementPrometheus); - string[] exclusions = - { - SteeltoeAssemblyNames.ManagementWavefront - }; - - webAppBuilder.AddSteeltoe(SteeltoeAssemblyNames.All.Except(exclusions)); - webAppBuilder.WebHost.UseTestServer(); - WebApplication webApp = webAppBuilder.Build(); + host.Services.GetService().Should().NotBeNull(); + } - webApp.UseRouting(); - await webApp.StartAsync(); + [Fact] + public async Task WavefrontMetricsExporter_IsAutowired() + { + await using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ManagementWavefront); - var meterProvider = webApp.Services.GetRequiredService(); - Assert.NotNull(meterProvider); + host.Services.GetService().Should().NotBeNull(); } [Fact] public async Task WavefrontTraceExporter_IsAutowired() { - WebApplicationBuilder webAppBuilder = WebApplication.CreateBuilder(); - webAppBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); - webAppBuilder.Configuration.AddInMemoryCollection(TestHelpers.WavefrontConfiguration); - - string[] exclusions = - { - SteeltoeAssemblyNames.ManagementTracing - }; - - webAppBuilder.AddSteeltoe(SteeltoeAssemblyNames.All.Except(exclusions)); - webAppBuilder.WebHost.UseTestServer(); - WebApplication webApp = webAppBuilder.Build(); - - webApp.UseRouting(); - await webApp.StartAsync(); + await using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ManagementTracing); - var tracerProvider = webApp.Services.GetRequiredService(); - - PropertyInfo processorProperty = - tracerProvider.GetType().GetProperty("Processor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + var tracerProvider = host.Services.GetRequiredService(); - Assert.NotNull(processorProperty); + PropertyInfo? processorProperty = tracerProvider.GetType().GetProperty("Processor", BindingFlags.NonPublic | BindingFlags.Instance); + processorProperty.Should().NotBeNull(); - object processor = processorProperty.GetValue(tracerProvider); - Assert.NotNull(processor); + object? processor = processorProperty!.GetValue(tracerProvider); + processor.Should().NotBeNull(); - FieldInfo exporterField = processor.GetType().GetField("exporter", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(exporterField); + FieldInfo? exporterField = processor!.GetType().GetField("exporter", BindingFlags.NonPublic | BindingFlags.Instance); + exporterField.Should().NotBeNull(); - object exporter = exporterField.GetValue(processor); - Assert.IsType(exporter); + object? exporter = exporterField!.GetValue(processor); + exporter.Should().BeOfType(); } [Fact] public async Task KubernetesActuators_AreAutowired() { - WebApplication webApp = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.ManagementKubernetes); - webApp.UseRouting(); - await webApp.StartAsync(); + await using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ManagementKubernetes); + await host.StartAsync(); - IEnumerable handlers = webApp.Services.GetServices(); - Assert.Single(handlers); + IActuatorEndpointHandler[] handlers = host.Services.GetServices().ToArray(); + handlers.Should().HaveCount(1); - _ = webApp.Services.GetRequiredService(); + var filter = host.Services.GetRequiredService(); + filter.Should().BeOfType(); - await ActuatorTestAsync(webApp.GetTestClient()); + using HttpClient testClient = host.GetTestClient(); + await AssertActuatorEndpointsSucceedAsync(testClient); } [Fact] public async Task AllActuators_AreAutowired() { - WebApplication webApp = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.ManagementEndpoint); - webApp.UseRouting(); - await webApp.StartAsync(); + await using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ManagementEndpoint); + await host.StartAsync(); - IEnumerable handlers = webApp.Services.GetServices(); - Assert.Single(handlers); + IActuatorEndpointHandler[] handlers = host.Services.GetServices().ToArray(); + handlers.Should().HaveCount(1); - var filter = webApp.Services.GetRequiredService(); - Assert.IsType(filter); + var filter = host.Services.GetRequiredService(); + filter.Should().BeOfType(); - await ActuatorTestAsync(webApp.GetTestClient()); + using HttpClient testClient = host.GetTestClient(); + await AssertActuatorEndpointsSucceedAsync(testClient); } [Fact] public void Tracing_IsAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.ManagementTracing); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.ManagementTracing); var tracerProvider = host.Services.GetRequiredService(); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + + FieldInfo? instrumentationsField = tracerProvider.GetType().GetField("instrumentations", BindingFlags.NonPublic | BindingFlags.Instance); + instrumentationsField.Should().NotBeNull(); - // confirm instrumentation(s) were added as expected - FieldInfo instrumentationsField = tracerProvider.GetType().GetField("instrumentations", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(instrumentationsField); + var instrumentations = (List?)instrumentationsField!.GetValue(tracerProvider); - var instrumentations = (List)instrumentationsField.GetValue(tracerProvider); - Assert.NotNull(instrumentations); - Assert.Equal(2, instrumentations.Count); - Assert.Contains(instrumentations, obj => obj.GetType().Name.Contains("Http", StringComparison.Ordinal)); - Assert.Contains(instrumentations, obj => obj.GetType().Name.Contains("AspNetCore", StringComparison.Ordinal)); + instrumentations.Should().HaveCount(2); + instrumentations.Should().ContainSingle(instance => instance.GetType().Name == "HttpClientInstrumentation"); + instrumentations.Should().ContainSingle(instance => instance.GetType().Name == "AspNetCoreInstrumentation"); } [Fact] public void CloudFoundryContainerSecurity_IsAutowired() { - WebApplication host = GetWebApplicationWithSteeltoe(SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry); - var configurationRoot = (IConfigurationRoot)(ConfigurationManager)host.Services.GetRequiredService(); + using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry); + var configuration = host.Services.GetRequiredService(); + + configuration.FindConfigurationProvider().Should().NotBeNull(); + + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + } - Assert.Single(configurationRoot.Providers.OfType()); - Assert.NotNull(host.Services.GetRequiredService>()); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); + private static WebApplication GetWebApplicationForOnly(string assemblyNameToInclude) + { + IReadOnlySet exclusions = SteeltoeAssemblyNames.Only(assemblyNameToInclude); + return GetWebApplicationExcluding(exclusions); } - private WebApplication GetWebApplicationWithSteeltoe(params string[] assemblyNamesToInclude) + private static WebApplication GetWebApplicationExcluding(IReadOnlySet assemblyNamesToExclude) { - WebApplicationBuilder webAppBuilder = WebApplication.CreateBuilder(); - webAppBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); - webAppBuilder.Configuration.AddInMemoryCollection(TestHelpers.FastTestsConfiguration); - webAppBuilder.AddSteeltoe(SteeltoeAssemblyNames.All.Except(assemblyNamesToInclude)); - webAppBuilder.Services.AddActionDescriptorCollectionProvider(); - webAppBuilder.WebHost.UseTestServer(); - return webAppBuilder.Build(); + WebApplicationBuilder builder = WebApplication.CreateBuilder(); + builder.WebHost.UseDefaultServiceProvider(options => options.ValidateScopes = true); + builder.Configuration.AddInMemoryCollection(TestHelpers.FastTestsConfiguration); + builder.Services.AddActionDescriptorCollectionProvider(); + builder.WebHost.UseTestServer(); + + builder.AddSteeltoe(assemblyNamesToExclude); + + WebApplication host = builder.Build(); + host.UseRouting(); + + return host; } - private async Task ActuatorTestAsync(HttpClient testClient) + internal static async Task AssertActuatorEndpointsSucceedAsync(HttpClient httpClient) { - HttpResponseMessage response = await testClient.GetAsync(new Uri("/actuator", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); + HttpResponseMessage response = await httpClient.GetAsync(new Uri("/actuator", UriKind.Relative)); + response.StatusCode.Should().Be(HttpStatusCode.OK); - response = await testClient.GetAsync(new Uri("/actuator/info", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response = await httpClient.GetAsync(new Uri("/actuator/info", UriKind.Relative)); + response.StatusCode.Should().Be(HttpStatusCode.OK); - response = await testClient.GetAsync(new Uri("/actuator/health", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response = await httpClient.GetAsync(new Uri("/actuator/health", UriKind.Relative)); + response.StatusCode.Should().Be(HttpStatusCode.OK); - response = await testClient.GetAsync(new Uri("/actuator/health/liveness", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("\"LivenessState\":\"CORRECT\"", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal); + response = await httpClient.GetAsync(new Uri("/actuator/health/liveness", UriKind.Relative)); + response.StatusCode.Should().Be(HttpStatusCode.OK); + string responseContent = await response.Content.ReadAsStringAsync(); + responseContent.Should().Contain(@"""LivenessState"":""CORRECT"""); - response = await testClient.GetAsync(new Uri("/actuator/health/readiness", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("\"ReadinessState\":\"ACCEPTING_TRAFFIC\"", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal); + response = await httpClient.GetAsync(new Uri("/actuator/health/readiness", UriKind.Relative)); + response.StatusCode.Should().Be(HttpStatusCode.OK); + responseContent = await response.Content.ReadAsStringAsync(); + responseContent.Should().Contain(@"""ReadinessState"":""ACCEPTING_TRAFFIC"""); } } diff --git a/src/Bootstrap/test/AutoConfiguration.Test/WebHostBuilderExtensionsTest.cs b/src/Bootstrap/test/AutoConfiguration.Test/WebHostBuilderExtensionsTest.cs index 2c7225a2b7..07669d3c83 100644 --- a/src/Bootstrap/test/AutoConfiguration.Test/WebHostBuilderExtensionsTest.cs +++ b/src/Bootstrap/test/AutoConfiguration.Test/WebHostBuilderExtensionsTest.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System.Net; using System.Reflection; using FluentAssertions; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -56,150 +56,84 @@ namespace Steeltoe.Bootstrap.AutoConfiguration.Test; public sealed class WebHostBuilderExtensionsTest { - private readonly IWebHostBuilder _testServerWithRouting = new WebHostBuilder().UseTestServer() - .ConfigureServices(s => s.AddRouting().AddActionDescriptorCollectionProvider()).Configure(a => a.UseRouting()); - [Fact] public void ConfigServerConfiguration_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationConfigServer - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder() - .ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(TestHelpers.FastTestsConfiguration)).Configure(_ => - { - }); - - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ConfigurationConfigServer); var configuration = host.Services.GetRequiredService(); - Assert.NotNull(configuration.FindConfigurationProvider()); - Assert.NotNull(configuration.FindConfigurationProvider()); + configuration.FindConfigurationProvider().Should().NotBeNull(); + configuration.FindConfigurationProvider().Should().NotBeNull(); } [Fact] public void CloudFoundryConfiguration_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationCloudFoundry - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); - - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ConfigurationCloudFoundry); + var configuration = host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers.OfType()); + configuration.FindConfigurationProvider().Should().NotBeNull(); } - [Fact(Skip = "Requires Kubernetes")] + [Fact] public void KubernetesConfiguration_IsAutowired() { - using var scope = new EnvironmentVariableScope("KUBERNETES_SERVICE_HOST", "TEST"); - - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationKubernetes - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); + using var hostScope = new EnvironmentVariableScope("KUBERNETES_SERVICE_HOST", "TEST"); + using var testScope = new EnvironmentVariableScope("STEELTOE_USE_KUBERNETES_FAKE_CLIENT_FOR_TEST", "true"); - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ConfigurationKubernetes); var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); - Assert.Equal(2, configurationRoot.Providers.OfType().Count()); - Assert.Equal(2, configurationRoot.Providers.OfType().Count()); + configurationRoot.Providers.OfType().Should().HaveCount(2); + configurationRoot.Providers.OfType().Should().HaveCount(2); } [Fact] public void RandomValueConfiguration_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationRandomValue - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); - - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ConfigurationRandomValue); + var configuration = host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers.OfType()); + configuration.FindConfigurationProvider().Should().NotBeNull(); } [Fact] public void PlaceholderResolver_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ConfigurationPlaceholder - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); - - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ConfigurationPlaceholder); var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); - Assert.Single(configurationRoot.Providers); - Assert.Single(configurationRoot.Providers.OfType()); + configurationRoot.Providers.OfType().Should().HaveCount(1); } [Fact] public void Connectors_AreAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.Connectors - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); - - hostBuilder.AddSteeltoe(exclusions); - - IWebHost host = hostBuilder.Build(); - var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.Connectors); + var configuration = host.Services.GetRequiredService(); - configurationRoot.Providers.Should().ContainSingle(provider => provider is KubernetesServiceBindingConfigurationProvider); - configurationRoot.Providers.Should().ContainSingle(provider => provider is CloudFoundryServiceBindingConfigurationProvider); - - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); - host.Services.GetRequiredService>().Should().NotBeNull(); + configuration.FindConfigurationProvider().Should().NotBeNull(); + configuration.FindConfigurationProvider().Should().NotBeNull(); + + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService>().Should().NotBeNull(); } [Fact] - public void SqlServerConnector_NotAutowiredIfExcluded() + public void SqlServerConnector_NotAutowiredIfDependenciesExcluded() { var exclusions = new HashSet(SteeltoeAssemblyNames.All); exclusions.Remove(SteeltoeAssemblyNames.Connectors); exclusions.Add("Microsoft.Data.SqlClient"); exclusions.Add("System.Data.SqlClient"); - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); - - hostBuilder.AddSteeltoe(exclusions); - - IWebHost host = hostBuilder.Build(); + using IWebHost host = GetWebHostExcluding(exclusions); host.Services.GetService>().Should().BeNull(); } @@ -207,184 +141,141 @@ public void SqlServerConnector_NotAutowiredIfExcluded() [Fact] public void DynamicSerilog_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.LoggingDynamicSerilog - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); - - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.LoggingDynamicSerilog); var loggerProvider = host.Services.GetRequiredService(); - Assert.IsType(loggerProvider); + loggerProvider.Should().BeOfType(); } [Fact] public void ServiceDiscovery_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.DiscoveryClient - }).ToArray(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.DiscoveryClient); + IDiscoveryClient[] discoveryClients = host.Services.GetServices().ToArray(); - IWebHostBuilder hostBuilder = new WebHostBuilder() - .ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(TestHelpers.FastTestsConfiguration)).Configure(_ => - { - }); + discoveryClients.Should().HaveCount(1); + discoveryClients[0].Should().BeOfType(); + } - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - IDiscoveryClient[] discoveryClients = host.Services.GetServices().ToArray(); + [Fact] + public void Prometheus_IsAutowired() + { + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ManagementPrometheus); - Assert.Single(discoveryClients); - Assert.IsType(discoveryClients[0]); + host.Services.GetService().Should().NotBeNull(); } [Fact] public void WavefrontMetricsExporter_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementWavefront - }).ToArray(); - - IWebHost host = new WebHostBuilder().ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(TestHelpers.WavefrontConfiguration)) - .AddSteeltoe(exclusions).Configure(_ => - { - }).Build(); - - var meterProvider = host.Services.GetRequiredService(); - Assert.NotNull(meterProvider); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ManagementWavefront); + + host.Services.GetService().Should().NotBeNull(); } [Fact] public void WavefrontTraceExporter_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementTracing - }).ToArray(); - - IWebHost host = new WebHostBuilder().ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(TestHelpers.WavefrontConfiguration)) - .AddSteeltoe(exclusions).Configure(_ => - { - }).Build(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ManagementTracing); var tracerProvider = host.Services.GetRequiredService(); - PropertyInfo processorProperty = - tracerProvider.GetType().GetProperty("Processor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - - Assert.NotNull(processorProperty); + PropertyInfo? processorProperty = tracerProvider.GetType().GetProperty("Processor", BindingFlags.NonPublic | BindingFlags.Instance); + processorProperty.Should().NotBeNull(); - object processor = processorProperty.GetValue(tracerProvider); - Assert.NotNull(processor); + object? processor = processorProperty!.GetValue(tracerProvider); + processor.Should().NotBeNull(); - FieldInfo exporterField = processor.GetType().GetField("exporter", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(exporterField); + FieldInfo? exporterField = processor!.GetType().GetField("exporter", BindingFlags.NonPublic | BindingFlags.Instance); + exporterField.Should().NotBeNull(); - object exporter = exporterField.GetValue(processor); - Assert.NotNull(exporter); - Assert.IsType(exporter); + object? exporter = exporterField!.GetValue(processor); + exporter.Should().BeOfType(); } [Fact] public async Task KubernetesActuators_AreAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementKubernetes - }).ToArray(); - - IWebHostBuilder hostBuilder = _testServerWithRouting; - - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Start(); - HttpClient testClient = host.GetTestServer().CreateClient(); - - HttpResponseMessage response = await testClient.GetAsync(new Uri("/actuator", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await testClient.GetAsync(new Uri("/actuator/info", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await testClient.GetAsync(new Uri("/actuator/health", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await testClient.GetAsync(new Uri("/actuator/health/liveness", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("\"LivenessState\":\"CORRECT\"", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal); - response = await testClient.GetAsync(new Uri("/actuator/health/readiness", UriKind.Relative)); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("\"ReadinessState\":\"ACCEPTING_TRAFFIC\"", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ManagementKubernetes); + await host.StartAsync(); + + IActuatorEndpointHandler[] handlers = host.Services.GetServices().ToArray(); + handlers.Should().HaveCount(1); + + var filter = host.Services.GetRequiredService(); + filter.Should().BeOfType(); + + using HttpClient testClient = host.GetTestClient(); + await WebApplicationBuilderExtensionsTest.AssertActuatorEndpointsSucceedAsync(testClient); } [Fact] - public void AllActuators_AreAutowired() + public async Task AllActuators_AreAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementEndpoint - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); - - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - IEnumerable handlers = host.Services.GetServices(); - Assert.Single(handlers); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ManagementEndpoint); + await host.StartAsync(); + + IActuatorEndpointHandler[] handlers = host.Services.GetServices().ToArray(); + handlers.Should().HaveCount(1); + var filter = host.Services.GetRequiredService(); - Assert.IsType(filter); + filter.Should().BeOfType(); + + using HttpClient testClient = host.GetTestClient(); + await WebApplicationBuilderExtensionsTest.AssertActuatorEndpointsSucceedAsync(testClient); } [Fact] public void Tracing_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.ManagementTracing - }).ToArray(); - - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); - - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.ManagementTracing); var tracerProvider = host.Services.GetRequiredService(); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + + FieldInfo? instrumentationsField = tracerProvider.GetType().GetField("instrumentations", BindingFlags.NonPublic | BindingFlags.Instance); + instrumentationsField.Should().NotBeNull(); - // confirm instrumentation(s) were added as expected - FieldInfo instrumentationsField = tracerProvider.GetType().GetField("instrumentations", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(instrumentationsField); + var instrumentations = (List?)instrumentationsField!.GetValue(tracerProvider); - var instrumentations = (List)instrumentationsField.GetValue(tracerProvider); - Assert.NotNull(instrumentations); - Assert.Equal(2, instrumentations.Count); - Assert.Contains(instrumentations, obj => obj.GetType().Name.Contains("Http", StringComparison.Ordinal)); - Assert.Contains(instrumentations, obj => obj.GetType().Name.Contains("AspNetCore", StringComparison.Ordinal)); + instrumentations.Should().HaveCount(2); + instrumentations.Should().ContainSingle(instance => instance.GetType().Name == "HttpClientInstrumentation"); + instrumentations.Should().ContainSingle(instance => instance.GetType().Name == "AspNetCoreInstrumentation"); } [Fact] public void CloudFoundryContainerSecurity_IsAutowired() { - string[] exclusions = SteeltoeAssemblyNames.All.Except(new[] - { - SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry - }).ToArray(); + using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.SecurityAuthenticationCloudFoundry); + var configuration = host.Services.GetRequiredService(); - IWebHostBuilder hostBuilder = new WebHostBuilder().Configure(_ => - { - }); + configuration.FindConfigurationProvider().Should().NotBeNull(); - IWebHost host = hostBuilder.AddSteeltoe(exclusions).Build(); - var configurationRoot = (IConfigurationRoot)host.Services.GetRequiredService(); + host.Services.GetService>().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + host.Services.GetService().Should().NotBeNull(); + } + + private static IWebHost GetWebHostForOnly(string assemblyNameToInclude) + { + IReadOnlySet exclusions = SteeltoeAssemblyNames.Only(assemblyNameToInclude); + return GetWebHostExcluding(exclusions); + } + + private static IWebHost GetWebHostExcluding(IReadOnlySet assemblyNamesToExclude) + { + IWebHostBuilder builder = WebHost.CreateDefaultBuilder(); + builder.UseDefaultServiceProvider(options => options.ValidateScopes = true); + builder.ConfigureAppConfiguration(configurationBuilder => configurationBuilder.AddInMemoryCollection(TestHelpers.FastTestsConfiguration)); + builder.ConfigureServices(services => services.AddActionDescriptorCollectionProvider()); + builder.Configure(applicationBuilder => applicationBuilder.UseRouting()); + builder.UseTestServer(); + + builder.AddSteeltoe(assemblyNamesToExclude); - Assert.Single(configurationRoot.Providers.OfType()); - Assert.NotNull(host.Services.GetRequiredService>()); - Assert.NotNull(host.Services.GetRequiredService()); - Assert.NotNull(host.Services.GetRequiredService()); + return builder.Build(); } } diff --git a/src/Bootstrap/test/EmptyAutoConfiguration.Test/EmptyAutoConfigurationTest.cs b/src/Bootstrap/test/EmptyAutoConfiguration.Test/EmptyAutoConfigurationTest.cs index 0a02094fa8..c2bd8ad6d5 100644 --- a/src/Bootstrap/test/EmptyAutoConfiguration.Test/EmptyAutoConfigurationTest.cs +++ b/src/Bootstrap/test/EmptyAutoConfiguration.Test/EmptyAutoConfigurationTest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using FluentAssertions; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; @@ -20,14 +21,15 @@ public void Bootstrap_does_not_depend_on_other_Steeltoe_packages() var whitelist = new HashSet(StringComparer.OrdinalIgnoreCase) { "Steeltoe.Bootstrap.AutoConfiguration.dll", - "Steeltoe.Common.Abstractions.dll", "Steeltoe.Common.dll", + "Steeltoe.Common.Abstractions.dll", + "Steeltoe.Common.Hosting.dll", "Steeltoe.Bootstrap.EmptyAutoConfiguration.Test.dll", "Steeltoe.Common.TestResources.dll" }; - string[] files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "Steeltoe*.dll").Select(Path.GetFileName) + string[] files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "Steeltoe*.dll").Select(Path.GetFileName).Select(fileName => fileName!) .Where(fileName => !whitelist.Contains(fileName)).ToArray(); files.Should().BeEmpty(); @@ -37,7 +39,7 @@ public void Bootstrap_does_not_depend_on_other_Steeltoe_packages() public void Loads_without_any_Steeltoe_references_using_WebApplicationBuilder() { WebApplicationBuilder builder = WebApplication.CreateBuilder(); - builder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); + builder.WebHost.UseDefaultServiceProvider(options => options.ValidateScopes = true); Action action = () => builder.AddSteeltoe(); @@ -47,9 +49,8 @@ public void Loads_without_any_Steeltoe_references_using_WebApplicationBuilder() [Fact] public void Loads_without_any_Steeltoe_references_using_WebHostBuilder() { - IWebHostBuilder builder = new WebHostBuilder().Configure(_ => - { - }); + IWebHostBuilder builder = WebHost.CreateDefaultBuilder(); + builder.UseDefaultServiceProvider(options => options.ValidateScopes = true); Action action = () => builder.AddSteeltoe(); @@ -59,7 +60,8 @@ public void Loads_without_any_Steeltoe_references_using_WebHostBuilder() [Fact] public void Loads_without_any_Steeltoe_references_using_HostBuilder() { - var builder = new HostBuilder(); + IHostBuilder builder = new HostBuilder(); + builder.UseDefaultServiceProvider(options => options.ValidateScopes = true); Action action = () => builder.AddSteeltoe(); diff --git a/src/Bootstrap/test/EmptyAutoConfiguration.Test/Steeltoe.Bootstrap.EmptyAutoConfiguration.Test.csproj b/src/Bootstrap/test/EmptyAutoConfiguration.Test/Steeltoe.Bootstrap.EmptyAutoConfiguration.Test.csproj index c89d5699f3..a86273c674 100644 --- a/src/Bootstrap/test/EmptyAutoConfiguration.Test/Steeltoe.Bootstrap.EmptyAutoConfiguration.Test.csproj +++ b/src/Bootstrap/test/EmptyAutoConfiguration.Test/Steeltoe.Bootstrap.EmptyAutoConfiguration.Test.csproj @@ -1,6 +1,7 @@ net8.0;net6.0 + enable diff --git a/src/Bootstrap/test/EmptyAutoConfiguration.Test/xunit.runner.json b/src/Bootstrap/test/EmptyAutoConfiguration.Test/xunit.runner.json deleted file mode 100644 index fdeefaa456..0000000000 --- a/src/Bootstrap/test/EmptyAutoConfiguration.Test/xunit.runner.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "maxParallelThreads": 1, - "parallelizeTestCollections": false -} diff --git a/src/Common/src/Abstractions/DynamicTypeAccess/PackageResolver.cs b/src/Common/src/Abstractions/DynamicTypeAccess/PackageResolver.cs index a28b2c61c9..571f16d5bd 100644 --- a/src/Common/src/Abstractions/DynamicTypeAccess/PackageResolver.cs +++ b/src/Common/src/Abstractions/DynamicTypeAccess/PackageResolver.cs @@ -4,6 +4,7 @@ #nullable enable +using System.Collections.Immutable; using System.Reflection; namespace Steeltoe.Common.DynamicTypeAccess; @@ -13,7 +14,7 @@ namespace Steeltoe.Common.DynamicTypeAccess; /// internal abstract class PackageResolver { - private static readonly IReadOnlySet EmptySet = new HashSet(); + private static readonly IReadOnlySet EmptySet = ImmutableHashSet.Empty; private readonly IReadOnlyList _assemblyNames; private readonly IReadOnlyList _packageNames; diff --git a/src/Common/src/Common.Hosting/HostBuilderContextWrapper.cs b/src/Common/src/Common.Hosting/HostBuilderContextWrapper.cs new file mode 100644 index 0000000000..1e542ff32b --- /dev/null +++ b/src/Common/src/Common.Hosting/HostBuilderContextWrapper.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; + +namespace Steeltoe.Common.Hosting; + +/// +/// Wraps a host builder context for . +/// +internal sealed class HostBuilderContextWrapper +{ + private readonly object _innerContext; + + public IConfiguration Configuration { get; } + public IHostEnvironment HostEnvironment { get; } + + private HostBuilderContextWrapper(IConfiguration configuration, IHostEnvironment hostEnvironment, object innerContext) + { + _innerContext = innerContext; + Configuration = configuration; + HostEnvironment = hostEnvironment; + } + + public static HostBuilderContextWrapper Wrap(HostBuilderContext context) + { + ArgumentGuard.NotNull(context); + + return new HostBuilderContextWrapper(context.Configuration, context.HostingEnvironment, context); + } + + public static HostBuilderContextWrapper Wrap(WebHostBuilderContext context) + { + ArgumentGuard.NotNull(context); + + return new HostBuilderContextWrapper(context.Configuration, context.HostingEnvironment, context); + } + +#if NET6_0 + public static HostBuilderContextWrapper Wrap(WebApplicationBuilder context) +#else + public static HostBuilderContextWrapper Wrap(IHostApplicationBuilder context) +#endif + { + ArgumentGuard.NotNull(context); + + return new HostBuilderContextWrapper(context.Configuration, context.Environment, context); + } + + public static Action? WrapAction(Action? action) + { + return WrapGenericAction(action); + } + + public static Action? WrapAction(Action? action) + { + return WrapGenericAction(action); + } + + public static Action? WrapAction(Action? action) + { + return WrapGenericAction(action); + } + + private static Action? WrapGenericAction(Action? action) + { + if (action == null) + { + return null; + } + + return (contextWrapper, argument) => + { + var context = Unwrap(contextWrapper); + action(context, argument); + }; + } + + private static TContext Unwrap(HostBuilderContextWrapper contextWrapper) + { + if (contextWrapper._innerContext is not TContext context) + { + throw new InvalidOperationException($"Type '{typeof(TContext)}' is incompatible with type '{contextWrapper._innerContext.GetType()}'."); + } + + return context; + } +} diff --git a/src/Common/src/Common.Hosting/HostBuilderWrapper.cs b/src/Common/src/Common.Hosting/HostBuilderWrapper.cs new file mode 100644 index 0000000000..a06de6e783 --- /dev/null +++ b/src/Common/src/Common.Hosting/HostBuilderWrapper.cs @@ -0,0 +1,221 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace Steeltoe.Common.Hosting; + +/// +/// A host-agnostic wrapper for , and . Intended to reduce +/// code duplication when targeting the various host builders. +/// +internal sealed class HostBuilderWrapper +{ + private readonly List> _configureServicesActions = new(); + private readonly List> _configureAppConfigurationActions = new(); + private readonly List> _configureLoggingActions = new(); + private readonly object _innerBuilder; + + private HostBuilderWrapper(object innerBuilder) + { + _innerBuilder = innerBuilder; + } + + public static HostBuilderWrapper Wrap(IHostBuilder builder) + { + ArgumentGuard.NotNull(builder); + + var wrapper = new HostBuilderWrapper(builder); + + builder.ConfigureServices((context, services) => + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(context); + InvokeDeferredActions(wrapper._configureServicesActions, contextWrapper, services); + }); + + builder.ConfigureAppConfiguration((context, configurationBuilder) => + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(context); + InvokeDeferredActions(wrapper._configureAppConfigurationActions, contextWrapper, configurationBuilder); + }); + + builder.ConfigureLogging((context, loggingBuilder) => + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(context); + InvokeDeferredActions(wrapper._configureLoggingActions, contextWrapper, loggingBuilder); + }); + + return wrapper; + } + + public static HostBuilderWrapper Wrap(IWebHostBuilder builder) + { + ArgumentGuard.NotNull(builder); + + var wrapper = new HostBuilderWrapper(builder); + + builder.ConfigureServices((context, services) => + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(context); + InvokeDeferredActions(wrapper._configureServicesActions, contextWrapper, services); + }); + + builder.ConfigureAppConfiguration((context, configurationBuilder) => + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(context); + InvokeDeferredActions(wrapper._configureAppConfigurationActions, contextWrapper, configurationBuilder); + }); + + builder.ConfigureLogging((context, loggingBuilder) => + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(context); + InvokeDeferredActions(wrapper._configureLoggingActions, contextWrapper, loggingBuilder); + }); + + return wrapper; + } + +#if NET6_0 + public static HostBuilderWrapper Wrap(WebApplicationBuilder builder) +#else + public static HostBuilderWrapper Wrap(IHostApplicationBuilder builder) +#endif + { + ArgumentGuard.NotNull(builder); + + // WebApplicationBuilder/IHostApplicationBuilder immediately execute callbacks, so don't capture them for deferred execution. + + return new HostBuilderWrapper(builder); + } + + private static void InvokeDeferredActions(IEnumerable> actions, + HostBuilderContextWrapper contextWrapper, TArgument argument) + { + foreach (Action action in actions) + { + action(contextWrapper, argument); + } + } + + public HostBuilderWrapper ConfigureServices(Action configureAction) + { + ArgumentGuard.NotNull(configureAction); + + return ConfigureServices((_, services) => configureAction(services)); + } + + public HostBuilderWrapper ConfigureServices(Action configureAction) + { + ArgumentGuard.NotNull(configureAction); + +#if NET6_0 + if (_innerBuilder is WebApplicationBuilder applicationBuilder) +#else + if (_innerBuilder is IHostApplicationBuilder applicationBuilder) +#endif + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(applicationBuilder); + configureAction(contextWrapper, applicationBuilder.Services); + } + else + { + _configureServicesActions.Add(configureAction); + } + + return this; + } + + public HostBuilderWrapper ConfigureAppConfiguration(Action configureAction) + { + ArgumentGuard.NotNull(configureAction); + + return ConfigureAppConfiguration((_, configurationBuilder) => configureAction(configurationBuilder)); + } + + public HostBuilderWrapper ConfigureAppConfiguration(Action configureAction) + { + ArgumentGuard.NotNull(configureAction); + +#if NET6_0 + if (_innerBuilder is WebApplicationBuilder applicationBuilder) +#else + if (_innerBuilder is IHostApplicationBuilder applicationBuilder) +#endif + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(applicationBuilder); + configureAction(contextWrapper, applicationBuilder.Configuration); + } + else + { + _configureAppConfigurationActions.Add(configureAction); + } + + return this; + } + + public HostBuilderWrapper ConfigureLogging(Action configureAction) + { + ArgumentGuard.NotNull(configureAction); + + return ConfigureLogging((_, configurationBuilder) => configureAction(configurationBuilder)); + } + + public HostBuilderWrapper ConfigureLogging(Action configureAction) + { + ArgumentGuard.NotNull(configureAction); + +#if NET6_0 + if (_innerBuilder is WebApplicationBuilder applicationBuilder) +#else + if (_innerBuilder is IHostApplicationBuilder applicationBuilder) +#endif + { + HostBuilderContextWrapper contextWrapper = HostBuilderContextWrapper.Wrap(applicationBuilder); + configureAction(contextWrapper, applicationBuilder.Logging); + } + else + { + _configureLoggingActions.Add(configureAction); + } + + return this; + } + + public HostBuilderWrapper ConfigureWebHost(Action configureAction) + { + ArgumentGuard.NotNull(configureAction); + + if (_innerBuilder is IHostBuilder hostBuilder) + { + hostBuilder.ConfigureWebHost(configureAction); + } + else if (_innerBuilder is IWebHostBuilder webHostBuilder) + { + configureAction(webHostBuilder); + } + else if (_innerBuilder is WebApplicationBuilder webApplicationBuilder) + { + configureAction(webApplicationBuilder.WebHost); + } +#if !NET6_0 + else if (_innerBuilder is IHostApplicationBuilder) + { + // This is not a web application, so silently ignore. + } +#endif + else + { + throw new NotSupportedException($"Unknown host builder type '{_innerBuilder.GetType()}'."); + } + + return this; + } +} diff --git a/src/Common/src/Common.Hosting/Properties/AssemblyInfo.cs b/src/Common/src/Common.Hosting/Properties/AssemblyInfo.cs index a5b15288bf..27820255cf 100644 --- a/src/Common/src/Common.Hosting/Properties/AssemblyInfo.cs +++ b/src/Common/src/Common.Hosting/Properties/AssemblyInfo.cs @@ -4,5 +4,8 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Steeltoe.Bootstrap.AutoConfiguration")] [assembly: InternalsVisibleTo("Steeltoe.Common.Hosting.Test")] +[assembly: InternalsVisibleTo("Steeltoe.Logging.DynamicSerilog")] [assembly: InternalsVisibleTo("Steeltoe.Management.Endpoint")] +[assembly: InternalsVisibleTo("Steeltoe.Management.Kubernetes")] diff --git a/src/Common/src/Common.Kubernetes/KubernetesClientHelpers.cs b/src/Common/src/Common.Kubernetes/KubernetesClientHelpers.cs index 63918c448c..31f9d03d32 100644 --- a/src/Common/src/Common.Kubernetes/KubernetesClientHelpers.cs +++ b/src/Common/src/Common.Kubernetes/KubernetesClientHelpers.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. +using System.Net; using k8s; using k8s.Exceptions; using Microsoft.Extensions.Configuration; @@ -20,6 +21,12 @@ public static IKubernetes GetKubernetesClient(IConfiguration configuration, Acti public static IKubernetes GetKubernetesClient(KubernetesApplicationOptions appInfo, Action kubernetesClientConfiguration = null, ILogger logger = null) { + if (Environment.GetEnvironmentVariable("STEELTOE_USE_KUBERNETES_FAKE_CLIENT_FOR_TEST") == "true") + { + // Used for testing Bootstrap, where we can't inject a custom service. + return UseKubernetesFakeClientForTest(); + } + KubernetesClientConfiguration configuration = null; try @@ -49,4 +56,26 @@ public static IKubernetes GetKubernetesClient(KubernetesApplicationOptions appIn return new k8s.Kubernetes(configuration); } + + private static IKubernetes UseKubernetesFakeClientForTest() + { + var delegatingHandler = new TestDelegatingHandler(); + + return new k8s.Kubernetes(new KubernetesClientConfiguration + { + Host = "http://localhost:8080" + }, delegatingHandler); + } + + private sealed class TestDelegatingHandler : DelegatingHandler + { + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var responseMessage = new HttpResponseMessage(HttpStatusCode.OK); + responseMessage.RequestMessage = request; + responseMessage.Content = new StringContent("{}"); + + return Task.FromResult(responseMessage); + } + } } diff --git a/src/Common/test/Common.TestResources/TestHelpers.cs b/src/Common/test/Common.TestResources/TestHelpers.cs index b3d0b8e01e..c2a5a9e8e1 100644 --- a/src/Common/test/Common.TestResources/TestHelpers.cs +++ b/src/Common/test/Common.TestResources/TestHelpers.cs @@ -41,11 +41,7 @@ public static class TestHelpers { "spring:cloud:config:enabled", "false" }, { "eureka:client:serviceUrl", "http://127.0.0.1" }, { "eureka:client:enabled", "false" }, - { "management:endpoints:actuator:exposure:include:0", "*" } - }.ToImmutableDictionary(); - - public static readonly ImmutableDictionary WavefrontConfiguration = new Dictionary - { + { "management:endpoints:actuator:exposure:include:0", "*" }, { "management:metrics:export:wavefront:uri", "proxy://localhost:7828" } }.ToImmutableDictionary(); diff --git a/src/Configuration/src/CloudFoundry/CloudFoundryHostBuilderExtensions.cs b/src/Configuration/src/CloudFoundry/CloudFoundryHostBuilderExtensions.cs index 144674c0d4..7cc4d13290 100644 --- a/src/Configuration/src/CloudFoundry/CloudFoundryHostBuilderExtensions.cs +++ b/src/Configuration/src/CloudFoundry/CloudFoundryHostBuilderExtensions.cs @@ -22,7 +22,7 @@ public static IWebHostBuilder AddCloudFoundryConfiguration(this IWebHostBuilder ArgumentGuard.NotNull(hostBuilder); hostBuilder.ConfigureAppConfiguration((_, builder) => builder.AddCloudFoundry()); - hostBuilder.ConfigureServices((_, serviceCollection) => serviceCollection.RegisterCloudFoundryApplicationInstanceInfo()); + hostBuilder.ConfigureServices(serviceCollection => serviceCollection.RegisterCloudFoundryApplicationInstanceInfo()); return hostBuilder; } @@ -38,7 +38,7 @@ public static IHostBuilder AddCloudFoundryConfiguration(this IHostBuilder hostBu ArgumentGuard.NotNull(hostBuilder); hostBuilder.ConfigureAppConfiguration((_, builder) => builder.AddCloudFoundry()); - hostBuilder.ConfigureServices((_, serviceCollection) => serviceCollection.RegisterCloudFoundryApplicationInstanceInfo()); + hostBuilder.ConfigureServices(serviceCollection => serviceCollection.RegisterCloudFoundryApplicationInstanceInfo()); return hostBuilder; } diff --git a/src/Configuration/src/ConfigServer/ConfigServerHostBuilderExtensions.cs b/src/Configuration/src/ConfigServer/ConfigServerHostBuilderExtensions.cs index 55849e832b..21ae746098 100644 --- a/src/Configuration/src/ConfigServer/ConfigServerHostBuilderExtensions.cs +++ b/src/Configuration/src/ConfigServer/ConfigServerHostBuilderExtensions.cs @@ -45,7 +45,7 @@ public static IWebHostBuilder AddConfigServer(this IWebHostBuilder hostBuilder, ArgumentGuard.NotNull(loggerFactory); hostBuilder.ConfigureAppConfiguration((context, builder) => builder.AddConfigServer(context.HostingEnvironment, loggerFactory)); - hostBuilder.ConfigureServices((_, services) => services.AddConfigServerServices()); + hostBuilder.ConfigureServices(services => services.AddConfigServerServices()); return hostBuilder; } @@ -82,7 +82,7 @@ public static IHostBuilder AddConfigServer(this IHostBuilder hostBuilder, ILogge ArgumentGuard.NotNull(loggerFactory); hostBuilder.ConfigureAppConfiguration((context, builder) => builder.AddConfigServer(context.HostingEnvironment, loggerFactory)); - hostBuilder.ConfigureServices((_, services) => services.AddConfigServerServices()); + hostBuilder.ConfigureServices(services => services.AddConfigServerServices()); return hostBuilder; } diff --git a/src/Discovery/src/Client/DiscoveryHostBuilderExtensions.cs b/src/Discovery/src/Client/DiscoveryHostBuilderExtensions.cs index 5847b34c7f..ddfab77ea8 100644 --- a/src/Discovery/src/Client/DiscoveryHostBuilderExtensions.cs +++ b/src/Discovery/src/Client/DiscoveryHostBuilderExtensions.cs @@ -55,6 +55,6 @@ public static IHostBuilder AddDiscoveryClient(this IHostBuilder hostBuilder) /// public static IHostBuilder AddServiceDiscovery(this IHostBuilder hostBuilder, Action optionsAction) { - return hostBuilder.ConfigureServices((_, collection) => collection.AddServiceDiscovery(optionsAction)); + return hostBuilder.ConfigureServices(collection => collection.AddServiceDiscovery(optionsAction)); } } diff --git a/src/Discovery/src/Client/DiscoveryWebHostBuilderExtensions.cs b/src/Discovery/src/Client/DiscoveryWebHostBuilderExtensions.cs index 8793817e45..255144b611 100644 --- a/src/Discovery/src/Client/DiscoveryWebHostBuilderExtensions.cs +++ b/src/Discovery/src/Client/DiscoveryWebHostBuilderExtensions.cs @@ -30,7 +30,7 @@ public static class DiscoveryWebHostBuilderExtensions /// public static IWebHostBuilder AddDiscoveryClient(this IWebHostBuilder hostBuilder) { - return hostBuilder.ConfigureServices((_, collection) => collection.AddDiscoveryClient()); + return hostBuilder.ConfigureServices(collection => collection.AddDiscoveryClient()); } /// @@ -55,6 +55,6 @@ public static IWebHostBuilder AddDiscoveryClient(this IWebHostBuilder hostBuilde /// public static IWebHostBuilder AddServiceDiscovery(this IWebHostBuilder hostBuilder, Action optionsAction) { - return hostBuilder.ConfigureServices((_, collection) => collection.AddServiceDiscovery(optionsAction)); + return hostBuilder.ConfigureServices(collection => collection.AddServiceDiscovery(optionsAction)); } } diff --git a/src/Logging/src/DynamicSerilog/HostBuilderWrapperExtensions.cs b/src/Logging/src/DynamicSerilog/HostBuilderWrapperExtensions.cs new file mode 100644 index 0000000000..a3cded6829 --- /dev/null +++ b/src/Logging/src/DynamicSerilog/HostBuilderWrapperExtensions.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using Serilog; +using Steeltoe.Common; +using Steeltoe.Common.Hosting; + +namespace Steeltoe.Logging.DynamicSerilog; + +internal static class HostBuilderWrapperExtensions +{ + public static HostBuilderWrapper AddDynamicSerilog(this HostBuilderWrapper wrapper, Action? configureLogger, + bool preserveDefaultConsole) + { + ArgumentGuard.NotNull(wrapper); + + wrapper.ConfigureLogging((hostContext, loggingBuilder) => + { + LoggerConfiguration? loggerConfiguration = null; + + if (configureLogger != null) + { + loggerConfiguration = new LoggerConfiguration(); + configureLogger(hostContext, loggerConfiguration); + } + + loggingBuilder.AddDynamicSerilog(loggerConfiguration, preserveDefaultConsole); + }); + + return wrapper; + } +} diff --git a/src/Logging/src/DynamicSerilog/Properties/AssemblyInfo.cs b/src/Logging/src/DynamicSerilog/Properties/AssemblyInfo.cs index e74dba04fc..11d98f63f2 100644 --- a/src/Logging/src/DynamicSerilog/Properties/AssemblyInfo.cs +++ b/src/Logging/src/DynamicSerilog/Properties/AssemblyInfo.cs @@ -4,4 +4,5 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Steeltoe.Bootstrap.AutoConfiguration")] [assembly: InternalsVisibleTo("Steeltoe.Logging.DynamicSerilog.Test")] diff --git a/src/Logging/src/DynamicSerilog/SerilogHostBuilderExtensions.cs b/src/Logging/src/DynamicSerilog/SerilogHostBuilderExtensions.cs index 89fd441217..4e96ae6e56 100644 --- a/src/Logging/src/DynamicSerilog/SerilogHostBuilderExtensions.cs +++ b/src/Logging/src/DynamicSerilog/SerilogHostBuilderExtensions.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Hosting; using Serilog; using Steeltoe.Common; +using Steeltoe.Common.Hosting; namespace Steeltoe.Logging.DynamicSerilog; @@ -78,17 +79,9 @@ public static IHostBuilder AddDynamicSerilog(this IHostBuilder hostBuilder, Acti { ArgumentGuard.NotNull(hostBuilder); - return hostBuilder.ConfigureLogging((hostContext, loggingBuilder) => - { - LoggerConfiguration? loggerConfiguration = null; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(hostBuilder); + wrapper.AddDynamicSerilog(HostBuilderContextWrapper.WrapAction(configureLogger), preserveDefaultConsole); - if (configureLogger != null) - { - loggerConfiguration = new LoggerConfiguration(); - configureLogger(hostContext, loggerConfiguration); - } - - loggingBuilder.AddDynamicSerilog(loggerConfiguration, preserveDefaultConsole); - }); + return hostBuilder; } } diff --git a/src/Logging/src/DynamicSerilog/SerilogWebApplicationBuilderExtensions.cs b/src/Logging/src/DynamicSerilog/SerilogWebApplicationBuilderExtensions.cs index f093d70338..e291bd0b8c 100644 --- a/src/Logging/src/DynamicSerilog/SerilogWebApplicationBuilderExtensions.cs +++ b/src/Logging/src/DynamicSerilog/SerilogWebApplicationBuilderExtensions.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Builder; using Serilog; using Steeltoe.Common; +using Steeltoe.Common.Hosting; namespace Steeltoe.Logging.DynamicSerilog; @@ -79,15 +80,9 @@ public static WebApplicationBuilder AddDynamicSerilog(this WebApplicationBuilder { ArgumentGuard.NotNull(hostBuilder); - LoggerConfiguration? loggerConfiguration = null; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(hostBuilder); + wrapper.AddDynamicSerilog(HostBuilderContextWrapper.WrapAction(configureLogger), preserveDefaultConsole); - if (configureLogger != null) - { - loggerConfiguration = new LoggerConfiguration(); - configureLogger(hostBuilder, loggerConfiguration); - } - - hostBuilder.Logging.AddDynamicSerilog(loggerConfiguration, preserveDefaultConsole); return hostBuilder; } } diff --git a/src/Logging/src/DynamicSerilog/SerilogWebHostBuilderExtensions.cs b/src/Logging/src/DynamicSerilog/SerilogWebHostBuilderExtensions.cs index 3925b73444..c887c0df75 100644 --- a/src/Logging/src/DynamicSerilog/SerilogWebHostBuilderExtensions.cs +++ b/src/Logging/src/DynamicSerilog/SerilogWebHostBuilderExtensions.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Hosting; using Serilog; using Steeltoe.Common; +using Steeltoe.Common.Hosting; namespace Steeltoe.Logging.DynamicSerilog; @@ -78,17 +79,9 @@ public static IWebHostBuilder AddDynamicSerilog(this IWebHostBuilder hostBuilder { ArgumentGuard.NotNull(hostBuilder); - return hostBuilder.ConfigureLogging((hostContext, loggingBuilder) => - { - LoggerConfiguration? loggerConfiguration = null; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(hostBuilder); + wrapper.AddDynamicSerilog(HostBuilderContextWrapper.WrapAction(configureLogger), preserveDefaultConsole); - if (configureLogger != null) - { - loggerConfiguration = new LoggerConfiguration(); - configureLogger(hostContext, loggerConfiguration); - } - - loggingBuilder.AddDynamicSerilog(loggerConfiguration, preserveDefaultConsole); - }); + return hostBuilder; } } diff --git a/src/Logging/src/DynamicSerilog/Steeltoe.Logging.DynamicSerilog.csproj b/src/Logging/src/DynamicSerilog/Steeltoe.Logging.DynamicSerilog.csproj index 7cd29e01e5..1bd684503a 100644 --- a/src/Logging/src/DynamicSerilog/Steeltoe.Logging.DynamicSerilog.csproj +++ b/src/Logging/src/DynamicSerilog/Steeltoe.Logging.DynamicSerilog.csproj @@ -22,6 +22,7 @@ + diff --git a/src/Management/src/Endpoint/ActuatorServiceCollectionExtensions.cs b/src/Management/src/Endpoint/ActuatorServiceCollectionExtensions.cs index f8fccc93a0..2bdd345224 100755 --- a/src/Management/src/Endpoint/ActuatorServiceCollectionExtensions.cs +++ b/src/Management/src/Endpoint/ActuatorServiceCollectionExtensions.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors.Infrastructure; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -93,11 +95,8 @@ public static IServiceCollection AddAllActuators(this IServiceCollection service } services.AddHypermediaActuator(); - services.AddThreadDumpActuator(version); - services.AddHeapDumpActuator(); - services.AddDbMigrationsActuator(); services.AddEnvironmentActuator(); services.AddInfoActuator(); @@ -107,6 +106,7 @@ public static IServiceCollection AddAllActuators(this IServiceCollection service services.AddMappingsActuator(); services.AddMetricsActuator(); services.AddRefreshActuator(); + return services; } @@ -136,4 +136,29 @@ private static void AddSteeltoeCors(this IServiceCollection services, Action + /// Registers an that will map all configured actuators, initialize health. + /// + /// + /// that has actuators to activate. + /// + public static IEndpointConventionBuilder ActivateActuatorEndpoints(this IServiceCollection collection) + { + ArgumentGuard.NotNull(collection); + + // check for existing AllActuatorsStartupFilter + IEnumerable existingStartupFilters = collection.Where(descriptor => + descriptor.ImplementationType == typeof(AllActuatorsStartupFilter) || + descriptor.ImplementationFactory?.Method.ReturnType == typeof(AllActuatorsStartupFilter)); + + var actuatorConventionBuilder = new ActuatorConventionBuilder(); + + if (!existingStartupFilters.Any()) + { + collection.AddTransient(_ => new AllActuatorsStartupFilter(actuatorConventionBuilder)); + } + + return actuatorConventionBuilder; + } } diff --git a/src/Management/src/Endpoint/Health/EndpointServiceCollectionExtensions.cs b/src/Management/src/Endpoint/Health/EndpointServiceCollectionExtensions.cs index 482f2e7176..baef23b10e 100644 --- a/src/Management/src/Endpoint/Health/EndpointServiceCollectionExtensions.cs +++ b/src/Management/src/Endpoint/Health/EndpointServiceCollectionExtensions.cs @@ -46,7 +46,7 @@ public static void AddHealthActuator(this IServiceCollection services, params Ty ArgumentGuard.NotNull(services); ArgumentGuard.NotNull(contributorTypes); - services.AddHealthActuator(new HealthRegistrationsAggregator(), contributorTypes); + AddHealthActuator(services, new HealthRegistrationsAggregator(), contributorTypes); } /// diff --git a/src/Management/src/Endpoint/HostBuilderWrapperExtensions.cs b/src/Management/src/Endpoint/HostBuilderWrapperExtensions.cs new file mode 100644 index 0000000000..d1ca46efc6 --- /dev/null +++ b/src/Management/src/Endpoint/HostBuilderWrapperExtensions.cs @@ -0,0 +1,145 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Cors.Infrastructure; +using Steeltoe.Common.HealthChecks; +using Steeltoe.Common.Hosting; +using Steeltoe.Logging.DynamicLogger; +using Steeltoe.Management.Endpoint.CloudFoundry; +using Steeltoe.Management.Endpoint.DbMigrations; +using Steeltoe.Management.Endpoint.Environment; +using Steeltoe.Management.Endpoint.Health; +using Steeltoe.Management.Endpoint.HeapDump; +using Steeltoe.Management.Endpoint.Info; +using Steeltoe.Management.Endpoint.Loggers; +using Steeltoe.Management.Endpoint.ManagementPort; +using Steeltoe.Management.Endpoint.Metrics; +using Steeltoe.Management.Endpoint.Refresh; +using Steeltoe.Management.Endpoint.RouteMappings; +using Steeltoe.Management.Endpoint.ThreadDump; +using Steeltoe.Management.Endpoint.Trace; +using Steeltoe.Management.Endpoint.Web.Hypermedia; +using Steeltoe.Management.Info; + +namespace Steeltoe.Management.Endpoint; + +internal static class HostBuilderWrapperExtensions +{ + public static void AddAllActuators(this HostBuilderWrapper wrapper, Action? configureEndpoints, + MediaTypeVersion mediaTypeVersion, Action? buildCorsPolicy) + { + wrapper.ConfigureLogging(loggingBuilder => loggingBuilder.AddDynamicConsole()); + wrapper.ConfigureServices(services => services.AddAllActuators(mediaTypeVersion, buildCorsPolicy)); + RegisterActuatorEndpoints(wrapper, configureEndpoints); + } + + public static void AddDbMigrationsActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddDbMigrationsActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddEnvironmentActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddEnvironmentActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddHealthActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddHealthActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddHealthActuator(this HostBuilderWrapper wrapper, Type[] contributorTypes) + { + wrapper.ConfigureServices(services => services.AddHealthActuator(contributorTypes)); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddHealthActuator(this HostBuilderWrapper wrapper, IHealthAggregator aggregator, Type[] contributorTypes) + { + wrapper.ConfigureServices(services => services.AddHealthActuator(aggregator, contributorTypes)); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddHeapDumpActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddHeapDumpActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddHypermediaActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddHypermediaActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddInfoActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddInfoActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddInfoActuator(this HostBuilderWrapper wrapper, IInfoContributor[] contributors) + { + wrapper.ConfigureServices(services => services.AddInfoActuator(contributors)); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddLoggersActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureLogging(loggingBuilder => loggingBuilder.AddDynamicConsole()); + wrapper.ConfigureServices(services => services.AddLoggersActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddMappingsActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddMappingsActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddMetricsActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddMetricsActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddRefreshActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddRefreshActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddThreadDumpActuator(this HostBuilderWrapper wrapper, MediaTypeVersion mediaTypeVersion) + { + wrapper.ConfigureServices(services => services.AddThreadDumpActuator(mediaTypeVersion)); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddTraceActuator(this HostBuilderWrapper wrapper, MediaTypeVersion mediaTypeVersion) + { + wrapper.ConfigureServices(services => services.AddTraceActuator(mediaTypeVersion)); + RegisterActuatorEndpoints(wrapper, null); + } + + public static void AddCloudFoundryActuator(this HostBuilderWrapper wrapper) + { + wrapper.ConfigureServices(services => services.AddCloudFoundryActuator()); + RegisterActuatorEndpoints(wrapper, null); + } + + private static void RegisterActuatorEndpoints(HostBuilderWrapper wrapper, Action? configureEndpoints) + { + wrapper.ConfigureServices(services => + { + IEndpointConventionBuilder conventionBuilder = services.ActivateActuatorEndpoints(); + configureEndpoints?.Invoke(conventionBuilder); + }); + + wrapper.ConfigureWebHost(webHostBuilder => webHostBuilder.AddManagementPort()); + } +} diff --git a/src/Management/src/Endpoint/ManagementHostBuilderExtensions.cs b/src/Management/src/Endpoint/ManagementHostBuilderExtensions.cs index 4acd5576ad..e2e10dc6b7 100755 --- a/src/Management/src/Endpoint/ManagementHostBuilderExtensions.cs +++ b/src/Management/src/Endpoint/ManagementHostBuilderExtensions.cs @@ -4,26 +4,10 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors.Infrastructure; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Steeltoe.Common; using Steeltoe.Common.HealthChecks; using Steeltoe.Common.Hosting; -using Steeltoe.Logging.DynamicLogger; -using Steeltoe.Management.Endpoint.CloudFoundry; -using Steeltoe.Management.Endpoint.DbMigrations; -using Steeltoe.Management.Endpoint.Environment; -using Steeltoe.Management.Endpoint.Health; -using Steeltoe.Management.Endpoint.HeapDump; -using Steeltoe.Management.Endpoint.Info; -using Steeltoe.Management.Endpoint.Loggers; -using Steeltoe.Management.Endpoint.Metrics; -using Steeltoe.Management.Endpoint.Refresh; -using Steeltoe.Management.Endpoint.RouteMappings; -using Steeltoe.Management.Endpoint.ThreadDump; -using Steeltoe.Management.Endpoint.Trace; -using Steeltoe.Management.Endpoint.Web.Hypermedia; using Steeltoe.Management.Info; namespace Steeltoe.Management.Endpoint; @@ -33,80 +17,88 @@ public static class ManagementHostBuilderExtensions /// /// Adds the Database Migrations actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddDbMigrationsActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddDbMigrationsActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddDbMigrationsActuator(); - ActivateActuatorEndpoints(collection); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddDbMigrationsActuator(); + + return builder; } /// /// Adds the Environment actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddEnvironmentActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddEnvironmentActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddEnvironmentActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddEnvironmentActuator(); - ActivateActuatorEndpoints(collection); - }); + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddHealthActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddHealthActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHealthActuator(); - ActivateActuatorEndpoints(collection); - }); + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Types that contribute to the overall health of the app. /// - public static IHostBuilder AddHealthActuator(this IHostBuilder hostBuilder, params Type[] contributorTypes) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddHealthActuator(this IHostBuilder builder, params Type[] contributorTypes) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(contributorTypes); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHealthActuator(contributorTypes); - ActivateActuatorEndpoints(collection); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(contributorTypes); + + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Custom health aggregator. @@ -114,356 +106,334 @@ public static IHostBuilder AddHealthActuator(this IHostBuilder hostBuilder, para /// /// Types that contribute to the overall health of the app. /// - public static IHostBuilder AddHealthActuator(this IHostBuilder hostBuilder, IHealthAggregator aggregator, params Type[] contributorTypes) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddHealthActuator(this IHostBuilder builder, IHealthAggregator aggregator, params Type[] contributorTypes) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(aggregator); ArgumentGuard.NotNull(contributorTypes); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHealthActuator(aggregator, contributorTypes); - ActivateActuatorEndpoints(collection); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(aggregator, contributorTypes); + + return builder; } /// /// Adds the HeapDump actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddHeapDumpActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddHeapDumpActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHeapDumpActuator(); - ActivateActuatorEndpoints(collection); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHeapDumpActuator(); + + return builder; } /// /// Adds the Hypermedia actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddHypermediaActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddHypermediaActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHypermediaActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHypermediaActuator(); - ActivateActuatorEndpoints(collection); - }); + return builder; } /// /// Adds the Info actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddInfoActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddInfoActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddInfoActuator(); - ActivateActuatorEndpoints(collection); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddInfoActuator(); + + return builder; } /// /// Adds the Info actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Contributors to application information. /// - public static IHostBuilder AddInfoActuator(this IHostBuilder hostBuilder, params IInfoContributor[] contributors) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddInfoActuator(this IHostBuilder builder, params IInfoContributor[] contributors) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(contributors); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddInfoActuator(contributors); - ActivateActuatorEndpoints(collection); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddInfoActuator(contributors); + + return builder; } /// /// Adds the Loggers actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddLoggersActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddLoggersActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureLogging(builder => builder.AddDynamicConsole()).ConfigureServices((_, collection) => - { - collection.AddLoggersActuator(); - ActivateActuatorEndpoints(collection); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddLoggersActuator(); + + return builder; } /// /// Adds the Mappings actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddMappingsActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddMappingsActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddMappingsActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddMappingsActuator(); - ActivateActuatorEndpoints(collection); - }); + return builder; } /// /// Adds the Metrics actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddMetricsActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddMetricsActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddMetricsActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddMetricsActuator(); - ActivateActuatorEndpoints(collection); - }); + return builder; } /// /// Adds the Refresh actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddRefreshActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddRefreshActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddRefreshActuator(); - ActivateActuatorEndpoints(collection); - }); - } + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddRefreshActuator(); - /// - /// Adds the ThreadDump actuator to the application. - /// - /// - /// Your HostBuilder. - /// - /// - /// Specify the media type version to use in the response. - /// - public static IHostBuilder AddThreadDumpActuator(this IHostBuilder hostBuilder, MediaTypeVersion mediaTypeVersion) - { - ArgumentGuard.NotNull(hostBuilder); - - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddThreadDumpActuator(mediaTypeVersion); - ActivateActuatorEndpoints(collection); - }); + return builder; } /// /// Adds the ThreadDump actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddThreadDumpActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddThreadDumpActuator(this IHostBuilder builder) { - return hostBuilder.AddThreadDumpActuator(MediaTypeVersion.V2); + return AddThreadDumpActuator(builder, MediaTypeVersion.V2); } /// - /// Adds the Trace actuator to the application. + /// Adds the ThreadDump actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Specify the media type version to use in the response. /// - public static IHostBuilder AddTraceActuator(this IHostBuilder hostBuilder, MediaTypeVersion mediaTypeVersion) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddThreadDumpActuator(this IHostBuilder builder, MediaTypeVersion mediaTypeVersion) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddThreadDumpActuator(mediaTypeVersion); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddTraceActuator(mediaTypeVersion); - ActivateActuatorEndpoints(collection); - }); + return builder; } /// /// Adds the Trace actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddTraceActuator(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddTraceActuator(this IHostBuilder builder) { - return AddTraceActuator(hostBuilder, MediaTypeVersion.V2); + return AddTraceActuator(builder, MediaTypeVersion.V2); } /// - /// Adds the Cloud Foundry actuator to the application. + /// Adds the Trace actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IHostBuilder AddCloudFoundryActuator(this IHostBuilder hostBuilder) + /// + /// Specify the media type version to use in the response. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddTraceActuator(this IHostBuilder builder, MediaTypeVersion mediaTypeVersion) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddTraceActuator(mediaTypeVersion); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddCloudFoundryActuator(); - ActivateActuatorEndpoints(collection); - }); + return builder; } /// - /// Adds all standard actuators to the application. + /// Adds the Cloud Foundry actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - /// - /// Customize endpoint behavior. Useful for tailoring auth requirements. - /// - /// - /// Specify the media type version to use in the response. - /// - /// - /// Customize the CORS policy. - /// - /// - /// Does not add platform specific features (like for Cloud Foundry or Kubernetes). - /// - public static IHostBuilder AddAllActuators(this IHostBuilder hostBuilder, Action? configureEndpoints, - MediaTypeVersion mediaTypeVersion, Action? buildCorsPolicy) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddCloudFoundryActuator(this IHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); - - return hostBuilder.ConfigureLogging(builder => builder.AddDynamicConsole()).AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddAllActuators(mediaTypeVersion, buildCorsPolicy); - IEndpointConventionBuilder endpointConventionBuilder = ActivateActuatorEndpoints(collection); - configureEndpoints?.Invoke(endpointConventionBuilder); - }); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddCloudFoundryActuator(); + + return builder; } /// /// Adds all standard actuators to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Does not add platform specific features (like for Cloud Foundry or Kubernetes). /// - public static IHostBuilder AddAllActuators(this IHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddAllActuators(this IHostBuilder builder) { - return AddAllActuators(hostBuilder, null); + return AddAllActuators(builder, null); } /// /// Adds all standard actuators to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Customize endpoint behavior. Useful for tailoring auth requirements. /// - /// - /// Specify the media type version to use in the response. - /// /// /// Does not add platform specific features (like for Cloud Foundry or Kubernetes). /// - public static IHostBuilder AddAllActuators(this IHostBuilder hostBuilder, Action? configureEndpoints, - MediaTypeVersion mediaTypeVersion) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddAllActuators(this IHostBuilder builder, Action? configureEndpoints) { - return AddAllActuators(hostBuilder, configureEndpoints, mediaTypeVersion, null); + return AddAllActuators(builder, configureEndpoints, MediaTypeVersion.V2, null); } /// /// Adds all standard actuators to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Customize endpoint behavior. Useful for tailoring auth requirements. /// + /// + /// Specify the media type version to use in the response. + /// + /// + /// Customize the CORS policy. + /// /// /// Does not add platform specific features (like for Cloud Foundry or Kubernetes). /// - public static IHostBuilder AddAllActuators(this IHostBuilder hostBuilder, Action? configureEndpoints) - { - return AddAllActuators(hostBuilder, configureEndpoints, MediaTypeVersion.V2); - } - - /// - /// Registers an that will map all configured actuators, initialize health. - /// - /// - /// that has actuators to activate. - /// - public static IEndpointConventionBuilder ActivateActuatorEndpoints(this IServiceCollection collection) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IHostBuilder AddAllActuators(this IHostBuilder builder, Action? configureEndpoints, + MediaTypeVersion mediaTypeVersion, Action? buildCorsPolicy) { - ArgumentGuard.NotNull(collection); - - // check for existing AllActuatorsStartupFilter - IEnumerable existingStartupFilters = collection.Where(descriptor => - descriptor.ImplementationType == typeof(AllActuatorsStartupFilter) || - descriptor.ImplementationFactory?.Method.ReturnType == typeof(AllActuatorsStartupFilter)); + ArgumentGuard.NotNull(builder); - var actuatorConventionBuilder = new ActuatorConventionBuilder(); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddAllActuators(configureEndpoints, mediaTypeVersion, buildCorsPolicy); - if (!existingStartupFilters.Any()) - { - collection.AddTransient(_ => new AllActuatorsStartupFilter(actuatorConventionBuilder)); - } - - return actuatorConventionBuilder; - } - - private static IHostBuilder AddManagementPort(this IHostBuilder hostBuilder) - { - return hostBuilder.ConfigureWebHost(webHostBuilder => - { - (int? httpPort, int? httpsPort) = webHostBuilder.GetManagementPorts(); - - if (httpPort.HasValue || httpsPort.HasValue) - { - webHostBuilder.UseCloudHosting(httpPort, httpsPort); - } - }); + return builder; } } diff --git a/src/Management/src/Endpoint/ManagementPort/ErrorResponse.cs b/src/Management/src/Endpoint/ManagementPort/ErrorResponse.cs deleted file mode 100644 index 418a6ee4b7..0000000000 --- a/src/Management/src/Endpoint/ManagementPort/ErrorResponse.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License. -// See the LICENSE file in the project root for more information. - -using System.Text.Json.Serialization; - -namespace Steeltoe.Management.Endpoint.ManagementPort; - -internal sealed class ErrorResponse -{ - [JsonPropertyName("timestamp")] - public DateTime Timestamp { get; } - - [JsonPropertyName("status")] - public int Status { get; } - - [JsonPropertyName("error")] - public string Error { get; } - - [JsonPropertyName("message")] - public string Message { get; } - - [JsonPropertyName("path")] - public string Path { get; } - - public ErrorResponse(DateTime timestamp, int status, string error, string message, string path) - { - Timestamp = timestamp; - Status = status; - Error = error; - Message = message; - Path = path; - } -} diff --git a/src/Management/src/Endpoint/ManagementPort/ManagementPortMiddleware.cs b/src/Management/src/Endpoint/ManagementPort/ManagementPortMiddleware.cs index cfc2bba6a3..94f2098469 100644 --- a/src/Management/src/Endpoint/ManagementPort/ManagementPortMiddleware.cs +++ b/src/Management/src/Endpoint/ManagementPort/ManagementPortMiddleware.cs @@ -42,7 +42,7 @@ public async Task InvokeAsync(HttpContext context) if (!allowRequest) { - await ReturnErrorAsync(context, managementOptions.Port); + SetResponseError(context, managementOptions.Port); } else { @@ -53,16 +53,18 @@ public async Task InvokeAsync(HttpContext context) } } - private Task ReturnErrorAsync(HttpContext context, string? managementPort) + private void SetResponseError(HttpContext context, string? managementPort) { - var errorResponse = new ErrorResponse(DateTime.UtcNow, StatusCodes.Status404NotFound, "Not Found", "Path not found at port", context.Request.Path); + int? defaultPort = null; - _logger.LogError("ManagementMiddleWare Error: Access denied on {port} since Management Port is set to {managementPort}", context.Request.Host.Port, - managementPort); + if (context.Request.Host.Port == null) + { + defaultPort = context.Request.Scheme == "http" ? 80 : 443; + } - context.Response.Headers.Append("Content-Type", "application/json;charset=UTF-8"); - context.Response.StatusCode = StatusCodes.Status404NotFound; + _logger.LogError("ManagementMiddleWare Error: Access denied on {port} since Management Port is set to {managementPort}", + defaultPort ?? context.Request.Host.Port, managementPort); - return context.Response.WriteAsJsonAsync(errorResponse); + context.Response.StatusCode = StatusCodes.Status404NotFound; } } diff --git a/src/Management/src/Endpoint/ManagementPort/ManagementPortWebHostBuilderExtensions.cs b/src/Management/src/Endpoint/ManagementPort/ManagementPortWebHostBuilderExtensions.cs new file mode 100644 index 0000000000..7f25c85249 --- /dev/null +++ b/src/Management/src/Endpoint/ManagementPort/ManagementPortWebHostBuilderExtensions.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Steeltoe.Common; +using Steeltoe.Common.Hosting; + +namespace Steeltoe.Management.Endpoint.ManagementPort; + +internal static class ManagementPortWebHostBuilderExtensions +{ + private const string ManagementPortKey = "management:endpoints:port"; + private const string ManagementSslKey = "management:endpoints:sslenabled"; + + public static IWebHostBuilder AddManagementPort(this IWebHostBuilder webHostBuilder) + { + (int? httpPort, int? httpsPort) = GetManagementPorts(webHostBuilder); + + if (httpPort.HasValue || httpsPort.HasValue) + { + webHostBuilder.UseCloudHosting(httpPort, httpsPort); + } + + return webHostBuilder; + } + + private static (int? HttpPort, int? HttpsPort) GetManagementPorts(this IWebHostBuilder webHostBuilder) + { + ArgumentGuard.NotNull(webHostBuilder); + + string? portSetting = webHostBuilder.GetSetting(ManagementPortKey); + string? sslSetting = webHostBuilder.GetSetting(ManagementSslKey); + + int? httpPort = null; + int? httpsPort = null; + + if (string.IsNullOrEmpty(portSetting)) + { + IConfiguration? configuration = GetConfigurationFallback(); // try reading directly from appsettings.json + portSetting = configuration?[ManagementPortKey]; + sslSetting = configuration?[ManagementSslKey]; + } + + if (int.TryParse(portSetting, out int managementPort) && managementPort > 0) + { + if (bool.TryParse(sslSetting, out bool enableSsl) && enableSsl) + { + httpsPort = managementPort; + } + else + { + httpPort = managementPort; + } + } + + return (httpPort, httpsPort); + } + + private static IConfiguration? GetConfigurationFallback() + { + IConfiguration? configuration = null; + + try + { + string? environment = System.Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + + if (environment != null) + { + configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").AddJsonFile($"appsettings.{environment}.json", true).Build(); + } + } + catch (Exception) + { + // Not much we can do ... + } + + return configuration; + } +} diff --git a/src/Management/src/Endpoint/ManagementWebApplicationBuilderExtensions.cs b/src/Management/src/Endpoint/ManagementWebApplicationBuilderExtensions.cs index 3ee9fddd92..78cb47b11d 100755 --- a/src/Management/src/Endpoint/ManagementWebApplicationBuilderExtensions.cs +++ b/src/Management/src/Endpoint/ManagementWebApplicationBuilderExtensions.cs @@ -3,23 +3,10 @@ // See the LICENSE file in the project root for more information. using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Cors.Infrastructure; using Steeltoe.Common; using Steeltoe.Common.HealthChecks; using Steeltoe.Common.Hosting; -using Steeltoe.Logging.DynamicLogger; -using Steeltoe.Management.Endpoint.CloudFoundry; -using Steeltoe.Management.Endpoint.DbMigrations; -using Steeltoe.Management.Endpoint.Environment; -using Steeltoe.Management.Endpoint.Health; -using Steeltoe.Management.Endpoint.HeapDump; -using Steeltoe.Management.Endpoint.Info; -using Steeltoe.Management.Endpoint.Loggers; -using Steeltoe.Management.Endpoint.Metrics; -using Steeltoe.Management.Endpoint.Refresh; -using Steeltoe.Management.Endpoint.RouteMappings; -using Steeltoe.Management.Endpoint.ThreadDump; -using Steeltoe.Management.Endpoint.Trace; -using Steeltoe.Management.Endpoint.Web.Hypermedia; using Steeltoe.Management.Info; namespace Steeltoe.Management.Endpoint; @@ -29,72 +16,88 @@ public static class ManagementWebApplicationBuilderExtensions /// /// Adds the Database Migrations actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddDbMigrationsActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddDbMigrationsActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); - applicationBuilder.Services.AddDbMigrationsActuator(); - applicationBuilder.Services.ActivateActuatorEndpoints(); - return applicationBuilder; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddDbMigrationsActuator(); + + return builder; } /// /// Adds the Environment actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddEnvironmentActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddEnvironmentActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddEnvironmentActuator(); - applicationBuilder.Services.AddEnvironmentActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddHealthActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddHealthActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(); - applicationBuilder.Services.AddHealthActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// /// /// Types that contribute to the overall health of the app. /// - public static WebApplicationBuilder AddHealthActuator(this WebApplicationBuilder applicationBuilder, params Type[] contributorTypes) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddHealthActuator(this WebApplicationBuilder builder, params Type[] contributorTypes) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(contributorTypes); - applicationBuilder.Services.AddHealthActuator(contributorTypes); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(contributorTypes); + + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// /// /// Custom health aggregator. @@ -102,274 +105,325 @@ public static WebApplicationBuilder AddHealthActuator(this WebApplicationBuilder /// /// Types that contribute to the overall health of the app. /// - public static WebApplicationBuilder AddHealthActuator(this WebApplicationBuilder applicationBuilder, IHealthAggregator aggregator, - params Type[] contributorTypes) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddHealthActuator(this WebApplicationBuilder builder, IHealthAggregator aggregator, params Type[] contributorTypes) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(aggregator); ArgumentGuard.NotNull(contributorTypes); - applicationBuilder.Services.AddHealthActuator(aggregator, contributorTypes); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(aggregator, contributorTypes); + + return builder; } /// /// Adds the HeapDump actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddHeapDumpActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddHeapDumpActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHeapDumpActuator(); - applicationBuilder.Services.AddHeapDumpActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + return builder; } /// /// Adds the Hypermedia actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddHypermediaActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddHypermediaActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); - applicationBuilder.Services.AddHypermediaActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHypermediaActuator(); + + return builder; } /// /// Adds the Info actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddInfoActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddInfoActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddInfoActuator(); - applicationBuilder.Services.AddInfoActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + return builder; } /// /// Adds the Info actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// /// /// Contributors to application information. /// - public static WebApplicationBuilder AddInfoActuator(this WebApplicationBuilder applicationBuilder, params IInfoContributor[] contributors) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddInfoActuator(this WebApplicationBuilder builder, params IInfoContributor[] contributors) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(contributors); - applicationBuilder.Services.AddInfoActuator(contributors); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddInfoActuator(contributors); + + return builder; } /// /// Adds the Loggers actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddLoggersActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddLoggersActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); - applicationBuilder.Logging.AddDynamicConsole(); - applicationBuilder.Services.AddLoggersActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddLoggersActuator(); + + return builder; } /// /// Adds the Mappings actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddMappingsActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddMappingsActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddMappingsActuator(); - applicationBuilder.Services.AddMappingsActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + return builder; } /// /// Adds the Metrics actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddMetricsActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddMetricsActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddMetricsActuator(); - applicationBuilder.Services.AddMetricsActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + return builder; } /// /// Adds the Refresh actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddRefreshActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddRefreshActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); - applicationBuilder.Services.AddRefreshActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddRefreshActuator(); + + return builder; + } + + /// + /// Adds the ThreadDump actuator to the application. + /// + /// + /// The to configure. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddThreadDumpActuator(this WebApplicationBuilder builder) + { + return AddThreadDumpActuator(builder, MediaTypeVersion.V2); } /// /// Adds the ThreadDump actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// /// /// Specify the media type version to use in the response. /// - public static WebApplicationBuilder AddThreadDumpActuator(this WebApplicationBuilder applicationBuilder, MediaTypeVersion mediaTypeVersion) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddThreadDumpActuator(this WebApplicationBuilder builder, MediaTypeVersion mediaTypeVersion) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddThreadDumpActuator(mediaTypeVersion); - applicationBuilder.Services.AddThreadDumpActuator(mediaTypeVersion); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + return builder; } /// - /// Adds the ThreadDump actuator to the application. + /// Adds the Trace actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddThreadDumpActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddTraceActuator(this WebApplicationBuilder builder) { - return AddThreadDumpActuator(applicationBuilder, MediaTypeVersion.V2); + return AddTraceActuator(builder, MediaTypeVersion.V2); } /// /// Adds the Trace actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// /// /// Specify the media type version to use in the response. /// - public static WebApplicationBuilder AddTraceActuator(this WebApplicationBuilder applicationBuilder, MediaTypeVersion mediaTypeVersion) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddTraceActuator(this WebApplicationBuilder builder, MediaTypeVersion mediaTypeVersion) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); - applicationBuilder.Services.AddTraceActuator(mediaTypeVersion); - applicationBuilder.AddCommonServices(); - return applicationBuilder; - } + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddTraceActuator(mediaTypeVersion); - /// - /// Adds the Trace actuator to the application. - /// - /// - /// Your . - /// - public static WebApplicationBuilder AddTraceActuator(this WebApplicationBuilder applicationBuilder) - { - return AddTraceActuator(applicationBuilder, MediaTypeVersion.V2); + return builder; } /// /// Adds the Cloud Foundry actuator to the application. /// - /// - /// Your . + /// + /// The to configure. /// - public static WebApplicationBuilder AddCloudFoundryActuator(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddCloudFoundryActuator(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddCloudFoundryActuator(); - applicationBuilder.Services.AddCloudFoundryActuator(); - applicationBuilder.AddCommonServices(); - return applicationBuilder; + return builder; } /// /// Adds all Steeltoe Actuators to the application. /// - /// - /// Your . - /// - /// - /// . - /// - /// - /// Specify the media type version to use in the response. + /// + /// The to configure. /// - public static WebApplicationBuilder AddAllActuators(this WebApplicationBuilder applicationBuilder, Action? configureEndpoints, - MediaTypeVersion mediaTypeVersion) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddAllActuators(this WebApplicationBuilder builder) { - ArgumentGuard.NotNull(applicationBuilder); - - applicationBuilder.Logging.AddDynamicConsole(); - applicationBuilder.Services.AddAllActuators(mediaTypeVersion); - applicationBuilder.AddCommonServices(configureEndpoints); - return applicationBuilder; + return AddAllActuators(builder, null); } /// /// Adds all Steeltoe Actuators to the application. /// - /// - /// Your . + /// + /// The to configure. + /// + /// + /// . /// - public static WebApplicationBuilder AddAllActuators(this WebApplicationBuilder applicationBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddAllActuators(this WebApplicationBuilder builder, Action? configureEndpoints) { - return AddAllActuators(applicationBuilder, null); + return AddAllActuators(builder, configureEndpoints, MediaTypeVersion.V2, null); } /// /// Adds all Steeltoe Actuators to the application. /// - /// - /// Your . + /// + /// The to configure. /// /// /// . /// - public static WebApplicationBuilder AddAllActuators(this WebApplicationBuilder applicationBuilder, Action? configureEndpoints) - { - return AddAllActuators(applicationBuilder, configureEndpoints, MediaTypeVersion.V2); - } - - private static void AddCommonServices(this WebApplicationBuilder applicationBuilder, Action? configureEndpoints = null) + /// + /// Specify the media type version to use in the response. + /// + /// + /// Customize the CORS policy. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static WebApplicationBuilder AddAllActuators(this WebApplicationBuilder builder, Action? configureEndpoints, + MediaTypeVersion mediaTypeVersion, Action? buildCorsPolicy) { - (int? httpPort, int? httpsPort) = applicationBuilder.WebHost.GetManagementPorts(); + ArgumentGuard.NotNull(builder); - if (httpPort.HasValue || httpsPort.HasValue) - { - applicationBuilder.UseCloudHosting(httpPort, httpsPort); - } + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddAllActuators(configureEndpoints, mediaTypeVersion, buildCorsPolicy); - IEndpointConventionBuilder endpointConventionBuilder = applicationBuilder.Services.ActivateActuatorEndpoints(); - configureEndpoints?.Invoke(endpointConventionBuilder); + return builder; } } diff --git a/src/Management/src/Endpoint/ManagementWebHostBuilderExtensions.cs b/src/Management/src/Endpoint/ManagementWebHostBuilderExtensions.cs index f93a27f453..0d8974c362 100755 --- a/src/Management/src/Endpoint/ManagementWebHostBuilderExtensions.cs +++ b/src/Management/src/Endpoint/ManagementWebHostBuilderExtensions.cs @@ -3,111 +3,102 @@ // See the LICENSE file in the project root for more information. using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Steeltoe.Common; using Steeltoe.Common.HealthChecks; using Steeltoe.Common.Hosting; -using Steeltoe.Logging.DynamicLogger; -using Steeltoe.Management.Endpoint.CloudFoundry; -using Steeltoe.Management.Endpoint.DbMigrations; -using Steeltoe.Management.Endpoint.Environment; -using Steeltoe.Management.Endpoint.Health; -using Steeltoe.Management.Endpoint.HeapDump; -using Steeltoe.Management.Endpoint.Info; -using Steeltoe.Management.Endpoint.Loggers; -using Steeltoe.Management.Endpoint.Metrics; -using Steeltoe.Management.Endpoint.Refresh; -using Steeltoe.Management.Endpoint.RouteMappings; -using Steeltoe.Management.Endpoint.ThreadDump; -using Steeltoe.Management.Endpoint.Trace; -using Steeltoe.Management.Endpoint.Web.Hypermedia; using Steeltoe.Management.Info; namespace Steeltoe.Management.Endpoint; public static class ManagementWebHostBuilderExtensions { - private const string ManagementPortKey = "management:endpoints:port"; - private const string ManagementSslKey = "management:endpoints:sslenabled"; - /// /// Adds the Database Migrations actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddDbMigrationsActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddDbMigrationsActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddDbMigrationsActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddDbMigrationsActuator(); - collection.ActivateActuatorEndpoints(); - }); + return builder; } /// /// Adds the Environment actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddEnvironmentActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddEnvironmentActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddEnvironmentActuator(); - collection.ActivateActuatorEndpoints(); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddEnvironmentActuator(); + + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddHealthActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddHealthActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHealthActuator(); - collection.ActivateActuatorEndpoints(); - }); + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Types that contribute to the overall health of the app. /// - public static IWebHostBuilder AddHealthActuator(this IWebHostBuilder hostBuilder, params Type[] contributorTypes) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddHealthActuator(this IWebHostBuilder builder, params Type[] contributorTypes) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(contributorTypes); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHealthActuator(contributorTypes); - collection.ActivateActuatorEndpoints(); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(contributorTypes); + + return builder; } /// /// Adds the Health actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Custom health aggregator. @@ -115,350 +106,325 @@ public static IWebHostBuilder AddHealthActuator(this IWebHostBuilder hostBuilder /// /// Types that contribute to the overall health of the app. /// - public static IWebHostBuilder AddHealthActuator(this IWebHostBuilder hostBuilder, IHealthAggregator aggregator, params Type[] contributorTypes) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddHealthActuator(this IWebHostBuilder builder, IHealthAggregator aggregator, params Type[] contributorTypes) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(aggregator); ArgumentGuard.NotNull(contributorTypes); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHealthActuator(aggregator, contributorTypes); - collection.ActivateActuatorEndpoints(); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHealthActuator(aggregator, contributorTypes); + + return builder; } /// /// Adds the HeapDump actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddHeapDumpActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddHeapDumpActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHeapDumpActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHeapDumpActuator(); - collection.ActivateActuatorEndpoints(); - }); + return builder; } /// /// Adds the Hypermedia actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddHypermediaActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddHypermediaActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddHypermediaActuator(); - collection.ActivateActuatorEndpoints(); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddHypermediaActuator(); + + return builder; } /// /// Adds the Info actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddInfoActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddInfoActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddInfoActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddInfoActuator(); - collection.ActivateActuatorEndpoints(); - }); + return builder; } /// /// Adds the Info actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Contributors to application information. /// - public static IWebHostBuilder AddInfoActuator(this IWebHostBuilder hostBuilder, params IInfoContributor[] contributors) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddInfoActuator(this IWebHostBuilder builder, params IInfoContributor[] contributors) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(contributors); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddInfoActuator(contributors); - collection.ActivateActuatorEndpoints(); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddInfoActuator(contributors); + + return builder; } /// /// Adds the Loggers actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddLoggersActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddLoggersActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddLoggersActuator(); - return hostBuilder.AddManagementPort().ConfigureLogging(builder => builder.AddDynamicConsole()).ConfigureServices((_, collection) => - { - collection.AddLoggersActuator(); - collection.ActivateActuatorEndpoints(); - }); + return builder; } /// /// Adds the Mappings actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddMappingsActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddMappingsActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddMappingsActuator(); - collection.ActivateActuatorEndpoints(); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddMappingsActuator(); + + return builder; } /// /// Adds the Metrics actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddMetricsActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddMetricsActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddMetricsActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddMetricsActuator(); - collection.ActivateActuatorEndpoints(); - }); + return builder; } /// /// Adds the Refresh actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddRefreshActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddRefreshActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddRefreshActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddRefreshActuator(); - collection.ActivateActuatorEndpoints(); - }); + return builder; } /// /// Adds the ThreadDump actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddThreadDumpActuator(this IWebHostBuilder builder) + { + return AddThreadDumpActuator(builder, MediaTypeVersion.V2); + } + + /// + /// Adds the ThreadDump actuator to the application. + /// + /// + /// The to configure. /// /// /// Specify the media type version to use in the response. /// - public static IWebHostBuilder AddThreadDumpActuator(this IWebHostBuilder hostBuilder, MediaTypeVersion mediaTypeVersion) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddThreadDumpActuator(this IWebHostBuilder builder, MediaTypeVersion mediaTypeVersion) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddThreadDumpActuator(mediaTypeVersion); - collection.ActivateActuatorEndpoints(); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddThreadDumpActuator(mediaTypeVersion); + + return builder; } /// - /// Adds the ThreadDump actuator to the application. + /// Adds the Trace actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddThreadDumpActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddTraceActuator(this IWebHostBuilder builder) { - return AddThreadDumpActuator(hostBuilder, MediaTypeVersion.V2); + return AddTraceActuator(builder, MediaTypeVersion.V2); } /// /// Adds the Trace actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// Specify the media type version to use in the response. /// - public static IWebHostBuilder AddTraceActuator(this IWebHostBuilder hostBuilder, MediaTypeVersion mediaTypeVersion) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddTraceActuator(this IWebHostBuilder builder, MediaTypeVersion mediaTypeVersion) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddTraceActuator(mediaTypeVersion); - collection.ActivateActuatorEndpoints(); - }); - } + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddTraceActuator(mediaTypeVersion); - /// - /// Adds the Trace actuator to the application. - /// - /// - /// Your HostBuilder. - /// - public static IWebHostBuilder AddTraceActuator(this IWebHostBuilder hostBuilder) - { - return hostBuilder.AddTraceActuator(MediaTypeVersion.V2); + return builder; } /// /// Adds the Cloud Foundry actuator to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddCloudFoundryActuator(this IWebHostBuilder hostBuilder) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddCloudFoundryActuator(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); + ArgumentGuard.NotNull(builder); + + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddCloudFoundryActuator(); - return hostBuilder.AddManagementPort().ConfigureServices((_, collection) => - { - collection.AddCloudFoundryActuator(); - collection.ActivateActuatorEndpoints(); - }); + return builder; } /// /// Adds all Steeltoe Actuators to the application. /// - /// - /// Your HostBuilder. - /// - /// - /// . + /// + /// The to configure. /// - /// - /// Specify the media type version to use in the response. - /// - public static IWebHostBuilder AddAllActuators(this IWebHostBuilder hostBuilder, Action? configureEndpoints, - MediaTypeVersion mediaTypeVersion) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddAllActuators(this IWebHostBuilder builder) { - ArgumentGuard.NotNull(hostBuilder); - - return hostBuilder.AddManagementPort().ConfigureLogging(builder => builder.AddDynamicConsole()).ConfigureServices((_, collection) => - { - collection.AddAllActuators(mediaTypeVersion); - IEndpointConventionBuilder conventionBuilder = collection.ActivateActuatorEndpoints(); - configureEndpoints?.Invoke(conventionBuilder); - }); + return AddAllActuators(builder, null); } /// /// Adds all Steeltoe Actuators to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// /// /// . /// - public static IWebHostBuilder AddAllActuators(this IWebHostBuilder hostBuilder, Action? configureEndpoints) + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddAllActuators(this IWebHostBuilder builder, Action? configureEndpoints) { - return AddAllActuators(hostBuilder, configureEndpoints, MediaTypeVersion.V2); + return AddAllActuators(builder, configureEndpoints, MediaTypeVersion.V2, null); } /// /// Adds all Steeltoe Actuators to the application. /// - /// - /// Your HostBuilder. + /// + /// The to configure. /// - public static IWebHostBuilder AddAllActuators(this IWebHostBuilder hostBuilder) - { - return AddAllActuators(hostBuilder, null); - } - - internal static (int? HttpPort, int? HttpsPort) GetManagementPorts(this IWebHostBuilder webHostBuilder) - { - ArgumentGuard.NotNull(webHostBuilder); - - string? portSetting = webHostBuilder.GetSetting(ManagementPortKey); - string? sslSetting = webHostBuilder.GetSetting(ManagementSslKey); - - int? httpPort = null; - int? httpsPort = null; - - if (string.IsNullOrEmpty(portSetting)) - { - IConfiguration? configuration = GetConfigurationFallback(); // try reading directly from appsettings.json - portSetting = configuration?[ManagementPortKey]; - sslSetting = configuration?[ManagementSslKey]; - } - - if (int.TryParse(portSetting, out int managementPort) && managementPort > 0) - { - if (bool.TryParse(sslSetting, out bool enableSsl) && enableSsl) - { - httpsPort = managementPort; - } - else - { - httpPort = managementPort; - } - } - - return (httpPort, httpsPort); - } - - private static IWebHostBuilder AddManagementPort(this IWebHostBuilder webHostBuilder) + /// + /// . + /// + /// + /// Specify the media type version to use in the response. + /// + /// + /// Customize the CORS policy. + /// + /// + /// The incoming , so that additional calls can be chained. + /// + public static IWebHostBuilder AddAllActuators(this IWebHostBuilder builder, Action? configureEndpoints, + MediaTypeVersion mediaTypeVersion, Action? buildCorsPolicy) { - (int? httpPort, int? httpsPort) = webHostBuilder.GetManagementPorts(); + ArgumentGuard.NotNull(builder); - if (httpPort.HasValue || httpsPort.HasValue) - { - webHostBuilder.UseCloudHosting(httpPort, httpsPort); - } + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(builder); + wrapper.AddAllActuators(configureEndpoints, mediaTypeVersion, buildCorsPolicy); - return webHostBuilder; - } - - private static IConfiguration? GetConfigurationFallback() - { - IConfiguration? configuration = null; - - try - { - string? environment = System.Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); - - if (environment != null) - { - configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").AddJsonFile($"appsettings.{environment}.json", true).Build(); - } - } - catch (Exception) - { - // Not much we can do ... - } - - return configuration; + return builder; } } diff --git a/src/Management/src/Endpoint/Properties/AssemblyInfo.cs b/src/Management/src/Endpoint/Properties/AssemblyInfo.cs index 84a378631c..708833e400 100644 --- a/src/Management/src/Endpoint/Properties/AssemblyInfo.cs +++ b/src/Management/src/Endpoint/Properties/AssemblyInfo.cs @@ -5,6 +5,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] +[assembly: InternalsVisibleTo("Steeltoe.Bootstrap.AutoConfiguration")] [assembly: InternalsVisibleTo("Steeltoe.Management.Endpoint.Test")] [assembly: InternalsVisibleTo("Steeltoe.Management.Prometheus")] [assembly: InternalsVisibleTo("Steeltoe.Management.Wavefront")] diff --git a/src/Management/src/Endpoint/PublicAPI.Unshipped.txt b/src/Management/src/Endpoint/PublicAPI.Unshipped.txt index f89c85e4b3..96f39d5af0 100755 --- a/src/Management/src/Endpoint/PublicAPI.Unshipped.txt +++ b/src/Management/src/Endpoint/PublicAPI.Unshipped.txt @@ -14,6 +14,7 @@ override Steeltoe.Management.Endpoint.Refresh.RefreshEndpointOptions.AllowedVerb static Steeltoe.Management.Endpoint.ActuatorRouteBuilderExtensions.MapAllActuators(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! builder) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder! static Steeltoe.Management.Endpoint.ActuatorRouteBuilderExtensions.MapAllActuators(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! routeBuilder, Steeltoe.Management.Endpoint.ActuatorConventionBuilder? conventionBuilder) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder! static Steeltoe.Management.Endpoint.ActuatorRouteBuilderExtensions.MapAllActuators(this Microsoft.AspNetCore.Routing.IRouteBuilder! builder) -> Microsoft.AspNetCore.Routing.IRouteBuilder! +static Steeltoe.Management.Endpoint.ActuatorServiceCollectionExtensions.ActivateActuatorEndpoints(this Microsoft.Extensions.DependencyInjection.IServiceCollection! collection) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder! static Steeltoe.Management.Endpoint.ActuatorServiceCollectionExtensions.AddAllActuators(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Steeltoe.Management.Endpoint.ActuatorServiceCollectionExtensions.AddAllActuators(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, Steeltoe.Management.Endpoint.MediaTypeVersion version) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Steeltoe.Management.Endpoint.ActuatorServiceCollectionExtensions.AddAllActuators(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, Steeltoe.Management.Endpoint.MediaTypeVersion version, System.Action? buildCorsPolicy) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! @@ -39,71 +40,69 @@ static Steeltoe.Management.Endpoint.Info.EndpointServiceCollectionExtensions.Add static Steeltoe.Management.Endpoint.Info.ServiceCollectionExtensions.AddInfoActuatorServices(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Steeltoe.Management.Endpoint.Loggers.EndpointServiceCollectionExtensions.AddLoggersActuator(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> void static Steeltoe.Management.Endpoint.Loggers.ServiceCollectionExtensions.AddLoggersActuatorServices(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.ActivateActuatorEndpoints(this Microsoft.Extensions.DependencyInjection.IServiceCollection! collection) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddAllActuators(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddAllActuators(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, System.Action? configureEndpoints) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddAllActuators(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, System.Action? configureEndpoints, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddAllActuators(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, System.Action? configureEndpoints, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion, System.Action? buildCorsPolicy) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddCloudFoundryActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddDbMigrationsActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddEnvironmentActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHealthActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHealthActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, params System.Type![]! contributorTypes) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHealthActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, Steeltoe.Common.HealthChecks.IHealthAggregator! aggregator, params System.Type![]! contributorTypes) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHeapDumpActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHypermediaActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddInfoActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddInfoActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, params Steeltoe.Management.Info.IInfoContributor![]! contributors) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddLoggersActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddMappingsActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddMetricsActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddRefreshActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddThreadDumpActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddThreadDumpActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddTraceActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddTraceActuator(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.Extensions.Hosting.IHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder, System.Action? configureEndpoints) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder, System.Action? configureEndpoints, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddCloudFoundryActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddDbMigrationsActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddEnvironmentActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder, params System.Type![]! contributorTypes) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder, Steeltoe.Common.HealthChecks.IHealthAggregator! aggregator, params System.Type![]! contributorTypes) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHeapDumpActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHypermediaActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddInfoActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddInfoActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder, params Steeltoe.Management.Info.IInfoContributor![]! contributors) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddLoggersActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddMappingsActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddMetricsActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddRefreshActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddThreadDumpActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddThreadDumpActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddTraceActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddTraceActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder, System.Action? configureEndpoints) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder, System.Action? configureEndpoints, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddCloudFoundryActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddDbMigrationsActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddEnvironmentActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder, params System.Type![]! contributorTypes) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder, Steeltoe.Common.HealthChecks.IHealthAggregator! aggregator, params System.Type![]! contributorTypes) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHeapDumpActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHypermediaActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddInfoActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddInfoActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder, params Steeltoe.Management.Info.IInfoContributor![]! contributors) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddLoggersActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddMappingsActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddMetricsActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddRefreshActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddThreadDumpActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddThreadDumpActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddTraceActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! -static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddTraceActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddAllActuators(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddAllActuators(this Microsoft.Extensions.Hosting.IHostBuilder! builder, System.Action? configureEndpoints) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddAllActuators(this Microsoft.Extensions.Hosting.IHostBuilder! builder, System.Action? configureEndpoints, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion, System.Action? buildCorsPolicy) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddCloudFoundryActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddDbMigrationsActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddEnvironmentActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHealthActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHealthActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder, params System.Type![]! contributorTypes) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHealthActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder, Steeltoe.Common.HealthChecks.IHealthAggregator! aggregator, params System.Type![]! contributorTypes) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHeapDumpActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddHypermediaActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddInfoActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddInfoActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder, params Steeltoe.Management.Info.IInfoContributor![]! contributors) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddLoggersActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddMappingsActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddMetricsActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddRefreshActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddThreadDumpActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddThreadDumpActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddTraceActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementHostBuilderExtensions.AddTraceActuator(this Microsoft.Extensions.Hosting.IHostBuilder! builder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.Extensions.Hosting.IHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, System.Action? configureEndpoints) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, System.Action? configureEndpoints, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion, System.Action? buildCorsPolicy) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddCloudFoundryActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddDbMigrationsActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddEnvironmentActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, params System.Type![]! contributorTypes) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, Steeltoe.Common.HealthChecks.IHealthAggregator! aggregator, params System.Type![]! contributorTypes) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHeapDumpActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddHypermediaActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddInfoActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddInfoActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, params Steeltoe.Management.Info.IInfoContributor![]! contributors) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddLoggersActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddMappingsActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddMetricsActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddRefreshActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddThreadDumpActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddThreadDumpActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddTraceActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebApplicationBuilderExtensions.AddTraceActuator(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! builder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, System.Action? configureEndpoints) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddAllActuators(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, System.Action? configureEndpoints, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion, System.Action? buildCorsPolicy) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddCloudFoundryActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddDbMigrationsActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddEnvironmentActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, params System.Type![]! contributorTypes) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHealthActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, Steeltoe.Common.HealthChecks.IHealthAggregator! aggregator, params System.Type![]! contributorTypes) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHeapDumpActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddHypermediaActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddInfoActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddInfoActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, params Steeltoe.Management.Info.IInfoContributor![]! contributors) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddLoggersActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddMappingsActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddMetricsActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddRefreshActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddThreadDumpActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddThreadDumpActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddTraceActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! +static Steeltoe.Management.Endpoint.ManagementWebHostBuilderExtensions.AddTraceActuator(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! builder, Steeltoe.Management.Endpoint.MediaTypeVersion mediaTypeVersion) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! static Steeltoe.Management.Endpoint.Metrics.EndpointServiceCollectionExtensions.AddMetricsActuator(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> void static Steeltoe.Management.Endpoint.Metrics.EndpointServiceCollectionExtensions.AddMetricsObservers(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> void static Steeltoe.Management.Endpoint.Metrics.ServiceCollectionExtensions.AddMetricsActuatorServices(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! diff --git a/src/Management/src/Kubernetes/HostBuilderExtensions.cs b/src/Management/src/Kubernetes/HostBuilderExtensions.cs index 2d4ada1094..6d582bd254 100644 --- a/src/Management/src/Kubernetes/HostBuilderExtensions.cs +++ b/src/Management/src/Kubernetes/HostBuilderExtensions.cs @@ -4,9 +4,9 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Steeltoe.Common; +using Steeltoe.Common.Hosting; using Steeltoe.Logging.DynamicLogger; using Steeltoe.Management.Endpoint; @@ -38,12 +38,10 @@ public static IHostBuilder AddKubernetesActuators(this IHostBuilder hostBuilder, { ArgumentGuard.NotNull(hostBuilder); - return hostBuilder.ConfigureLogging((_, configureLogging) => configureLogging.AddDynamicConsole()).ConfigureServices((_, collection) => - { - collection.AddKubernetesActuators(); - IEndpointConventionBuilder epBuilder = collection.ActivateActuatorEndpoints(); - configureEndpoints?.Invoke(epBuilder); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(hostBuilder); + wrapper.AddKubernetesActuators(configureEndpoints); + + return hostBuilder; } /// @@ -70,12 +68,10 @@ public static IWebHostBuilder AddKubernetesActuators(this IWebHostBuilder webHos { ArgumentGuard.NotNull(webHostBuilder); - return webHostBuilder.ConfigureLogging((_, configureLogging) => configureLogging.AddDynamicConsole()).ConfigureServices((_, collection) => - { - collection.AddKubernetesActuators(); - IEndpointConventionBuilder epBuilder = collection.ActivateActuatorEndpoints(); - configureEndpoints?.Invoke(epBuilder); - }); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(webHostBuilder); + wrapper.AddKubernetesActuators(configureEndpoints); + + return webHostBuilder; } /// @@ -103,12 +99,22 @@ public static WebApplicationBuilder AddKubernetesActuators(this WebApplicationBu { ArgumentGuard.NotNull(webApplicationBuilder); - webApplicationBuilder.Logging.AddDynamicConsole(); - - IServiceCollection services = webApplicationBuilder.Services.AddKubernetesActuators(); - IEndpointConventionBuilder epBuilder = services.ActivateActuatorEndpoints(); - configureEndpoints?.Invoke(epBuilder); + HostBuilderWrapper wrapper = HostBuilderWrapper.Wrap(webApplicationBuilder); + wrapper.AddKubernetesActuators(configureEndpoints); return webApplicationBuilder; } + + internal static void AddKubernetesActuators(this HostBuilderWrapper wrapper, Action? configureEndpoints) + { + wrapper.ConfigureLogging(loggingBuilder => loggingBuilder.AddDynamicConsole()); + + wrapper.ConfigureServices(services => + { + services.AddKubernetesActuators(); + + IEndpointConventionBuilder endpointBuilder = services.ActivateActuatorEndpoints(); + configureEndpoints?.Invoke(endpointBuilder); + }); + } } diff --git a/src/Management/src/Kubernetes/Properties/AssemblyInfo.cs b/src/Management/src/Kubernetes/Properties/AssemblyInfo.cs index f96f080a87..8e5aa60723 100755 --- a/src/Management/src/Kubernetes/Properties/AssemblyInfo.cs +++ b/src/Management/src/Kubernetes/Properties/AssemblyInfo.cs @@ -4,4 +4,5 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Steeltoe.Bootstrap.AutoConfiguration")] [assembly: InternalsVisibleTo("Steeltoe.Management.Kubernetes.Test")] diff --git a/src/Management/src/Tracing/Steeltoe.Management.Tracing.csproj b/src/Management/src/Tracing/Steeltoe.Management.Tracing.csproj index 3782efa3f4..41372a6f74 100644 --- a/src/Management/src/Tracing/Steeltoe.Management.Tracing.csproj +++ b/src/Management/src/Tracing/Steeltoe.Management.Tracing.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Management/src/Wavefront/PublicAPI.Unshipped.txt b/src/Management/src/Wavefront/PublicAPI.Unshipped.txt index 742d627acc..e14df32df8 100644 --- a/src/Management/src/Wavefront/PublicAPI.Unshipped.txt +++ b/src/Management/src/Wavefront/PublicAPI.Unshipped.txt @@ -3,10 +3,7 @@ override Steeltoe.Management.Wavefront.Exporters.WavefrontMetricsExporter.Export override Steeltoe.Management.Wavefront.Exporters.WavefrontTraceExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult static Steeltoe.Management.Wavefront.Exporters.WavefrontTraceExtensions.AddWavefrontTraceExporter(this OpenTelemetry.Trace.TracerProviderBuilder! builder, Steeltoe.Management.Wavefront.Exporters.WavefrontExporterOptions! options, Microsoft.Extensions.Logging.ILogger! logger) -> OpenTelemetry.Trace.TracerProviderBuilder! static Steeltoe.Management.Wavefront.WavefrontExtensions.AddWavefrontExporter(this OpenTelemetry.Metrics.MeterProviderBuilder! builder) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static Steeltoe.Management.Wavefront.WavefrontExtensions.AddWavefrontMetrics(this Microsoft.AspNetCore.Builder.WebApplicationBuilder! applicationBuilder) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder! -static Steeltoe.Management.Wavefront.WavefrontExtensions.AddWavefrontMetrics(this Microsoft.AspNetCore.Hosting.IWebHostBuilder! hostBuilder) -> Microsoft.AspNetCore.Hosting.IWebHostBuilder! static Steeltoe.Management.Wavefront.WavefrontExtensions.AddWavefrontMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Steeltoe.Management.Wavefront.WavefrontExtensions.AddWavefrontMetrics(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder! Steeltoe.Management.Wavefront.Exporters.WavefrontApplicationOptions Steeltoe.Management.Wavefront.Exporters.WavefrontApplicationOptions.Name.get -> string? Steeltoe.Management.Wavefront.Exporters.WavefrontApplicationOptions.Name.set -> void diff --git a/src/Management/src/Wavefront/WavefrontExtensions.cs b/src/Management/src/Wavefront/WavefrontExtensions.cs index d3fd1aca38..afaba962c6 100644 --- a/src/Management/src/Wavefront/WavefrontExtensions.cs +++ b/src/Management/src/Wavefront/WavefrontExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; @@ -49,52 +47,6 @@ public static IServiceCollection AddWavefrontMetrics(this IServiceCollection ser return services; } - /// - /// Add wavefront metrics to the application. - /// - /// - /// Your Hostbuilder. - /// - /// - /// The updated HostBuilder. - /// - public static IHostBuilder AddWavefrontMetrics(this IHostBuilder hostBuilder) - { - ArgumentGuard.NotNull(hostBuilder); - - return hostBuilder.ConfigureServices((_, collection) => - { - collection.AddWavefrontMetrics(); - }); - } - - /// - /// Add Wavefront Metrics Exporter. - /// - /// - /// Your . - /// - public static WebApplicationBuilder AddWavefrontMetrics(this WebApplicationBuilder applicationBuilder) - { - ArgumentGuard.NotNull(applicationBuilder); - - applicationBuilder.Services.AddWavefrontMetrics(); - return applicationBuilder; - } - - /// - /// Adds Wavefront to the application. - /// - /// - /// Your HostBuilder. - /// - public static IWebHostBuilder AddWavefrontMetrics(this IWebHostBuilder hostBuilder) - { - ArgumentGuard.NotNull(hostBuilder); - - return hostBuilder.ConfigureServices((_, collection) => collection.AddWavefrontMetrics()); - } - public static MeterProviderBuilder AddWavefrontExporter(this MeterProviderBuilder builder) { ArgumentGuard.NotNull(builder); diff --git a/src/Management/test/Endpoint.Test/ActuatorRouteBuilderExtensionsTest.cs b/src/Management/test/Endpoint.Test/ActuatorRouteBuilderExtensionsTest.cs index ca43da47ef..c747f6856f 100644 --- a/src/Management/test/Endpoint.Test/ActuatorRouteBuilderExtensionsTest.cs +++ b/src/Management/test/Endpoint.Test/ActuatorRouteBuilderExtensionsTest.cs @@ -56,7 +56,7 @@ private static IHostBuilder GetHostBuilder(Action po { "management:endpoints:actuator:exposure:include:0", "*" } }; - return new HostBuilder().ConfigureLogging(builder => builder.AddDynamicConsole()).ConfigureServices((_, services) => + return new HostBuilder().ConfigureLogging(builder => builder.AddDynamicConsole()).ConfigureServices(services => { services.AddAllActuators(); services.AddRouting(); diff --git a/src/Management/test/Endpoint.Test/ActuatorServiceCollectionExtensionsTest.cs b/src/Management/test/Endpoint.Test/ActuatorServiceCollectionExtensionsTest.cs index e7e4d770e5..d0a37a2284 100644 --- a/src/Management/test/Endpoint.Test/ActuatorServiceCollectionExtensionsTest.cs +++ b/src/Management/test/Endpoint.Test/ActuatorServiceCollectionExtensionsTest.cs @@ -23,7 +23,7 @@ public void AddAllActuators_ConfiguresCorsDefaults() { }); - IWebHost host = hostBuilder.ConfigureServices((_, services) => services.AddAllActuators()).Build(); + IWebHost host = hostBuilder.ConfigureServices(services => services.AddAllActuators()).Build(); var options = new ApplicationBuilder(host.Services).ApplicationServices.GetService(typeof(IOptions)) as IOptions; Assert.NotNull(options); @@ -41,7 +41,7 @@ public void AddAllActuators_ConfiguresCorsCustom() { }); - IWebHost host = hostBuilder.ConfigureServices((_, services) => services.AddAllActuators(myPolicy => myPolicy.WithOrigins("http://google.com"))).Build(); + IWebHost host = hostBuilder.ConfigureServices(services => services.AddAllActuators(myPolicy => myPolicy.WithOrigins("http://google.com"))).Build(); var options = new ApplicationBuilder(host.Services).ApplicationServices.GetService(typeof(IOptions)) as IOptions; @@ -64,7 +64,7 @@ public void AddAllActuators_YesCF_onCF() { }).ConfigureAppConfiguration(cfg => cfg.AddCloudFoundry()); - IWebHost host = hostBuilder.ConfigureServices((_, services) => services.AddAllActuators()).Build(); + IWebHost host = hostBuilder.ConfigureServices(services => services.AddAllActuators()).Build(); Assert.NotNull(host.Services.GetService()); } @@ -76,7 +76,7 @@ public void AddAllActuators_NoCF_offCF() { }).ConfigureAppConfiguration(cfg => cfg.AddCloudFoundry()); - IWebHost host = hostBuilder.ConfigureServices((_, services) => services.AddAllActuators()).Build(); + IWebHost host = hostBuilder.ConfigureServices(services => services.AddAllActuators()).Build(); Assert.Null(host.Services.GetService()); } diff --git a/src/Management/test/Endpoint.Test/ManagementPort/ManagementEndpointServedOnDifferentPort.cs b/src/Management/test/Endpoint.Test/ManagementPort/ManagementEndpointServedOnDifferentPort.cs deleted file mode 100644 index 58eabeb3cb..0000000000 --- a/src/Management/test/Endpoint.Test/ManagementPort/ManagementEndpointServedOnDifferentPort.cs +++ /dev/null @@ -1,171 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License. -// See the LICENSE file in the project root for more information. - -using System.Net; -using System.Net.Http.Json; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Steeltoe.Common.Hosting; -using Steeltoe.Common.TestResources; -using Steeltoe.Management.Endpoint.ManagementPort; -using Xunit; - -namespace Steeltoe.Management.Endpoint.Test.ManagementPort; - -public sealed class ManagementEndpointServedOnDifferentPort -{ - [Fact] - public async Task AddAllActuators_WebApplication_MakeSureTheManagementPortIsSet() - { - var appsettings = new Dictionary - { - { "management:endpoints:port", "9090" } - }; - - WebApplicationBuilder hostBuilder = WebApplication.CreateBuilder(); - hostBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); - hostBuilder.Configuration.AddInMemoryCollection(appsettings); - hostBuilder.AddAllActuators(); - hostBuilder.WebHost.UseTestServer(); - hostBuilder.Services.AddActionDescriptorCollectionProvider(); - - WebApplication app = hostBuilder.Build(); - app.MapGet("/", () => "Hello World!"); - app.Start(); - - using HttpClient httpClient = app.GetTestServer().CreateClient(); - HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://localhost:9090/actuator")); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await httpClient.GetAsync(new Uri("http://localhost:8080")); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - - [Fact] - public async Task AddAllActuators_WorksWithUseCloudHosting() - { - var appsettings = new Dictionary - { - { "management:endpoints:port", "9090" } - }; - - WebApplicationBuilder hostBuilder = WebApplication.CreateBuilder(); - hostBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); - hostBuilder.Configuration.AddInMemoryCollection(appsettings); - hostBuilder.UseCloudHosting(); - hostBuilder.AddAllActuators(); - hostBuilder.Services.AddActionDescriptorCollectionProvider(); - hostBuilder.WebHost.UseTestServer(); - - WebApplication app = hostBuilder.Build(); - app.MapGet("/", () => "Hello World!"); - app.Start(); - - using HttpClient httpClient = app.GetTestServer().CreateClient(); - HttpResponseMessage response = await httpClient.GetAsync(new Uri("https://localhost:9090/actuator")); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await httpClient.GetAsync(new Uri("http://localhost:5100")); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - - [Fact] - public async Task AddAllActuators_WebApplication_MakeSure_SSLEnabled() - { - using var scope1 = new EnvironmentVariableScope("ASPNETCORE_URLS", null); - using var scope2 = new EnvironmentVariableScope("PORT", null); - - var appsettings = new Dictionary - { - { "management:endpoints:port", "9090" }, - { "management:endpoints:sslenabled", "true" } - }; - - WebApplicationBuilder hostBuilder = WebApplication.CreateBuilder(); - hostBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); - hostBuilder.Configuration.AddInMemoryCollection(appsettings); - hostBuilder.AddAllActuators(); - - hostBuilder.Services.AddActionDescriptorCollectionProvider(); - hostBuilder.WebHost.UseTestServer(); - - WebApplication app = hostBuilder.Build(); - app.MapGet("/", () => "Hello World!"); - app.Start(); - - using HttpClient httpClient = app.GetTestServer().CreateClient(); - HttpResponseMessage response = await httpClient.GetAsync(new Uri("https://localhost:9090/actuator")); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - response = await httpClient.GetAsync(new Uri("http://localhost:8080")); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - - [Fact] - public async Task AddAllActuators_GenericHost_MakeSureTheManagementPortIsSet() - { - var settings = new Dictionary - { - { "management:endpoints:port", "9090" }, - { "management:endpoints:sslenabled", "true" } - }; - - IHostBuilder hostBuilder = new HostBuilder().ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(settings)).ConfigureWebHost( - webHostBuilder => - { - webHostBuilder.Configure(app => app.UseRouting()); - webHostBuilder.ConfigureServices(svc => svc.AddRouting()); - webHostBuilder.UseSetting("management:endpoints:port", "9090"); - webHostBuilder.ConfigureServices(svc => svc.AddActionDescriptorCollectionProvider()); - webHostBuilder.AddAllActuators(); - - webHostBuilder.UseTestServer().ConfigureServices(services => services.AddRouting()) - .Configure(applicationBuilder => applicationBuilder.UseRouting()); - }); - - using IHost host = hostBuilder.Build(); - - host.Start(); - - using HttpClient httpClient = host.GetTestServer().CreateClient(); - HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://localhost:9090/actuator")); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - - [Fact] - public async Task AddAllActuators_GenericHost_MakeSure_SSLEnabled() - { - using var scope1 = new EnvironmentVariableScope("ASPNETCORE_URLS", null); - using var scope2 = new EnvironmentVariableScope("PORT", null); - - IHostBuilder hostBuilder = new HostBuilder().ConfigureWebHost(webHostBuilder => - { - webHostBuilder.Configure(app => app.UseRouting().Run(async context => await context.Response.WriteAsync("Response from Run Middleware"))); - webHostBuilder.ConfigureServices(svc => svc.AddRouting()); - webHostBuilder.ConfigureServices(svc => svc.AddActionDescriptorCollectionProvider()); - webHostBuilder.UseSetting("management:endpoints:port", "9090"); - webHostBuilder.UseSetting("management:endpoints:sslenabled", "true"); - - webHostBuilder.UseTestServer().ConfigureServices(services => services.AddRouting()) - .Configure(applicationBuilder => applicationBuilder.UseRouting()); - - webHostBuilder.AddAllActuators(); - }); - - using IHost host = hostBuilder.Build(); - - host.Start(); - using HttpClient httpClient = host.GetTestServer().CreateClient(); - HttpResponseMessage response = await httpClient.GetAsync(new Uri("https://localhost:9090/actuator")); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - - response = await httpClient.GetAsync(new Uri("http://localhost:8080/actuator")); - Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); - var jsonResponse = await response.Content.ReadFromJsonAsync(); - Assert.Equal("Not Found", jsonResponse?.Error); - Assert.Equal("Path not found at port", jsonResponse?.Message); - } -} diff --git a/src/Management/test/Endpoint.Test/ManagementPort/ManagementEndpointServedOnDifferentPortTest.cs b/src/Management/test/Endpoint.Test/ManagementPort/ManagementEndpointServedOnDifferentPortTest.cs new file mode 100644 index 0000000000..cb7228d835 --- /dev/null +++ b/src/Management/test/Endpoint.Test/ManagementPort/ManagementEndpointServedOnDifferentPortTest.cs @@ -0,0 +1,279 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using System.Net; +using FluentAssertions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Steeltoe.Common.Hosting; +using Steeltoe.Common.TestResources; +using Xunit; + +namespace Steeltoe.Management.Endpoint.Test.ManagementPort; + +public sealed class ManagementEndpointServedOnDifferentPortTest +{ + [Fact] + public async Task AddAllActuators_WebApplication_ManagementPortIsSet() + { + var appSettings = new Dictionary + { + { "management:endpoints:port", "9090" } + }; + + WebApplicationBuilder hostBuilder = WebApplication.CreateBuilder(); + hostBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); + hostBuilder.Configuration.AddInMemoryCollection(appSettings); + hostBuilder.AddAllActuators(); + hostBuilder.Services.AddActionDescriptorCollectionProvider(); + + await using WebApplication app = hostBuilder.Build(); + app.MapGet("/", () => "Hello World!"); + app.Start(); + + var addressFeature = ((IApplicationBuilder)app).ServerFeatures.Get(); + addressFeature.Should().NotBeNull(); + addressFeature!.Addresses.Should().ContainSingle(address => address.Contains(":9090", StringComparison.Ordinal)); + } + + [Fact] + public async Task AddAllActuators_WebApplication_MiddlewareOnlyAllowsManagementPort() + { + var appSettings = new Dictionary + { + { "management:endpoints:port", "9090" } + }; + + WebApplicationBuilder hostBuilder = WebApplication.CreateBuilder(); + hostBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); + hostBuilder.Configuration.AddInMemoryCollection(appSettings); + hostBuilder.AddAllActuators(); + hostBuilder.Services.AddActionDescriptorCollectionProvider(); + + await using WebApplication app = hostBuilder.Build(); + app.MapGet("/", () => "Hello World!"); + app.Start(); + + using var httpClient = new HttpClient(); + HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://localhost:9090/actuator")); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response = await httpClient.GetAsync(new Uri("http://localhost:8080/actuator")); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task AddAllActuators_WebApplicationWithUseCloudHosting_ManagementPortIsSet() + { + var appSettings = new Dictionary + { + { "management:endpoints:port", "9090" } + }; + + WebApplicationBuilder hostBuilder = WebApplication.CreateBuilder(); + hostBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); + hostBuilder.Configuration.AddInMemoryCollection(appSettings); + hostBuilder.UseCloudHosting(); + hostBuilder.AddAllActuators(); + hostBuilder.Services.AddActionDescriptorCollectionProvider(); + + await using WebApplication app = hostBuilder.Build(); + app.MapGet("/", () => "Hello World!"); + app.Start(); + + var addressFeature = ((IApplicationBuilder)app).ServerFeatures.Get(); + addressFeature.Should().NotBeNull(); + addressFeature!.Addresses.Should().ContainSingle(address => address.Contains(":9090", StringComparison.Ordinal)); + } + + [Fact] + public async Task AddAllActuators_WebApplicationWithUseCloudHosting_MiddlewareOnlyAllowsManagementPort() + { + var appSettings = new Dictionary + { + { "management:endpoints:port", "9090" } + }; + + WebApplicationBuilder hostBuilder = WebApplication.CreateBuilder(); + hostBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); + hostBuilder.Configuration.AddInMemoryCollection(appSettings); + hostBuilder.UseCloudHosting(); + hostBuilder.AddAllActuators(); + hostBuilder.Services.AddActionDescriptorCollectionProvider(); + + await using WebApplication app = hostBuilder.Build(); + app.MapGet("/", () => "Hello World!"); + app.Start(); + + using var httpClient = new HttpClient(); + HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://localhost:9090/actuator")); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response = await httpClient.GetAsync(new Uri("http://localhost:8080/actuator")); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + [Trait("Category", "SkipOnMacOS")] // https://github.com/dotnet/aspnetcore/issues/42273 + public async Task AddAllActuators_WebApplication_RequiresSSL() + { + using var scope1 = new EnvironmentVariableScope("ASPNETCORE_URLS", null); + using var scope2 = new EnvironmentVariableScope("PORT", null); + + var appSettings = new Dictionary + { + { "management:endpoints:port", "9090" }, + { "management:endpoints:sslenabled", "true" } + }; + + WebApplicationBuilder hostBuilder = WebApplication.CreateBuilder(); + hostBuilder.Host.UseDefaultServiceProvider(options => options.ValidateScopes = true); + hostBuilder.Configuration.AddInMemoryCollection(appSettings); + hostBuilder.AddAllActuators(); + hostBuilder.Services.AddActionDescriptorCollectionProvider(); + + await using WebApplication app = hostBuilder.Build(); + app.MapGet("/", () => "Hello World!"); + app.Start(); + + using var httpClient = new HttpClient(new HttpClientHandler + { + ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator + }); + + HttpResponseMessage response = await httpClient.GetAsync(new Uri("https://localhost:9090/actuator")); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response = await httpClient.GetAsync(new Uri("http://localhost:8080/actuator")); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public void AddAllActuators_GenericHost_ManagementPortIsSet() + { + IHostBuilder hostBuilder = new HostBuilder().ConfigureWebHost(webHostBuilder => + { + webHostBuilder.UseDefaultServiceProvider(options => options.ValidateScopes = true); + webHostBuilder.ConfigureServices(services => services.AddRouting().AddActionDescriptorCollectionProvider()); + webHostBuilder.UseSetting("management:endpoints:port", "9090"); + webHostBuilder.AddAllActuators(); + webHostBuilder.Configure(app => app.Run(async context => await context.Response.WriteAsync("Hello World!"))); + webHostBuilder.Configure(applicationBuilder => applicationBuilder.UseRouting()); + webHostBuilder.UseKestrel(); + }); + + using IHost host = hostBuilder.Build(); + host.Start(); + + var addressFeature = host.Services.GetRequiredService().Features.Get(); + addressFeature.Should().NotBeNull(); + addressFeature!.Addresses.Should().ContainSingle(address => address.Contains(":9090", StringComparison.Ordinal)); + } + + [Fact] + public async Task AddAllActuators_GenericHost_MiddlewareOnlyAllowsManagementPort() + { + IHostBuilder hostBuilder = new HostBuilder().ConfigureWebHost(webHostBuilder => + { + webHostBuilder.UseDefaultServiceProvider(options => options.ValidateScopes = true); + webHostBuilder.ConfigureServices(services => services.AddRouting().AddActionDescriptorCollectionProvider()); + webHostBuilder.UseSetting("management:endpoints:port", "9090"); + webHostBuilder.AddAllActuators(); + webHostBuilder.Configure(app => app.Run(async context => await context.Response.WriteAsync("Hello World!"))); + webHostBuilder.Configure(applicationBuilder => applicationBuilder.UseRouting()); + webHostBuilder.UseKestrel(); + }); + + using IHost host = hostBuilder.Build(); + host.Start(); + + using var httpClient = new HttpClient(); + HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://localhost:9090/actuator")); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response = await httpClient.GetAsync(new Uri("http://localhost:8080/actuator")); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public void AddAllActuators_GenericHostWithUseCloudHosting_ManagementPortIsSet() + { + IHostBuilder hostBuilder = new HostBuilder().ConfigureWebHost(webHostBuilder => + { + webHostBuilder.UseDefaultServiceProvider(options => options.ValidateScopes = true); + webHostBuilder.ConfigureServices(services => services.AddRouting().AddActionDescriptorCollectionProvider()); + webHostBuilder.UseSetting("management:endpoints:port", "9090"); + webHostBuilder.UseCloudHosting(); + webHostBuilder.AddAllActuators(); + webHostBuilder.Configure(app => app.Run(async context => await context.Response.WriteAsync("Hello World!"))); + webHostBuilder.Configure(applicationBuilder => applicationBuilder.UseRouting()); + webHostBuilder.UseKestrel(); + }); + + using IHost host = hostBuilder.Build(); + host.Start(); + + var addressFeature = host.Services.GetRequiredService().Features.Get(); + addressFeature.Should().NotBeNull(); + addressFeature!.Addresses.Should().ContainSingle(address => address.Contains(":9090", StringComparison.Ordinal)); + } + + [Fact] + public async Task AddAllActuators_GenericHostWithUseCloudHosting_MiddlewareOnlyAllowsManagementPort() + { + IHostBuilder hostBuilder = new HostBuilder().ConfigureWebHost(webHostBuilder => + { + webHostBuilder.UseDefaultServiceProvider(options => options.ValidateScopes = true); + webHostBuilder.ConfigureServices(services => services.AddRouting().AddActionDescriptorCollectionProvider()); + webHostBuilder.UseSetting("management:endpoints:port", "9090"); + webHostBuilder.UseCloudHosting(); + webHostBuilder.AddAllActuators(); + webHostBuilder.Configure(app => app.Run(async context => await context.Response.WriteAsync("Hello World!"))); + webHostBuilder.Configure(applicationBuilder => applicationBuilder.UseRouting()); + webHostBuilder.UseKestrel(); + }); + + using IHost host = hostBuilder.Build(); + host.Start(); + + using var httpClient = new HttpClient(); + HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://localhost:9090/actuator")); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response = await httpClient.GetAsync(new Uri("http://localhost:8080/actuator")); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + [Trait("Category", "SkipOnMacOS")] // https://github.com/dotnet/aspnetcore/issues/42273 + public async Task AddAllActuators_GenericHost_RequiresSSL() + { + IHostBuilder hostBuilder = new HostBuilder().ConfigureWebHost(webHostBuilder => + { + webHostBuilder.UseDefaultServiceProvider(options => options.ValidateScopes = true); + webHostBuilder.ConfigureServices(services => services.AddRouting().AddActionDescriptorCollectionProvider()); + webHostBuilder.UseSetting("management:endpoints:port", "9090"); + webHostBuilder.UseSetting("management:endpoints:sslenabled", "true"); + webHostBuilder.UseCloudHosting(); + webHostBuilder.AddAllActuators(); + webHostBuilder.Configure(app => app.Run(async context => await context.Response.WriteAsync("Hello World!"))); + webHostBuilder.Configure(applicationBuilder => applicationBuilder.UseRouting()); + webHostBuilder.UseKestrel(); + }); + + using IHost host = hostBuilder.Build(); + host.Start(); + + using var httpClient = new HttpClient(new HttpClientHandler + { + ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator + }); + + HttpResponseMessage response = await httpClient.GetAsync(new Uri("https://localhost:9090/actuator")); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response = await httpClient.GetAsync(new Uri("http://localhost:8080/actuator")); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } +}