Skip to content

Commit 25b41ef

Browse files
author
John Luo
committed
Merge branch 'master' of dotnet/extensions
2 parents 47a7fe9 + 4aab03b commit 25b41ef

File tree

350 files changed

+27632
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

350 files changed

+27632
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project>
2+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
3+
4+
<PropertyGroup>
5+
<GenerateDocumentationFile Condition=" '$(IsUnitTestProject)' != 'true' AND '$(IsSampleProject)' != 'true' ">true</GenerateDocumentationFile>
6+
<PackageTags>configuration</PackageTags>
7+
<NoWarn>$(NoWarn);PKG0001</NoWarn>
8+
</PropertyGroup>
9+
</Project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!-- This file is automatically generated. -->
2+
<Project Sdk="Microsoft.NET.Sdk">
3+
<PropertyGroup>
4+
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
5+
</PropertyGroup>
6+
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
7+
<Compile Include="Microsoft.Extensions.Configuration.KeyPerFile.netstandard2.0.cs" />
8+
<Reference Include="Microsoft.Extensions.Configuration" />
9+
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
10+
</ItemGroup>
11+
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
12+
<Compile Include="Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp.cs" />
13+
<Reference Include="Microsoft.Extensions.Configuration" />
14+
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
15+
</ItemGroup>
16+
</Project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.Extensions.Configuration
5+
{
6+
public static partial class KeyPerFileConfigurationBuilderExtensions
7+
{
8+
public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, System.Action<Microsoft.Extensions.Configuration.KeyPerFile.KeyPerFileConfigurationSource> configureSource) { throw null; }
9+
public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string directoryPath) { throw null; }
10+
public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string directoryPath, bool optional) { throw null; }
11+
public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string directoryPath, bool optional, bool reloadOnChange) { throw null; }
12+
}
13+
}
14+
namespace Microsoft.Extensions.Configuration.KeyPerFile
15+
{
16+
public partial class KeyPerFileConfigurationProvider : Microsoft.Extensions.Configuration.ConfigurationProvider, System.IDisposable
17+
{
18+
public KeyPerFileConfigurationProvider(Microsoft.Extensions.Configuration.KeyPerFile.KeyPerFileConfigurationSource source) { }
19+
public void Dispose() { }
20+
public override void Load() { }
21+
public override string ToString() { throw null; }
22+
}
23+
public partial class KeyPerFileConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource
24+
{
25+
public KeyPerFileConfigurationSource() { }
26+
public Microsoft.Extensions.FileProviders.IFileProvider FileProvider { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
27+
public System.Func<string, bool> IgnoreCondition { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
28+
public string IgnorePrefix { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
29+
public bool Optional { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
30+
public int ReloadDelay { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
31+
public bool ReloadOnChange { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
32+
public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; }
33+
}
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.Extensions.Configuration
5+
{
6+
public static partial class KeyPerFileConfigurationBuilderExtensions
7+
{
8+
public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, System.Action<Microsoft.Extensions.Configuration.KeyPerFile.KeyPerFileConfigurationSource> configureSource) { throw null; }
9+
public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string directoryPath) { throw null; }
10+
public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string directoryPath, bool optional) { throw null; }
11+
public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string directoryPath, bool optional, bool reloadOnChange) { throw null; }
12+
}
13+
}
14+
namespace Microsoft.Extensions.Configuration.KeyPerFile
15+
{
16+
public partial class KeyPerFileConfigurationProvider : Microsoft.Extensions.Configuration.ConfigurationProvider, System.IDisposable
17+
{
18+
public KeyPerFileConfigurationProvider(Microsoft.Extensions.Configuration.KeyPerFile.KeyPerFileConfigurationSource source) { }
19+
public void Dispose() { }
20+
public override void Load() { }
21+
public override string ToString() { throw null; }
22+
}
23+
public partial class KeyPerFileConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource
24+
{
25+
public KeyPerFileConfigurationSource() { }
26+
public Microsoft.Extensions.FileProviders.IFileProvider FileProvider { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
27+
public System.Func<string, bool> IgnoreCondition { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
28+
public string IgnorePrefix { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
29+
public bool Optional { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
30+
public int ReloadDelay { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
31+
public bool ReloadOnChange { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
32+
public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; }
33+
}
34+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using System.IO;
3+
using Microsoft.Extensions.Configuration.KeyPerFile;
4+
using Microsoft.Extensions.FileProviders;
5+
6+
namespace Microsoft.Extensions.Configuration
7+
{
8+
/// <summary>
9+
/// Extension methods for registering <see cref="KeyPerFileConfigurationProvider"/> with <see cref="IConfigurationBuilder"/>.
10+
/// </summary>
11+
public static class KeyPerFileConfigurationBuilderExtensions
12+
{
13+
/// <summary>
14+
/// Adds configuration using files from a directory. File names are used as the key,
15+
/// file contents are used as the value.
16+
/// </summary>
17+
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
18+
/// <param name="directoryPath">The path to the directory.</param>
19+
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
20+
public static IConfigurationBuilder AddKeyPerFile(this IConfigurationBuilder builder, string directoryPath)
21+
=> builder.AddKeyPerFile(directoryPath, optional: false, reloadOnChange: false);
22+
23+
/// <summary>
24+
/// Adds configuration using files from a directory. File names are used as the key,
25+
/// file contents are used as the value.
26+
/// </summary>
27+
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
28+
/// <param name="directoryPath">The path to the directory.</param>
29+
/// <param name="optional">Whether the directory is optional.</param>
30+
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
31+
public static IConfigurationBuilder AddKeyPerFile(this IConfigurationBuilder builder, string directoryPath, bool optional)
32+
=> builder.AddKeyPerFile(directoryPath, optional, reloadOnChange: false);
33+
34+
/// <summary>
35+
/// Adds configuration using files from a directory. File names are used as the key,
36+
/// file contents are used as the value.
37+
/// </summary>
38+
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
39+
/// <param name="directoryPath">The path to the directory.</param>
40+
/// <param name="optional">Whether the directory is optional.</param>
41+
/// <param name="reloadOnChange">Whether the configuration should be reloaded if the files are changed, added or removed.</param>
42+
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
43+
public static IConfigurationBuilder AddKeyPerFile(this IConfigurationBuilder builder, string directoryPath, bool optional, bool reloadOnChange)
44+
=> builder.AddKeyPerFile(source =>
45+
{
46+
// Only try to set the file provider if its not optional or the directory exists
47+
if (!optional || Directory.Exists(directoryPath))
48+
{
49+
source.FileProvider = new PhysicalFileProvider(directoryPath);
50+
}
51+
source.Optional = optional;
52+
source.ReloadOnChange = reloadOnChange;
53+
});
54+
55+
/// <summary>
56+
/// Adds configuration using files from a directory. File names are used as the key,
57+
/// file contents are used as the value.
58+
/// </summary>
59+
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
60+
/// <param name="configureSource">Configures the source.</param>
61+
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
62+
public static IConfigurationBuilder AddKeyPerFile(this IConfigurationBuilder builder, Action<KeyPerFileConfigurationSource> configureSource)
63+
=> builder.Add(configureSource);
64+
}
65+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Threading;
5+
using Microsoft.Extensions.Primitives;
6+
7+
namespace Microsoft.Extensions.Configuration.KeyPerFile
8+
{
9+
/// <summary>
10+
/// A <see cref="ConfigurationProvider"/> that uses a directory's files as configuration key/values.
11+
/// </summary>
12+
public class KeyPerFileConfigurationProvider : ConfigurationProvider, IDisposable
13+
{
14+
private readonly IDisposable _changeTokenRegistration;
15+
16+
KeyPerFileConfigurationSource Source { get; set; }
17+
18+
/// <summary>
19+
/// Initializes a new instance.
20+
/// </summary>
21+
/// <param name="source">The settings.</param>
22+
public KeyPerFileConfigurationProvider(KeyPerFileConfigurationSource source)
23+
{
24+
Source = source ?? throw new ArgumentNullException(nameof(source));
25+
26+
if (Source.ReloadOnChange && Source.FileProvider != null)
27+
{
28+
_changeTokenRegistration = ChangeToken.OnChange(
29+
() => Source.FileProvider.Watch("*"),
30+
() =>
31+
{
32+
Thread.Sleep(Source.ReloadDelay);
33+
Load(reload: true);
34+
});
35+
}
36+
37+
}
38+
39+
private static string NormalizeKey(string key)
40+
=> key.Replace("__", ConfigurationPath.KeyDelimiter);
41+
42+
private static string TrimNewLine(string value)
43+
=> value.EndsWith(Environment.NewLine)
44+
? value.Substring(0, value.Length - Environment.NewLine.Length)
45+
: value;
46+
47+
/// <summary>
48+
/// Loads the configuration values.
49+
/// </summary>
50+
public override void Load()
51+
{
52+
Load(reload: false);
53+
}
54+
55+
private void Load(bool reload)
56+
{
57+
var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
58+
59+
if (Source.FileProvider == null)
60+
{
61+
if (Source.Optional || reload) // Always optional on reload
62+
{
63+
Data = data;
64+
return;
65+
}
66+
67+
throw new DirectoryNotFoundException("A non-null file provider for the directory is required when this source is not optional.");
68+
}
69+
70+
var directory = Source.FileProvider.GetDirectoryContents("/");
71+
if (!directory.Exists)
72+
{
73+
if (Source.Optional || reload) // Always optional on reload
74+
{
75+
Data = data;
76+
return;
77+
}
78+
throw new DirectoryNotFoundException("The root directory for the FileProvider doesn't exist and is not optional.");
79+
}
80+
else
81+
{
82+
foreach (var file in directory)
83+
{
84+
if (file.IsDirectory)
85+
{
86+
continue;
87+
}
88+
89+
using var stream = file.CreateReadStream();
90+
using var streamReader = new StreamReader(stream);
91+
92+
if (Source.IgnoreCondition == null || !Source.IgnoreCondition(file.Name))
93+
{
94+
data.Add(NormalizeKey(file.Name), TrimNewLine(streamReader.ReadToEnd()));
95+
}
96+
97+
}
98+
}
99+
100+
Data = data;
101+
}
102+
103+
private string GetDirectoryName()
104+
=> Source.FileProvider?.GetFileInfo("/")?.PhysicalPath ?? "<Unknown>";
105+
106+
/// <summary>
107+
/// Generates a string representing this provider name and relevant details.
108+
/// </summary>
109+
/// <returns> The configuration name. </returns>
110+
public override string ToString()
111+
=> $"{GetType().Name} for files in '{GetDirectoryName()}' ({(Source.Optional ? "Optional" : "Required")})";
112+
113+
/// <inheritdoc />
114+
public void Dispose()
115+
{
116+
_changeTokenRegistration?.Dispose();
117+
}
118+
}
119+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.IO;
3+
using Microsoft.Extensions.FileProviders;
4+
5+
namespace Microsoft.Extensions.Configuration.KeyPerFile
6+
{
7+
/// <summary>
8+
/// An <see cref="IConfigurationSource"/> used to configure <see cref="KeyPerFileConfigurationProvider"/>.
9+
/// </summary>
10+
public class KeyPerFileConfigurationSource : IConfigurationSource
11+
{
12+
/// <summary>
13+
/// Constructor;
14+
/// </summary>
15+
public KeyPerFileConfigurationSource()
16+
=> IgnoreCondition = s => IgnorePrefix != null && s.StartsWith(IgnorePrefix);
17+
18+
/// <summary>
19+
/// The FileProvider whos root "/" directory files will be used as configuration data.
20+
/// </summary>
21+
public IFileProvider FileProvider { get; set; }
22+
23+
/// <summary>
24+
/// Files that start with this prefix will be excluded.
25+
/// Defaults to "ignore.".
26+
/// </summary>
27+
public string IgnorePrefix { get; set; } = "ignore.";
28+
29+
/// <summary>
30+
/// Used to determine if a file should be ignored using its name.
31+
/// Defaults to using the IgnorePrefix.
32+
/// </summary>
33+
public Func<string, bool> IgnoreCondition { get; set; }
34+
35+
/// <summary>
36+
/// If false, will throw if the directory doesn't exist.
37+
/// </summary>
38+
public bool Optional { get; set; }
39+
40+
/// <summary>
41+
/// Determines whether the source will be loaded if the underlying file changes.
42+
/// </summary>
43+
public bool ReloadOnChange { get; set; }
44+
45+
/// <summary>
46+
/// Number of milliseconds that reload will wait before calling Load. This helps
47+
/// avoid triggering reload before a file is completely written. Default is 250.
48+
/// </summary>
49+
public int ReloadDelay { get; set; } = 250;
50+
51+
/// <summary>
52+
/// Builds the <see cref="KeyPerFileConfigurationProvider"/> for this source.
53+
/// </summary>
54+
/// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
55+
/// <returns>A <see cref="KeyPerFileConfigurationProvider"/></returns>
56+
public IConfigurationProvider Build(IConfigurationBuilder builder)
57+
=> new KeyPerFileConfigurationProvider(this);
58+
}
59+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<Description>Configuration provider that uses files in a directory for Microsoft.Extensions.Configuration.</Description>
5+
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
6+
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
7+
<IsPackable>true</IsPackable>
8+
<IsShipping>true</IsShipping>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<Reference Include="Microsoft.Extensions.Configuration" />
13+
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
This is a configuration provider that uses a directory's files as data. A file's name is the key and the contents are the value.

0 commit comments

Comments
 (0)