From e892ed8bbdcd25a0dafc1850033398dc57f65fe1 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 27 Oct 2017 16:52:39 -0700 Subject: [PATCH] Add a way to prevent specific hosting startup from runnning (#1243) --- .../WebHostDefaults.cs | 1 + .../Internal/WebHost.cs | 2 +- .../Internal/WebHostOptions.cs | 30 +++++++++++++++++-- .../WebHostBuilder.cs | 4 +-- .../WebHostBuilderTests.cs | 17 +++++++++++ 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNetCore.Hosting.Abstractions/WebHostDefaults.cs b/src/Microsoft.AspNetCore.Hosting.Abstractions/WebHostDefaults.cs index 5f57a07dce..4de391d0a2 100644 --- a/src/Microsoft.AspNetCore.Hosting.Abstractions/WebHostDefaults.cs +++ b/src/Microsoft.AspNetCore.Hosting.Abstractions/WebHostDefaults.cs @@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Hosting public static readonly string ApplicationKey = "applicationName"; public static readonly string StartupAssemblyKey = "startupAssembly"; public static readonly string HostingStartupAssembliesKey = "hostingStartupAssemblies"; + public static readonly string HostingStartupExcludeAssembliesKey = "hostingStartupExcludeAssemblies"; public static readonly string DetailedErrorsKey = "detailedErrors"; public static readonly string EnvironmentKey = "environment"; diff --git a/src/Microsoft.AspNetCore.Hosting/Internal/WebHost.cs b/src/Microsoft.AspNetCore.Hosting/Internal/WebHost.cs index 540b6a0ecc..da74e1d1ea 100644 --- a/src/Microsoft.AspNetCore.Hosting/Internal/WebHost.cs +++ b/src/Microsoft.AspNetCore.Hosting/Internal/WebHost.cs @@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal // Log the fact that we did load hosting startup assemblies. if (_logger.IsEnabled(LogLevel.Debug)) { - foreach (var assembly in _options.HostingStartupAssemblies) + foreach (var assembly in _options.GetFinalHostingStartupAssemblies()) { _logger.LogDebug("Loaded hosting startup assembly {assemblyName}", assembly); } diff --git a/src/Microsoft.AspNetCore.Hosting/Internal/WebHostOptions.cs b/src/Microsoft.AspNetCore.Hosting/Internal/WebHostOptions.cs index 7894e3ba5f..e9e611bc69 100644 --- a/src/Microsoft.AspNetCore.Hosting/Internal/WebHostOptions.cs +++ b/src/Microsoft.AspNetCore.Hosting/Internal/WebHostOptions.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using Microsoft.Extensions.Configuration; namespace Microsoft.AspNetCore.Hosting.Internal @@ -33,8 +34,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal SuppressStatusMessages = WebHostUtilities.ParseBool(configuration, WebHostDefaults.SuppressStatusMessagesKey); // Search the primary assembly and configured assemblies. - HostingStartupAssemblies = $"{ApplicationName};{configuration[WebHostDefaults.HostingStartupAssembliesKey]}" - .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) ?? new string[0]; + HostingStartupAssemblies = Split($"{ApplicationName};{configuration[WebHostDefaults.HostingStartupAssembliesKey]}"); + HostingStartupExcludeAssemblies = Split(configuration[WebHostDefaults.HostingStartupExcludeAssembliesKey]); var timeout = configuration[WebHostDefaults.ShutdownTimeoutKey]; if (!string.IsNullOrEmpty(timeout) @@ -52,6 +53,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal public IReadOnlyList HostingStartupAssemblies { get; set; } + public IReadOnlyList HostingStartupExcludeAssemblies { get; set; } + public bool DetailedErrors { get; set; } public bool CaptureStartupErrors { get; set; } @@ -66,5 +69,28 @@ namespace Microsoft.AspNetCore.Hosting.Internal public TimeSpan ShutdownTimeout { get; set; } = TimeSpan.FromSeconds(5); + public IEnumerable GetFinalHostingStartupAssemblies() + { + return HostingStartupAssemblies.Except(HostingStartupExcludeAssemblies, StringComparer.OrdinalIgnoreCase); + } + + private IReadOnlyList Split(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + return Array.Empty(); + } + + var list = new List(); + foreach (var part in value.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) + { + var trimmedPart = part; + if (!string.IsNullOrEmpty(trimmedPart)) + { + list.Add(trimmedPart); + } + } + return list; + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Hosting/WebHostBuilder.cs b/src/Microsoft.AspNetCore.Hosting/WebHostBuilder.cs index 7c9a9950ae..f0dede89fd 100644 --- a/src/Microsoft.AspNetCore.Hosting/WebHostBuilder.cs +++ b/src/Microsoft.AspNetCore.Hosting/WebHostBuilder.cs @@ -176,7 +176,7 @@ namespace Microsoft.AspNetCore.Hosting var logger = hostingServiceProvider.GetRequiredService>(); // Warn about duplicate HostingStartupAssemblies - foreach (var assemblyName in _options.HostingStartupAssemblies.GroupBy(a => a, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1)) + foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().GroupBy(a => a, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1)) { logger.LogWarning($"The assembly {assemblyName} was specified multiple times. Hosting startup assemblies should only be specified once."); } @@ -206,7 +206,7 @@ namespace Microsoft.AspNetCore.Hosting var exceptions = new List(); // Execute the hosting startup assemblies - foreach (var assemblyName in _options.HostingStartupAssemblies.Distinct(StringComparer.OrdinalIgnoreCase)) + foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().Distinct(StringComparer.OrdinalIgnoreCase)) { try { diff --git a/test/Microsoft.AspNetCore.Hosting.Tests/WebHostBuilderTests.cs b/test/Microsoft.AspNetCore.Hosting.Tests/WebHostBuilderTests.cs index 7007b24236..f479c93a3d 100644 --- a/test/Microsoft.AspNetCore.Hosting.Tests/WebHostBuilderTests.cs +++ b/test/Microsoft.AspNetCore.Hosting.Tests/WebHostBuilderTests.cs @@ -779,6 +779,23 @@ namespace Microsoft.AspNetCore.Hosting } } + [Fact] + public void Build_HostingStartupAssemblyCanBeExcluded() + { + var builder = CreateWebHostBuilder() + .CaptureStartupErrors(false) + .UseSetting(WebHostDefaults.HostingStartupAssembliesKey, typeof(TestStartupAssembly1.TestHostingStartup1).GetTypeInfo().Assembly.FullName) + .UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, typeof(TestStartupAssembly1.TestHostingStartup1).GetTypeInfo().Assembly.FullName) + .Configure(app => { }) + .UseServer(new TestServer()); + + using (var host = builder.Build()) + { + Assert.Null(builder.GetSetting("testhostingstartup1")); + Assert.Equal("0", builder.GetSetting("testhostingstartup_chain")); + } + } + [Fact] public void Build_ConfigureLoggingInHostingStartupWorks() {