Skip to content

Commit

Permalink
[Host] Allow disabling reloadOnChange for Host's CreateDefaultBuilder (
Browse files Browse the repository at this point in the history
…#2940)

* Add environment var to allow disabling live reload in default builder

* Switch to using hostingContext, rename flag to fit nomenclature.

* Change flag to memory data source. Change content root default instead of runtime default.

* Update config key to be hierarchical. Change await on positive case to be longer and cancel using the reload token.

* Uncomment a development test case.

* Apply suggestions from code review

Co-authored-by: Chris Ross <Tratcher@Outlook.com>
  • Loading branch information
kjerk and Tratcher authored Mar 19, 2020
1 parent e71b6a8 commit 64140f9
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/Hosting/Hosting/src/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ public static IHostBuilder CreateDefaultBuilder(string[] args)
builder.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;

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

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: 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))
{
Expand Down
77 changes: 77 additions & 0 deletions src/Hosting/Hosting/test/HostTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using System.Diagnostics.Tracing;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -82,6 +84,81 @@ public void CreateDefaultBuilder_EnablesValidateOnBuild()
Assert.Throws<AggregateException>(() => hostBuilder.Build());
}

[Fact]
public async Task CreateDefaultBuilder_ConfigJsonDoesNotReload()
{
var reloadFlagConfig = new Dictionary<string, string>() {{ "hostbuilder:reloadConfigOnChange", "false" }};
var appSettingsPath = Path.Combine(Path.GetTempPath(), "appsettings.json");

string SaveRandomConfig()
{
var newMessage = $"Hello ASP.NET Core: {Guid.NewGuid():N}";
File.WriteAllText(appSettingsPath, $"{{ \"Hello\": \"{newMessage}\" }}");
return newMessage;
}

var dynamicConfigMessage1 = SaveRandomConfig();

var host = Host.CreateDefaultBuilder()
.UseContentRoot(Path.GetDirectoryName(appSettingsPath))
.ConfigureHostConfiguration(builder =>
{
builder.AddInMemoryCollection(reloadFlagConfig);
})
.Build();

var config = host.Services.GetRequiredService<IConfiguration>();

Assert.Equal(dynamicConfigMessage1, config["Hello"]);

var dynamicConfigMessage2 = SaveRandomConfig();
await Task.Delay(1000); // Give reload time to fire if it's going to.
Assert.NotEqual(dynamicConfigMessage1, dynamicConfigMessage2); // Messages are different.
Assert.Equal(dynamicConfigMessage1, config["Hello"]); // Config did not reload
}

[Fact]
public async Task CreateDefaultBuilder_ConfigJsonDoesReload()
{
var reloadFlagConfig = new Dictionary<string, string>() { { "hostbuilder:reloadConfigOnChange", "true" } };
var appSettingsPath = Path.Combine(Path.GetTempPath(), "appsettings.json");

string SaveRandomConfig()
{
var newMessage = $"Hello ASP.NET Core: {Guid.NewGuid():N}";
File.WriteAllText(appSettingsPath, $"{{ \"Hello\": \"{newMessage}\" }}");
return newMessage;
}

var dynamicConfigMessage1 = SaveRandomConfig();

var host = Host.CreateDefaultBuilder()
.UseContentRoot(Path.GetDirectoryName(appSettingsPath))
.ConfigureHostConfiguration(builder =>
{
builder.AddInMemoryCollection(reloadFlagConfig);
})
.Build();

var config = host.Services.GetRequiredService<IConfiguration>();

Assert.Equal(dynamicConfigMessage1, config["Hello"]);

var dynamicConfigMessage2 = SaveRandomConfig();

var configReloadedCancelTokenSource = new CancellationTokenSource();
var configReloadedCancelToken = configReloadedCancelTokenSource.Token;

config.GetReloadToken().RegisterChangeCallback(o =>
{
configReloadedCancelTokenSource.Cancel();
}, null);
// Wait for up to 10 seconds, if config reloads at any time, cancel the wait.
await Task.WhenAny(Task.Delay(10000, configReloadedCancelToken)); // Task.WhenAny ignores the task throwing on cancellation.
Assert.NotEqual(dynamicConfigMessage1, dynamicConfigMessage2); // Messages are different.
Assert.Equal(dynamicConfigMessage2, config["Hello"]); // Config DID reload from disk
}

internal class ServiceA { }

internal class ServiceB
Expand Down

0 comments on commit 64140f9

Please sign in to comment.