Skip to content

Commit

Permalink
Started work on configuration enhancements including local configurat…
Browse files Browse the repository at this point in the history
…ion files, and the ability to insert additional configurations after the other typical configuration items
  • Loading branch information
david-driscoll committed Oct 31, 2019
1 parent 676e712 commit 08b6c8f
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 55 deletions.
27 changes: 27 additions & 0 deletions src/Configuration.Abstractions/ConfigurationOptions.cs
@@ -0,0 +1,27 @@
using System.Collections.Generic;
using Microsoft.Extensions.FileProviders;

namespace Rocket.Surgery.Extensions.Configuration
{
/// <summary>
/// Options for configuring a hosting environment
/// </summary>
public class ConfigurationOptions
{
/// <summary>
/// Additional settings providers to be inserted after the default application settings file (typically appsettings.json)
/// </summary>
public List<SettingsConfigurationSourceProvider> SettingsConfigurationSourceProviders { get; } = new List<SettingsConfigurationSourceProvider>();

/// <summary>
/// Additional settings providers to be inserted after the default environment application settings file (typically appsettings.{env}.json)
/// </summary>
public List<EnvironmentSettingsConfigurationSourceProvider> EnvironmentSettingsConfigurationSourceProviders { get; } = new List<EnvironmentSettingsConfigurationSourceProvider>();

/// <summary>
/// Additional settings providers to be inserted after the environment application settings file and after the first local config file (typically appsettings.local.json)
/// .local files are not generally checked into source control.
/// </summary>
public List<SettingsConfigurationSourceProvider> LocalSettingsConfigurationSourceProvider { get; } = new List<SettingsConfigurationSourceProvider>();
}
}
@@ -0,0 +1,11 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;

namespace Rocket.Surgery.Extensions.Configuration
{
/// <summary>
/// Returns a <see cref="IConfigurationSource"/> that may relate to the given file provider.
/// This is inserted after appsettings.{env}.json
/// </summary>
public delegate IConfigurationSource EnvironmentSettingsConfigurationSourceProvider(IFileProvider fileProvider, string environmentName);
}
2 changes: 1 addition & 1 deletion src/Configuration.Abstractions/IConfigurationBuilder.cs
@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;
using Rocket.Surgery.Conventions;
using Rocket.Surgery.Conventions.Reflection;
using Rocket.Surgery.Conventions.Scanners;
Expand Down
@@ -0,0 +1,11 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;

