ASP.NET Core の構成

作成者: Rick Anderson および Kirk Larkin

ASP.NET Core のアプリケーション構成は、1 つまたは複数の構成プロバイダーを使用して実行されます。 構成プロバイダーは、以下のようなさまざまな構成ソースを使用して、キーと値のペアから構成データを読み取ります:

  • appsettings.json などの設定ファイル
  • 環境変数
  • Azure Key Vault
  • Azure App Configuration
  • コマンド ライン引数
  • インストール済みまたは作成済みのカスタム プロバイダー
  • ディレクトリ ファイル
  • メモリ内 .NET オブジェクト

この記事では ASP.NET Core の構成について説明します。 コンソール アプリでの構成の使用方法について詳しくは、.NET 構成に関する記事をご覧ください。

アプリケーションとホストの構成

ASP.NET Core アプリはホストを構成して起動します。 ホストはアプリの起動と有効期間の管理を担当します。 ASP.NET Core テンプレートを使用すると、ホストを WebApplicationBuilder 含むテンプレートを作成できます。 一部の構成についてはホストおよびアプリケーション構成プロバイダーの両方で行うことができますが、一般には、ホストに必要な構成のみをホスト構成で行う必要があります。

アプリケーションの構成は最も優先度が高く、次のセクションで詳しく説明します。 ホスト構成 はアプリケーション構成に従っています。この記事で説明します。

既定のアプリケーション構成ソース

dotnet new または Visual Studio で作成された ASP.NET Core の web アプリが、次のコードを生成します:

var builder = WebApplication.CreateBuilder(args);

WebApplication.CreateBuilder は、事前に構成された既定値を使用して WebApplicationBuilder クラスの新しいインスタンスを初期化します。 WebApplicationBuilder (builder) を初期化すると、優先度の高い方から低い方へ、次の順序でアプリの既定の構成が提供されます。

  1. コマンドライン構成プロバイダーを使用するコマンドライン引数。
  2. 接頭辞なしの環境変数構成プロバイダーを使用した接頭辞なしの環境変数。
  3. 環境でアプリが実行される場合に使用されるユーザー シークレット
  4. JSON 構成プロバイダーを使用する appsettings.{Environment}.json。 たとえば、appsettings.Production.jsonappsettings.Development.json です。
  5. JSON 構成プロバイダーを使用する appsettings.json
  6. 次のセクションで説明するホスト構成へのフォールバック。

既定のホスト構成ソース

次の一覧には、WebApplicationBuilder について、優先度が最も高いものから最も低いものまで、既定のホスト構成ソースが含まれています。

  1. コマンドライン構成プロバイダーを使用するコマンドライン引数。
  2. 環境変数構成プロバイダーを使用する、プレフィックス DOTNET_ が付いた環境変数。
  3. 環境変数構成プロバイダーを使用する、プレフィックス ASPNETCORE_ が付いた環境変数。

.NET Generic HostWeb Host の場合、既定のホスト構成ソースを、優先度の高いものから順に並べると、次のようになります。

  1. 環境変数構成プロバイダーを使用する、プレフィックス ASPNETCORE_ が付いた環境変数。
  2. コマンドライン構成プロバイダーを使用するコマンドライン引数。
  3. 環境変数構成プロバイダーを使用する、プレフィックス DOTNET_ が付いた環境変数。

ホストとアプリケーションの構成で構成値を設定する場合は、アプリケーション構成を使用します。

ホスト変数

次の変数は、ホスト ビルダーを初期化するときに早期にロックされ、アプリケーション構成の影響を受けることはありません。

その他のホスト設定はすべて、ホスト構成からではなくアプリケーション構成から読み取られます。

URLS は、ブートストラップ設定ではない多くの一般的なホスト設定の 1 つです。 前の一覧にない他のすべてのホスト設定と同様に、URLS はアプリケーション構成から後で読み取られます。ホスト構成はアプリケーション構成のフォールバックであるため、ホスト構成を使用して URLS を設定できますが、appsettings.json のようにアプリケーション構成内の任意の構成ソースによってオーバーライドされます。

詳細については、「コンテンツ ルート、アプリ名、環境の変更」および「環境変数またはコマンド ラインを使用したコンテンツ ルート、アプリ名、環境の変更、アプリ名、環境の変更」を参照してください。

この記事の残りのセクションでは、アプリケーションの構成を参照してください。

アプリケーション構成プロバイダー

以下のコードでは、追加した順に、有効な構成プロバイダーが表示されます:

public class Index2Model : PageModel
{
    private IConfigurationRoot ConfigRoot;

    public Index2Model(IConfiguration configRoot)
    {
        ConfigRoot = (IConfigurationRoot)configRoot;
    }

    public ContentResult OnGet()
    {           
        string str = "";
        foreach (var provider in ConfigRoot.Providers.ToList())
        {
            str += provider.ToString() + "\n";
        }

        return Content(str);
    }
}

上記の優先度が最も高い既定の構成ソースから最も低い既定の構成ソースまでの一覧では、テンプレートで生成されたアプリケーションに追加される順序とは逆の順序でプロバイダーを示しています。 たとえば、JSON 構成プロバイダーは、コマンドライン構成プロバイダーの前に追加されます。

後から追加された構成プロバイダーは優先度がより高く、それによって、それ以前のキー設定はオーバーライドされます。 たとえば、MyKeyappsettings.json と環境の両方で設定されている場合、環境の値が使用されます。 既定の構成プロバイダーを使用すると、コマンドライン構成プロバイダーによって他のすべてのプロバイダーがオーバーライドされます。

CreateBuilder の詳細については、既定のビルダー設定を参照してください。

appsettings.json

次の appsettings.json ファイルを考えてみます。

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey": "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

サンプル ダウンロード の次のコードでは、上記の構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

既定の JsonConfigurationProvider は、以下の順序で構成を読み込みます:

  1. appsettings.json
  2. appsettings.{Environment}.json: appsettings.Production.json または appsettings.Development.json ファイルなど。 ファイルの環境バージョンは、IHostingEnvironment.EnvironmentNameに基づいて読み込まれます。 詳細については、「ASP.NET Core で複数の環境を使用する」を参照してください。

appsettings.{Environment}.json 値によって appsettings.json 内のキーがオーバーライドされます。 たとえば、既定では次のようになります:

  • 開発中は、appsettings.json で見つかった値は appsettings.Development.json 構成によって上書きされます。
  • 運用環境では、appsettings.json で見つかった値は appsettings.Production.json 構成によって上書きされます。 たとえば、Azure にアプリをデプロイする場合。

構成値を保証する必要がある場合は、「GetValue」を参照してください。 前の例では文字列が読み取られるだけで、既定値はサポートされていません。

既定の構成を利用する場合、reloadOnChange: trueappsettings.json ファイルと appsettings.{Environment}.json ファイルを有効にすることができます。 アプリの開始 "" に appsettings.json ファイルと appsettings.{Environment}.json ファイルに加えられた変更は、JSON 構成プロバイダーによって読み取られます。

オプションパターンを使用して、階層型の構成データをバインドします

関連する構成値を読み取る方法としては、オプション パターンを使用することをお勧めします。 たとえば、以下の構成値を読み取るには、次のようにします:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

次の PositionOptions クラスを作成します:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; } = String.Empty;
    public string Name { get; set; } = String.Empty;
}

オプション クラス:

  • パラメーターのないパブリック コンストラクターを持った非抽象でなければなりません。
  • 型のパブリックな読み取り/書き込みプロパティは、すべてバインドされます。
  • フィールドはバインド "されません"。 上のコード Position はバインドされません。 Position フィールドは、クラスを構成プロバイダーにバインドするときに、アプリで文字列 "Position" をハードコーディングする必要をなくすために使用されます。

コード例を次に示します。

  • ConfigurationBinder.Bind を呼び出して、 クラスを Position セクションにバインドします。
  • Position 構成データを表示します。
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

上記のコードでは、アプリが開始された後の JSON 構成ファイルへの変更は既定で読み取られます。

ConfigurationBinder.Get<T> 指定された型をバインドして返します。 ConfigurationBinder.Get<T>ConfigurationBinder.Bind を使用するよりも便利な場合があります。 次のコードは、PositionOptions クラスで ConfigurationBinder.Get<T> を使用する方法を示しています:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions? positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

上記のコードでは、アプリが開始された後の JSON 構成ファイルへの変更は既定で読み取られます。

"オプション パターン" を使用するときのもう 1 つの方法は、Position セクションをバインドし、それを依存関係挿入サービス コンテナーに追加することです。 次のコードでは、PositionOptionsConfigure でサービスコンテナーに追加され、構成にバインドされます:

using ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));

var app = builder.Build();

下記のコードは、上記のコードを使用して位置オプションを読み取ります:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

上のコードでは、アプリが開始された後の JSON 構成ファイルへの変更は読み取られ "ません"。 アプリの開始後に変更を読み取るには、IOptionsSnapshot を使用します。

既定の構成を利用する場合、reloadOnChange: trueappsettings.json ファイルと appsettings.{Environment}.json ファイルを有効にすることができます。 アプリの開始 "" に appsettings.json ファイルと appsettings.{Environment}.json ファイルに加えられた変更は、JSON 構成プロバイダーによって読み取られます。

追加の JSON 構成ファイルを追加する方法の詳細については、このドキュメント中の「JSON 構成プロバイダー」を参照してください。

サービス コレクションの結合

サービスを登録し、オプションを構成する以下について考えてみましょう。

using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(
    builder.Configuration.GetSection(ColorOptions.Color));

builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();

var app = builder.Build();

関連する登録グループは、サービスを登録するための拡張メソッドに移動できます。 たとえば、構成サービスは次のクラスに追加されます。

using ConfigSample.Options;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class MyConfigServiceCollectionExtensions
    {
        public static IServiceCollection AddConfig(
             this IServiceCollection services, IConfiguration config)
        {
            services.Configure<PositionOptions>(
                config.GetSection(PositionOptions.Position));
            services.Configure<ColorOptions>(
                config.GetSection(ColorOptions.Color));

            return services;
        }

        public static IServiceCollection AddMyDependencyGroup(
             this IServiceCollection services)
        {
            services.AddScoped<IMyDependency, MyDependency>();
            services.AddScoped<IMyDependency2, MyDependency2>();

            return services;
        }
    }
}

残りのサービスは、同様のクラスに登録されます。 次のコードでは、新しい拡張メソッドを使用してサービスを登録します。

using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddConfig(builder.Configuration)
    .AddMyDependencyGroup();

builder.Services.AddRazorPages();

var app = builder.Build();

注:services.Add{GROUP_NAME} 拡張メソッドは、サービスを追加、場合によっては構成します。 たとえば、AddControllersWithViews ではビューを持つ MVC コントローラーで必要なサービスが追加され、AddRazorPages では Razor Pages で必要なサービスが追加されます。

セキュリティとユーザー シークレット

構成データのガイドライン:

  • 構成プロバイダーのコードやプレーンテキストの構成ファイルには、パスワードなどの機密データを格納しないでください。 Secret Manager ツールを使用すると、開発時にシークレットを格納できます。
  • 開発環境やテスト環境では運用シークレットを使用しないでください。
  • プロジェクトの外部にシークレットを指定してください。そうすれば、誤ってリソース コード リポジトリにコミットされることはありません。

既定では、ユーザー シークレットの構成ソースは、JSON 構成ソースの後に登録されます。 そのため、ユーザー シークレット キーは appsettings.jsonappsettings.{Environment}.json のキーよりも優先されます。

パスワードその他の機密データの格納については、次を参照してください:

Azure Key Vault では、ASP.NET Core アプリのアプリのシークレットが安全に保存されます。 詳細については、「ASP.NET Core の Azure Key Vault 構成プロバイダー」を参照してください。

プレフィックスが付いていない環境変数

プレフィックスが付いていない環境変数は、プレフィックス ASPNETCORE_ または DOTNET_ が付いたもの以外の環境変数です。 たとえば、ASP.NET Core Web アプリケーション テンプレートを使用すると、launchSettings.json"ASPNETCORE_ENVIRONMENT": "Development" が設定されます。 環境変数 ASPNETCORE_ および DOTNET_ の詳細については、次を参照してください。

既定の構成を使用すると、EnvironmentVariablesConfigurationProvider によって、appsettings.jsonappsettings.{Environment}.json、およびユーザー シークレットの読み取り後に、環境変数のキーと値のペアから構成が読み込まれます。 そのため、環境から読み取られたキー値によって、appsettings.jsonappsettings.{Environment}.json、およびユーザー シークレットから読み取られた値がオーバーライドされます。

: の区切り記号は、すべてのプラットフォームの環境変数階層キーには対応していません。 __(ダブルアンダースコア)は、

  • すべてのプラットフォームに対応しています。 たとえば、:: の区切り記号には対応していませんが、__ には対応しています。
  • 自動で : に置換されます。

次の set コマンドは:

  • Windows で 上記の例 の環境キーと値を設定します。
  • サンプル ダウンロードを使用する際に、設定をテストします。 dotnet run コマンドは、プロジェクト ディレクトリで実行する必要があります。
set MyKey="My key from Environment"
set Position__Title=Environment_Editor
set Position__Name=Environment_Rick
dotnet run

上記の環境設定は:

  • コマンド ウィンドウから起動されたプロセスでのみ設定可能です。
  • Visual Studio で起動されたブラウザーでは読み取れません。

次の setx コマンドで、Windows 上の環境キーと値を設定できます。 set とは異なり、setx 設定は保持されます。 /M は、システム環境で変数を設定します。 /M スイッチが使用されていない場合には、ユーザー環境変数が設定されます。

setx MyKey "My key from setx Environment" /M
setx Position__Title Environment_Editor /M
setx Position__Name Environment_Rick /M

