.NET 構成バインダーは、構成プロバイダーを介して構成値を取得し、それらの値をオブジェクト のプロパティにバインドしようとします。 以前は、構成値が null の場合、バインダーは値がまったく存在しないかのように処理するため、バインディングをスキップしていました。 つまり、 null 値と欠損値は区別されませんでした。 この動作により、構成で明示的に定義された null 値が尊重され、適切にバインドされることが予想されるユーザーにとって、大きな混乱が生じていました。
さらに、JSON 構成プロバイダーは、構成内の null 値を空の文字列に以前に変換しました。 これは、これらの値にバインドされたプロパティが予期される null ではなく空の文字列を受け取るので、混乱の一因となります。
この変更は、両方の問題に対処します。 JSON 構成プロバイダーは、 null 値を変更せずに正しくレポートするようになりました。バインダーは、 null 値を有効な入力として扱い、他の値と同様にバインドします。
この更新プログラムには、配列内の null 値のバインドをサポートし、空の配列のバインドを有効にするための機能強化も含まれています。
導入されたバージョン
.NET 10
以前の動作
以前は、構成値が nullされたときに、バインダーは値がまったく存在しないかのように処理するため、バインディングをスキップしていました。 システムは、 null 値と欠損値を区別しませんでした。
さらに、JSON 構成プロバイダーは、構成内の null 値を空の文字列に変換しました。 これにより、これらの値にバインドされたプロパティは、予期される nullではなく、空の文字列を受け取ります。
次の構成ファイル appsettings.json 内容を検討してください。
{
"NullConfiguration": {
"StringProperty": null,
"IntProperty": null,
"Array1": [null, null],
"Array2": []
}
}
対応するバインド コードは次のとおりです。
public class NullConfiguration
{
public NullConfiguration()
{
// Initialize with non-default value to
// ensure binding overrides these values.
StringProperty = "Initial Value";
IntProperty = 123;
}
public string? StringProperty { get; set; }
public int? IntProperty { get; set; }
public string[]? Array1 { get; set; }
public string[]? Array2 { get; set; }
}
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build().GetSection("NullConfiguration");
// Now bind the configuration.
NullConfiguration? result = configuration.Get<NullConfiguration>();
Console.WriteLine($"StringProperty: '{result!.StringProperty}', intProperty: {(result!.IntProperty.HasValue ? result!.IntProperty : "null")}");
Console.WriteLine($"Array1: {(result!.Array1 is null ?
"null" : string.Join(", ", result!.Array1.Select(a => $"'{(a is null ? "null" : a)}'")))}");
Console.WriteLine($"Array2: {(result!.Array2 is null ?
"null" : string.Join(", ", result!.Array2.Select(a => $"'{(a is null ? "null" : a)}'")))}");
アウトプット:
StringProperty: '', intProperty: 123
Array1: '', ''
Array2: null
出力の説明:
-
StringProperty: JSON のnull値が JSON プロバイダーによって空の文字列 ("") に変換され、初期値が上書きされました。 -
IntProperty: プロバイダーがnullを空の文字列に変換したため(123)変更されず、int?として解析できなかったため、元の値は保持されました。 -
Array1: 各null配列要素が空の文字列として扱われたため、2 つの空の文字列を含む配列にバインドされます。 -
Array2: JSON 内の空の配列nullがバインダーによって無視されたため、[]残ります。
新しい動作
.NET 10 以降では、 null 値が配列要素を含む対応するプロパティに適切にバインドされるようになりました。 空の配列でも、無視されるのではなく、正しく認識され、空の配列としてバインドされます。
同じコード サンプルを実行すると、JSON 構成プロバイダーを使用して次の結果が生成されます。
StringProperty: 'null', intProperty: null
Array1: 'null', 'null'
Array2:
Null を許容しない値型
バインダーは、nullを型の既定値 (int) に設定することで、null 非許容値型のプロパティ (bool、default(T)、列挙型など) にもバインドするようになりました。
以前は、JSON 構成プロバイダーを使用して、このようなプロパティに null をバインドすると、次のような InvalidOperationException がスローされました。これは、プロバイダーが null を空の文字列に変換し、空の文字列をターゲット値型に変換できないためです。
Failed to convert configuration value at 'SomeSection:DayOfWeekProperty' to type 'System.DayOfWeek'.
.NET 10 以降では、同じバインドが成功し、プロパティが既定値に設定されます。 たとえば、null プロパティにバインドされたDayOfWeekはDayOfWeek.Sunday (0) になり、null プロパティにバインドされたintは0になります。 例外はスローされません。
メモリ内プロバイダーなど、実際のnull値を格納するプロバイダーは、.NET 10 より前であっても既定値を設定することによって、nullを null 非許容値型プロパティに既にバインドしており、構成ソース ジェネレーターもこの動作と一致します。 この変更により、JSON プロバイダーとリフレクション ベースのバインダーは、その動作と一貫性が保たれます。
破壊的変更の種類
これは動作の 変化です。
変更の理由
以前の動作は混乱を招き、多くの場合、ユーザーの苦情につながりました。 この問題に対処することで、構成バインド プロセスの直感的さと一貫性が向上し、混乱を減らし、動作をユーザーの期待に合わせて調整できるようになりました。
推奨されるアクション
前の動作を希望する場合は、それに応じて構成を調整できます。
- JSON 構成プロバイダーを使用する場合は、
null値を空の文字列 ("") に置き換えて、nullの代わりに空の文字列がバインドされている元の動作を復元します。 -
null値をサポートする他のプロバイダーの場合は、構成からnullエントリを削除して、欠損値が無視され、既存のプロパティ値が変更されない以前の動作をレプリケートします。 - 以前に、
null値が null 非許容値型プロパティにバインドされたときに例外に依存していた場合は、バインダーによってプロパティが既定値に設定されるようになったことに注意してください。 欠損値またはnull値を実際の値と区別するには、プロパティを null 許容にし (int?やDayOfWeek?など)、バインド後にnullを確認するか、構成を明示的に検証します。
影響を受ける API
.NET