Negli ultimi anni c’è stato un ritorno di fiamma per i tool da riga di comando. Siamo passati da applicazioni con icone colorate in 3d a tornare ad avere una moltitudine di tool che si utilizzano da riga di comando.
Questi tool non sono solo strumenti per sviluppatori, ma spesso vengono anche rilasciati ad utenti finali.
Vediamo come crearne uno in modo relativamente semplice con .NET Core e qualche libreria esterna a supporto.
Ovviamente, essendo scritta in .NET Core, può essere utilizzata cross-platform su Linux e Mac.
Prerequisiti
Quello che serve per iniziare sono poche cose:
- .NET Core 3.1 installato e funzionante sulla vostra macchina di sviluppo
- Visual Studio Code o Visual Studio 2019
I primi passi
Ovviamente, volendo realizzare un tool da riga di comando, il progetto da cui partire è una normalissima Console Application.
State solo attenti a selezionare il progetto .NET Core della Console invece di quello .NET normale.
Se invece volete creare il progetto da riga di comando (da Mac o Linux), potete usare questo:
dotnet new console
Adesso dovete aggiungere due pacchetti NuGet realizzati direttamente da Microsoft che sono ancora in fase “Experimental” ma sembrano molto promettenti.
Quindi da “Dependencies” del progetto, cliccate su “Manage NuGet Packages” e cercate questi due pacchetti. Visto che sono ancora in fase di sviluppo, ricordatevi di spuntare il check “Include prerelease”.
Se anche in questo caso siete amanti della riga di comando, potete fare la stessa operazione con i seguenti due comandi:
dotnet add package System.CommandLine.Experimental -v 0.3.0-*
dotnet add package System.CommandLine.DragonFruit -v 0.3.0-*
Potete trovare maggiori informazioni su questi pacchetti NuGet direttamente sul repository ufficiale di Microsoft su GitHub.
Ok, adesso siamo pronti per iniziare a creare il nostro tool.
Aggiungere il primo comando
Ovviamente si inizia sempre con un Hello World, altrimenti non sarebbe un test da vero developer.
In questo caso è veramente semplice perchè una volta aggiunte le dipendenze ci vengono messi a disposizione una serie di oggetti che possiamo andare ad usare nel nostro programma per arricchire il nostro tool.
Gli oggetti fondamentali di questa libreria sono il RootCommand e i Command.
In questa porzione di codice (tranquilli, trovate tutto sul mio repository GitHub) sono andato a inserire il minimo indispensabile per far partire la console application.
Adesso per far partire la vostra console avete due opzioni.
La prima è aggiungere dentro Visual Studio dalle proprietà del progetto -> Debug -> Application Arguments il valore “greeting” e lanciare una nuova istanza di debug.
L’altra è direttamente da riga di comando.
Una volta che avete compilato il progetto, lanciate una nuova instanza del vostro terminal preferito e posizionatevi nella cartella “Debug/netcoreapp3.1”. A questo punto lanciate il comando:
dotnet ConsoleHero.dll greeting
Dovrebbe partirvi la vostra applicazione e mostrare il seguente messaggio.
Nel caso non passiate nessun parametro alla vostra applicazione, vedrete apparire la classica schermata con la lista dei comandi e in automatico troverete anche un comando denominato “–version”, che se usato, vi fa vedere la versione dell’assembly che state utilizzando.
Un comando molto utile in fase di rilascio in produzione per capire la versione attuale che stanno utilizzando gli utenti.
Aggiungiamo dei parametri
Come ogni tool da riga di comando che si rispetti, ha bisogno di parametri in ingresso.
Anche in questo caso ci vengono incontro le librerie che abbiamo aggiunto in precedenza.
Per questo esempio ho creato una nuova funzione chiamata “helloWorldWithName” che anche in questo caso ha come tipo di ritorno un Command.
A differenza del metodo precedente però, una volta creato il command, bisogna andare ad aggiungere una Option con il metodo AddOption dell’oggetto Command.
Io nell’esempio l’ho inizializzato direttamente durante l’aggiunta, ma ovviamente potete creare l’oggetto Option prima di chiamare il metodo AddOption.
Nel codice se vedete sono andato a creare un parametro di nome “–name” che ha pure come valore breve (è una best practices molto usata) il valore “-n”.
Inoltre ho dichiarato che deve essere solamente uno e quindi non posso mettere più parametri “–name”.
A questo punto la nuova chiamata al nostro tool sarà:
dotnet ConsoleHero.dll greeting –name Emanuele
o
dotnet ConsoleHero.dll greeting -n Emanuele
Parametri di Switch
Un altro caso molto comune in questi tool è quello di poter utilizzare dei parametri che vengono chiamati di Switch, ovvero dei parametri che non hanno bisogno di nessun valore ma basta che siano presenti.
Metto qua solo la porzione del codice del nuovo Command, in quanto il resto è praticamente tutto invariato.
Come potete vedere il secondo parametro del CommandHandler è di tipo bool e serve a capire se è presente o meno il parametro “german”.
Ovviamente potete utilizzarlo in modo diverso rispetto a un operatore ternario per visualizzare una stringa nella console, ma è il concetto che conta.
Io ad esempio li utilizzo per fare delle console con delle “WhatIf”, cioè simulare tutto lo script con i parametri reali, ma senza fare il “commit” delle modifiche al database o chiamare i servizi API di produzione.
Ma ci sono tanti altri scenari in cui possono essere utili.
Visualizzare dati formattati
Ultima cosa che ci tengo a condivere è la possibilità di renderizzare dei dati non solo in forma testuale, ma aggiungere una tabella in modo da visualizzare più facilmente informazioni come elenco.
Per fare questo dobbiamo aggiungere un po’ di codice alla funzione Main per inizializzare due oggeti che andremo a utilizzare nel Command vero e proprio.
Istanziate e assegnate queste due proprietà, possiamo andare ad aggiungere nella “Main” il comando “richList” che andrà appunto a renderizzare una tabella nella vostra console.
Il codice è abbastanza intuitivo ma vi spiego i punti salienti.
E’ buona norma creare un modello dei dati che dovete andare a renderizzare. Io in questo caso ho creato un modello denominato “Post” con tre proprietà.
Poi ho usato il servizio jsonplaceholder per ottenere dei dati di esempio invece di crearli io manualmente nella funzione e soprattutto per rendere l’esempio più simile alla realtà.
Ovviamente il codice per chiamare il servizio in modo asincrono sarà diverso e magari avrete una parte di autenticazione ma era per rendere l’idea di come sia possibile realizzarlo.
A questo punto poi dovete andarvi a creare dentro all’handler del vostro comando un oggetto TableView e passare alla proprietà Items gli elementi che avete ricevuto in risposta dai vostri servizi.
Nell’esempio, volutamente, ho omesso di renderizzare la proprietà Body del modello per far vedere che si possono aggiungere solo le colonne che ci interessano alla tabella.
La chiamata da fare e il risultato ottenuto sono come nell’immagine qua sotto.
Conclusioni
In questo articolo ho provato a raccogliere i punti chiave per avere le basi di un tool CLI based cross-platform. Se volete approfondire l’argomento in modo più dettagliato, potete andare sul repository GitHub ufficiale delle librerie che ho utilizzato e scoprire altre features.
Se volete invece giocare il codice sorgente della soluzione che ho usato in questo articolo, potete trovarlo qua.
More from Strumenti
OBS vs Streamlabs: quale scegliere e perchè
Una delle domande che mi viene fatta più di frequente è: perchè usi Streamlabs invece di OBS? La risposta è molto …
Fare debug da Visual Studio con i browser in incognito
Di default, quando facciamo debug di applicazioni web, Visual Studio lancia una nuova finestra del browser che utilizza, ovviamente, cache, …
I migliori 5 JavaScript editor online
Ad ogni developer che si rispetti piace avere il proprio ambiente di sviluppo bello e configurato sulla propria macchina. Questo …