Eseguire processi di sistema in una Web API C#
Alcuni contesti applicativi richiedono l’esecuzione di processi di sistema o console application per assolvere alle funzioni richieste dall’utente, e talvolta è necessario impacchettare tali funzionalità all’interno di una REST API.
Ad esempio potremmo essere di fronte ad un revamping di funzionalità fornite da console application o da software on-premise, o potrebbero esserci contesti operativi in cui si vogliono utilizzare programmi di terze parti distribuite direttamente in formato eseguibile.
Qualsiasi sia il vostro contesto operativo, è molto semplice inglobare tali software all’interno di una API, utilizzando le classi messe a disposizione dal namespace System.Diagnostics
e redirigendo i flussi standard di input, output ed errore.
L’esempio che ho pubblicato su Github è ispirato da un post di qualche settimana fa di Marco Giannini sul suo blog Marco’s Box, che spiegava come utilizzare fortune per stampare nella CLI Linux delle piccole perle di saggezza, personalizzabile anche con dizionari custom.
I punti di interesse di questo progetto di esempio sono due: come utilizzare un processo di sistema (in questo caso fortune
con dizionari personalizzati in un container Debian) e come aggiungere applicazioni nel container Docker che ospita l’applicativo.
Eseguire un processo di sistema all’interno di una Web API C#
Esattamente come nei contesti più classici (console application e applicazioni desktop), per eseguire un processo di sistema è sufficiente istanziare un nuovo oggetto System.Diagnostics.ProcessStartInfo
in cui inserire tutti i parametri del processo da lanciare, e su cui configurare il redirect dei flussi standard di input, output ed errore:
// https://github.com/Defkon1/pikaquote/blob/main/Pikaquote/Pikaquote.Core/Services/QuotesService.cs try { var psi = new ProcessStartInfo() { FileName = "/usr/games/fortune", Arguments = argument, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true }; using (var process = Process.Start(psi)) { errors = await process.StandardError.ReadToEndAsync(); results = await process.StandardOutput.ReadToEndAsync(); } return new QuoteDto() { CreatedAt = DateTime.UtcNow, Message = results, UsedDictionary = supportedDictionary?.Name ?? _supportedDictionaries.First(d => string.IsNullOrEmpty(d.Slug)).Name }; } catch (System.ComponentModel.Win32Exception exception) { _logger.LogError(exception, message: errors); } catch (Exception exception) { _logger.LogError(exception, "Unknown error"); }
In questo caso il processo di fortune è installato in /usr/games/fortune
e prende come argomento l’eventuale dizionario personalizzato da utilizzare; il risultato (la perla di saggezza) viene recuperata redirigendo lo standard output, mentre gli eventuali errori vengono catturati direttamente dallo standard error.
Il risultato viene impacchettato in DTO di risposta e restituito al controller. Semplice e veloce.
Aggiungere applicazioni di sistema nel container Docker Web API
L’immagine di default utilizzata da ASP.NET Core (nel caso mostrato basata su Debian) non include fortune
out-of-the-box, per cui ho modificato il DockerFile
per fare nell’ordine:
- aggiungere
contrib
all’elenco sorgenti - installare i pacchett
fortune-mod
,wget
edos2unix
- scaricare da PasteBin i dizionari personalizzati citati nell’articolo di Marco Giannini con
wget
- convertire i line break dei file scaricati da formato DOS a formato Unix con
dos2unix
- trasformare i file di testo scaricati in dizionari per
fortune
constrfile
(incluso nel pacchettofortune-mod
)
Tutte queste operazioni sono facilmente eseguite mediante comandi RUN
direttamente nel DockerFile sull’immagine base:
RUN sed -i'.bak' 's/$/ contrib/' /etc/apt/sources.list RUN apt-get update && apt-get install -y fortune-mod RUN apt-get install -y wget RUN apt-get install -y dos2unix RUN wget --no-check-certificate https://pastebin.com/raw/p296KDcE -O /usr/games/fortune-devops RUN dos2unix /usr/games/fortune-devops RUN strfile /usr/games/fortune-devops
In questo modo il container risulta essere già pronto con tutti gli strumenti necessari all’invocazione del processo dall’interno dell’API.
Il codice sorgente completo dell’esempio è disponibile su Github con licenza MIT: https://github.com/Defkon1/pikaquote/ (la stellina è sempre gradita)
Have fun!