上記のコマンドによって appsettings.jsonappsettings.{Environment}.json がオーバーライドされることをテストするには:

  • Visual Studio の場合:Visual Studio を終了して再起動します。
  • CLI の場合:新しいコマンド ウィンドウを起動し、dotnet run を入力します。

環境変数のプレフィックスを指定する文字列を指定して AddEnvironmentVariables を呼び出します:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_");

var app = builder.Build();

上のコードでは以下の操作が行われます。

  • builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_")既定の構成プロバイダーの後に追加されます。 構成プロバイダーの順序付けの例については、「JSON 構成プロバイダー」を参照してください。
  • MyCustomPrefix_ プレフィックスを使用して設定された環境変数は、既定の構成プロバイダーをオーバーライドします。 これには、プレフィックスのない環境変数が含まれます。

構成のキーと値のペアの読み取り時に、プレフィックスは削除されます。

次のコマンドは、カスタム プレフィックスをテストします:

set MyCustomPrefix_MyKey="My key with MyCustomPrefix_ Environment"
set MyCustomPrefix_Position__Title=Editor_with_customPrefix
set MyCustomPrefix_Position__Name=Environment_Rick_cp
dotnet run

既定の構成では、DOTNET_ASPNETCORE_ のプレフィックスが付いた環境変数とコマンド ライン引数を読み込みます。 DOTNET_ASPNETCORE_ のプレフィックスは ASP.NET Core によってホストとアプリの構成に使用されますが、ユーザーの構成には使用されません。 ホストとアプリの構成の詳細については、「.NET 汎用ホスト」を参照してください。

Azure App Service の、[設定] > [構成] ページで [新しいアプリケーション設定] を選択します。 Azure App Service アプリケーションの設定は:

  • 保存時に暗号化され、暗号化されたチャネルで送信されます。
  • 環境変数として公開されます。

詳細については、「Azure アプリ: Azure Portal を使用してアプリの構成をオーバーライドする」を参照してください。

Azure データベース接続文字列の詳細については、「接続文字列のプレフィックス」を参照してください。

環境変数の名前付け

環境変数名には、 appsettings.json ファイルの構造が反映されます。 階層内の各要素は、二重アンダースコア (推奨) またはコロンによって区切られます。 要素構造に配列が含まれている場合は、配列のインデックスをこのパスの追加の要素名として扱う必要があります。 次の appsettings.json ファイルと、環境変数として表されたその同等の値を考えてみましょう。

appsettings.json

{
    "SmtpServer": "smtp.example.com",
    "Logging": [
        {
            "Name": "ToEmail",
            "Level": "Critical",
            "Args": {
                "FromAddress": "MySystem@example.com",
                "ToAddress": "SRE@example.com"
            }
        },
        {
            "Name": "ToConsole",
            "Level": "Information"
        }
    ]
}

環境変数

setx SmtpServer smtp.example.com
setx Logging__0__Name ToEmail
setx Logging__0__Level Critical
setx Logging__0__Args__FromAddress MySystem@example.com
setx Logging__0__Args__ToAddress SRE@example.com
setx Logging__1__Name ToConsole
setx Logging__1__Level Information

生成された launchSettings.json に設定されている環境変数

launchSettings.json に設定されている環境変数で、システム環境に設定されているそれらがオーバーライドされます。 たとえば、ASP.NET Core Web テンプレートでは、エンドポイント構成を次のように設定する launchSettings.json ファイルが生成されます。

"applicationUrl": "https://localhost:5001;http://localhost:5000"

applicationUrl を構成すると ASPNETCORE_URLS 環境変数が設定され、環境で設定されている値がオーバーライドされます。

Linux で環境変数をエスケープする

Linux では、systemd で解析できるように URL 環境変数の値をエスケープする必要があります。 Linux ツール systemd-escape を使用すると、http:--localhost:5001 が生成されます

groot@terminus:~$ systemd-escape http://localhost:5001
http:--localhost:5001

環境変数を表示する

次のコードでは、アプリケーションの起動時に環境変数と値が表示されます。これは環境設定をデバッグするときに役立つことがあります。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

foreach (var c in builder.Configuration.AsEnumerable())
{
    Console.WriteLine(c.Key + " = " + c.Value);
}

コマンド ライン

既定の構成を使用して、CommandLineConfigurationProvider は、以下の構成ソースの後にコマンド ライン引数のキーと値のペアから構成を読み込みます:

  • appsettings.json および appsettings.{Environment}.json ファイル。
  • 開発環境でのアプリ シークレット
  • 環境変数。

既定では、コマンド ラインで設定された構成値は、他のすべての構成プロバイダーで設定された構成値をオーバーライドします。

コマンド ライン引数

次のコマンドは = を使用してキーと値を設定します:

dotnet run MyKey="Using =" Position:Title=Cmd Position:Name=Cmd_Rick

次のコマンドは / を使用してキーと値を設定します:

dotnet run /MyKey "Using /" /Position:Title=Cmd /Position:Name=Cmd_Rick

次のコマンドは -- を使用してキーと値を設定します:

dotnet run --MyKey "Using --" --Position:Title=Cmd --Position:Name=Cmd_Rick

キーの値:

  • = の後に続ける必要があります。または、値がスペースの後にある場合は、キーのプレフィックスが -- または / である必要があります。
  • = を使用する場合は必要ありません。 たとえば、MySetting= のようにします。

同じコマンド内では、= を使用するコマンド ライン引数のキーと値のペアを、スペースを使用するキーと値のペアと混在させないでください。

スイッチ マッピング

スイッチ マッピングでは、キー名の置換ロジックが許可されます。 AddCommandLine メソッドにスイッチ置換するディクショナリを提供します。

スイッチ マッピング ディクショナリが使用されている場合、そのディレクトリで、コマンドライン引数によって指定されたキーと一致するキーが確認されます。 ディクショナリ中にコマンド ライン キーが見つかった場合は、そのディクショナリの値が返され、キーと値のペアがアプリの構成に設定されます。 スイッチ マッピングは、単一のダッシュ (-) が前に付いたすべてのコマンドライン キーに必要です。

スイッチ マッピング ディクショナリ キーの規則:

  • スイッチは - または --で始める必要があります。
  • スイッチ マッピング ディクショナリに重複キーを含めることはできません。

スイッチ マッピング ディクショナリを使用するには、それを AddCommandLine の呼び出しに渡します:


var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var switchMappings = new Dictionary<string, string>()
         {
             { "-k1", "key1" },
             { "-k2", "key2" },
             { "--alt3", "key3" },
             { "--alt4", "key4" },
             { "--alt5", "key5" },
             { "--alt6", "key6" },
         };

builder.Configuration.AddCommandLine(args, switchMappings);

var app = builder.Build();

次のコマンドを実行して、キーの置換をテストします:

dotnet run -k1 value1 -k2 value2 --alt3=value2 /alt4=value3 --alt5 value5 /alt6 value6

次のコードは、置換されたキーのキー値を示しています:

public class Test3Model : PageModel
{
    private readonly IConfiguration Config;

    public Test3Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        return Content(
                $"Key1: '{Config["Key1"]}'\n" +
                $"Key2: '{Config["Key2"]}'\n" +
                $"Key3: '{Config["Key3"]}'\n" +
                $"Key4: '{Config["Key4"]}'\n" +
                $"Key5: '{Config["Key5"]}'\n" +
                $"Key6: '{Config["Key6"]}'");
    }
}

スイッチ マッピングを使用するアプリでは、CreateDefaultBuilder への呼び出しで引数を渡すことはできません。 CreateDefaultBuilder メソッドの AddCommandLine 呼び出しには、マップされたスイッチが含まれていないため、スイッチ マッピング ディクショナリを CreateDefaultBuilder に渡すことはできません。 解決策は、CreateDefaultBuilder に引数を渡す代わりに、ConfigurationBuilder メソッドの AddCommandLine メソッドに、引数とスイッチ マッピング ディクショナリの両方を処理させることです。

Visual Studio で環境とコマンド ライン引数を設定する

環境およびコマンド ラインの引数は、Visual Studio の起動プロファイル ダイアログから設定できます。

  • ソリューション エクスプローラーで、プロジェクトを右クリックして [プロパティ] を選択します。
  • [デバッグ] > [全般] タブの順に選択し、[Open debug launch profiles UI](デバッグ起動プロファイル UI を開く) を選択します。

階層的な構成データ

構成 API では、構成キーの区切り記号を使用して階層データをフラット化することにより、階層型の構成データの読み取りが行われます。

サンプル ダウンロードには、次の appsettings.json ファイルが含まれます。

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey": "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

サンプル ダウンロード の次のコードでは、構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

階層型の構成データを読み取る方法としては、オプション パターンを使用することをお勧めします。 詳細については、このドキュメント中の「階層型の構成データをバインドする」を参照してください。

GetSection メソッドと GetChildren メソッドを使用して、構成データ内のセクションとセクションの子を分離することができます。 これらのメソッドについては、後ほど「GetSection、GetChildren、Exists」で説明します。

構成キーと値

構成キー:

  • 構成キーでは、大文字と小文字は区別されません。 たとえば、ConnectionStringconnectionstring は同等のキーとして扱われます。
  • キーと値が複数の構成プロバイダーで設定されている場合は、最後に追加されたプロバイダーの値が使用されます。 詳細については、「既定の構成」を参照してください。
  • 階層キー
    • 構成 API 内では、すべてのプラットフォームでコロン (:) の区切りが機能します。
    • 環境変数内では、コロン区切りがすべてのプラットフォームでは機能しない場合があります。 ダブル アンダースコア (__) はすべてのプラットフォームでサポートされ、コロン : に自動で変換されます。
    • Azure Key Vault では、階層型のキーは区切り記号に -- を使用します。 シークレットがアプリの構成に読み込まれると、Azure Key Vault 構成プロバイダーによって --: に自動的に置き換えられます。
  • ConfigurationBinder は、構成キーで配列インデックスを使用して、オブジェクトに対する配列のバインドをサポートしています。 配列のバインドについては、「配列をクラスにバインドする」セクションで説明します。

構成値:

  • 構成値は文字列です。
  • Null 値を構成に格納したり、オブジェクトにバインドしたりすることはできません。

構成プロバイダー

ASP.NET Core アプリで使用できる構成プロバイダーを次の表に示します。

プロバイダー 以下から構成を提供します
Azure Key Vault 構成プロバイダー Azure Key Vault
Azure App Configuration プロバイダー Azure App Configuration
コマンド ライン構成プロバイダー コマンド ライン パラメーター
カスタム構成プロバイダー カスタム ソース
環境変数構成プロバイダー 環境変数
ファイル構成プロバイダー INI、JSON、および XML ファイル
ファイルごとのキーの構成プロバイダー ディレクトリ ファイル
メモリ構成プロバイダー メモリ内コレクション
ユーザー シークレット ユーザー プロファイル ディレクトリ内のファイル

構成ソースは、構成プロバイダーで指定された順序で読み取られます。 アプリで必要とされる、基になる構成ソースの優先順位に合わせるために、コード内で構成プロバイダーを並べ替えます。

一般的な一連の構成プロバイダーは次のとおりです。

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. ユーザー シークレット
  4. 環境変数構成プロバイダーを使用する環境変数。
  5. コマンドライン構成プロバイダーを使用するコマンドライン引数。

コマンド ライン引数が他のプロバイダーによって設定された構成をオーバーライドできるようにするには、コマンド ラインの構成プロバイダーを一連のプロバイダーの最後に配置するのが一般的です。

上記の一連のプロバイダーは、既定の構成で使用されます。

接続文字列のプレフィックス

構成 API には、4つの接続文字列環境変数に対する特別なプロセスルールがあります。 これらの接続文字列は、アプリ環境用の Azure 接続文字列の構成に含まれています。 表に示されたプレフィックスを持つ環境変数は、既定の構成 を使用するとき、または AddEnvironmentVariables にプレフィックスが指定されていない場合に、アプリに読み込まれます。

接続文字列のプレフィックス プロバイダー
CUSTOMCONNSTR_ カスタム プロバイダー
MYSQLCONNSTR_ MySQL
SQLAZURECONNSTR_ Azure SQL Database
SQLCONNSTR_ SQL Server

表に示す 4 つのプレフィックスのいずれかを使用して、環境変数が検出され構成に読み込まれた場合:

  • 環境変数のプレフィックスを削除し、構成キーのセクション (ConnectionStrings) を追加することによって、構成キーが作成されます。
  • データベースの接続プロバイダーを表す新しい構成のキーと値のペアが作成されます (示されたプロバイダーを含まない CUSTOMCONNSTR_ を除く)。
環境変数キー 変換された構成キー プロバイダーの構成エントリ
CUSTOMCONNSTR_{KEY} ConnectionStrings:{KEY} 構成エントリは作成されません。
MYSQLCONNSTR_{KEY} ConnectionStrings:{KEY} キー: ConnectionStrings:{KEY}_ProviderName:
値: MySql.Data.MySqlClient
SQLAZURECONNSTR_{KEY} ConnectionStrings:{KEY} キー: ConnectionStrings:{KEY}_ProviderName:
値: System.Data.SqlClient
SQLCONNSTR_{KEY} ConnectionStrings:{KEY} キー: ConnectionStrings:{KEY}_ProviderName:
値: System.Data.SqlClient

ファイル構成プロバイダー

FileConfigurationProvider は、ファイル システムから構成を読み込むための基本クラスです。 以下の構成プロバイダーは FileConfigurationProvider から派生したものです:

INI 構成プロバイダー

IniConfigurationProvider では、実行時に INI ファイルのキーと値のペアから構成が読み込まれます。

次のコードは、すべての構成プロバイダーをクリアし、いくつかの構成プロバイダーを追加します:

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();

    var env = hostingContext.HostingEnvironment;

    config.AddIniFile("MyIniConfig.ini", optional: true, reloadOnChange: true)
          .AddIniFile($"MyIniConfig.{env.EnvironmentName}.ini",
                         optional: true, reloadOnChange: true);

    config.AddEnvironmentVariables();

    if (args != null)
    {
        config.AddCommandLine(args);
    }
});

