Valori nulli conservati nella configurazione

Il componente di associazione della configurazione di .NET recupera i valori di configurazione attraverso i provider di configurazione e tenta di associarli alle proprietà degli oggetti. In precedenza, quando un valore di configurazione era Null, il binder lo ha considerato come se il valore non esistesse affatto e quindi ignorato l'associazione. In altre parole, non distingueva tra i valori null e i valori mancanti. Questo comportamento ha causato confusione significativa per gli utenti che si aspettavano che i valori definiti null in modo esplicito nella configurazione vengano rispettati e associati correttamente.

Inoltre, il provider di configurazione JSON ha convertito null in precedenza i valori nella configurazione in stringhe vuote. Ciò ha contribuito ulteriormente alla confusione, poiché le proprietà associate a questi valori riceveranno una stringa vuota anziché il valore Null previsto.

Questa modifica risolve entrambi i problemi. Il provider di configurazione JSON ora segnala null correttamente i valori senza modificarli e il gestore di associazione considera null i valori come input validi, associandoli come qualsiasi altro valore.

L'aggiornamento include anche miglioramenti per supportare i valori di associazione null all'interno di matrici e abilita l'associazione di matrici vuote.

Versione introdotta

.NET 10

Comportamento precedente

In precedenza, quando un valore di configurazione era null, il binder lo ha considerato come se il valore non esistesse affatto e quindi ignorato l'associazione. Il sistema non distingueva i null valori e i valori mancanti.

Inoltre, il provider di configurazione JSON ha convertito null i valori nella configurazione in stringhe vuote. In questo modo, le proprietà associate a questi valori ricevono una stringa vuota anziché l'oggetto previsto null.

Considerare il contenuto del file appsettings.json di configurazione seguente:

{
    "NullConfiguration": {
        "StringProperty": null,
        "IntProperty": null,
        "Array1": [null, null],
        "Array2": []
    }
}

E il codice di associazione corrispondente:

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)}'")))}");

Risultato:

StringProperty: '', intProperty: 123
Array1: '', ''
Array2: null

Spiegazione dell'output:

  • StringProperty: il null valore in JSON è stato convertito dal provider JSON in una stringa vuota (""), sovrascrivendo il valore iniziale.
  • IntProperty: Rimasto invariato (123) perché il provider ha convertito null in una stringa vuota, che non poteva essere analizzata come int?, quindi è stato mantenuto il valore originale.
  • Array1: associato a una matrice contenente due stringhe vuote perché ogni null elemento della matrice è stato considerato come una stringa vuota.
  • Array2: è rimasto null perché una matrice [] vuota nel codice JSON è stata ignorata dal gestore di associazione.

Nuovo comportamento

A partire da .NET 10, null i valori sono ora associati correttamente alle proprietà corrispondenti, inclusi gli elementi della matrice. Anche le matrici vuote vengono riconosciute correttamente e associate come matrici vuote anziché essere ignorate.

L'esecuzione dello stesso esempio di codice produce i risultati seguenti usando il provider di configurazione JSON:

StringProperty: 'null', intProperty: null
Array1: 'null', 'null'
Array2:

Tipi valore non nullable

Il binder ora associa anche null a proprietà di tipo valore che non ammettono valori null (ad esempio, int, bool o un enum), impostandole al valore predefinito del tipo (default(T)).

In precedenza, con il provider di configurazione JSON, l'associazione di un null a una proprietà di questo tipo generava un'eccezione InvalidOperationException simile alla seguente, perché il provider aveva convertito null in una stringa vuota e una stringa vuota non può essere convertita nel tipo di valore di destinazione:

Failed to convert configuration value at 'SomeSection:DayOfWeekProperty' to type 'System.DayOfWeek'.

A partire da .NET 10, la stessa associazione ha esito positivo e la proprietà viene impostata sul valore predefinito. Ad esempio, un null oggetto associato a una DayOfWeek proprietà restituisce DayOfWeek.Sunday (0) e un null associato a una int proprietà restituisce 0. Non viene generata alcuna eccezione.

I provider che archiviano un valore null reale, ad esempio il provider in memoria, associano già null alle proprietà di tipo valore che non ammettono valori null impostando il valore predefinito, già prima di .NET 10, e anche il generatore di codice sorgente per la configurazione si comporta allo stesso modo. La modifica allinea il provider JSON e il binder basato sulla riflessione a tale comportamento.

Tipo di cambiamento che interrompe la compatibilità

Si tratta di una modifica comportamentale .

Motivo della modifica

Il comportamento precedente era confuso e spesso ha portato a reclami degli utenti. Risolvendo questo problema, il processo di associazione di configurazione è ora più intuitivo e coerente, riducendo la confusione e allineando il comportamento alle aspettative degli utenti.

Se si preferisce il comportamento precedente, è possibile modificare la configurazione di conseguenza:

  • Quando si usa il provider di configurazione JSON, sostituire null i valori con stringhe vuote ("") per ripristinare il comportamento originale, in cui le stringhe vuote vengono associate anziché null.
  • Per altri provider che supportano i valori null, rimuovete le voci null dalla configurazione per replicare il comportamento precedente, in cui i valori mancanti vengono ignorati e i valori delle proprietà esistenti rimangono invariati.
  • Se in precedenza si affidava a un'eccezione quando il valore null veniva associato a una proprietà di tipo valore che non ammette valori null, si noti che il meccanismo di associazione ora imposta invece la proprietà sul valore predefinito. Per distinguere un valore mancante o null da un valore reale, rendere nullable la proprietà (ad esempio, int? o DayOfWeek?) e verificare la presenza di null dopo il binding, oppure convalidare esplicitamente la configurazione.

Le API interessate