Se vi siete imbattuti in questo articolo è probabile che vi siate imbattuti in un problema piuttosto comune legato all'utilizzo del comando dotnet ef di Entity Framework Core all'interno di un progetto .NET Core su Visual Studio... o per meglio dire tentato utilizzo, visto che la riga di comando restituisce il seguente errore:
No executable found matching command "dotnet-ef"
Questa problematica è piuttosto fastidiosa, anche perché il framework non fornisce nessuna indicazione per poterla risolvere e diventa quindi difficile risalire alle cause del mancato funzionamento del comando. Questo articolo è stato scritto proprio con l'intento di fare luce sull'argomento e suggerire alcune possibili soluzioni per risolvere l'anomalia.
Il Problema
Prima di dedicarci alla risoluzione è opportuno fare alcune considerazioni generali allo scopo di comprendere bene il contesto in cui si verifica questo errore e sgombrare il campo da possibili dubbi, false piste e ipotesi infondate:
- Cominciamo dalla variabile di ambiente PATH, che ha il compito di indicare al sistema operativo le directory all'interno delle quali cercare i programmi che vogliamo eseguire da prompt dei comandi: l'esperienza ci porta a pensare che quando il sistema non trova un eseguibile la causa è molto spesso da ricondurre a questa variabile, o per meglio dire alle cartelle che essa (non) contiene. Effettivamente la variabile PATH è molto spesso collegata a problematiche legate all'utilizzo di Visual Studio, visto che il programma è solitamente piuttosto restio a includere gli eseguibili di terze parti e i tool dedicati che egli stesso utilizza nelle ultime versioni (node, npm, il transpiler TypeScript e così via). Sfortunatamente, non è questo il caso: la variabile PATH e il suo contenuto non hanno niente a che spartire con il comando dotnet-ef o con la capacità del framework di trovarlo/eseguirlo o meno. Il problema risiede altrove, quindi scartiamo questa possibilità e andiamo oltre.
- Per utilizzare il comando dotnet ef da PowerShell e da CLI è necessario aver scaricato e installato i seguenti pacchetti NuGet: Microsoft.EntityFrameworkCore.Tools e Microsoft.EntityFrameworkCore.Tools.DotNet. Se non lo avete fatto, è del tutto normale che il comando dotnet-ef non sia disponibile e il sistema restituisca l'errore di cui sopra.
- Il comando dotnet ef va necessariamente eseguito all'interno della directory principale del progetto che vogliamo configurare. Il motivo è presto detto: il comando effettua una scansione dei file di configurazione contenuti nella directory di esecuzione (project.json oppure <projectName>.csproj, a seconda della versione di .NET Core utilizzata dal progetto), aspettandosi di trovare al loro interno un riferimento esplicito alle librerie di tooling di cui al punto precedente: se non le trova, non avrà modo di funzionare, e il sistema restituirà l'errore di cui sopra. Questo ci porta finalmente a comprendere il reale significato dell'errore che stiamo cercando di risolvere: stiamo chiedendo al sistema di utilizzare il comando ef, ma il file di configurazione del progetto non contiene una tooling library che sia in grado di poterlo eseguire.
- Il riferimento esplicito di cui sopra non viene inserito automaticamente da Visual Studio all'interno del nostro file di configurazione di progetto, neppure quando le librerie vengono regolarmente installate tramite NuGet. Questa singola cosa è, nella maggior parte dei casi, la causa principale del verificarsi del nostro errore.
Ora che abbiamo compreso il contesto, le circostanze e le probabili cause dell'errore, possiamo dedicarci ad analizzare le possibili soluzioni.
La Soluzione
La prima cosa da fare è, ovviamente, assicurarsi di aver installato correttamente i pacchetti NuGet Microsoft.EntityFrameworkCore.Tools e Microsoft.EntityFrameworkCore.Tools.DotNete di trovarsi ad eseguire il comando dotnet ef nella cartella principale del progetto. Subito dopo, è opportuno aprire manualmente il file <projectName>.csproj con un qualsiasi editor di testo, e controllare la presenza dei seguenti riferimenti all'interno di un elemento <ItemGroup> :
1 2 3 4 |
<ItemGroup> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" /> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /> </ItemGroup> |
Ovviamente il valore dell'attributo Version può cambiare a seconda della versione installata.
Nel caso in cui il vostro progetto sia basato su .NET Core 1.x, la presenza dei medesimi riferimenti andrà controllata all'interno del file project.json:
1 2 3 4 |
"tools": { "Microsoft.EntityFrameworkCore.Tools": "1.0.0" "Microsoft.EntityFrameworkCore.Tools.DotNet": "1.0.0" } |
Se questi riferimenti non sono presenti, cosa molto probabile se state leggendo questo articolo, avete appena trovato la causa del vostro problema: per risolverlo, non vi resta che aggiungerli manualmente. Nell'improbabile eventualità in cui questo provochi qualche conflitto tra i vari pacchetti NuGet installati, potete provare a risolvere il problema eseguendo il comando dotnet update, avendo cura anche in questo caso di lanciarlo dalla cartella principale del progetto.
Resta da chiarire come mai, come anticipato nel paragrafo precedente, Visual Studio non inserisca automaticamente questi riferimenti al momento di installare i pacchetti NuGet ad essi relativi, lasciando allo sviluppatore l'onere di provvedere. Questo singolare comportamento, oggi come oggi piuttosto incomprensibile, poteva avere un barlume di senso nei progetti basati su .NET Core 1.x, quando il file di progetto project.json era modificabile direttamente tramite la GUI di Visual Studio: con il passaggio a .NET Core 2, e il ritorno al file di progetto in formato .csproj, l'aggiunta manuale dei tooling packages è diventata decisamente più scomoda, oltre ad essere clamorosamente meno intuitiva.
Non resta che sperare che il team che si occupa dello sviluppo di Visual Studio ne prenda atto e risolva il problema con un automatismo che aggiunga i riferimenti necessari al momento dell'installazione dei NuGet packages di cui sopra, sollevando lo sviluppatore dalla necessità di doverlo fare manualmente: del resto, che senso avrebbe scaricarli se non per utilizzare i relativi comandi?
Per il momento è tutto: ci auguriamo sinceramente che questo articolo possa aiutare altri sviluppatori .NET a risolvere il problema.