builder.Services.AddRazorPages();

var app = builder.Build();

上記のコードでは、MyIniConfig.ini および MyIniConfig.{Environment}.ini ファイルの設定は、以下の設定によってオーバーライドされます:

サンプル ダウンロードには、次の MyIniConfig.ini ファイルが含まれます。

MyKey="MyIniConfig.ini Value"

[Position]
Title="My INI Config title"
Name="My INI Config name"

[Logging:LogLevel]
Default=Information
Microsoft=Warning

サンプル ダウンロード の次のコードでは、上記の構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

JSON 構成プロバイダー

JsonConfigurationProvider では、JSON ファイルのキーと値のペアから構成が読み込みまれます。

オーバーロードでは、次の指定ができます:

  • ファイルを省略可能かどうか。
  • ファイルが変更された場合に構成を再度読み込むかどうか。

次のコードがあるとします。

using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile("MyConfig.json",
                       optional: true,
                       reloadOnChange: true);
});

builder.Services.AddRazorPages();

var app = builder.Build();

上記のコードでは次の操作が行われます。

  • 次のオプションを使用して、MyConfig.json ファイルを読み込むように JSON 構成プロバイダーを構成します:
    • optional: true:ファイルは省略可能です。
    • reloadOnChange: true は、次のとおりです。変更が保存されると、ファイルが再読み込みされます。
  • MyConfig.json ファイルの前に既定の構成プロバイダーを読み取ります。 環境変数構成プロバイダー および コマンド ライン構成プロバイダーを含む、既定の構成プロバイダーでの MyConfig.json ファイルのオーバーライドの設定。

通常は、環境変数構成プロバイダーおよびコマンドライン構成プロバイダーで設定されている値をオーバーライドするカスタム JSON ファイルは必要 "ありません"。

XML 構成プロバイダー

XmlConfigurationProvider では、実行時に XML ファイルのキーと値のペアから構成が読み込まれます。

次のコードは、すべての構成プロバイダーをクリアし、いくつかの構成プロバイダーを追加します:

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();

    var env = hostingContext.HostingEnvironment;

    config.AddXmlFile("MyXMLFile.xml", optional: true, reloadOnChange: true)
          .AddXmlFile($"MyXMLFile.{env.EnvironmentName}.xml",
                         optional: true, reloadOnChange: true);

    config.AddEnvironmentVariables();

    if (args != null)
    {
        config.AddCommandLine(args);
    }
});

builder.Services.AddRazorPages();

var app = builder.Build();

上記のコードでは、MyXMLFile.xml および MyXMLFile.{Environment}.xml ファイルの設定は、以下の設定によってオーバーライドされます:

サンプル ダウンロードには、次の MyXMLFile.xml ファイルが含まれます。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <MyKey>MyXMLFile Value</MyKey>
  <Position>
    <Title>Title from  MyXMLFile</Title>
    <Name>Name from MyXMLFile</Name>
  </Position>
  <Logging>
    <LogLevel>
      <Default>Information</Default>
      <Microsoft>Warning</Microsoft>
    </LogLevel>
  </Logging>
</configuration>

サンプル ダウンロード の次のコードでは、上記の構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

同じ要素名を使用する要素の繰り返しは、要素を区別するために name 属性を使用する場合に機能します。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section name="section0">
    <key name="key0">value 00</key>
    <key name="key1">value 01</key>
  </section>
  <section name="section1">
    <key name="key0">value 10</key>
    <key name="key1">value 11</key>
  </section>
</configuration>

以下のコードでは、前の構成ファイルを読み取って、キーと値を表示します:

public class IndexModel : PageModel
{
    private readonly IConfiguration Configuration;

    public IndexModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var key00 = "section:section0:key:key0";
        var key01 = "section:section0:key:key1";
        var key10 = "section:section1:key:key0";
        var key11 = "section:section1:key:key1";

        var val00 = Configuration[key00];
        var val01 = Configuration[key01];
        var val10 = Configuration[key10];
        var val11 = Configuration[key11];

        return Content($"{key00} value: {val00} \n" +
                       $"{key01} value: {val01} \n" +
                       $"{key10} value: {val10} \n" +
                       $"{key10} value: {val11} \n"
                       );
    }
}

値を指定するために属性を使用できます。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <key attribute="value" />
  <section>
    <key attribute="value" />
  </section>
</configuration>

前の構成ファイルでは、value を使用して次のキーが読み込まれます。

  • key:attribute
  • section:key:attribute

ファイルごとのキーの構成プロバイダー

KeyPerFileConfigurationProvider では、構成のキーと値のペアとしてディレクトリのファイルが使用されます。 キーはファイル名です。 値にはファイルのコンテンツが含まれます。 ファイルごとのキーの構成プロバイダーは、Docker ホスティングのシナリオで使用されます。

ファイルごとのキーの構成をアクティブにするには、ConfigurationBuilder のインスタンスの AddKeyPerFile 拡張メソッドを呼び出します。 ファイルに対する directoryPath は、絶対パスである必要があります。

オーバーロードによって次のものを指定できます。

  • ソースを構成する Action<KeyPerFileConfigurationSource> デリゲート。
  • ディレクトリを省略可能かどうか、またディレクトリへのパス。

アンダースコア 2 つ (__) は、ファイル名で構成キーの区切り記号として使用されます。 たとえば、ファイル名 Logging__LogLevel__System では、構成キー Logging:LogLevel:System が生成されます。

ホストをビルドするときに ConfigureAppConfiguration を呼び出して、アプリの構成を指定します。

.ConfigureAppConfiguration((hostingContext, config) =>
{
    var path = Path.Combine(
        Directory.GetCurrentDirectory(), "path/to/files");
    config.AddKeyPerFile(directoryPath: path, optional: true);
})

メモリ構成プロバイダー

MemoryConfigurationProvider では、構成のキーと値のペアとして、メモリ内コレクションが使用されます。

次のコードでは、構成システムにメモリコ レクションが追加されています:

var builder = WebApplication.CreateBuilder(args);

var Dict = new Dictionary<string, string>
        {
           {"MyKey", "Dictionary MyKey Value"},
           {"Position:Title", "Dictionary_Title"},
           {"Position:Name", "Dictionary_Name" },
           {"Logging:LogLevel:Default", "Warning"}
        };

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();

    config.AddInMemoryCollection(Dict);

    config.AddEnvironmentVariables();

    if (args != null)
    {
        config.AddCommandLine(args);
    }
});

builder.Services.AddRazorPages();

var app = builder.Build();

サンプルのダウンロード の以下のコードでは、上記の構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

上記のコードでは、既定の構成プロバイダーの後に config.AddInMemoryCollection(Dict) が追加されています。 構成プロバイダーの順序付けの例については、「JSON 構成プロバイダー」を参照してください。

MemoryConfigurationProvider を使用した別の例については、配列をバインドを参照してください。

Kestrel エンドポイント構成

Kestrel 固有のエンドポイント構成によって、すべてのサーバー間のエンドポイント構成がオーバーライドされます。 サーバー間のエンドポイント構成には、次のものがあります。

ASP.NET Core Web アプリで使用される次の appsettings.json ファイルについて考えてみましょう。

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:9999"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
} 

前述の強調表示されているマークアップが ASP.NET Core Web アプリで使用され、"かつ" 次のサーバー間エンドポイント構成を使用してコマンド ラインでアプリが起動される場合:

dotnet run --urls="https://localhost:7777"

Kestrel は、https://localhost:7777 ではなく、 appsettings.json ファイルで Kestrel 専用に構成されたエンドポイント (https://localhost:9999) にバインドされます。

環境変数として構成された Kestrel 固有のエンドポイントを考えてみます。

set Kestrel__Endpoints__Https__Url=https://localhost:8888

上記の環境変数では、Https が Kestrel 固有のエンドポイントの名前です。 前の appsettings.json ファイルでも、Https という名前の Kestrel 固有のエンドポイントが定義されています。 既定で、環境変数構成プロバイダーを使用している環境変数は appsettings.{Environment}.json の後に読み取られます。したがって、上記の環境変数は Https エンドポイント用に使用されます。

GetValue

ConfigurationBinder.GetValue 指定したキーを使用して、構成から単一の値を抽出し、それを指定した型に変換します:

public class TestNumModel : PageModel
{
    private readonly IConfiguration Configuration;

    public TestNumModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var number = Configuration.GetValue<int>("NumberKey", 99);
        return Content($"{number}");
    }
}

上記のコードでは、NumberKey が構成中に見つからない場合には 99 の既定値が使用されます。

GetSection、GetChildren、Exists

以下の例では、次の MySubsection.json ファイルについて考えます。

{
  "section0": {
    "key0": "value00",
    "key1": "value01"
  },
  "section1": {
    "key0": "value10",
    "key1": "value11"
  },
  "section2": {
    "subsection0": {
      "key0": "value200",
      "key1": "value201"
    },
    "subsection1": {
      "key0": "value210",
      "key1": "value211"
    }
  }
}

以下のコードでは、MySubsection.jsonを構成プロバイダーに追加します:

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile("MySubsection.json",
                       optional: true,
                       reloadOnChange: true);
});

builder.Services.AddRazorPages();

var app = builder.Build();

GetSection

IConfiguration.GetSection は、指定されたサブセクションのキーを持つ構成サブセクションを返します。

次のコードは、section1 の値を返します:

public class TestSectionModel : PageModel
{
    private readonly IConfiguration Config;

    public TestSectionModel(IConfiguration configuration)
    {
        Config = configuration.GetSection("section1");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section1:key0: '{Config["key0"]}'\n" +
                $"section1:key1: '{Config["key1"]}'");
    }
}

次のコードは、section2:subsection0 の値を返します:

public class TestSection2Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection2Model(IConfiguration configuration)
    {
        Config = configuration.GetSection("section2:subsection0");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                $"section2:subsection0:key1:'{Config["key1"]}'");
    }
}

GetSectionnull を返すことはありません。 一致するセクションが見つからない場合は、空の IConfigurationSection が返されます。

GetSection で一致するセクションが返されると、Value は設定されません。 KeyPath はセクションが存在する場合に返されます。

GetChildren と Exists

次のコードは、IConfiguration.GetChildren を呼び出し、section2:subsection0 の値を返します:

public class TestSection4Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection4Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        string s = "";
        var selection = Config.GetSection("section2");
        if (!selection.Exists())
        {
            throw new Exception("section2 does not exist.");
        }
        var children = selection.GetChildren();

        foreach (var subSection in children)
        {
            int i = 0;
            var key1 = subSection.Key + ":key" + i++.ToString();
            var key2 = subSection.Key + ":key" + i.ToString();
            s += key1 + " value: " + selection[key1] + "\n";
            s += key2 + " value: " + selection[key2] + "\n";
        }
        return Content(s);
    }
}

上記のコードは、ConfigurationExtensions.Exists を呼び出し、セクションが存在することを確認します:

配列をバインドする

ConfigurationBinder.Bind は、構成キーで配列インデックスを使用して、オブジェクトに対する配列のバインドをサポートしています。 数値のキー セグメントを公開する配列形式は、すべて POCO クラスの配列にバインドできます。

サンプル ダウンロードMyArray.json について考えます:

{
  "array": {
    "entries": {
      "0": "value00",
      "1": "value10",
      "2": "value20",
      "4": "value40",
      "5": "value50"
    }
  }
}

次のコードでは、MyArray.json を構成プロバイダーに追加します:

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile("MyArray.json",
                        optional: true,
                        reloadOnChange: true); ;
});

builder.Services.AddRazorPages();

var app = builder.Build();

次のコードでは、構成を読み取り、値を表示します:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample? _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
       _array = Config.GetSection("array").Get<ArrayExample>();
        if (_array == null)
        {
            throw new ArgumentNullException(nameof(_array));
        }
        string s = String.Empty;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}
public class ArrayExample
{
    public string[]? Entries { get; set; } 
}

上記のコードは、次の出力を返します:

Index: 0  Value: value00
Index: 1  Value: value10
Index: 2  Value: value20
Index: 3  Value: value40
Index: 4  Value: value50

上記の出力では、インデックス 3 の値が value40 になります。これは MyArray.json"4": "value40", に対応しています。 このバインドされた配列インデックスは連続的であり、構成キーインデックスにバインドされていません。 構成バインダーは、バインドされたオブジェクトに null 値をバインドしたり、null エントリを作成したりはできません。

カスタム構成プロバイダー

サンプル アプリでは、Entity Framework (EF) を使用してデータベースから構成のキーと値のペアを読み取る、基本的な構成プロバイダーを作成する方法を示します。

プロバイダーの特徴は次のとおりです。

  • EF のメモリ内データベースは、デモンストレーションのために使用されます。 接続文字列を必要とするデータベースを使用するには、第 2 の ConfigurationBuilder を実装して、別の構成プロバイダーからの接続文字列を指定します。
  • プロバイダーは、起動時に、構成にデータベース テーブルを読み取ります。 プロバイダーは、キー単位でデータベースを照会しません。
  • 変更時に再度読み込む機能は実装されていません。このため、アプリの起動後にデータベースを更新しても、アプリの構成には影響がありません。

データベースに構成値を格納するための EFConfigurationValue エンティティを定義します。

Models/EFConfigurationValue.cs:

public class EFConfigurationValue
{
    public string Id { get; set; } = String.Empty;
    public string Value { get; set; } = String.Empty;
}

構成した値を格納し、その値にアクセスするための EFConfigurationContext を追加します。

EFConfigurationProvider/EFConfigurationContext.cs:

public class EFConfigurationContext : DbContext
{
    public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
    {
    }

    public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
}

IConfigurationSource を実装するクラスを作成します。

EFConfigurationProvider/EFConfigurationSource.cs:

