Gestire gli aggiornamenti delle dipendenze nel progetto .NET

Completato

Prima o poi sarà necessario eseguire l'aggiornamento a una nuova versione di una libreria, È possibile che una funzione sai contrassegnata come deprecata o che sia disponibile una nuova funzionalità in una versione successiva di un pacchetto in uso.

Tenere presenti queste considerazioni prima di provare ad aggiornare una libreria:

  • Tipo di aggiornamento: che tipo di aggiornamento è disponibile? Si tratta di una piccola correzione di bug? Viene aggiunta una nuova funzionalità necessaria? Il codice esistente non funziona più? È possibile comunicare il tipo di aggiornamento usando un sistema denominato versionamento semantico. Il modo in cui viene espresso il numero di versione della libreria comunica agli sviluppatori il tipo di aggiornamento da gestire.
  • Se il progetto è configurato correttamente: è possibile configurare il progetto .NET in modo da ottenere solo i tipi di aggiornamenti desiderati. Si esegue un aggiornamento solo se è disponibile un tipo specifico di aggiornamento. Si tratta di un approccio consigliato perché consente di evitare sorprese.
  • Problemi di sicurezza: per gestire le dipendenze del progetto nel tempo è importante essere consapevoli dei problemi che potrebbero verificarsi. I problemi sorgono, ad esempio, quando vengono rilevate vulnerabilità. Nel migliore dei casi, vengono rilasciate patch che sarà possibile scaricare. Lo strumento .NET Core consente di eseguire un controllo sulle librerie per determinare se sono presenti pacchetti che devono essere aggiornati. Consente anche di eseguire l'azione appropriata per risolvere un problema.

Usare il versionamento semantico

È presente uno standard di settore, chiamato controllo delle versioni semantico, che consente di esprimere il tipo di modifica che uno sviluppatore introduce in una libreria. Il controllo delle versioni semantico assicura che un pacchetto abbia un numero di versione e che il numero di versione sia suddiviso nelle sezioni seguenti:

  • Versione principale: il numero più a sinistra. Ad esempio, è il 1 in 1.0.0. Una modifica a questo numero indica che è possibile prevedere modifiche che causano "interruzioni" nel codice. e potrebbe essere necessario riscrivere parte del codice.
  • Versione secondaria: il numero intermedio. Ad esempio, è il 2 in 1.2.0. Una modifica a questo numero indica che sono state aggiunte funzionalità. Il codice dovrebbe continuare a funzionare. È in genere sicuro accettare l'aggiornamento.
  • Versione patch: il numero più a destra. Ad esempio, è il 3 in 1.2.3. Una modifica a questo numero indica che è stata applicata una modifica che corregge una parte del codice non funzionante. È in genere sicuro accettare l'aggiornamento.

Questa tabella illustra come cambia il numero di versione per ogni tipo di versione:

Tipo Effetti
Versione principale 1.0.0 modifiche a 2.0.0
Versione secondaria 1.1.1 modifiche a 1.2.0
Versione della patch 1.0.1 modifiche a 1.0.2

Molte aziende e sviluppatori usano questo sistema. Se si prevede di pubblicare pacchetti ed eseguirne il push nel registro NuGet, è consigliabile seguire il versionamento semantico. Anche se si scaricano solo pacchetti dal registro NuGet, è probabile che questi pacchetti seguano il versionamento semantico.

Le modifiche apportate a un pacchetto possono comportare rischi, incluso quello che un bug possa danneggiare l'azienda. Alcuni rischi possono costringere a riscrivere parte del codice. La riscrittura del codice richiede tempo e costi.

Approccio all'aggiornamento

Gli sviluppatori .NET possono indicare a .NET il comportamento di aggiornamento desiderato. Considerare i rischi posti dall'aggiornamento. Ecco alcuni approcci:

  • Versione principale: si consente l'aggiornamento alla versione principale più recente non appena sarà disponibile. Si accetta il fatto che potrebbe essere necessario modificare il codice sviluppato.
  • Versione secondaria: l'aggiunta di una nuova funzionalità non è un problema, ma lo è l'interruzione del codice.
  • Versione della patch: si accettano gli aggiornamenti corrispondenti a correzioni di bug.

Se si gestisce un progetto .NET nuovo o di dimensioni minori, ci si può permettere una maggiore libertà nel definire la strategia di aggiornamento. Ad esempio, è sempre possibile eseguire l'aggiornamento alla versione più recente. Per i progetti più complessi esistono altre sfumature da valutare, che verranno illustrate in un modulo successivo.

In generale, più limitata è la dipendenza che si sta aggiornando, minore sarà il numero di dipendenze e maggiore sarà la probabilità che il processo di aggiornamento sia semplice.