namespace Rocket.Surgery.Extensions.Configuration
{
/// <summary>
/// Returns a <see cref="IConfigurationSource"/> that may relate to the given file provider.!--
/// This is inserted after appsettings.json
/// </summary>
public delegate IConfigurationSource SettingsConfigurationSourceProvider(IFileProvider fileProvider);
}
1 change: 1 addition & 0 deletions src/Hosting.Abstractions/IRocketHostBuilder.cs
Expand Up @@ -4,6 +4,7 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Rocket.Surgery.Conventions;
Expand Down
2 changes: 1 addition & 1 deletion src/Hosting.Functions/RocketBooster.cs
Expand Up @@ -27,7 +27,7 @@ public static class RocketBooster
DependencyContext dependencyContext,
DiagnosticSource? diagnosticSource = null)
{
return (builder , startupInstance) =>
return (builder, startupInstance) =>
{
var b = RocketHostExtensions.GetOrCreateBuilder(builder, startupInstance, null);
if (diagnosticSource != null)
Expand Down
26 changes: 18 additions & 8 deletions src/Hosting.Functions/RocketFunctionHostBuilder.cs
Expand Up @@ -10,6 +10,7 @@
using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Rocket.Surgery.Conventions;
Expand Down Expand Up @@ -174,17 +175,26 @@ private IConfiguration SetupConfiguration()
var existingConfiguration = Builder.Services.First(z => z.ServiceType == typeof(IConfiguration))
.ImplementationInstance as IConfiguration;

var configurationOptions = this.GetOrAdd(() => new ConfigurationOptions());

var fileProvider = new PhysicalFileProvider(currentDirectory);
var configurationBuilder = new MsftConfigurationBuilder()
.SetBasePath(currentDirectory)
.AddConfiguration(existingConfiguration)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: true)
.AddYamlFile("appsettings.yaml", optional: true, reloadOnChange: true)
.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{_environment.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddYamlFile($"appsettings.{_environment.EnvironmentName}.yml", optional: true, reloadOnChange: true)
.AddYamlFile($"appsettings.{_environment.EnvironmentName}.yaml", optional: true, reloadOnChange: true)
.AddIniFile($"appsettings.{_environment.EnvironmentName}.ini", optional: true, reloadOnChange: true);
.AddJsonFile(fileProvider, "appsettings.json", optional: true, reloadOnChange: true);

foreach (var provider in configurationOptions.SettingsConfigurationSourceProviders)
configurationBuilder = configurationBuilder.Add(provider(fileProvider));

configurationBuilder.AddJsonFile($"appsettings.{_environment.EnvironmentName}.json", optional: true, reloadOnChange: true);

foreach (var provider in configurationOptions.EnvironmentSettingsConfigurationSourceProviders)
configurationBuilder = configurationBuilder.Add(provider(fileProvider, _environment.EnvironmentName));

configurationBuilder.AddJsonFile($"appsettings.local.json", optional: true, reloadOnChange: true);

foreach (var provider in configurationOptions.LocalSettingsConfigurationSourceProvider)
configurationBuilder = configurationBuilder.Add(provider(fileProvider));

if (_environment.IsDevelopment())
{
Expand Down
75 changes: 75 additions & 0 deletions src/Hosting.Functions/RocketHostExtensions.cs
Expand Up @@ -6,13 +6,16 @@
using System.Runtime.CompilerServices;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Ini;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NetEscapades.Configuration.Yaml;
using Rocket.Surgery.Conventions;
using Rocket.Surgery.Conventions.Reflection;
using Rocket.Surgery.Conventions.Scanners;
using Rocket.Surgery.Extensions.Configuration;
//using Microsoft.Azure.WebJobs.Hosting;

namespace Rocket.Surgery.Hosting.Functions
Expand Down Expand Up @@ -315,6 +318,78 @@ internal static RocketFunctionHostBuilder GetOrCreateBuilder(IWebJobsBuilder bui
properties.Set(HostType.Live);
var scanner = new SimpleConventionScanner(assemblyCandidateFinder, properties, logger);
conventionalBuilder = new RocketFunctionHostBuilder(builder, functionsAssembly, startupInstance, environment!, scanner, assemblyCandidateFinder, assemblyProvider, diagnosticSource, properties);
conventionalBuilder.Set(new ConfigurationOptions()
{
SettingsConfigurationSourceProviders = {
(fileProvider) => new YamlConfigurationSource()
{
Path = $"appsettings.yml",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
},
(fileProvider) => new YamlConfigurationSource()
{
Path = $"appsettings.yaml",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
},
(fileProvider) => new IniConfigurationSource()
{
Path = $"appsettings.ini",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
}
},
EnvironmentSettingsConfigurationSourceProviders = {
(fileProvider, environmentName) => new YamlConfigurationSource()
{
Path = $"appsettings.{environmentName}.yml",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
},
(fileProvider, environmentName) => new YamlConfigurationSource()
{
Path = $"appsettings.{environmentName}.yaml",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
},
(fileProvider, environmentName) => new IniConfigurationSource()
{
Path = $"appsettings.{environmentName}.ini",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
}
},
LocalSettingsConfigurationSourceProvider = {
(fileProvider) => new YamlConfigurationSource()
{
Path = $"appsettings.local.yml",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
},
(fileProvider) => new YamlConfigurationSource()
{
Path = $"appsettings.local.yaml",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
},
(fileProvider) => new IniConfigurationSource()
{
Path = $"appsettings.local.ini",
FileProvider = fileProvider,
Optional = true,
ReloadOnChange = true,
}
}
});
Builders.Add(builder, conventionalBuilder);
}

Expand Down
95 changes: 51 additions & 44 deletions src/Hosting/RocketContext.cs
Expand Up @@ -7,11 +7,13 @@
using Microsoft.Extensions.Configuration.Ini;
using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NetEscapades.Configuration.Yaml;
using Rocket.Surgery.Conventions;
using Rocket.Surgery.Extensions.CommandLine;
using Rocket.Surgery.Extensions.Configuration;
using Rocket.Surgery.Extensions.DependencyInjection;
using ConfigurationBuilder = Rocket.Surgery.Extensions.Configuration.ConfigurationBuilder;
using IMsftConfigurationBuilder = Microsoft.Extensions.Configuration.IConfigurationBuilder;
Expand Down Expand Up @@ -105,57 +107,48 @@ public void ReplaceArguments(IMsftConfigurationBuilder configurationBuilder)
public void ConfigureAppConfiguration(HostBuilderContext context, IMsftConfigurationBuilder configurationBuilder)
{
var rocketHostBuilder = RocketHostExtensions.GetConventionalHostBuilder(_hostBuilder);
var configurationOptions = rocketHostBuilder.GetOrAdd(() => new ConfigurationOptions());
InsertConfigurationSourceAfter(
configurationBuilder.Sources,
sources => sources.OfType<JsonConfigurationSource>().FirstOrDefault(x => x.Path == "appsettings.json"),
(source) => new YamlConfigurationSource()
{
Path = "appsettings.yml",
FileProvider = source.FileProvider,
Optional = true,
ReloadOnChange = true,
},
(source) => new YamlConfigurationSource()
{
Path = "appsettings.yaml",
FileProvider = source.FileProvider,
Optional = true,
ReloadOnChange = true,
},
(source) => new IniConfigurationSource()
{
Path = "appsettings.ini",
FileProvider = source.FileProvider,
Optional = true,
ReloadOnChange = true,
});
x => x.FileProvider,
configurationOptions.SettingsConfigurationSourceProviders
);

InsertConfigurationSourceAfter(
configurationBuilder.Sources,
sources => sources.OfType<JsonConfigurationSource>().FirstOrDefault(x =>
string.Equals(x.Path, $"appsettings.{context.HostingEnvironment.EnvironmentName}.json",
StringComparison.OrdinalIgnoreCase)),
(source) => new YamlConfigurationSource()
{
Path = $"appsettings.{context.HostingEnvironment.EnvironmentName}.yml",
FileProvider = source.FileProvider,
Optional = true,
ReloadOnChange = true,
},
(source) => new YamlConfigurationSource()
{
Path = $"appsettings.{context.HostingEnvironment.EnvironmentName}.yaml",
FileProvider = source.FileProvider,
Optional = true,
ReloadOnChange = true,
},
(source) => new IniConfigurationSource()
{
Path = $"appsettings.{context.HostingEnvironment.EnvironmentName}.ini",
FileProvider = source.FileProvider,
Optional = true,
ReloadOnChange = true,
});
x => x.FileProvider,
new SettingsConfigurationSourceProvider[] {
(fp) => new JsonConfigurationSource() {
FileProvider = fp,
Path = "appsettings.local.json",
Optional = true,
ReloadOnChange = true,
}
}
);

InsertConfigurationSourceAfter(
configurationBuilder.Sources,
sources => sources.OfType<JsonConfigurationSource>().FirstOrDefault(x =>
string.Equals(x.Path, $"appsettings.{context.HostingEnvironment.EnvironmentName}.json",
StringComparison.OrdinalIgnoreCase)),
x => x.FileProvider,
context.HostingEnvironment.EnvironmentName,
configurationOptions.EnvironmentSettingsConfigurationSourceProviders
);

InsertConfigurationSourceAfter(
configurationBuilder.Sources,
sources => sources.OfType<JsonConfigurationSource>().FirstOrDefault(x =>
string.Equals(x.Path, $"appsettings.local.json",
StringComparison.OrdinalIgnoreCase)),
x => x.FileProvider,
configurationOptions.LocalSettingsConfigurationSourceProvider
);

InsertConfigurationSourceBefore(
configurationBuilder.Sources,
Expand Down Expand Up @@ -192,7 +185,21 @@ public void ConfigureAppConfiguration(HostBuilderContext context, IMsftConfigura
});
}

private static void InsertConfigurationSourceAfter<T>(IList<IConfigurationSource> sources, Func<IList<IConfigurationSource>, T> getSource, params Func<T, IConfigurationSource>[] createSourceFrom)
private static void InsertConfigurationSourceAfter<T>(IList<IConfigurationSource> sources, Func<IList<IConfigurationSource>, T> getSource, Func<T, IFileProvider> getFileProvider, IEnumerable<SettingsConfigurationSourceProvider> createSourceFrom)
where T : IConfigurationSource
{
var source = getSource(sources);
if (source != null)
{
var index = sources.IndexOf(source);
foreach (var m in createSourceFrom.Reverse())
{
sources.Insert(index + 1, m(getFileProvider(source)));
}
}
}

private static void InsertConfigurationSourceAfter<T>(IList<IConfigurationSource> sources, Func<IList<IConfigurationSource>, T> getSource, Func<T, IFileProvider> getFileProvider, string environmentName, IEnumerable<EnvironmentSettingsConfigurationSourceProvider> createSourceFrom)
where T : IConfigurationSource
{
var source = getSource(sources);
Expand All @@ -201,7 +208,7 @@ private static void InsertConfigurationSourceAfter<T>(IList<IConfigurationSource
var index = sources.IndexOf(source);
foreach (var m in createSourceFrom.Reverse())
{
sources.Insert(index + 1, m(source));
sources.Insert(index + 1, m(getFileProvider(source), environmentName));
}
}
}
Expand Down

0 comments on commit 08b6c8f

Please sign in to comment.