Fix reload behavior and renable tests
This commit is contained in:
Родитель
7fcca8970b
Коммит
ca67d2251f
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.Extensions.Configuration
|
||||
|
@ -30,7 +31,10 @@ namespace Microsoft.Extensions.Configuration
|
|||
{
|
||||
ChangeToken.OnChange(
|
||||
() => Source.FileProvider.Watch(Source.Path),
|
||||
() => Load(reload: true));
|
||||
() => {
|
||||
Thread.Sleep(Source.ReloadDelay);
|
||||
Load(reload: true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,6 +64,11 @@ namespace Microsoft.Extensions.Configuration
|
|||
}
|
||||
else
|
||||
{
|
||||
// Always create new Data on reload to drop old keys
|
||||
if (reload)
|
||||
{
|
||||
Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
using (var stream = file.CreateReadStream())
|
||||
{
|
||||
try
|
||||
|
|
|
@ -32,6 +32,12 @@ namespace Microsoft.Extensions.Configuration
|
|||
/// </summary>
|
||||
public bool ReloadOnChange { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of milliseconds that reload will wait before calling Load. This helps
|
||||
/// avoid triggering reload before a file is completely written. Default is 250.
|
||||
/// </summary>
|
||||
public int ReloadDelay { get; set; } = 250;
|
||||
|
||||
/// <summary>
|
||||
/// Will be called if an uncaught exception occurs in FileConfigurationProvider.Load.
|
||||
/// </summary>
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
},
|
||||
"netstandard1.3": {
|
||||
"dependencies": {
|
||||
"System.AppContext": "4.1.0-*"
|
||||
"System.AppContext": "4.1.0-*",
|
||||
"System.Threading.Thread": "4.0.0-*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -518,6 +518,26 @@ IniKey1=IniValue2");
|
|||
Assert.Equal("XmlValue6", config["CommonKey1:CommonKey2:CommonKey3:CommonKey4"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReloadOnChangeWorksAfterError()
|
||||
{
|
||||
File.WriteAllText(Path.Combine(_basePath, "reload.json"), @"{""JsonKey1"": ""JsonValue1""}");
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddJsonFile("reload.json", optional: false, reloadOnChange: true)
|
||||
.Build();
|
||||
Assert.Equal("JsonValue1", config["JsonKey1"]);
|
||||
|
||||
// Introduce an error and make sure the old key is removed
|
||||
File.WriteAllText(Path.Combine(_basePath, "reload.json"), @"{""JsonKey1"": ");
|
||||
await Task.Delay(2000); // wait for notification
|
||||
Assert.Null(config["JsonKey1"]);
|
||||
|
||||
// Update the file again to make sure the config is updated
|
||||
File.WriteAllText(Path.Combine(_basePath, "reload.json"), @"{""JsonKey1"": ""JsonValue2""}");
|
||||
await Task.Delay(1100); // wait for notification
|
||||
Assert.Equal("JsonValue2", config["JsonKey1"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TouchingFileWillReload()
|
||||
{
|
||||
|
@ -573,8 +593,7 @@ IniKey1=IniValue2");
|
|||
//Assert.True(token2.HasChanged, "Deleted");
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[OSSkipCondition(OperatingSystems.Linux)] // File watching is flaky on Linux CI
|
||||
[Fact]
|
||||
public async Task CreatingOptionalFileInNonExistentDirectoryWillReload()
|
||||
{
|
||||
var directory = Path.Combine(_basePath, Path.GetRandomFileName());
|
||||
|
@ -602,7 +621,7 @@ IniKey1=IniValue2");
|
|||
File.WriteAllText(iniFile, @"IniKey1 = IniValue1");
|
||||
File.WriteAllText(xmlFile, @"<settings XmlKey1=""XmlValue1""/>");
|
||||
|
||||
await Task.Delay(2000);
|
||||
await Task.Delay(1100);
|
||||
|
||||
Assert.Equal("JsonValue1", config["JsonKey1"]);
|
||||
Assert.Equal("IniValue1", config["IniKey1"]);
|
||||
|
@ -641,7 +660,7 @@ IniKey1=IniValue2");
|
|||
File.Delete(iniFile);
|
||||
File.Delete(xmlFile);
|
||||
|
||||
await Task.Delay(2000);
|
||||
await Task.Delay(1100);
|
||||
|
||||
Assert.Null(config["JsonKey1"]);
|
||||
Assert.Null(config["IniKey1"]);
|
||||
|
@ -649,8 +668,7 @@ IniKey1=IniValue2");
|
|||
Assert.True(token.HasChanged);
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[OSSkipCondition(OperatingSystems.Linux)] // File watching is flaky on Linux CI
|
||||
[Fact]
|
||||
public async Task CreatingWritingDeletingCreatingFileWillReload()
|
||||
{
|
||||
var iniFile = Path.Combine(_basePath, Path.GetRandomFileName());
|
||||
|
@ -674,7 +692,7 @@ IniKey1=IniValue2");
|
|||
File.WriteAllText(iniFile, @"IniKey1 = IniValue1");
|
||||
File.WriteAllText(xmlFile, @"<settings XmlKey1=""XmlValue1""/>");
|
||||
|
||||
await Task.Delay(2000);
|
||||
await Task.Delay(1100);
|
||||
|
||||
Assert.Equal("JsonValue1", config["JsonKey1"]);
|
||||
Assert.Equal("IniValue1", config["IniKey1"]);
|
||||
|
@ -687,7 +705,7 @@ IniKey1=IniValue2");
|
|||
File.WriteAllText(iniFile, @"IniKey1 = IniValue2");
|
||||
File.WriteAllText(xmlFile, @"<settings XmlKey1=""XmlValue2""/>");
|
||||
|
||||
await Task.Delay(2000);
|
||||
await Task.Delay(1100);
|
||||
|
||||
Assert.Equal("JsonValue2", config["JsonKey1"]);
|
||||
Assert.Equal("IniValue2", config["IniKey1"]);
|
||||
|
@ -702,7 +720,7 @@ IniKey1=IniValue2");
|
|||
File.Delete(iniFile);
|
||||
File.Delete(xmlFile);
|
||||
|
||||
await Task.Delay(2000);
|
||||
await Task.Delay(1100);
|
||||
|
||||
Assert.Null(config["JsonKey1"]);
|
||||
Assert.Null(config["IniKey1"]);
|
||||
|
@ -715,7 +733,7 @@ IniKey1=IniValue2");
|
|||
File.WriteAllText(iniFile, @"IniKey1 = IniValue1");
|
||||
File.WriteAllText(xmlFile, @"<settings XmlKey1=""XmlValue1""/>");
|
||||
|
||||
await Task.Delay(2000);
|
||||
await Task.Delay(1100);
|
||||
|
||||
Assert.Equal("JsonValue1", config["JsonKey1"]);
|
||||
Assert.Equal("IniValue1", config["IniKey1"]);
|
||||
|
|
Загрузка…
Ссылка в новой задаче