Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the ConfigureDefaults API, as an extension method of IHostBuilder #50447

Merged
merged 3 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public static partial class HostingHostBuilderExtensions
{
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureAppConfiguration(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Configuration.IConfigurationBuilder> configureDelegate) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureContainer<TContainerBuilder>(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<TContainerBuilder> configureDelegate) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureDefaults(this Microsoft.Extensions.Hosting.IHostBuilder builder, string[] args) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureLogging(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Hosting.HostBuilderContext, Microsoft.Extensions.Logging.ILoggingBuilder> configureLogging) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureLogging(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Logging.ILoggingBuilder> configureLogging) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureServices(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection> configureDelegate) { throw null; }
Expand Down
83 changes: 3 additions & 80 deletions src/libraries/Microsoft.Extensions.Hosting/src/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.EventLog;

namespace Microsoft.Extensions.Hosting
{
Expand Down Expand Up @@ -52,85 +49,11 @@ public static IHostBuilder CreateDefaultBuilder() =>
/// </list>
/// </remarks>
/// <param name="args">The command line args.</param>
/// <returns>The initialized <see cref="IHostBuilder"/>.</returns>
/// <returns>The configured <see cref="IHostBuilder"/>.</returns>
IEvangelist marked this conversation as resolved.
Show resolved Hide resolved
IEvangelist marked this conversation as resolved.
Show resolved Hide resolved
public static IHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = new HostBuilder();

builder.UseContentRoot(Directory.GetCurrentDirectory());
builder.ConfigureHostConfiguration(config =>
{
config.AddEnvironmentVariables(prefix: "DOTNET_");
if (args != null)
{
config.AddCommandLine(args);
}
});

builder.ConfigureAppConfiguration((hostingContext, config) =>
{
IHostEnvironment env = hostingContext.HostingEnvironment;

bool reloadOnChange = hostingContext.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true);

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: reloadOnChange)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: reloadOnChange);

if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange);
}
}

config.AddEnvironmentVariables();

if (args != null)
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext, logging) =>
{
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

// IMPORTANT: This needs to be added *before* configuration is loaded, this lets
// the defaults be overridden by the configuration.
if (isWindows)
{
// Default the EventLogLoggerProvider to warning or above
logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
}

logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();

if (isWindows)
{
// Add the EventLogLoggerProvider on windows machines
logging.AddEventLog();
}

logging.Configure(options =>
{
options.ActivityTrackingOptions = ActivityTrackingOptions.SpanId
| ActivityTrackingOptions.TraceId
| ActivityTrackingOptions.ParentId;
});

})
.UseDefaultServiceProvider((context, options) =>
{
bool isDevelopment = context.HostingEnvironment.IsDevelopment();
options.ValidateScopes = isDevelopment;
options.ValidateOnBuild = isDevelopment;
});

return builder;
HostBuilder builder = new();
return builder.ConfigureDefaults(args);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.EventLog;

namespace Microsoft.Extensions.Hosting
{
Expand Down Expand Up @@ -45,7 +49,7 @@ public static IHostBuilder UseContentRoot(this IHostBuilder hostBuilder, string
configBuilder.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>(HostDefaults.ContentRootKey,
contentRoot ?? throw new ArgumentNullException(nameof(contentRoot)))
contentRoot ?? throw new ArgumentNullException(nameof(contentRoot)))
});
});
}
Expand Down Expand Up @@ -134,6 +138,105 @@ public static IHostBuilder ConfigureContainer<TContainerBuilder>(this IHostBuild
return hostBuilder.ConfigureContainer<TContainerBuilder>((context, builder) => configureDelegate(builder));
}