public class EFConfigurationSource : IConfigurationSource
{
    private readonly Action<DbContextOptionsBuilder> _optionsAction;

    public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;

    public IConfigurationProvider Build(IConfigurationBuilder builder) => new EFConfigurationProvider(_optionsAction);
}

ConfigurationProvider から継承して、カスタム構成プロバイダーを作成します。 データベースが空だった場合、構成プロバイダーはこれを初期化します。 構成キーでは大文字と小文字が区別されないため、データベースの初期化に使用されるディクショナリは、大文字と小文字を区別しない比較子 (StringComparer.OrdinalIgnoreCase) を使用して作成されます。

EFConfigurationProvider/EFConfigurationProvider.cs:

public class EFConfigurationProvider : ConfigurationProvider
{
    public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<EFConfigurationContext>();

        OptionsAction(builder);

        using (var dbContext = new EFConfigurationContext(builder.Options))
        {
            if (dbContext == null || dbContext.Values == null)
            {
                throw new Exception("Null DB context");
            }
            dbContext.Database.EnsureCreated();

            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private static IDictionary<string, string> CreateAndSaveDefaultValues(
        EFConfigurationContext dbContext)
    {
        // Quotes (c)2005 Universal Pictures: Serenity
        // https://www.uphe.com/movies/serenity-2005
        var configValues =
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                    { "quote1", "I aim to misbehave." },
                    { "quote2", "I swallowed a bug." },
                    { "quote3", "You can't stop the signal, Mal." }
            };

        if (dbContext == null || dbContext.Values == null)
        {
            throw new Exception("Null DB context");
        }

        dbContext.Values.AddRange(configValues
            .Select(kvp => new EFConfigurationValue
            {
                Id = kvp.Key,
                Value = kvp.Value
            })
            .ToArray());

        dbContext.SaveChanges();

        return configValues;
    }
}

AddEFConfiguration 拡張メソッドを使用すると、ConfigurationBuilder に構成ソースを追加できます。

Extensions/EntityFrameworkExtensions.cs:

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEFConfiguration(
               this IConfigurationBuilder builder,
               Action<DbContextOptionsBuilder> optionsAction)
    {
        return builder.Add(new EFConfigurationSource(optionsAction));
    }
}

次のコードでは、Program.cs でカスタムの EFConfigurationProvider を使用する方法を示します。

//using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddEFConfiguration(
    opt => opt.UseInMemoryDatabase("InMemoryDb"));

var app = builder.Build();

app.Run();

依存関係の挿入 (DI) を使用したアクセス構成

IConfiguration サービスを解決することで、依存関係の挿入 (DI) を使用してサービスに構成を挿入できます。

public class Service
{
    private readonly IConfiguration _config;

    public Service(IConfiguration config) =>
        _config = config;

    public void DoSomething()
    {
        var configSettingValue = _config["ConfigSetting"];

        // ...
    }
}

IConfiguration を使用して値にアクセスする方法については、この記事の「GetValue」と「GetSection、GetChildren、Exists」を参照してください。

Razor ページの構成にアクセスする

次のコードでは Razor ページの構成データが表示されます:

@page
@model Test5Model
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

次のコードでは、MyOptionsConfigure でサービスコンテナーに追加され、構成にバインドされます:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(
    builder.Configuration.GetSection("MyOptions"));

var app = builder.Build();

次のマークアップは、@injectRazor ディレクティブを使用して、オプションの値を解決して表示します。

@page
@model SampleApp.Pages.Test3Model
@using Microsoft.Extensions.Options
@using SampleApp.Models
@inject IOptions<MyOptions> optionsAccessor


<p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
<p><b>Option2:</b> @optionsAccessor.Value.Option2</p>

MVC ビューファイルの構成へのアクセス

次のコードでは、MVC ビューの構成データが表示されます:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

Program.cs でのアクセス構成

次のコードは、Program.cs ファイル内の構成にアクセスします。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

var key1 = app.Configuration.GetValue<int>("KeyOne");
var key2 = app.Configuration.GetValue<bool>("KeyTwo");

app.Logger.LogInformation($"KeyOne = {key1}");
app.Logger.LogInformation($"KeyTwo = {key2}");

app.Run();

デリゲートでオプションを構成する

デリゲートで構成されたオプションは、構成プロバイダーで設定された値をオーバーライドします。

次のコードでは、IConfigureOptions<TOptions> サービスがサービス コンテナーに追加されます。 デリゲートを利用して MyOptions の値が構成されます。

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "Value configured in delegate";
    myOptions.Option2 = 500;
});

var app = builder.Build();

このコードには、次のオプションの値が表示されます。

[!code-csharp[~/fundamentals/configuration/optionssamples/6.x/OptionsSample/Pages/Test2.cshtml.cs?name=snippet)]

先の例では、値 Option1Option2appsettings.json で指定されてから、構成されているデリゲートによりオーバーライドされます。

ホストとアプリの構成

アプリを構成して起動する前に、"ホスト" を構成して起動します。 ホストはアプリの起動と有効期間の管理を担当します。 アプリとホストは、両方ともこのトピックで説明する構成プロバイダーを使用して構成します。 ホスト構成のキーと値のペアも、アプリの構成に含まれます。 ホストをビルドするときの構成プロバイダーの使用方法、およびホストの構成に対する構成ソースの影響について詳しくは、ASP.NET Core の基礎の概要に関する記事を参照してください。

既定のホスト構成

Web ホストを使用する場合の既定の構成の詳細については、このトピックの ASP.NET Core 2.2 バージョンを参照してください。

  • ホストの構成は、次から提供されます。
  • Web ホストの既定の構成が確立されます (ConfigureWebHostDefaults)。
    • Kestrel は Web サーバーとして使用され、アプリの構成プロバイダーを使用して構成されます。
    • Host Filtering Middleware を追加します。
    • ASPNETCORE_FORWARDEDHEADERS_ENABLED 環境変数が true に設定されている場合は、Forwarded Headers Middleware を追加します。
    • IIS 統合を有効にします。

その他の構成

このトピックは、"アプリの構成" のみに関連しています。 ASP.NET Core アプリの実行とホストに関するその他の側面は、このトピックでは扱わない構成ファイルを使って構成されます。

launchSettings.json に設定されている環境変数で、システム環境に設定されているそれらがオーバーライドされます。

以前のバージョンの ASP.NET からアプリの構成を移行する方法について詳しくは、「ASP.NET から ASP.NET Core への移行」を参照してください。

外部アセンブリから構成を追加する

IHostingStartup の実装により、アプリの Startup クラスの外部にある外部アセンブリから、起動時に拡張機能をアプリに追加できるようになります。 詳細については、「ASP.NET Core でホスティング スタートアップ アセンブリを使用する」を参照してください。

その他の技術情報

ASP.NET Core のアプリケーション構成は、1 つまたは複数の構成プロバイダーを使用して実行されます。 構成プロバイダーは、以下のようなさまざまな構成ソースを使用して、キーと値のペアから構成データを読み取ります:

  • appsettings.json などの設定ファイル
  • 環境変数
  • Azure Key Vault
  • Azure App Configuration
  • コマンド ライン引数
  • インストール済みまたは作成済みのカスタム プロバイダー
  • ディレクトリ ファイル
  • メモリ内 .NET オブジェクト

この記事では ASP.NET Core の構成について説明します。 コンソール アプリでの構成の使用方法について詳しくは、.NET 構成に関する記事をご覧ください。

アプリケーションとホストの構成

ASP.NET Core アプリはホストを構成して起動します。 ホストはアプリの起動と有効期間の管理を担当します。 ASP.NET Core テンプレートを使用すると、ホストを WebApplicationBuilder 含むテンプレートを作成できます。 一部の構成についてはホストおよびアプリケーション構成プロバイダーの両方で行うことができますが、一般には、ホストに必要な構成のみをホスト構成で行う必要があります。

アプリケーションの構成は最も優先度が高く、次のセクションで詳しく説明します。 ホスト構成 はアプリケーション構成に従っています。この記事で説明します。

既定のアプリケーション構成ソース

dotnet new または Visual Studio で作成された ASP.NET Core の web アプリが、次のコードを生成します:

var builder = WebApplication.CreateBuilder(args);

WebApplication.CreateBuilder は、事前に構成された既定値を使用して WebApplicationBuilder クラスの新しいインスタンスを初期化します。 WebApplicationBuilder (builder) を初期化すると、優先度の高い方から低い方へ、次の順序でアプリの既定の構成が提供されます。

  1. コマンドライン構成プロバイダーを使用するコマンドライン引数。
  2. 接頭辞なしの環境変数構成プロバイダーを使用した接頭辞なしの環境変数。
  3. 環境でアプリが実行される場合に使用されるユーザー シークレット
  4. JSON 構成プロバイダーを使用する appsettings.{Environment}.json。 たとえば、appsettings.Production.jsonappsettings.Development.json です。
  5. JSON 構成プロバイダーを使用する appsettings.json
  6. 次のセクションで説明するホスト構成へのフォールバック。

既定のホスト構成ソース

次の一覧には、優先度が最も高いものから最も低いものまで、既定のホスト構成ソースが含まれています。

  1. 環境変数構成プロバイダーを使用する、プレフィックス ASPNETCORE_ が付いた環境変数。
  2. コマンドライン構成プロバイダーを使用するコマンドライン引数。
  3. 環境変数構成プロバイダーを使用する、プレフィックス DOTNET_ が付いた環境変数。

ホストとアプリケーションの構成で構成値を設定する場合は、アプリケーション構成を使用します。

ホスト構成でプレフィックス ASPNETCORE_ が付いた環境変数がコマンドライン引数よりも優先される理由の説明については、この GitHub コメントの説明を参照してください。

ホスト変数

次の変数は、ホスト ビルダーを初期化するときに早期にロックされ、アプリケーション構成の影響を受けることはありません。

その他のホスト設定はすべて、ホスト構成からではなくアプリケーション構成から読み取られます。

URLS は、ブートストラップ設定ではない多くの一般的なホスト設定の 1 つです。 前の一覧にない他のすべてのホスト設定と同様に、URLS はアプリケーション構成から後で読み取られます。ホスト構成はアプリケーション構成のフォールバックであるため、ホスト構成を使用して URLS を設定できますが、appsettings.json のようにアプリケーション構成内の任意の構成ソースによってオーバーライドされます。

詳細については、「コンテンツ ルート、アプリ名、環境の変更」および「環境変数またはコマンド ラインを使用したコンテンツ ルート、アプリ名、環境の変更、アプリ名、環境の変更」を参照してください。

この記事の残りのセクションでは、アプリケーションの構成を参照してください。

アプリケーション構成プロバイダー

以下のコードでは、追加した順に、有効な構成プロバイダーが表示されます:

public class Index2Model : PageModel
{
    private IConfigurationRoot ConfigRoot;

    public Index2Model(IConfiguration configRoot)
    {
        ConfigRoot = (IConfigurationRoot)configRoot;
    }

    public ContentResult OnGet()
    {           
        string str = "";
        foreach (var provider in ConfigRoot.Providers.ToList())
        {
            str += provider.ToString() + "\n";
        }

        return Content(str);
    }
}

上記の優先度が最も高い既定の構成ソースから最も低い既定の構成ソースまでの一覧では、テンプレートで生成されたアプリケーションに追加される順序とは逆の順序でプロバイダーを示しています。 たとえば、JSON 構成プロバイダーは、コマンドライン構成プロバイダーの前に追加されます。

後から追加された構成プロバイダーは優先度がより高く、それによって、それ以前のキー設定はオーバーライドされます。 たとえば、MyKeyappsettings.json と環境の両方で設定されている場合、環境の値が使用されます。 既定の構成プロバイダーを使用すると、コマンドライン構成プロバイダーによって他のすべてのプロバイダーがオーバーライドされます。

CreateBuilder の詳細については、既定のビルダー設定を参照してください。

appsettings.json

次の appsettings.json ファイルを考えてみます。

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey": "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

サンプル ダウンロード の次のコードでは、上記の構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

既定の JsonConfigurationProvider は、以下の順序で構成を読み込みます:

  1. appsettings.json
  2. appsettings.{Environment}.json: appsettings.Production.json または appsettings.Development.json ファイルなど。 ファイルの環境バージョンは、IHostingEnvironment.EnvironmentNameに基づいて読み込まれます。 詳細については、「ASP.NET Core で複数の環境を使用する」を参照してください。

appsettings.{Environment}.json 値によって appsettings.json 内のキーがオーバーライドされます。 たとえば、既定では次のようになります:

  • 開発中は、appsettings.json で見つかった値は appsettings.Development.json 構成によって上書きされます。
  • 運用環境では、appsettings.json で見つかった値は appsettings.Production.json 構成によって上書きされます。 たとえば、Azure にアプリをデプロイする場合。

構成値を保証する必要がある場合は、「GetValue」を参照してください。 前の例では文字列が読み取られるだけで、既定値はサポートされていません。

既定の構成を利用する場合、reloadOnChange: trueappsettings.json ファイルと appsettings.{Environment}.json ファイルを有効にすることができます。 アプリの開始 "" に appsettings.json ファイルと appsettings.{Environment}.json ファイルに加えられた変更は、JSON 構成プロバイダーによって読み取られます。

オプションパターンを使用して、階層型の構成データをバインドします

関連する構成値を読み取る方法としては、オプション パターンを使用することをお勧めします。 たとえば、以下の構成値を読み取るには、次のようにします:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

次の PositionOptions クラスを作成します:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; } = String.Empty;
    public string Name { get; set; } = String.Empty;
}

オプション クラス:

  • パラメーターのないパブリック コンストラクターを持った非抽象でなければなりません。
  • 型のパブリックな読み取り/書き込みプロパティは、すべてバインドされます。
  • フィールドはバインド "されません"。 上のコード Position はバインドされません。 Position フィールドは、クラスを構成プロバイダーにバインドするときに、アプリで文字列 "Position" をハードコーディングする必要をなくすために使用されます。

