Learn

Accedere a feed NuGet privati: nuget restore o dotnet restore?

3 Luglio 2020 - 6 minuti di lettura

Di recente, per questioni lavorative, ho imparato molto sulla questione della gestione di dipendenze per un progetto .NET.

Mi sono infatti imbattuto nel problema del restore di dipendenze e pacchetti attraverso il comando dotnet restore. Comando che internamente fa uso di NuGet per eseguire l’operazione di restore.

Apparentemente non cambia nulla nell’usare dotnet restore piuttosto che nuget restore.

Se lavori con Windows, a quanto pare non avrai alcun problema (almeno non per il comando nuget).

Se invece usi un Mac allora ti consiglio di proseguire la lettura, vedrai quanto è profonda la tana del Bianconiglio!

.NET Core e NuGet

dotnet restore è uno dei tanti comandi dell’interfaccia della riga di comando (CLI) di .NET Core (1). Questa CLI mette a disposizione una catena di strumenti multipiattaforma per lo sviluppo, la compilazione, l’esecuzione e la pubblicazione di applicazioni .NET Core.

Il comando dotnet restore usa NuGet (2), package manager per .NET, per ripristinare le dipendenze e gli strumenti specifici del progetto definiti nel file di progetto.
Per ripristinare le dipendenze, NuGet necessita dei feed in cui si trovano i pacchetti. I feed vengono forniti in genere tramite il file di configurazione nuget.config. Quando viene installato il .NET Core SDK, viene fornito un file di configurazione predefinito. Per specificare feed aggiuntivi, effettuare una delle operazioni seguenti:

  • Creare il proprio file NuGet. config nella directory del progetto.
  • Usare i comandi dotnet nuget comandi come dotnet nuget add source.

Per ulteriori informazioni sul comando dotnet restore, si rimanda alla documentazione ufficiale (3).

‘nuget restore’ vs ‘dotnet restore’, quale usare?

Tra i due comandi apparentemente non c’è differenza. Entrambi servono per scaricare dipendenze e pacchetti utili per il progetto, come spiegato anche in un post su Stack Overflow (4).

Apparentemente.

Il comando nuget restore usa la configurazione presa dal file ~/.config/NuGet/NuGet.config mentre dotnet restore usa la configurazione in ~/.nuget/NuGet/NuGet.config.

“Come faccio a saperlo?”, vi starete domandando. Qualche indizio lo si trova consultando questa issue (5) ma, se come me, volete avere la conferma dal vostro computer potete fare così:

  • per dotnet
    • modificate il file ~/.config/NuGet/NuGet.config rendendolo invalido, ad esempio aggiungendo in un punto qualunque la stringa >?>?>E>F?>SFS>FE?>;
    • eseguite dotnet restore; noterete che il comando non darà errori;
    • ora modificate il file ~/.nuget/NuGet/NuGet.config rendendolo invalido;
    • eseguite nuovamente dotnet restore; noterete che qualcosa non va.
  • per nuget
    • eseguite nuget restore;
    • osservate l’output del comando. Nei log finali viene chiaramente scritto quali configurazioni sono usate:
      NuGet Config files used:
      /Users/<user>/proj/repos/<project-name>/NuGet.Config
      /Users/<user>/.config/NuGet/NuGet.Config
    • Se si provasse ad invalidare il file in .nuget, l’esecuzione del comando non fallirebbe.

Detto questo, quale comando devo lanciare per eseguire il restore dei pacchetti?

Potete usare quello che preferite: come spiegato all’inizio quando viene eseguito dotnet run a sua volta eseguirà dotnet restore. Anche se si volesse eseguire direttamente nuget restore, nella cache di pacchetti locali i pacchetti ci saranno già tutti e quindi NuGet non avrà bisogno di accedere al feed remoto privato perciò il restore funzionerà.

Personalmente propendo per dotnet restore.

Ci sono altre differenze?

nuget è interactive, nel senso che ti chiede la password in caso in cui non trova alcuna configurazione, mentre dotnet non lo è, nemmeno esplicitando il flag –interactive. Provate per credere (come ho fatto io). Per ulteriori dettagli sulla logica di ricerca delle credenziali da parte dei due comandi, vi rimando alla documentazione (6).

Configurare le credenziali per ‘dotnet restore’

Modificare il file ~/.nuget/NuGet/NuGet.config inserendo il seguente contenuto (per ragioni di privacy ho omesso il valore di alcuni campi):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <packageSources>
  <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
  <add key="webplu-devops" value="<package-url>/nuget/v3/index.json />
 </packageSources>
 <packageSourceCredentials>
  <your-package>
   <add key="Username" value="anything" />
   <add key="ClearTextPassword" value="<clear-text-password>" />
   <add key="ValidAuthenticationTypes" value="basic" />
  </your-package>
 </packageSourceCredentials>
</configuration>

Non clear text password

E se non volessi inserire una password?