/// <summary>
/// Configures an existing <see cref="IHostBuilder"/> instance with pre-configured defaults.
/// </summary>
/// <remarks>
/// The following defaults are applied to the <see cref="IHostBuilder"/>:
/// <list type="bullet">
/// <item><description>set the <see cref="IHostEnvironment.ContentRootPath"/> to the result of <see cref="Directory.GetCurrentDirectory()"/></description></item>
/// <item><description>load host <see cref="IConfiguration"/> from "DOTNET_" prefixed environment variables</description></item>
/// <item><description>load host <see cref="IConfiguration"/> from supplied command line args</description></item>
/// <item><description>load app <see cref="IConfiguration"/> from 'appsettings.json' and 'appsettings.[<see cref="IHostEnvironment.EnvironmentName"/>].json'</description></item>
/// <item><description>load app <see cref="IConfiguration"/> from User Secrets when <see cref="IHostEnvironment.EnvironmentName"/> is 'Development' using the entry assembly</description></item>
/// <item><description>load app <see cref="IConfiguration"/> from environment variables</description></item>
/// <item><description>load app <see cref="IConfiguration"/> from supplied command line args</description></item>
/// <item><description>configure the <see cref="ILoggerFactory"/> to log to the console, debug, and event source output</description></item>
/// <item><description>enables scope validation on the dependency injection container when <see cref="IHostEnvironment.EnvironmentName"/> is 'Development'</description></item>
/// </list>
/// </remarks>
/// <param name="builder">The existing builder to configure.</param>
/// <param name="args">The command line args.</param>
/// <returns>The same instance of the <see cref="IHostBuilder"/> for chaining.</returns>
public static IHostBuilder ConfigureDefaults(this IHostBuilder builder, string[] args)
{
builder.UseContentRoot(Directory.GetCurrentDirectory());
builder.ConfigureHostConfiguration(config =>
{
config.AddEnvironmentVariables(prefix: "DOTNET_");
if (args is { Length: > 0 })
{
config.AddCommandLine(args);
}
});

builder.ConfigureAppConfiguration((hostingContext, config) =>
{
IHostEnvironment env = hostingContext.HostingEnvironment;

bool reloadOnChange = hostingContext.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true);

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: reloadOnChange)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: reloadOnChange);

if (env.IsDevelopment() && env.ApplicationName is { Length: > 0 })
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly is not null)
{
config.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange);
}
}

config.AddEnvironmentVariables();

if (args is { Length: > 0 })
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext, logging) =>
{
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

// IMPORTANT: This needs to be added *before* configuration is loaded, this lets
// the defaults be overridden by the configuration.
if (isWindows)
{
// Default the EventLogLoggerProvider to warning or above
logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
}

logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();

if (isWindows)
{
// Add the EventLogLoggerProvider on windows machines
logging.AddEventLog();
}

logging.Configure(options =>
{
options.ActivityTrackingOptions =
ActivityTrackingOptions.SpanId |
ActivityTrackingOptions.TraceId |
ActivityTrackingOptions.ParentId;
});

})
.UseDefaultServiceProvider((context, options) =>
{
bool isDevelopment = context.HostingEnvironment.IsDevelopment();
options.ValidateScopes = isDevelopment;
options.ValidateOnBuild = isDevelopment;
});

return builder;
}

/// <summary>
/// Listens for Ctrl+C or SIGTERM and calls <see cref="IHostApplicationLifetime.StopApplication"/> to start the shutdown process.
/// This will unblock extensions like RunAsync and WaitForShutdownAsync.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -559,10 +559,23 @@ public void HostServicesSameServiceProviderAsInHostBuilder()
Assert.Same(appServicesFromHostBuilder, host.Services);
}

[Fact]
public void HostBuilderConfigureDefaultsInterleavesMissingConfigValues()
{
IHostBuilder hostBuilder = new HostBuilder();
hostBuilder.ConfigureDefaults(args: null);

using var host = hostBuilder.Build();
var env = host.Services.GetRequiredService<IHostEnvironment>();

var expectedContentRootPath = Directory.GetCurrentDirectory();
Assert.Equal(expectedContentRootPath, env.ContentRootPath);
}

private class FakeFileProvider : IFileProvider, IDisposable
{
public bool Disposed { get; set; }
public void Dispose() { Disposed = true; }
public bool Disposed { get; private set; }
public void Dispose() => Disposed = true;
public IDirectoryContents GetDirectoryContents(string subpath) => throw new NotImplementedException();
public IFileInfo GetFileInfo(string subpath) => throw new NotImplementedException();
public IChangeToken Watch(string filter) => throw new NotImplementedException();
Expand Down