コード例を次に示します。

  • ConfigurationBinder.Bind を呼び出して、 クラスを Position セクションにバインドします。
  • Position 構成データを表示します。
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

上記のコードでは、アプリが開始された後の JSON 構成ファイルへの変更は既定で読み取られます。

ConfigurationBinder.Get<T> 指定された型をバインドして返します。 ConfigurationBinder.Get<T>ConfigurationBinder.Bind を使用するよりも便利な場合があります。 次のコードは、PositionOptions クラスで ConfigurationBinder.Get<T> を使用する方法を示しています:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions? positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

上記のコードでは、アプリが開始された後の JSON 構成ファイルへの変更は既定で読み取られます。

"オプション パターン" を使用するときのもう 1 つの方法は、Position セクションをバインドし、それを依存関係挿入サービス コンテナーに追加することです。 次のコードでは、PositionOptionsConfigure でサービスコンテナーに追加され、構成にバインドされます:

using ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));

var app = builder.Build();

下記のコードは、上記のコードを使用して位置オプションを読み取ります:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

上のコードでは、アプリが開始された後の JSON 構成ファイルへの変更は読み取られ "ません"。 アプリの開始後に変更を読み取るには、IOptionsSnapshot を使用します。

既定の構成を利用する場合、reloadOnChange: trueappsettings.json ファイルと appsettings.{Environment}.json ファイルを有効にすることができます。 アプリの開始 "" に appsettings.json ファイルと appsettings.{Environment}.json ファイルに加えられた変更は、JSON 構成プロバイダーによって読み取られます。

追加の JSON 構成ファイルを追加する方法の詳細については、このドキュメント中の「JSON 構成プロバイダー」を参照してください。

サービス コレクションの結合

サービスを登録し、オプションを構成する以下について考えてみましょう。

using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(
    builder.Configuration.GetSection(ColorOptions.Color));

builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();

var app = builder.Build();

関連する登録グループは、サービスを登録するための拡張メソッドに移動できます。 たとえば、構成サービスは次のクラスに追加されます。

using ConfigSample.Options;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class MyConfigServiceCollectionExtensions
    {
        public static IServiceCollection AddConfig(
             this IServiceCollection services, IConfiguration config)
        {
            services.Configure<PositionOptions>(
                config.GetSection(PositionOptions.Position));
            services.Configure<ColorOptions>(
                config.GetSection(ColorOptions.Color));

            return services;
        }

        public static IServiceCollection AddMyDependencyGroup(
             this IServiceCollection services)
        {
            services.AddScoped<IMyDependency, MyDependency>();
            services.AddScoped<IMyDependency2, MyDependency2>();

            return services;
        }
    }
}

残りのサービスは、同様のクラスに登録されます。 次のコードでは、新しい拡張メソッドを使用してサービスを登録します。

using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddConfig(builder.Configuration)
    .AddMyDependencyGroup();

builder.Services.AddRazorPages();

var app = builder.Build();

注:services.Add{GROUP_NAME} 拡張メソッドは、サービスを追加、場合によっては構成します。 たとえば、AddControllersWithViews ではビューを持つ MVC コントローラーで必要なサービスが追加され、AddRazorPages では Razor Pages で必要なサービスが追加されます。

セキュリティとユーザー シークレット

構成データのガイドライン:

  • 構成プロバイダーのコードやプレーンテキストの構成ファイルには、パスワードなどの機密データを格納しないでください。 Secret Manager ツールを使用すると、開発時にシークレットを格納できます。
  • 開発環境やテスト環境では運用シークレットを使用しないでください。
  • プロジェクトの外部にシークレットを指定してください。そうすれば、誤ってリソース コード リポジトリにコミットされることはありません。

既定では、ユーザー シークレットの構成ソースは、JSON 構成ソースの後に登録されます。 そのため、ユーザー シークレット キーは appsettings.jsonappsettings.{Environment}.json のキーよりも優先されます。

パスワードその他の機密データの格納については、次を参照してください:

Azure Key Vault では、ASP.NET Core アプリのアプリのシークレットが安全に保存されます。 詳細については、「ASP.NET Core の Azure Key Vault 構成プロバイダー」を参照してください。

プレフィックスが付いていない環境変数

プレフィックスが付いていない環境変数は、プレフィックス ASPNETCORE_ または DOTNET_ が付いたもの以外の環境変数です。 たとえば、ASP.NET Core Web アプリケーション テンプレートを使用すると、launchSettings.json"ASPNETCORE_ENVIRONMENT": "Development" が設定されます。 環境変数 ASPNETCORE_ および DOTNET_ の詳細については、次を参照してください。

既定の構成を使用すると、EnvironmentVariablesConfigurationProvider によって、appsettings.jsonappsettings.{Environment}.json、およびユーザー シークレットの読み取り後に、環境変数のキーと値のペアから構成が読み込まれます。 そのため、環境から読み取られたキー値によって、appsettings.jsonappsettings.{Environment}.json、およびユーザー シークレットから読み取られた値がオーバーライドされます。

: の区切り記号は、すべてのプラットフォームの環境変数階層キーには対応していません。 __(ダブルアンダースコア)は、

  • すべてのプラットフォームに対応しています。 たとえば、:: の区切り記号には対応していませんが、__ には対応しています。
  • 自動で : に置換されます。

次の set コマンドは:

  • Windows で 上記の例 の環境キーと値を設定します。
  • サンプル ダウンロードを使用する際に、設定をテストします。 dotnet run コマンドは、プロジェクト ディレクトリで実行する必要があります。
set MyKey="My key from Environment"
set Position__Title=Environment_Editor
set Position__Name=Environment_Rick
dotnet run

上記の環境設定は:

  • コマンド ウィンドウから起動されたプロセスでのみ設定可能です。
  • Visual Studio で起動されたブラウザーでは読み取れません。

次の setx コマンドで、Windows 上の環境キーと値を設定できます。 set とは異なり、setx 設定は保持されます。 /M は、システム環境で変数を設定します。 /M スイッチが使用されていない場合には、ユーザー環境変数が設定されます。

setx MyKey "My key from setx Environment" /M
setx Position__Title Environment_Editor /M
setx Position__Name Environment_Rick /M

上記のコマンドによって appsettings.jsonappsettings.{Environment}.json がオーバーライドされることをテストするには:

  • Visual Studio の場合:Visual Studio を終了して再起動します。
  • CLI の場合:新しいコマンド ウィンドウを起動し、dotnet run を入力します。

環境変数のプレフィックスを指定する文字列を指定して AddEnvironmentVariables を呼び出します:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_");

var app = builder.Build();

上のコードでは以下の操作が行われます。

  • builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_")既定の構成プロバイダーの後に追加されます。 構成プロバイダーの順序付けの例については、「JSON 構成プロバイダー」を参照してください。
  • MyCustomPrefix_ プレフィックスを使用して設定された環境変数は、既定の構成プロバイダーをオーバーライドします。 これには、プレフィックスのない環境変数が含まれます。

構成のキーと値のペアの読み取り時に、プレフィックスは削除されます。

次のコマンドは、カスタム プレフィックスをテストします:

set MyCustomPrefix_MyKey="My key with MyCustomPrefix_ Environment"
set MyCustomPrefix_Position__Title=Editor_with_customPrefix
set MyCustomPrefix_Position__Name=Environment_Rick_cp
dotnet run

既定の構成では、DOTNET_ASPNETCORE_ のプレフィックスが付いた環境変数とコマンド ライン引数を読み込みます。 DOTNET_ASPNETCORE_ のプレフィックスは ASP.NET Core によってホストとアプリの構成に使用されますが、ユーザーの構成には使用されません。 ホストとアプリの構成の詳細については、「.NET 汎用ホスト」を参照してください。

Azure App Service の、[設定] > [構成] ページで [新しいアプリケーション設定] を選択します。 Azure App Service アプリケーションの設定は:

  • 保存時に暗号化され、暗号化されたチャネルで送信されます。
  • 環境変数として公開されます。

詳細については、「Azure アプリ: Azure Portal を使用してアプリの構成をオーバーライドする」を参照してください。

Azure データベース接続文字列の詳細については、「接続文字列のプレフィックス」を参照してください。

環境変数の名前付け

環境変数名には、 appsettings.json ファイルの構造が反映されます。 階層内の各要素は、二重アンダースコア (推奨) またはコロンによって区切られます。 要素構造に配列が含まれている場合は、配列のインデックスをこのパスの追加の要素名として扱う必要があります。 次の appsettings.json ファイルと、環境変数として表されたその同等の値を考えてみましょう。

appsettings.json

{
    "SmtpServer": "smtp.example.com",
    "Logging": [
        {
            "Name": "ToEmail",
            "Level": "Critical",
            "Args": {
                "FromAddress": "MySystem@example.com",
                "ToAddress": "SRE@example.com"
            }
        },
        {
            "Name": "ToConsole",
            "Level": "Information"
        }
    ]
}

環境変数

setx SmtpServer smtp.example.com
setx Logging__0__Name ToEmail
setx Logging__0__Level Critical
setx Logging__0__Args__FromAddress MySystem@example.com
setx Logging__0__Args__ToAddress SRE@example.com
setx Logging__1__Name ToConsole
setx Logging__1__Level Information

生成された launchSettings.json に設定されている環境変数

launchSettings.json に設定されている環境変数で、システム環境に設定されているそれらがオーバーライドされます。 たとえば、ASP.NET Core Web テンプレートでは、エンドポイント構成を次のように設定する launchSettings.json ファイルが生成されます。

"applicationUrl": "https://localhost:5001;http://localhost:5000"

applicationUrl を構成すると ASPNETCORE_URLS 環境変数が設定され、環境で設定されている値がオーバーライドされます。

Linux で環境変数をエスケープする

Linux では、systemd で解析できるように URL 環境変数の値をエスケープする必要があります。 Linux ツール systemd-escape を使用すると、http:--localhost:5001 が生成されます

groot@terminus:~$ systemd-escape http://localhost:5001
http:--localhost:5001

環境変数を表示する

次のコードでは、アプリケーションの起動時に環境変数と値が表示されます。これは環境設定をデバッグするときに役立つことがあります。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

foreach (var c in builder.Configuration.AsEnumerable())
{
    Console.WriteLine(c.Key + " = " + c.Value);
}

コマンド ライン

既定の構成を使用して、CommandLineConfigurationProvider は、以下の構成ソースの後にコマンド ライン引数のキーと値のペアから構成を読み込みます:

  • appsettings.json および appsettings.{Environment}.json ファイル。
  • 開発環境でのアプリ シークレット
  • 環境変数。

既定では、コマンド ラインで設定された構成値は、他のすべての構成プロバイダーで設定された構成値をオーバーライドします。

コマンド ライン引数

次のコマンドは = を使用してキーと値を設定します:

dotnet run MyKey="Using =" Position:Title=Cmd Position:Name=Cmd_Rick

次のコマンドは / を使用してキーと値を設定します:

dotnet run /MyKey "Using /" /Position:Title=Cmd /Position:Name=Cmd_Rick

次のコマンドは -- を使用してキーと値を設定します:

dotnet run --MyKey "Using --" --Position:Title=Cmd --Position:Name=Cmd_Rick

キーの値:

  • = の後に続ける必要があります。または、値がスペースの後にある場合は、キーのプレフィックスが -- または / である必要があります。
  • = を使用する場合は必要ありません。 たとえば、MySetting= のようにします。

同じコマンド内では、= を使用するコマンド ライン引数のキーと値のペアを、スペースを使用するキーと値のペアと混在させないでください。

スイッチ マッピング

スイッチ マッピングでは、キー名の置換ロジックが許可されます。 AddCommandLine メソッドにスイッチ置換するディクショナリを提供します。

スイッチ マッピング ディクショナリが使用されている場合、そのディレクトリで、コマンドライン引数によって指定されたキーと一致するキーが確認されます。 ディクショナリ中にコマンド ライン キーが見つかった場合は、そのディクショナリの値が返され、キーと値のペアがアプリの構成に設定されます。 スイッチ マッピングは、単一のダッシュ (-) が前に付いたすべてのコマンドライン キーに必要です。

スイッチ マッピング ディクショナリ キーの規則:

  • スイッチは - または --で始める必要があります。
  • スイッチ マッピング ディクショナリに重複キーを含めることはできません。

スイッチ マッピング ディクショナリを使用するには、それを AddCommandLine の呼び出しに渡します:


var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var switchMappings = new Dictionary<string, string>()
         {
             { "-k1", "key1" },
             { "-k2", "key2" },
             { "--alt3", "key3" },
             { "--alt4", "key4" },
             { "--alt5", "key5" },
             { "--alt6", "key6" },
         };

builder.Configuration.AddCommandLine(args, switchMappings);

var app = builder.Build();

次のコマンドを実行して、キーの置換をテストします:

dotnet run -k1 value1 -k2 value2 --alt3=value2 /alt4=value3 --alt5 value5 /alt6 value6

次のコードは、置換されたキーのキー値を示しています:

public class Test3Model : PageModel
{
    private readonly IConfiguration Config;

    public Test3Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        return Content(
                $"Key1: '{Config["Key1"]}'\n" +
                $"Key2: '{Config["Key2"]}'\n" +
                $"Key3: '{Config["Key3"]}'\n" +
                $"Key4: '{Config["Key4"]}'\n" +
                $"Key5: '{Config["Key5"]}'\n" +
                $"Key6: '{Config["Key6"]}'");
    }
}

スイッチ マッピングを使用するアプリでは、CreateDefaultBuilder への呼び出しで引数を渡すことはできません。 CreateDefaultBuilder メソッドの AddCommandLine 呼び出しには、マップされたスイッチが含まれていないため、スイッチ マッピング ディクショナリを CreateDefaultBuilder に渡すことはできません。 解決策は、CreateDefaultBuilder に引数を渡す代わりに、ConfigurationBuilder メソッドの AddCommandLine メソッドに、引数とスイッチ マッピング ディクショナリの両方を処理させることです。

