in Architettura Software, Informatica

L’era delle File-Based Apps in C#: Scripting e Prototipazione senza attriti

Con l’avvento di .NET 10, il panorama dello sviluppo in C# ha accolto una novità tanto attesa quanto rivoluzionaria: le File-Based Apps. Se fino a ieri la creazione di un piccolo tool o di uno script richiedeva la generazione di un’intera struttura di progetto (.csproj), oggi la barriera tra l’idea e l’esecuzione è stata praticamente abbattuta.

In questo articolo esploreremo cosa sono le app basate su file, come funzionano “sotto il cofano” e perché dovresti integrarle nel tuo workflow professionale.

Cosa sono le File-Based Apps?

In termini semplici, una File-Based App è un programma C# contenuto in un singolo file sorgente (.cs) che può essere compilato ed eseguito direttamente, senza la necessità di un file di progetto formale.

Questa funzionalità evolve il concetto di Top-Level Statements (introdotto con C# 9), eliminando la “cerimonia” burocratica delle cartelle e dei file di configurazione per tutti quegli scenari in cui la complessità di una soluzione enterprise sarebbe superflua.

Come funzionano: la magia del .NET SDK

Quando eseguiamo un comando come dotnet my-script.cs, il .NET SDK non si limita a interpretare il codice. Ecco cosa accade nel background:

  1. Analisi delle Direttive: L’SDK scansiona la parte superiore del file alla ricerca di direttive speciali (precedute da #:).
  2. Generazione Implicita: Viene creato un progetto temporaneo in memoria o in una cartelle di cache.
  3. Risoluzione delle Dipendenze: Se sono presenti pacchetti NuGet o riferimenti ad altri progetti, l’SDK li scarica e li collega automaticamente.
  4. Compilazione ed Esecuzione: Il codice viene compilato (spesso in modalità Native AOT di default per massimizzare le performance) e lanciato.

Anatomia di una File-Based App

La potenza di questo approccio risiede nelle nuove direttive che permettono di mantenere il file “auto-esplicativo”. Ecco i pilastri fondamentali:

  • #:package <Nome>: Per includere dipendenze NuGet (es. #:package Newtonsoft.Json).
  • #:property <Chiave>=<Valore>: Per impostare proprietà MSBuild (es. #:property TargetFramework=net10.0).
  • #:sdk <Nome>: Per specificare l’SDK di riferimento, come quello Web per micro-servizi rapidi.
  • Supporto Shebang (#!): Su sistemi Unix/Linux, permette di rendere il file eseguibile direttamente dal terminale come un normale script Bash o Python.
#!/usr/bin/env dotnet
#:package Spectre.Console@*

using Spectre.Console;

AnsiConsole.Markup("[bold green]Hello World[/] dalle File-Based Apps!");

Perché sono utili nel workflow professionale?

Nonostante la loro semplicità, queste applicazioni non sono “giocattoli”. Ecco i principali vantaggi:

  1. Scripting di Sistema: C# diventa un serio concorrente di Python e Bash per l’automazione DevOps, con il vantaggio della tipizzazione forte e delle performance di .NET.
  2. Prototipazione Rapida: Testare un algoritmo o una libreria NuGet diventa immediato. Basta un file e una tastiera.
  3. Apprendimento e Didattica: Ideali per chi si avvicina al linguaggio, permettendo di focalizzarsi sulla logica senza perdersi nella gestione delle soluzioni di Visual Studio.
  4. Utility Standalone: Grazie alla compilazione Native AOT predefinita, è possibile generare eseguibili leggeri, veloci e privi di dipendenze esterne in pochi secondi.

Le File-Based Apps non sostituiscono i progetti tradizionali per applicazioni complesse e multi-livello, ma riempiono un vuoto fondamentale nell’ecosistema C#: quello della agilità. Rendono .NET uno strumento versatile non solo per grandi architetture, ma anche per le piccole necessità quotidiane di ogni sviluppatore.

Oltre lo Scripting: Il confronto con Python e PowerShell

Molti sviluppatori si chiedono: “Perché usare C# per piccoli script quando esistono Python o PowerShell?”. La risposta risiede in tre pilastri:

  • Type Safety: Avere il controllo dei tipi di C# in uno script riduce drasticamente gli errori a runtime rispetto a Python.
  • Performance: Grazie a Native AOT, una File-Based App può essere fino a 10-20 volte più veloce di uno script interpretato.
  • Ecosistema Unificato: Puoi riutilizzare le tue librerie aziendali e la tua conoscenza di LINQ e della libreria standard .NET senza dover cambiare contesto mentale.

Caso d’uso: Uno script di Cleanup automatico

Immaginiamo di dover creare un tool che pulisca i log vecchi e invii un report JSON. In passato avresti creato un progetto Console; oggi basta questo singolo file CleanUp.cs:

#:package System.Text.Json
#:property PublishAot=true

using System.IO;
using System.Linq;
using System.Text.Json;

var logPath = "./logs";
var threshold = DateTime.Now.AddDays(-7);

var filesToDelete = Directory.GetFiles(logPath)
    .Select(f => new FileInfo(f))
    .Where(f => f.LastWriteTime < threshold)
    .ToList();

foreach (var file in filesToDelete)
{
    file.Delete();
    Console.WriteLine($"Eliminato: {file.Name}");
}

// Genera un piccolo report finale
var report = new { TotalDeleted = filesToDelete.Count, Date = DateTime.Now };
File.WriteAllText("report.json", JsonSerializer.Serialize(report));

Best Practices e Limitazioni

Sebbene la tentazione di usare un unico file per tutto sia forte, è bene ricordare alcuni punti chiave:

  • Modularità: Se il file supera le 500-600 righe, probabilmente è il momento di passare a un progetto .csproj standard.
  • Caching: La prima esecuzione potrebbe essere leggermente più lenta a causa del ripristino dei pacchetti NuGet. Le esecuzioni successive utilizzeranno la cache locale per una velocità istantanea.
  • Deployment: Se devi distribuire lo script su server senza .NET installato, usa la direttiva PublishAot=true per generare un binario self-contained.