.NET コンソールアプリで、構成情報を appsettings.json からロードする

2024/02/23
★★

コンソール アプリにおける構成情報のロード

以前の記事で、コンソール アプリで、Generic Host を使うことで、appsettings.json から構成情報をロードできることを説明しました。

Generic Host を使うことで、DI(Dependency Injection) 等の多くの機能が使えますが、構成情報のロードは、多くの機能の一部に過ぎません。

検証やデモ等で、簡単なコンソール アプリを開発する場合は、Generic Host の実装は、オーバースペックになるため、今回は、構成情報のロードに絞って説明します。

ConfigurationBuilder による構成情報のロード

プロジェクト直下に appsettings.json を追加し、プロパティから、[常にコピーする] に設定します。
add appsettings.json

appsettings.json に構成情報を定義します。

{
  "welcomeMessage": "Hello, configuration!"
}

NuGet から、Microsoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.Json をプロジェクトへ追加します。

コードでは、ConfigurationBuilder のインスタンスを生成し、AddJsonFile 拡張メソッドで、appsettings.json への参照を追加します。

using Microsoft.Extensions.Configuration;

namespace ConfigurationDemoConsoleApp001;

internal class Program
{
    static void Main(string[] args)
    {
        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")            
            .Build();

        var welcomeMessage = configuration["welcomeMessage"] 
            ?? throw new ArgumentNullException("welcomeMessage not found.");

        Console.WriteLine(welcomeMessage);

        Console.ReadLine();
    }
}

他のソース: 環境変数、コマンドライン オプションからも構成情報を取得したい場合は、同様に Microsoft.Extensions.Configuration.EnvironmentVariablesMicrosoft.Extensions.Configuration.CommandLine を NuGet から取得、プロジェクトへ追加し、以下のコードを書きます。

using Microsoft.Extensions.Configuration;

namespace ConfigurationDemoConsoleApp001;

internal class Program
{
    static void Main(string[] args)
    {
        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddEnvironmentVariables()
            .AddCommandLine(args)
            .Build();

        var welcomeMessage = configuration["welcomeMessage"] 
            ?? throw new ArgumentNullException("welcomeMessage not found.");

        Console.WriteLine(welcomeMessage);

        Console.ReadLine();
    }
}

AddEnvironmentVariables 拡張メソッドで、環境変数のロード、AddCommandLine 拡張メソッドで、コマンドライン オプションから構成情報を取得しています。 これらの拡張メソッドの順番にも意味があり、追加順で構成情報のロードをオーバーライドします。つまり、このコードの場合では、同一の値が、appsettings.json と、環境変数で定義されていた場合は、環境変数の値が適用されます。さらに、コマンドライン オプションでも同一の値が定義されていた場合は、コマンドライン オプションの値が適用されます。

Generic Host における構成情報ロードの実装

ここで、参考として Generic Host の実装を見てみます。 以下のコードのように Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder ファクトリ メソッドで、HostBuilder のインスタンスを生成します。

public class Program
{
	public static void Main(string[] args)
	{
		IHost host = Host.CreateDefaultBuilder(args)
			.ConfigureServices(services =>
			{
                // DI
				services.AddHostedService<Worker>();
			})
			.Build();

		host.Run();
	}
}

この CreateDefaultBuilder の実装は、以下から参照できます。

HostingHostBuilderExtensions.cs の ApplyDefaultAppConfiguration メソッドで、構成情報のロードが定義されています。

internal static void ApplyDefaultAppConfiguration(HostBuilderContext hostingContext, IConfigurationBuilder appConfigBuilder, string[]? args)
{
    IHostEnvironment env = hostingContext.HostingEnvironment;
    bool reloadOnChange = GetReloadConfigOnChangeValue(hostingContext);

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

    if (env.IsDevelopment() && env.ApplicationName is { Length: > 0 })
    {
        try
        {
            var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
            appConfigBuilder.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange);
        }
        catch (FileNotFoundException)
        {
            // The assembly cannot be found, so just skip it.
        }
    }

    appConfigBuilder.AddEnvironmentVariables();

    AddCommandLineConfig(appConfigBuilder, args);

    [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Calling IConfiguration.GetValue is safe when the T is bool.")]
    static bool GetReloadConfigOnChangeValue(HostBuilderContext hostingContext) => hostingContext.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true);
}

appsettings..json のサポートが記述されています。 IHostEnvironment.EnvironmentName は、起動プロファイルの選択により、Development, Production の値が入り、開発環境では、appsettings.Development.json を参照するといったように、実行環境に応じて、参照する appsettings.json を変更できます。

このあたりは、過去に、以下の記事に書いています。

また、AddUserSecrets により、ユーザーシークレットからのロードのサポートも記述されています。

このコードから、Generic Host を使用する場合、appSettings.json、appsettings..json、ユーザーシークレット、環境変数、コマンドライン オプションの順で、構成情報のロードの優先順位が高くなることが分かります。

以上、参考までに。

コメント (0)

コメントの投稿