Visual Studio で環境とコマンド ライン引数を設定する

環境およびコマンド ラインの引数は、Visual Studio の起動プロファイル ダイアログから設定できます。

  • ソリューション エクスプローラーで、プロジェクトを右クリックして [プロパティ] を選択します。
  • [デバッグ] > [全般] タブの順に選択し、[Open debug launch profiles UI](デバッグ起動プロファイル UI を開く) を選択します。

階層的な構成データ

構成 API では、構成キーの区切り記号を使用して階層データをフラット化することにより、階層型の構成データの読み取りが行われます。

サンプル ダウンロードには、次の appsettings.json ファイルが含まれます。

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey": "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

サンプル ダウンロード の次のコードでは、構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

階層型の構成データを読み取る方法としては、オプション パターンを使用することをお勧めします。 詳細については、このドキュメント中の「階層型の構成データをバインドする」を参照してください。

GetSection メソッドと GetChildren メソッドを使用して、構成データ内のセクションとセクションの子を分離することができます。 これらのメソッドについては、後ほど「GetSection、GetChildren、Exists」で説明します。

構成キーと値

構成キー:

  • 構成キーでは、大文字と小文字は区別されません。 たとえば、ConnectionStringconnectionstring は同等のキーとして扱われます。
  • キーと値が複数の構成プロバイダーで設定されている場合は、最後に追加されたプロバイダーの値が使用されます。 詳細については、「既定の構成」を参照してください。
  • 階層キー
    • 構成 API 内では、すべてのプラットフォームでコロン (:) の区切りが機能します。
    • 環境変数内では、コロン区切りがすべてのプラットフォームでは機能しない場合があります。 ダブル アンダースコア (__) はすべてのプラットフォームでサポートされ、コロン : に自動で変換されます。
    • Azure Key Vault では、階層型のキーは区切り記号に -- を使用します。 シークレットがアプリの構成に読み込まれると、Azure Key Vault 構成プロバイダーによって --: に自動的に置き換えられます。
  • ConfigurationBinder は、構成キーで配列インデックスを使用して、オブジェクトに対する配列のバインドをサポートしています。 配列のバインドについては、「配列をクラスにバインドする」セクションで説明します。

構成値:

  • 構成値は文字列です。
  • Null 値を構成に格納したり、オブジェクトにバインドしたりすることはできません。

構成プロバイダー

ASP.NET Core アプリで使用できる構成プロバイダーを次の表に示します。

プロバイダー 以下から構成を提供します
Azure Key Vault 構成プロバイダー Azure Key Vault
Azure App Configuration プロバイダー Azure App Configuration
コマンド ライン構成プロバイダー コマンド ライン パラメーター
カスタム構成プロバイダー カスタム ソース
環境変数構成プロバイダー 環境変数
ファイル構成プロバイダー INI、JSON、および XML ファイル
ファイルごとのキーの構成プロバイダー ディレクトリ ファイル
メモリ構成プロバイダー メモリ内コレクション
ユーザー シークレット ユーザー プロファイル ディレクトリ内のファイル

構成ソースは、構成プロバイダーで指定された順序で読み取られます。 アプリで必要とされる、基になる構成ソースの優先順位に合わせるために、コード内で構成プロバイダーを並べ替えます。

一般的な一連の構成プロバイダーは次のとおりです。

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. ユーザー シークレット
  4. 環境変数構成プロバイダーを使用する環境変数。
  5. コマンドライン構成プロバイダーを使用するコマンドライン引数。

コマンド ライン引数が他のプロバイダーによって設定された構成をオーバーライドできるようにするには、コマンド ラインの構成プロバイダーを一連のプロバイダーの最後に配置するのが一般的です。

上記の一連のプロバイダーは、既定の構成で使用されます。

接続文字列のプレフィックス

構成 API には、4つの接続文字列環境変数に対する特別なプロセスルールがあります。 これらの接続文字列は、アプリ環境用の Azure 接続文字列の構成に含まれています。 表に示されたプレフィックスを持つ環境変数は、既定の構成 を使用するとき、または AddEnvironmentVariables にプレフィックスが指定されていない場合に、アプリに読み込まれます。

接続文字列のプレフィックス プロバイダー
CUSTOMCONNSTR_ カスタム プロバイダー
MYSQLCONNSTR_ MySQL
SQLAZURECONNSTR_ Azure SQL Database
SQLCONNSTR_ SQL Server

表に示す 4 つのプレフィックスのいずれかを使用して、環境変数が検出され構成に読み込まれた場合:

  • 環境変数のプレフィックスを削除し、構成キーのセクション (ConnectionStrings) を追加することによって、構成キーが作成されます。
  • データベースの接続プロバイダーを表す新しい構成のキーと値のペアが作成されます (示されたプロバイダーを含まない CUSTOMCONNSTR_ を除く)。
環境変数キー 変換された構成キー プロバイダーの構成エントリ
CUSTOMCONNSTR_{KEY} ConnectionStrings:{KEY} 構成エントリは作成されません。
MYSQLCONNSTR_{KEY} ConnectionStrings:{KEY} キー: ConnectionStrings:{KEY}_ProviderName:
値: MySql.Data.MySqlClient
SQLAZURECONNSTR_{KEY} ConnectionStrings:{KEY} キー: ConnectionStrings:{KEY}_ProviderName:
値: System.Data.SqlClient
SQLCONNSTR_{KEY} ConnectionStrings:{KEY} キー: ConnectionStrings:{KEY}_ProviderName:
値: System.Data.SqlClient

ファイル構成プロバイダー

FileConfigurationProvider は、ファイル システムから構成を読み込むための基本クラスです。 以下の構成プロバイダーは FileConfigurationProvider から派生したものです:

INI 構成プロバイダー

IniConfigurationProvider では、実行時に INI ファイルのキーと値のペアから構成が読み込まれます。

次のコードは、すべての構成プロバイダーをクリアし、いくつかの構成プロバイダーを追加します:

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();

    var env = hostingContext.HostingEnvironment;

    config.AddIniFile("MyIniConfig.ini", optional: true, reloadOnChange: true)
          .AddIniFile($"MyIniConfig.{env.EnvironmentName}.ini",
                         optional: true, reloadOnChange: true);

    config.AddEnvironmentVariables();

    if (args != null)
    {
        config.AddCommandLine(args);
    }
});

builder.Services.AddRazorPages();

var app = builder.Build();

上記のコードでは、MyIniConfig.ini および MyIniConfig.{Environment}.ini ファイルの設定は、以下の設定によってオーバーライドされます:

サンプル ダウンロードには、次の MyIniConfig.ini ファイルが含まれます。

MyKey="MyIniConfig.ini Value"

[Position]
Title="My INI Config title"
Name="My INI Config name"

[Logging:LogLevel]
Default=Information
Microsoft=Warning

サンプル ダウンロード の次のコードでは、上記の構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

JSON 構成プロバイダー

JsonConfigurationProvider では、JSON ファイルのキーと値のペアから構成が読み込みまれます。

オーバーロードでは、次の指定ができます:

  • ファイルを省略可能かどうか。
  • ファイルが変更された場合に構成を再度読み込むかどうか。

次のコードがあるとします。

using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile("MyConfig.json",
                       optional: true,
                       reloadOnChange: true);
});

builder.Services.AddRazorPages();

var app = builder.Build();

上記のコードでは次の操作が行われます。

  • 次のオプションを使用して、MyConfig.json ファイルを読み込むように JSON 構成プロバイダーを構成します:
    • optional: true:ファイルは省略可能です。
    • reloadOnChange: true は、次のとおりです。変更が保存されると、ファイルが再読み込みされます。
  • MyConfig.json ファイルの前に既定の構成プロバイダーを読み取ります。 環境変数構成プロバイダー および コマンド ライン構成プロバイダーを含む、既定の構成プロバイダーでの MyConfig.json ファイルのオーバーライドの設定。

通常は、環境変数構成プロバイダーおよびコマンドライン構成プロバイダーで設定されている値をオーバーライドするカスタム JSON ファイルは必要 "ありません"。

XML 構成プロバイダー

XmlConfigurationProvider では、実行時に XML ファイルのキーと値のペアから構成が読み込まれます。

次のコードは、すべての構成プロバイダーをクリアし、いくつかの構成プロバイダーを追加します:

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();

    var env = hostingContext.HostingEnvironment;

    config.AddXmlFile("MyXMLFile.xml", optional: true, reloadOnChange: true)
          .AddXmlFile($"MyXMLFile.{env.EnvironmentName}.xml",
                         optional: true, reloadOnChange: true);

    config.AddEnvironmentVariables();

    if (args != null)
    {
        config.AddCommandLine(args);
    }
});

builder.Services.AddRazorPages();

var app = builder.Build();

上記のコードでは、MyXMLFile.xml および MyXMLFile.{Environment}.xml ファイルの設定は、以下の設定によってオーバーライドされます:

サンプル ダウンロードには、次の MyXMLFile.xml ファイルが含まれます。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <MyKey>MyXMLFile Value</MyKey>
  <Position>
    <Title>Title from  MyXMLFile</Title>
    <Name>Name from MyXMLFile</Name>
  </Position>
  <Logging>
    <LogLevel>
      <Default>Information</Default>
      <Microsoft>Warning</Microsoft>
    </LogLevel>
  </Logging>
</configuration>

サンプル ダウンロード の次のコードでは、上記の構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

同じ要素名を使用する要素の繰り返しは、要素を区別するために name 属性を使用する場合に機能します。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section name="section0">
    <key name="key0">value 00</key>
    <key name="key1">value 01</key>
  </section>
  <section name="section1">
    <key name="key0">value 10</key>
    <key name="key1">value 11</key>
  </section>
</configuration>

以下のコードでは、前の構成ファイルを読み取って、キーと値を表示します:

public class IndexModel : PageModel
{
    private readonly IConfiguration Configuration;

    public IndexModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var key00 = "section:section0:key:key0";
        var key01 = "section:section0:key:key1";
        var key10 = "section:section1:key:key0";
        var key11 = "section:section1:key:key1";

        var val00 = Configuration[key00];
        var val01 = Configuration[key01];
        var val10 = Configuration[key10];
        var val11 = Configuration[key11];

        return Content($"{key00} value: {val00} \n" +
                       $"{key01} value: {val01} \n" +
                       $"{key10} value: {val10} \n" +
                       $"{key10} value: {val11} \n"
                       );
    }
}

値を指定するために属性を使用できます。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <key attribute="value" />
  <section>
    <key attribute="value" />
  </section>
</configuration>

前の構成ファイルでは、value を使用して次のキーが読み込まれます。

  • key:attribute
  • section:key:attribute

ファイルごとのキーの構成プロバイダー

KeyPerFileConfigurationProvider では、構成のキーと値のペアとしてディレクトリのファイルが使用されます。 キーはファイル名です。 値にはファイルのコンテンツが含まれます。 ファイルごとのキーの構成プロバイダーは、Docker ホスティングのシナリオで使用されます。

ファイルごとのキーの構成をアクティブにするには、ConfigurationBuilder のインスタンスの AddKeyPerFile 拡張メソッドを呼び出します。 ファイルに対する directoryPath は、絶対パスである必要があります。

オーバーロードによって次のものを指定できます。

  • ソースを構成する Action<KeyPerFileConfigurationSource> デリゲート。
  • ディレクトリを省略可能かどうか、またディレクトリへのパス。

アンダースコア 2 つ (__) は、ファイル名で構成キーの区切り記号として使用されます。 たとえば、ファイル名 Logging__LogLevel__System では、構成キー Logging:LogLevel:System が生成されます。

ホストをビルドするときに ConfigureAppConfiguration を呼び出して、アプリの構成を指定します。

.ConfigureAppConfiguration((hostingContext, config) =>
{
    var path = Path.Combine(
        Directory.GetCurrentDirectory(), "path/to/files");
    config.AddKeyPerFile(directoryPath: path, optional: true);
})

メモリ構成プロバイダー

MemoryConfigurationProvider では、構成のキーと値のペアとして、メモリ内コレクションが使用されます。

次のコードでは、構成システムにメモリコ レクションが追加されています:

var builder = WebApplication.CreateBuilder(args);

var Dict = new Dictionary<string, string>
        {
           {"MyKey", "Dictionary MyKey Value"},
           {"Position:Title", "Dictionary_Title"},
           {"Position:Name", "Dictionary_Name" },
           {"Logging:LogLevel:Default", "Warning"}
        };

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();

    config.AddInMemoryCollection(Dict);

    config.AddEnvironmentVariables();

    if (args != null)
    {
        config.AddCommandLine(args);
    }
});

builder.Services.AddRazorPages();

var app = builder.Build();

サンプルのダウンロード の以下のコードでは、上記の構成設定のいくつかが表示されます:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

上記のコードでは、既定の構成プロバイダーの後に config.AddInMemoryCollection(Dict) が追加されています。 構成プロバイダーの順序付けの例については、「JSON 構成プロバイダー」を参照してください。

MemoryConfigurationProvider を使用した別の例については、配列をバインドを参照してください。

Kestrel エンドポイント構成

Kestrel 固有のエンドポイント構成によって、すべてのサーバー間のエンドポイント構成がオーバーライドされます。 サーバー間のエンドポイント構成には、次のものがあります。

ASP.NET Core Web アプリで使用される次の appsettings.json ファイルについて考えてみましょう。

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:9999"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
} 

前述の強調表示されているマークアップが ASP.NET Core Web アプリで使用され、"かつ" 次のサーバー間エンドポイント構成を使用してコマンド ラインでアプリが起動される場合:

dotnet run --urls="https://localhost:7777"

Kestrel は、https://localhost:7777 ではなく、 appsettings.json ファイルで Kestrel 専用に構成されたエンドポイント (https://localhost:9999) にバインドされます。

