// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.IO; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting.Fakes; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Xunit; namespace Microsoft.Extensions.Hosting { public class HostBuilderTests { [Fact] public void ConfigureHostConfigurationPropagated() { var host = new HostBuilder() .ConfigureHostConfiguration(configBuilder => { configBuilder.AddInMemoryCollection(new[] { new KeyValuePair("key1", "value1") }); }) .ConfigureHostConfiguration(configBuilder => { configBuilder.AddInMemoryCollection(new[] { new KeyValuePair("key2", "value2") }); }) .ConfigureHostConfiguration(configBuilder => { configBuilder.AddInMemoryCollection(new[] { // Hides value2 new KeyValuePair("key2", "value3") }); }) .ConfigureAppConfiguration((context, configBuilder) => { Assert.Equal("value1", context.Configuration["key1"]); Assert.Equal("value3", context.Configuration["key2"]); var config = configBuilder.Build(); Assert.Equal("value1", config["key1"]); Assert.Equal("value3", config["key2"]); }) .Build(); using (host) { var config = host.Services.GetRequiredService(); Assert.Equal("value1", config["key1"]); Assert.Equal("value3", config["key2"]); } } [Fact] public void CanConfigureAppConfigurationAndRetrieveFromDI() { var hostBuilder = new HostBuilder() .ConfigureAppConfiguration((configBuilder) => { configBuilder.AddInMemoryCollection( new KeyValuePair[] { new KeyValuePair("key1", "value1") }); }) .ConfigureAppConfiguration((configBuilder) => { configBuilder.AddInMemoryCollection( new KeyValuePair[] { new KeyValuePair("key2", "value2") }); }) .ConfigureAppConfiguration((configBuilder) => { configBuilder.AddInMemoryCollection( new KeyValuePair[] { // Hides value2 new KeyValuePair("key2", "value3") }); }); using (var host = hostBuilder.Build()) { var config = host.Services.GetService(); Assert.NotNull(config); Assert.Equal("value1", config["key1"]); Assert.Equal("value3", config["key2"]); } } [Fact] public void DefaultIHostingEnvironmentValues() { var hostBuilder = new HostBuilder() .ConfigureAppConfiguration((hostContext, appConfig) => { var env = hostContext.HostingEnvironment; Assert.Equal(EnvironmentName.Production, env.EnvironmentName); Assert.Null(env.ApplicationName); Assert.Equal(AppContext.BaseDirectory, env.ContentRootPath); Assert.IsAssignableFrom(env.ContentRootFileProvider); }); using (var host = hostBuilder.Build()) { var env = host.Services.GetRequiredService(); Assert.Equal(EnvironmentName.Production, env.EnvironmentName); Assert.Null(env.ApplicationName); Assert.Equal(AppContext.BaseDirectory, env.ContentRootPath); Assert.IsAssignableFrom(env.ContentRootFileProvider); } } [Fact] public void ConfigBasedSettingsConfigBasedOverride() { var settings = new Dictionary { { HostDefaults.EnvironmentKey, "EnvA" } }; var config = new ConfigurationBuilder() .AddInMemoryCollection(settings) .Build(); var overrideSettings = new Dictionary { { HostDefaults.EnvironmentKey, "EnvB" } }; var overrideConfig = new ConfigurationBuilder() .AddInMemoryCollection(overrideSettings) .Build(); var hostBuilder = new HostBuilder() .ConfigureHostConfiguration(configBuilder => configBuilder.AddConfiguration(config)) .ConfigureHostConfiguration(configBuilder => configBuilder.AddConfiguration(overrideConfig)); using (var host = hostBuilder.Build()) { Assert.Equal("EnvB", host.Services.GetRequiredService().EnvironmentName); } } [Fact] public void UseEnvironmentIsNotOverriden() { var vals = new Dictionary { { "ENV", "Dev" }, }; var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); var config = builder.Build(); var expected = "MY_TEST_ENVIRONMENT"; using (var host = new HostBuilder() .ConfigureHostConfiguration(configBuilder => configBuilder.AddConfiguration(config)) .UseEnvironment(expected) .Build()) { Assert.Equal(expected, host.Services.GetService().EnvironmentName); } } [Fact] public void BuildAndDispose() { using (var host = new HostBuilder() .Build()) { } } [Fact] public void UseBasePathConfiguresBasePath() { var vals = new Dictionary { { "ENV", "Dev" }, }; var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); var config = builder.Build(); using (var host = new HostBuilder() .ConfigureHostConfiguration(configBuilder => configBuilder.AddConfiguration(config)) .UseContentRoot("/") .Build()) { Assert.Equal("/", host.Services.GetService().ContentRootPath); } } [Fact] public void HostConfigParametersReadCorrectly() { var parameters = new Dictionary() { { "applicationName", "MyProjectReference"}, { "environment", EnvironmentName.Development}, { "contentRoot", Path.GetFullPath(".") } }; var host = new HostBuilder() .ConfigureHostConfiguration(config => { config.AddInMemoryCollection(parameters); }).Build(); var env = host.Services.GetRequiredService(); Assert.Equal("MyProjectReference", env.ApplicationName); Assert.Equal(EnvironmentName.Development, env.EnvironmentName); Assert.Equal(Path.GetFullPath("."), env.ContentRootPath); } [Fact] public void RelativeContentRootIsResolved() { using (var host = new HostBuilder() .UseContentRoot("testroot") .Build()) { var basePath = host.Services.GetRequiredService().ContentRootPath; Assert.True(Path.IsPathRooted(basePath)); Assert.EndsWith(Path.DirectorySeparatorChar + "testroot", basePath); } } [Fact] public void DefaultContentRootIsApplicationBasePath() { using (var host = new HostBuilder() .Build()) { var appBase = AppContext.BaseDirectory; Assert.Equal(appBase, host.Services.GetService().ContentRootPath); } } [Fact] public void DefaultServicesAreAvailable() { using (var host = new HostBuilder() .Build()) { Assert.NotNull(host.Services.GetRequiredService()); Assert.NotNull(host.Services.GetRequiredService()); Assert.NotNull(host.Services.GetRequiredService()); Assert.NotNull(host.Services.GetRequiredService()); Assert.NotNull(host.Services.GetRequiredService()); Assert.NotNull(host.Services.GetRequiredService>()); } } [Fact] public void DefaultCreatesLoggerFactory() { var hostBuilder = new HostBuilder(); using (var host = hostBuilder.Build()) { Assert.NotNull(host.Services.GetService()); } } [Fact] public void MultipleConfigureLoggingInvokedInOrder() { var callCount = 0; //Verify ordering var hostBuilder = new HostBuilder() .ConfigureLogging((hostContext, loggerFactory) => { Assert.Equal(0, callCount++); }) .ConfigureLogging((hostContext, loggerFactory) => { Assert.Equal(1, callCount++); }); using (hostBuilder.Build()) { Assert.Equal(2, callCount); } } [Fact] public void HostingContextContainsAppConfigurationDuringConfigureServices() { var hostBuilder = new HostBuilder() .ConfigureAppConfiguration((configBuilder) => configBuilder.AddInMemoryCollection( new KeyValuePair[] { new KeyValuePair("key1", "value1") })) .ConfigureServices((context, factory) => { Assert.Equal("value1", context.Configuration["key1"]); }); using (hostBuilder.Build()) { } } [Fact] public void ConfigureDefaultServiceProvider() { var hostBuilder = new HostBuilder() .ConfigureServices((s) => { s.AddTransient(); s.AddScoped(); }) .UseServiceProviderFactory(new DefaultServiceProviderFactory(new ServiceProviderOptions() { ValidateScopes = true, })); var host = hostBuilder.Build(); Assert.Throws(() => { host.Services.GetRequiredService(); }); } [Fact] public void ConfigureCustomServiceProvider() { var hostBuilder = new HostBuilder() .ConfigureServices((hostContext, s) => { s.AddTransient(); s.AddScoped(); }) .UseServiceProviderFactory(new FakeServiceProviderFactory()) .ConfigureContainer((container) => { Assert.Null(container.State); container.State = "1"; }) .ConfigureContainer((container) => { Assert.Equal("1", container.State); container.State = "2"; }); var host = hostBuilder.Build(); var fakeServices = host.Services.GetRequiredService(); Assert.Equal("2", fakeServices.State); } [Fact] public void CustomContainerTypeMismatchThrows() { var hostBuilder = new HostBuilder() .ConfigureServices((s) => { s.AddTransient(); s.AddScoped(); }) .UseServiceProviderFactory(new FakeServiceProviderFactory()) .ConfigureContainer((container) => { }); Assert.Throws(() => hostBuilder.Build()); } [Fact] public void HostingContextContainsAppConfigurationDuringConfigureLogging() { var hostBuilder = new HostBuilder() .ConfigureAppConfiguration((configBuilder) => configBuilder.AddInMemoryCollection( new KeyValuePair[] { new KeyValuePair("key1", "value1") })) .ConfigureLogging((context, factory) => { Assert.Equal("value1", context.Configuration["key1"]); }); using (hostBuilder.Build()) { } } [Fact] public void ConfigureServices_CanBeCalledMultipleTimes() { var callCount = 0; // Verify ordering var hostBuilder = new HostBuilder() .ConfigureServices((services) => { Assert.Equal(0, callCount++); services.AddTransient(); }) .ConfigureServices((services) => { Assert.Equal(1, callCount++); services.AddTransient(); }); using (var host = hostBuilder.Build()) { Assert.Equal(2, callCount); Assert.NotNull(host.Services.GetRequiredService()); Assert.NotNull(host.Services.GetRequiredService()); } } [Fact] public void Build_DoesNotAllowBuildingMuiltipleTimes() { var builder = new HostBuilder(); using (builder.Build()) { var ex = Assert.Throws(() => builder.Build()); Assert.Equal("Build can only be called once.", ex.Message); } } [Fact] public void SetsFullPathToContentRoot() { var host = new HostBuilder() .ConfigureHostConfiguration(config => { config.AddInMemoryCollection(new[] { new KeyValuePair(HostDefaults.ContentRootKey, Path.GetFullPath(".")) }); }) .Build(); var env = host.Services.GetRequiredService(); Assert.Equal(Path.GetFullPath("."), env.ContentRootPath); Assert.IsAssignableFrom(env.ContentRootFileProvider); } [Fact] public void BuilderPropertiesAreAvailableInBuilderAndContext() { var hostBuilder = new HostBuilder() .ConfigureServices((hostContext, services) => { Assert.Equal("value", hostContext.Properties["key"]); }); hostBuilder.Properties.Add("key", "value"); Assert.Equal("value", hostBuilder.Properties["key"]); using (hostBuilder.Build()) { } } private class ServiceC { public ServiceC(ServiceD serviceD) { } } internal class ServiceD { } internal class ServiceA { } internal class ServiceB { } } }