Configurare il file di progetto per l'aggiornamento

Nell'aggiungere una o più dipendenze, configurare il file di progetto in modo da ottenere un comportamento prevedibile durante il ripristino, la compilazione o l'esecuzione del progetto. È possibile comunicare l'approccio che si vuole adottare per un pacchetto. NuGet è basato sui concetti di intervallo di versioni e versione mobile.

Gli intervalli di versioni sono una notazione speciale che è possibile usare per indicare un intervallo specifico di versioni da risolvere.

Notazione Regola applicata Descrizione
1.0 x >= 1.0 Versione minima, inclusiva
(1.0,) x > 1.0 Versione minima, esclusiva
[1.0] x == 1.0 Corrispondenza esatta della versione
(,1.0] x ≤ 1.0 Versione massima, inclusiva
(,1.0) x < 1.0 Versione massima, esclusiva
[1.0,2.0] 1.0 ≤ x ≤ 2.0 Intervallo esatto, inclusivo
(1.0,2.0) 1.0 < x < 2.0 Intervallo esatto, esclusivo
[1.0,2.0) 1.0 ≤ x < 2.0 Versione minima inclusiva e massima esclusiva mista
(1.0) non valido non valido

NuGet supporta anche l'uso di una notazione di versione mobile per le parti principale, secondaria, patch e suffisso di versione non definitiva. Questa notazione è costituita da un asterisco (*). La specifica della versione 6.0.*, ad esempio, indica di usare la versione 6.0.x più recente. In un altro esempio, 4.* indica di usare la versione 4.x più recente. L'uso di una versione mobile riduce le modifiche a un file di progetto, mantenendolo aggiornato alla versione più recente di una dipendenza.

Nota

È consigliabile installare una versione specifica invece di usare una delle notazioni mobili. L'installazione di una versione specifica assicura che le compilazioni siano ripetibili, a meno che non si richieda esplicitamente un aggiornamento a una dipendenza.

Quando si usa una versione mobile, NuGet risolve l'ultima versione di un pacchetto corrispondente al modello di versione. Nell'esempio seguente, 6.0.* ottiene la versione più recente di un pacchetto che inizia con 6.0. Questa versione è la 6.0.1.

Diagramma che mostra la scelta dell'ultima versione quando viene richiesta una versione mobile.

Ecco alcuni esempi che è possibile configurare per la versione principale, secondaria o della patch:

<!-- Accepts any version 6.1 and later. -->
<PackageReference Include="ExamplePackage" Version="6.1" />

<!-- Accepts any 6.x.y version. -->
<PackageReference Include="ExamplePackage" Version="6.*" />
<PackageReference Include="ExamplePackage" Version="[6,7)" />

<!-- Accepts any later version, but not including 4.1.3. Could be
     used to guarantee a dependency with a specific bug fix. -->
<PackageReference Include="ExamplePackage" Version="(4.1.3,)" />

<!-- Accepts any version earlier than 5.x, which might be used to prevent pulling in a later
     version of a dependency that changed its interface. However, we don't recommend this form because determining the earliest version can be difficult. -->
<PackageReference Include="ExamplePackage" Version="(,5.0)" />

<!-- Accepts any 1.x or 2.x version, but not 0.x or 3.x and later. -->
<PackageReference Include="ExamplePackage" Version="[1,3)" />

<!-- Accepts 1.3.2 up to 1.4.x, but not 1.5 and later. -->
<PackageReference Include="ExamplePackage" Version="[1.3.2,1.5)" />

Trovare e aggiornare i pacchetti obsoleti

Il comando dotnet list package --outdated elenca i pacchetti obsoleti. Questo comando può essere utile per scoprire quando sono disponibili versioni più recenti dei pacchetti. Di seguito è riportato un output tipico del comando:

Top-level Package      Requested   Resolved   Latest
> Humanizer            2.7.*       2.7.9      2.8.26

Ecco i significati dei nomi delle colonne nell'output:

  • Requested: Versione o intervallo di versioni specificato.
  • Resolved: Versione effettiva scaricata per il progetto corrispondente alla versione specificata.
  • Latest: versione più recente disponibile per l'aggiornamento da NuGet.

Il flusso di lavoro consigliato prevede l'esecuzione dei comandi seguenti, in questo ordine:

  1. Eseguire dotnet list package --outdated. Questo comando elenca tutti i pacchetti obsoleti. Fornisce informazioni nelle colonne Requested, Resolved e Latest.
  2. Eseguire dotnet add package <package name>. Se eseguito, questo comando prova a eseguire l'aggiornamento all'ultima versione. È facoltativamente possibile passare --version=<version number/range>.