Purtroppo pare non essere possibile con dotnet restore. Funziona invece egregiamente con nuget restore.

Applicando la seguente procedura:

  • eseguire il comando
    nuget sources add -name webplu-devops -source <package-url>/nuget/v3/index.json -username anything -password <password>
  • copiare il contenuto dal file ~/.config/NuGet/NuGet.config nel file ~/.nuget/NuGet/NuGet.config;
  • eseguire dotnet restore.

Ho ottenuto l’errore “unable to load the service index for source […] Password decryption is not supported on .NET Core for this platform. […]Encryption is not supported on non-Windows platforms.”

A volte il restore ha funzionato ma questo potrebbe essere dovuto a qualche sorta di cache delle credenziali.

Caveat ‘packageSource key’ per ‘dotnet restore’

La configurazione usata da dotnet restore comprende sia i file nuget.config del progetto, sia la configurazione globale ~/.nuget.

Nell’ambito di un progetto, la configurazione che mi aspetterei di poter usare è la seguente combinazione: nel progetto specificare la packageSource e specificare poi le credenziali nella configurazione sul proprio computer, in modo che le password non vengano committate nel repository del progetto.

Questo si può fare a patto che il nome (key) della package source corrisponda con il nome del tag dentro packageSourceCredentials.

Attenzione perché se nel progetto c’è una source con nome xxxx e nella propria configurazione locale c’è la stessa source con nome yyyy e le credenziali si riferiscono a yyyy, nonostante abbiano lo stesso url, il comando di restore fallirà.

Essendo però la chiave della source un nome arbitrario, è necessario che ci sia una convenzione con il team o che la source non venga committata nel progetto e che ognuno la setti in autonomia nella cartella ~/.nuget.

Nota: per nuget restore il match viene fatto per url quindi se hai nel progetto una certa source con nome xxxx ma nella tua configurazione locale in .config hai una source yyyy con stesso url, userà le credenziali corrette.

Note per fare le prove

Per verificare che il restore stia funzionando veramente, bisogna cancellare un pacchetto (con autenticazione) dalla cartella ~/.nuget/packages.

Talvolta però questo non basta, pare per un problema di cache delle credenziali. In caso si volesse fare pulizia della cache, eseguire il comando dotnet nuget locals all -c.

Versioni di dotnet e nuget

Al momento non ho approfondito relazioni ed implicazioni. le versioni usate per fare le prove sono

$ nuget
NuGet Version: 4.7.0.5148
$ dotnet --info
.NET Core SDK (reflecting any global.json):
Version:   3.1.101
Commit:    b377529961

Ambiente di esecuzione:

  • Nome S.O.: Mac OS X
  • Versione S.O.: 10.15
  • Piattaforma S.O.: Darwin
  • RID: osx.10.15-x64

Ok, ‘dotnet restore’ non funziona su Mac, cosa devo fare?

Provate a seguire i seguenti passaggi:

  • Il comando fallisce per errori di tipo 401? NO: purtroppo questa guida non ti aiuterà. SI: vai avanti.
  • Leggi il contenuto dell’errore. Dovrebbe fornire l’indirizzo del feed per il quale non riesce ad autenticarsi, un file json. Appuntatelo da qualche parte. Il messaggio potrebbe essere qualcosa di simile: /usr/local/share/dotnet/sdk/3.1.101/NuGet.targets(123,5): error : Unable to load the service index for source <package>/nuget/v3/index.json.
  • Apri il file `~/.nuget/nuget/nuget.config`; al suo interno dovrebbe esserci una entry nel tag packageSources con key=valore arbitrario e value=l'indirizzo che ti sei appuntato prima. Se tale entry non compare, aggiungila.
  • Nella sezione packageSourceCredentials dovrebbe esserci un tag che si chiama come la key del punto precedente. Se non c’è aggiungila, con le credenziali (plain text) come nell’esempio di questa guida.
  • Verifica che le credenziali siano ancora valide:
    • qualora volessi chiedere a qualcuno di provarle ti consiglierei la seguente procedura:
      • non fargli cambiare nessuna configurazione;
      • chiedigli di cancellare la cache nuget come spiegato nel paragrafo Note per fare le prove;
      • fargli eseguire dotnet restore e vedere che tutto funzioni;
      • cancellare nuovamente la cache;
      • inserire le tue credenziali;
      • eseguire dotnet restore e vedere che tutto funzioni.
  • Se le credenziali sono valide e il comando restituisce ancora l’errore 401, puoi controllare se nella cartella del progetto c’è un altro nuget.config file e in caso affermativo assicurarsi che la chiave della source corrisponda al tag delle credenziali.
  • Non dovessero corrisponde, allineale (probabilmente modificando la tua locale perché immagino che l’altro file sia committato nel progetto e rischi di rompere le credenziali agli altri).
  • Dovessero corrispondere: purtroppo non sono in grado di aiutarti. se scopri qualcosa di diverso integriamo questa guida!
Articolo scritto da