Merge branch 'release' into dev
This commit is contained in:
Коммит
c634cacf4e
|
@ -1,94 +0,0 @@
|
|||
// 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.IO;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.Extensions.Configuration
|
||||
{
|
||||
public static class FileProviderExtensions
|
||||
{
|
||||
public static IConfigurationRoot ReloadOnChanged(this IConfigurationRoot config, string filename)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
if (filename == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filename));
|
||||
}
|
||||
#if NET451
|
||||
var basePath = AppDomain.CurrentDomain.GetData("APP_CONTEXT_BASE_DIRECTORY") as string ??
|
||||
AppDomain.CurrentDomain.BaseDirectory ??
|
||||
string.Empty;
|
||||
#else
|
||||
var basePath = AppContext.BaseDirectory ?? string.Empty;
|
||||
#endif
|
||||
return ReloadOnChanged(config, basePath, filename);
|
||||
}
|
||||
|
||||
public static IConfigurationRoot ReloadOnChanged(
|
||||
this IConfigurationRoot config,
|
||||
string basePath,
|
||||
string filename)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
if (basePath == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(basePath));
|
||||
}
|
||||
|
||||
if (filename == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filename));
|
||||
}
|
||||
|
||||
var fileProvider = new PhysicalFileProvider(basePath);
|
||||
return ReloadOnChanged(config, fileProvider, filename);
|
||||
}
|
||||
|
||||
public static IConfigurationRoot ReloadOnChanged(
|
||||
this IConfigurationRoot config,
|
||||
IFileProvider fileProvider,
|
||||
string filename)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
if (fileProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(fileProvider));
|
||||
}
|
||||
|
||||
if (filename == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filename));
|
||||
}
|
||||
|
||||
Action<object> callback = null;
|
||||
callback = _ =>
|
||||
{
|
||||
// The order here is important. We need to take the token and then apply our changes BEFORE
|
||||
// registering. This prevents us from possible having two change updates to process concurrently.
|
||||
//
|
||||
// If the file changes after we take the token, then we'll process the update immediately upon
|
||||
// registering the callback.
|
||||
var token = fileProvider.Watch(filename);
|
||||
config.Reload();
|
||||
token.RegisterChangeCallback(callback, null);
|
||||
};
|
||||
|
||||
fileProvider.Watch(filename).RegisterChangeCallback(callback, null);
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,6 +57,35 @@ namespace Microsoft.Extensions.Configuration
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the INI configuration provider at <paramref name="path"/> to <paramref name="builder"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
|
||||
/// <param name="path">Path relative to the base path stored in
|
||||
/// <see cref="IConfigurationBuilder.Properties"/> of <paramref name="builder"/>.</param>
|
||||
/// <param name="optional">Whether the file is optional.</param>
|
||||
/// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>
|
||||
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
|
||||
public static IConfigurationBuilder AddIniFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path));
|
||||
}
|
||||
|
||||
return AddIniFile(builder, source =>
|
||||
{
|
||||
source.Path = path;
|
||||
source.Optional = optional;
|
||||
source.ReloadOnChange = reloadOnChange;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a INI configuration source to <paramref name="builder"/>.
|
||||
/// </summary>
|
||||
|
|
|
@ -60,6 +60,35 @@ namespace Microsoft.Extensions.Configuration
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the JSON configuration provider at <paramref name="path"/> to <paramref name="builder"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
|
||||
/// <param name="path">Path relative to the base path stored in
|
||||
/// <see cref="IConfigurationBuilder.Properties"/> of <paramref name="builder"/>.</param>
|
||||
/// <param name="optional">Whether the file is optional.</param>
|
||||
/// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>
|
||||
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
|
||||
public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path));
|
||||
}
|
||||
|
||||
return AddJsonFile(builder, source =>
|
||||
{
|
||||
source.Path = path;
|
||||
source.Optional = optional;
|
||||
source.ReloadOnChange = reloadOnChange;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a JSON configuration source to <paramref name="builder"/>.
|
||||
/// </summary>
|
||||
|
|
|
@ -60,6 +60,35 @@ namespace Microsoft.Extensions.Configuration
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML configuration provider at <paramref name="path"/> to <paramref name="builder"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
|
||||
/// <param name="path">Path relative to the base path stored in
|
||||
/// <see cref="IConfigurationBuilder.Properties"/> of <paramref name="builder"/>.</param>
|
||||
/// <param name="optional">Whether the file is optional.</param>
|
||||
/// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>
|
||||
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
|
||||
public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path));
|
||||
}
|
||||
|
||||
return AddXmlFile(builder, source =>
|
||||
{
|
||||
source.Path = path;
|
||||
source.Optional = optional;
|
||||
source.ReloadOnChange = reloadOnChange;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a XML configuration source to <paramref name="builder"/>.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
// 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.Threading;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Extensions.Configuration
|
||||
{
|
||||
public class ConfigurationRootExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void ReloadOnChanged_GetTokenBeforeReload()
|
||||
{
|
||||
// Arrange
|
||||
var tokenSource1 = new CancellationTokenSource();
|
||||
var tokenSource2 = new CancellationTokenSource();
|
||||
|
||||
var fileProvider = new MockFileProvider();
|
||||
fileProvider.Cancel = tokenSource1;
|
||||
|
||||
var configuration = new MockConfigurationRoot();
|
||||
configuration.OnReload = () => Assert.Equal(2, fileProvider.WatchCount);
|
||||
|
||||
// Act-1
|
||||
configuration.ReloadOnChanged(fileProvider, "config.json");
|
||||
|
||||
// Assert-1
|
||||
Assert.Equal(1, fileProvider.WatchCount);
|
||||
Assert.Equal(0, configuration.ReloadCount);
|
||||
|
||||
// Act-2
|
||||
fileProvider.Cancel = tokenSource2;
|
||||
tokenSource1.Cancel();
|
||||
|
||||
Assert.Equal(2, fileProvider.WatchCount);
|
||||
Assert.Equal(1, configuration.ReloadCount);
|
||||
}
|
||||
|
||||
private class MockConfigurationRoot : IConfigurationRoot
|
||||
{
|
||||
public Action OnReload { get; set; }
|
||||
|
||||
public int ReloadCount { get; private set; }
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IConfigurationSection> GetChildren()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IChangeToken GetReloadToken()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IConfigurationSection GetSection(string key)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
OnReload?.Invoke();
|
||||
ReloadCount++;
|
||||
}
|
||||
|
||||
public void RaiseChanged()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IDisposable RegisterOnChange(Action<object> callback, object state)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class MockFileProvider : IFileProvider
|
||||
{
|
||||
public CancellationTokenSource Cancel { get; set; }
|
||||
|
||||
public int WatchCount { get; private set; }
|
||||
|
||||
public IDirectoryContents GetDirectoryContents(string subpath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IFileInfo GetFileInfo(string subpath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IChangeToken Watch(string filter)
|
||||
{
|
||||
WatchCount++;
|
||||
return new CancellationChangeToken(Cancel.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -251,21 +251,11 @@ CommonKey3:CommonKey4=IniValue6";
|
|||
File.WriteAllText(Path.Combine(_basePath, "reload.ini"), @"IniKey1 = IniValue1");
|
||||
File.WriteAllText(Path.Combine(_basePath, "reload.xml"), @"<settings XmlKey1=""XmlValue1""/>");
|
||||
|
||||
var config = new ConfigurationBuilder().AddIniFile(source =>
|
||||
{
|
||||
source.Path = "reload.ini";
|
||||
source.ReloadOnChange = true;
|
||||
})
|
||||
.AddJsonFile(source =>
|
||||
{
|
||||
source.Path = "reload.json";
|
||||
source.ReloadOnChange = true;
|
||||
})
|
||||
.AddXmlFile(source =>
|
||||
{
|
||||
source.Path = "reload.xml";
|
||||
source.ReloadOnChange = true;
|
||||
}).Build();
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddIniFile("reload.ini", optional: false, reloadOnChange: true)
|
||||
.AddJsonFile("reload.json", optional: false, reloadOnChange: true)
|
||||
.AddXmlFile("reload.xml", optional: false, reloadOnChange: true)
|
||||
.Build();
|
||||
|
||||
Assert.Equal("JsonValue1", config["JsonKey1"]);
|
||||
Assert.Equal("IniValue1", config["IniKey1"]);
|
||||
|
|
Загрузка…
Ссылка в новой задаче