環境変数として構成された Kestrel 固有のエンドポイントを考えてみます。

set Kestrel__Endpoints__Https__Url=https://localhost:8888

上記の環境変数では、Https が Kestrel 固有のエンドポイントの名前です。 前の appsettings.json ファイルでも、Https という名前の Kestrel 固有のエンドポイントが定義されています。 既定で、環境変数構成プロバイダーを使用している環境変数は appsettings.{Environment}.json の後に読み取られます。したがって、上記の環境変数は Https エンドポイント用に使用されます。

GetValue

ConfigurationBinder.GetValue 指定したキーを使用して、構成から単一の値を抽出し、それを指定した型に変換します:

public class TestNumModel : PageModel
{
    private readonly IConfiguration Configuration;

    public TestNumModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var number = Configuration.GetValue<int>("NumberKey", 99);
        return Content($"{number}");
    }
}

上記のコードでは、NumberKey が構成中に見つからない場合には 99 の既定値が使用されます。

GetSection、GetChildren、Exists

以下の例では、次の MySubsection.json ファイルについて考えます。

{
  "section0": {
    "key0": "value00",
    "key1": "value01"
  },
  "section1": {
    "key0": "value10",
    "key1": "value11"
  },
  "section2": {
    "subsection0": {
      "key0": "value200",
      "key1": "value201"
    },
    "subsection1": {
      "key0": "value210",
      "key1": "value211"
    }
  }
}

以下のコードでは、MySubsection.jsonを構成プロバイダーに追加します:

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile("MySubsection.json",
                       optional: true,
                       reloadOnChange: true);
});

builder.Services.AddRazorPages();

var app = builder.Build();

GetSection

IConfiguration.GetSection は、指定されたサブセクションのキーを持つ構成サブセクションを返します。

次のコードは、section1 の値を返します:

public class TestSectionModel : PageModel
{
    private readonly IConfiguration Config;

    public TestSectionModel(IConfiguration configuration)
    {
        Config = configuration.GetSection("section1");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section1:key0: '{Config["key0"]}'\n" +
                $"section1:key1: '{Config["key1"]}'");
    }
}

次のコードは、section2:subsection0 の値を返します:

public class TestSection2Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection2Model(IConfiguration configuration)
    {
        Config = configuration.GetSection("section2:subsection0");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                $"section2:subsection0:key1:'{Config["key1"]}'");
    }
}

GetSectionnull を返すことはありません。 一致するセクションが見つからない場合は、空の IConfigurationSection が返されます。

GetSection で一致するセクションが返されると、Value は設定されません。 KeyPath はセクションが存在する場合に返されます。

GetChildren と Exists

次のコードは、IConfiguration.GetChildren を呼び出し、section2:subsection0 の値を返します:

public class TestSection4Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection4Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        string s = "";
        var selection = Config.GetSection("section2");
        if (!selection.Exists())
        {
            throw new Exception("section2 does not exist.");
        }
        var children = selection.GetChildren();

        foreach (var subSection in children)
        {
            int i = 0;
            var key1 = subSection.Key + ":key" + i++.ToString();
            var key2 = subSection.Key + ":key" + i.ToString();
            s += key1 + " value: " + selection[key1] + "\n";
            s += key2 + " value: " + selection[key2] + "\n";
        }
        return Content(s);
    }
}

上記のコードは、ConfigurationExtensions.Exists を呼び出し、セクションが存在することを確認します:

配列をバインドする

ConfigurationBinder.Bind は、構成キーで配列インデックスを使用して、オブジェクトに対する配列のバインドをサポートしています。 数値のキー セグメントを公開する配列形式は、すべて POCO クラスの配列にバインドできます。

サンプル ダウンロードMyArray.json について考えます:

{
  "array": {
    "entries": {
      "0": "value00",
      "1": "value10",
      "2": "value20",
      "4": "value40",
      "5": "value50"
    }
  }
}

次のコードでは、MyArray.json を構成プロバイダーに追加します:

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile("MyArray.json",
                        optional: true,
                        reloadOnChange: true); ;
});

builder.Services.AddRazorPages();

var app = builder.Build();

次のコードでは、構成を読み取り、値を表示します:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample? _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
       _array = Config.GetSection("array").Get<ArrayExample>();
        if (_array == null)
        {
            throw new ArgumentNullException(nameof(_array));
        }
        string s = String.Empty;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}
public class ArrayExample
{
    public string[]? Entries { get; set; } 
}

上記のコードは、次の出力を返します:

Index: 0  Value: value00
Index: 1  Value: value10
Index: 2  Value: value20
Index: 3  Value: value40
Index: 4  Value: value50

上記の出力では、インデックス 3 の値が value40 になります。これは MyArray.json"4": "value40", に対応しています。 このバインドされた配列インデックスは連続的であり、構成キーインデックスにバインドされていません。 構成バインダーは、バインドされたオブジェクトに null 値をバインドしたり、null エントリを作成したりはできません。

カスタム構成プロバイダー

サンプル アプリでは、Entity Framework (EF) を使用してデータベースから構成のキーと値のペアを読み取る、基本的な構成プロバイダーを作成する方法を示します。

プロバイダーの特徴は次のとおりです。

  • EF のメモリ内データベースは、デモンストレーションのために使用されます。 接続文字列を必要とするデータベースを使用するには、第 2 の ConfigurationBuilder を実装して、別の構成プロバイダーからの接続文字列を指定します。
  • プロバイダーは、起動時に、構成にデータベース テーブルを読み取ります。 プロバイダーは、キー単位でデータベースを照会しません。
  • 変更時に再度読み込む機能は実装されていません。このため、アプリの起動後にデータベースを更新しても、アプリの構成には影響がありません。

データベースに構成値を格納するための EFConfigurationValue エンティティを定義します。

Models/EFConfigurationValue.cs:

public class EFConfigurationValue
{
    public string Id { get; set; } = String.Empty;
    public string Value { get; set; } = String.Empty;
}

構成した値を格納し、その値にアクセスするための EFConfigurationContext を追加します。

EFConfigurationProvider/EFConfigurationContext.cs:

public class EFConfigurationContext : DbContext
{
    public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
    {
    }

    public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
}

IConfigurationSource を実装するクラスを作成します。

EFConfigurationProvider/EFConfigurationSource.cs:

public class EFConfigurationSource : IConfigurationSource
{
    private readonly Action<DbContextOptionsBuilder> _optionsAction;

    public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;

    public IConfigurationProvider Build(IConfigurationBuilder builder) => new EFConfigurationProvider(_optionsAction);
}

ConfigurationProvider から継承して、カスタム構成プロバイダーを作成します。 データベースが空だった場合、構成プロバイダーはこれを初期化します。 構成キーでは大文字と小文字が区別されないため、データベースの初期化に使用されるディクショナリは、大文字と小文字を区別しない比較子 (StringComparer.OrdinalIgnoreCase) を使用して作成されます。

EFConfigurationProvider/EFConfigurationProvider.cs:

public class EFConfigurationProvider : ConfigurationProvider
{
    public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<EFConfigurationContext>();

        OptionsAction(builder);

        using (var dbContext = new EFConfigurationContext(builder.Options))
        {
            if (dbContext == null || dbContext.Values == null)
            {
                throw new Exception("Null DB context");
            }
            dbContext.Database.EnsureCreated();

            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private static IDictionary<string, string> CreateAndSaveDefaultValues(
        EFConfigurationContext dbContext)
    {
        // Quotes (c)2005 Universal Pictures: Serenity
        // https://www.uphe.com/movies/serenity-2005
        var configValues =
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                    { "quote1", "I aim to misbehave." },
                    { "quote2", "I swallowed a bug." },
                    { "quote3", "You can't stop the signal, Mal." }
            };

        if (dbContext == null || dbContext.Values == null)
        {
            throw new Exception("Null DB context");
        }

        dbContext.Values.AddRange(configValues
            .Select(kvp => new EFConfigurationValue
            {
                Id = kvp.Key,
                Value = kvp.Value
            })
            .ToArray());

        dbContext.SaveChanges();

        return configValues;
    }
}

AddEFConfiguration 拡張メソッドを使用すると、ConfigurationBuilder に構成ソースを追加できます。

Extensions/EntityFrameworkExtensions.cs:

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEFConfiguration(
               this IConfigurationBuilder builder,
               Action<DbContextOptionsBuilder> optionsAction)
    {
        return builder.Add(new EFConfigurationSource(optionsAction));
    }
}

次のコードでは、Program.cs でカスタムの EFConfigurationProvider を使用する方法を示します。

//using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddEFConfiguration(
    opt => opt.UseInMemoryDatabase("InMemoryDb"));

var app = builder.Build();

app.Run();

依存関係の挿入 (DI) を使用したアクセス構成

IConfiguration サービスを解決することで、依存関係の挿入 (DI) を使用してサービスに構成を挿入できます。

public class Service
{
    private readonly IConfiguration _config;

    public Service(IConfiguration config) =>
        _config = config;

    public void DoSomething()
    {
        var configSettingValue = _config["ConfigSetting"];

        // ...
    }
}

IConfiguration を使用して値にアクセスする方法については、この記事の「GetValue」と「GetSection、GetChildren、Exists」を参照してください。

Razor ページの構成にアクセスする

次のコードでは Razor ページの構成データが表示されます:

@page
@model Test5Model
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

次のコードでは、MyOptionsConfigure でサービスコンテナーに追加され、構成にバインドされます:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(
    builder.Configuration.GetSection("MyOptions"));

var app = builder.Build();

次のマークアップは、@injectRazor ディレクティブを使用して、オプションの値を解決して表示します。

@page
@model SampleApp.Pages.Test3Model
@using Microsoft.Extensions.Options
@using SampleApp.Models
@inject IOptions<MyOptions> optionsAccessor


<p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
<p><b>Option2:</b> @optionsAccessor.Value.Option2</p>

MVC ビューファイルの構成へのアクセス

次のコードでは、MVC ビューの構成データが表示されます:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

Program.cs でのアクセス構成

次のコードは、Program.cs ファイル内の構成にアクセスします。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

var key1 = app.Configuration.GetValue<int>("KeyOne");
var key2 = app.Configuration.GetValue<bool>("KeyTwo");

app.Logger.LogInformation($"KeyOne = {key1}");
app.Logger.LogInformation($"KeyTwo = {key2}");

app.Run();

デリゲートでオプションを構成する

デリゲートで構成されたオプションは、構成プロバイダーで設定された値をオーバーライドします。

次のコードでは、IConfigureOptions<TOptions> サービスがサービス コンテナーに追加されます。 デリゲートを利用して MyOptions の値が構成されます。

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "Value configured in delegate";
    myOptions.Option2 = 500;
});

var app = builder.Build();

このコードには、次のオプションの値が表示されます。

public class Test2Model : PageModel
{
    private readonly IOptions<MyOptions> _optionsDelegate;

    public Test2Model(IOptions<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.Value.Option1} \n" +
                       $"Option2: {_optionsDelegate.Value.Option2}");
    }
}

先の例では、値 Option1Option2appsettings.json で指定されてから、構成されているデリゲートによりオーバーライドされます。

ホストとアプリの構成

アプリを構成して起動する前に、"ホスト" を構成して起動します。 ホストはアプリの起動と有効期間の管理を担当します。 アプリとホストは、両方ともこのトピックで説明する構成プロバイダーを使用して構成します。 ホスト構成のキーと値のペアも、アプリの構成に含まれます。 ホストをビルドするときの構成プロバイダーの使用方法、およびホストの構成に対する構成ソースの影響について詳しくは、ASP.NET Core の基礎の概要に関する記事を参照してください。

既定のホスト構成

Web ホストを使用する場合の既定の構成の詳細については、このトピックの ASP.NET Core 2.2 バージョンを参照してください。

  • ホストの構成は、次から提供されます。
  • Web ホストの既定の構成が確立されます (ConfigureWebHostDefaults)。
    • Kestrel は Web サーバーとして使用され、アプリの構成プロバイダーを使用して構成されます。
    • Host Filtering Middleware を追加します。
    • ASPNETCORE_FORWARDEDHEADERS_ENABLED 環境変数が true に設定されている場合は、Forwarded Headers Middleware を追加します。
    • IIS 統合を有効にします。

その他の構成

このトピックは、"アプリの構成" のみに関連しています。 ASP.NET Core アプリの実行とホストに関するその他の側面は、このトピックでは扱わない構成ファイルを使って構成されます。

launchSettings.json に設定されている環境変数で、システム環境に設定されているそれらがオーバーライドされます。

以前のバージョンの ASP.NET からアプリの構成を移行する方法について詳しくは、「ASP.NET から ASP.NET Core への移行」を参照してください。

外部アセンブリから構成を追加する

IHostingStartup の実装により、アプリの Startup クラスの外部にある外部アセンブリから、起動時に拡張機能をアプリに追加できるようになります。 詳細については、「ASP.NET Core でホスティング スタートアップ アセンブリを使用する」を参照してください。

その他の技術情報

Kestrel エンドポイント構成

Kestrel 固有のエンドポイント構成によって、すべてのサーバー間のエンドポイント構成がオーバーライドされます。 サーバー間のエンドポイント構成には、次のものがあります。

ASP.NET Core Web アプリで使用される次の appsettings.json ファイルについて考えてみましょう。

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:9999"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
} 

前述の強調表示されているマークアップが ASP.NET Core Web アプリで使用され、"かつ" 次のサーバー間エンドポイント構成を使用してコマンド ラインでアプリが起動される場合:

dotnet run --urls="https://localhost:7777"

Kestrel は、https://localhost:7777 ではなく、 appsettings.json ファイルで Kestrel 専用に構成されたエンドポイント (https://localhost:9999) にバインドされます。

環境変数として構成された Kestrel 固有のエンドポイントを考えてみます。

set Kestrel__Endpoints__Https__Url=https://localhost:8888

上記の環境変数では、Https が Kestrel 固有のエンドポイントの名前です。 前の appsettings.json ファイルでも、Https という名前の Kestrel 固有のエンドポイントが定義されています。 既定で、環境変数構成プロバイダーを使用している環境変数は appsettings.{Environment}.json の後に読み取られます。したがって、上記の環境変数は Https エンドポイント用に使用されます。

GetValue

ConfigurationBinder.GetValue は指定したキーを使用して、構成から単一の値を抽出し、それを指定した型に変換します。 このメソッドは IConfiguration の拡張メソッドです。

public class TestNumModel : PageModel
{
    private readonly IConfiguration Configuration;

    public TestNumModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var number = Configuration.GetValue<int>("NumberKey", 99);
        return Content($"{number}");
    }
}

上記のコードでは、NumberKey が構成中に見つからない場合には 99 の既定値が使用されます。

GetSection、GetChildren、Exists

以下の例では、次の MySubsection.json ファイルについて考えます。

{
  "section0": {
    "key0": "value00",
    "key1": "value01"
  },
  "section1": {
    "key0": "value10",
    "key1": "value11"
  },
  "section2": {
    "subsection0": {
      "key0": "value200",
      "key1": "value201"
    },
    "subsection1": {
      "key0": "value210",
      "key1": "value211"
    }
  }
}

以下のコードでは、MySubsection.jsonを構成プロバイダーに追加します:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile("MySubsection.json", 
                    optional: true, 
                    reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

GetSection

IConfiguration.GetSection は、指定されたサブセクションのキーを持つ構成サブセクションを返します。

次のコードは、section1 の値を返します:

public class TestSectionModel : PageModel
{
    private readonly IConfiguration Config;

    public TestSectionModel(IConfiguration configuration)
    {
        Config = configuration.GetSection("section1");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section1:key0: '{Config["key0"]}'\n" +
                $"section1:key1: '{Config["key1"]}'");
    }
}

次のコードは、section2:subsection0 の値を返します:

public class TestSection2Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection2Model(IConfiguration configuration)
    {
        Config = configuration.GetSection("section2:subsection0");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                $"section2:subsection0:key1:'{Config["key1"]}'");
    }
}

GetSectionnull を返すことはありません。 一致するセクションが見つからない場合は、空の IConfigurationSection が返されます。

GetSection で一致するセクションが返されると、Value は設定されません。 KeyPath はセクションが存在する場合に返されます。

GetChildren と Exists

次のコードは、IConfiguration.GetChildren を呼び出し、section2:subsection0 の値を返します:

public class TestSection4Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection4Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        string s = null;
        var selection = Config.GetSection("section2");
        if (!selection.Exists())
        {
            throw new System.Exception("section2 does not exist.");
        }
        var children = selection.GetChildren();

        foreach (var subSection in children)
        {
            int i = 0;
            var key1 = subSection.Key + ":key" + i++.ToString();
            var key2 = subSection.Key + ":key" + i.ToString();
            s += key1 + " value: " + selection[key1] + "\n";
            s += key2 + " value: " + selection[key2] + "\n";
        }
        return Content(s);
    }
}

上記のコードは、ConfigurationExtensions.Exists を呼び出し、セクションが存在することを確認します:

配列をバインドする

ConfigurationBinder.Bind は、構成キーで配列インデックスを使用して、オブジェクトに対する配列のバインドをサポートしています。 数値のキー セグメントを公開する配列形式は、すべて POCO クラスの配列にバインドできます。

サンプル ダウンロードMyArray.json について考えます:

{
  "array": {
    "entries": {
      "0": "value00",
      "1": "value10",
      "2": "value20",
      "4": "value40",
      "5": "value50"
    }
  }
}

次のコードでは、MyArray.json を構成プロバイダーに追加します:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile("MyArray.json", 
                    optional: true, 
                    reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

次のコードでは、構成を読み取り、値を表示します:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

上記のコードは、次の出力を返します:

Index: 0  Value: value00
Index: 1  Value: value10
Index: 2  Value: value20
Index: 3  Value: value40
Index: 4  Value: value50

上記の出力では、インデックス 3 の値が value40 になります。これは MyArray.json"4": "value40", に対応しています。 このバインドされた配列インデックスは連続的であり、構成キーインデックスにバインドされていません。 構成バインダーは、バインドされたオブジェクトに null 値をバインドしたり、null エントリを作成したりはできません

次のコードでは、AddInMemoryCollection 拡張メソッドで array:entries 構成を読み込みます。

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var arrayDict = new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            //              3   Skipped
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }
}

次のコードでは、arrayDictDictionary の構成を読み取り、値を表示します。

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

上記のコードは、次の出力を返します:

Index: 0  Value: value0
Index: 1  Value: value1
Index: 2  Value: value2
Index: 3  Value: value4
Index: 4  Value: value5

バインドされたオブジェクトのインデックス #3 によって、array:4 構成キーの構成データと、その値 value4 が保持されます。 配列を含む構成データがバインドされている場合、構成キーの配列インデックスは、オブジェクト作成時の構成データの反復のために使用されます。 構成データに null 値を保持することはできません。また、構成キーの配列が 1 つまたは複数のインデックスをスキップしても、バインドされたオブジェクトに null 値のエントリは作成されません。

インデックス #3 に不足している構成項目は、ArrayExample インスタンスにバインドする前に、インデックス #3 のキーと値のペアを読み取る構成プロバイダーによって指定できます。 サンプルダウンロードの、次の Value3.json ファイルについて考えます:

{
  "array:entries:3": "value3"
}

次のコードには、Value3.jsonarrayDictDictionary の構成が含まれています:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var arrayDict = new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            //              3   Skipped
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile("Value3.json",
                                    optional: false, reloadOnChange: false);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }
}

次のコードは、上記の構成を読み取り、値を表示します:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

上記のコードは、次の出力を返します:

Index: 0  Value: value0
Index: 1  Value: value1
Index: 2  Value: value2
Index: 3  Value: value3
Index: 4  Value: value4
Index: 5  Value: value5

カスタム構成プロバイダーが配列のバインドを実装する必要はありません。

カスタム構成プロバイダー

サンプル アプリでは、Entity Framework (EF) を使用してデータベースから構成のキーと値のペアを読み取る、基本的な構成プロバイダーを作成する方法を示します。

プロバイダーの特徴は次のとおりです。

  • EF のメモリ内データベースは、デモンストレーションのために使用されます。 接続文字列を必要とするデータベースを使用するには、第 2 の ConfigurationBuilder を実装して、別の構成プロバイダーからの接続文字列を指定します。
  • プロバイダーは、起動時に、構成にデータベース テーブルを読み取ります。 プロバイダーは、キー単位でデータベースを照会しません。
  • 変更時に再度読み込む機能は実装されていません。このため、アプリの起動後にデータベースを更新しても、アプリの構成には影響がありません。

データベースに構成値を格納するための EFConfigurationValue エンティティを定義します。

Models/EFConfigurationValue.cs:

public class EFConfigurationValue
{
    public string Id { get; set; }
    public string Value { get; set; }
}

構成した値を格納し、その値にアクセスするための EFConfigurationContext を追加します。

EFConfigurationProvider/EFConfigurationContext.cs:

// using Microsoft.EntityFrameworkCore;

public class EFConfigurationContext : DbContext
{
    public EFConfigurationContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<EFConfigurationValue> Values { get; set; }
}

IConfigurationSource を実装するクラスを作成します。

EFConfigurationProvider/EFConfigurationSource.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public class EFConfigurationSource : IConfigurationSource
{
    private readonly Action<DbContextOptionsBuilder> _optionsAction;

    public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
    {
        _optionsAction = optionsAction;
    }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new EFConfigurationProvider(_optionsAction);
    }
}

ConfigurationProvider から継承して、カスタム構成プロバイダーを作成します。 データベースが空だった場合、構成プロバイダーはこれを初期化します。 構成キーでは大文字と小文字が区別されないため、データベースの初期化に使用されるディクショナリは、大文字と小文字を区別しない比較子 (StringComparer.OrdinalIgnoreCase) を使用して作成されます。

EFConfigurationProvider/EFConfigurationProvider.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public class EFConfigurationProvider : ConfigurationProvider
{
    public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<EFConfigurationContext>();

        OptionsAction(builder);

        using (var dbContext = new EFConfigurationContext(builder.Options))
        {
            dbContext.Database.EnsureCreated();

            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private static IDictionary<string, string> CreateAndSaveDefaultValues(
        EFConfigurationContext dbContext)
    {
        // Quotes (c)2005 Universal Pictures: Serenity
        // https://www.uphe.com/movies/serenity-2005
        var configValues = 
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                { "quote1", "I aim to misbehave." },
                { "quote2", "I swallowed a bug." },
                { "quote3", "You can't stop the signal, Mal." }
            };

        dbContext.Values.AddRange(configValues
            .Select(kvp => new EFConfigurationValue 
                {
                    Id = kvp.Key,
                    Value = kvp.Value
                })
            .ToArray());

        dbContext.SaveChanges();

        return configValues;
    }
}

AddEFConfiguration 拡張メソッドを使用すると、ConfigurationBuilder に構成ソースを追加できます。

Extensions/EntityFrameworkExtensions.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEFConfiguration(
        this IConfigurationBuilder builder, 
        Action<DbContextOptionsBuilder> optionsAction)
    {
        return builder.Add(new EFConfigurationSource(optionsAction));
    }
}

次のコードでは、Program.cs でカスタムの EFConfigurationProvider を使用する方法を示します。

// using Microsoft.EntityFrameworkCore;

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.AddEFConfiguration(
                options => options.UseInMemoryDatabase("InMemoryDb"));
        })

起動時の構成へのアクセス

次のコードでは Startup メソッドの構成データが表示されます:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        Console.WriteLine($"MyKey : {Configuration["MyKey"]}");
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        Console.WriteLine($"Position:Title : {Configuration["Position:Title"]}");

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

起動時の簡易メソッドを使用して構成にアクセスする例については、アプリ起動時の簡易メソッドに関連する記事をご覧ください。

Razor ページの構成にアクセスする

次のコードでは Razor ページの構成データが表示されます:

@page
@model Test5Model
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

次のコードでは、MyOptionsConfigure でサービスコンテナーに追加され、構成にバインドされます:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

次のマークアップは、@injectRazor ディレクティブを使用して、オプションの値を解決して表示します。

@page
@model SampleApp.Pages.Test3Model
@using Microsoft.Extensions.Options
@inject IOptions<MyOptions> optionsAccessor


<p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
<p><b>Option2:</b> @optionsAccessor.Value.Option2</p>

MVC ビューファイルの構成へのアクセス

次のコードでは、MVC ビューの構成データが表示されます:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

デリゲートでオプションを構成する

デリゲートで構成されたオプションは、構成プロバイダーで設定された値をオーバーライドします。

サンプル アプリの例 2 では、デリゲートでオプションを構成しています。

次のコードでは、IConfigureOptions<TOptions> サービスがサービス コンテナーに追加されます。 デリゲートを利用して MyOptions の値が構成されます。

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(myOptions =>
    {
        myOptions.Option1 = "Value configured in delegate";
        myOptions.Option2 = 500;
    });

    services.AddRazorPages();
}

このコードには、次のオプションの値が表示されます。

public class Test2Model : PageModel
{
    private readonly IOptions<MyOptions> _optionsDelegate;

    public Test2Model(IOptions<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.Value.Option1} \n" +
                       $"Option2: {_optionsDelegate.Value.Option2}");
    }
}

先の例では、値 Option1Option2appsettings.json で指定されてから、構成されているデリゲートによりオーバーライドされます。

ホストとアプリの構成

アプリを構成して起動する前に、"ホスト" を構成して起動します。 ホストはアプリの起動と有効期間の管理を担当します。 アプリとホストは、両方ともこのトピックで説明する構成プロバイダーを使用して構成します。 ホスト構成のキーと値のペアも、アプリの構成に含まれます。 ホストをビルドするときの構成プロバイダーの使用方法、およびホストの構成に対する構成ソースの影響について詳しくは、ASP.NET Core の基礎の概要に関する記事を参照してください。

既定のホスト構成

Web ホストを使用する場合の既定の構成の詳細については、このトピックの ASP.NET Core 2.2 バージョンを参照してください。

  • ホストの構成は、次から提供されます。
    • 環境変数構成プロバイダーを使用する、プレフィックス DOTNET_ (DOTNET_ENVIRONMENT など) が付いた環境変数。 構成のキーと値のペアが読み込まれるときに、プレフィックス (DOTNET_) は削除されます。
    • コマンドライン構成プロバイダーを使用するコマンドライン引数。
  • Web ホストの既定の構成が確立されます (ConfigureWebHostDefaults)。
    • Kestrel は Web サーバーとして使用され、アプリの構成プロバイダーを使用して構成されます。
    • Host Filtering Middleware を追加します。
    • ASPNETCORE_FORWARDEDHEADERS_ENABLED 環境変数が true に設定されている場合は、Forwarded Headers Middleware を追加します。
    • IIS 統合を有効にします。

その他の構成

このトピックは、"アプリの構成" のみに関連しています。 ASP.NET Core アプリの実行とホストに関するその他の側面は、このトピックでは扱わない構成ファイルを使って構成されます。

launchSettings.json に設定されている環境変数で、システム環境に設定されているそれらがオーバーライドされます。

以前のバージョンの ASP.NET からアプリの構成を移行する方法について詳しくは、「ASP.NET から ASP.NET Core への移行」を参照してください。

外部アセンブリから構成を追加する

IHostingStartup の実装により、アプリの Startup クラスの外部にある外部アセンブリから、起動時に拡張機能をアプリに追加できるようになります。 詳細については、「ASP.NET Core でホスティング スタートアップ アセンブリを使用する」を参照してください。

その他の技術情報