in Architettura Software, Informatica

Restituire File da Web API C# con PhysicalFileResult

Quando si sviluppa una Web API in C#, capita spesso di dover servire file direttamente dal server. Che si tratti di documenti, immagini o download generici, ASP.NET Core offre un metodo robusto e diretto per gestire questo scenario: il PhysicalFileResult. Questo tipo di risultato consente di inviare un file situato su un percorso fisico del server direttamente al client che ha effettuato la richiesta.

Come Funziona PhysicalFileResult

Il PhysicalFileResult è una classe derivata da FileResult che restituisce un file da un percorso assoluto o relativo sul file system del server. A differenza di altri metodi per la gestione dei file, come la restituzione di un byte[] o uno Stream, PhysicalFileResult è ottimizzato per servire file di grandi dimensioni in modo efficiente, gestendo direttamente il flusso di dati dal disco al client.

Per utilizzare PhysicalFileResult all’interno di un controller di una Web API, si deve ereditare da ControllerBase (o Controller). Questo fornisce accesso a metodi helper come PhysicalFile(), che semplificano il processo.

Componenti Chiave

Per una corretta implementazione, ci sono alcuni elementi fondamentali da considerare:

  • Percorso del File: È necessario fornire il percorso completo del file sul server.
  • Tipo MIME: Specificare il tipo MIME (Multipurpose Internet Mail Extensions) appropriato è cruciale. Questo informa il browser del client su come interpretare il file (ad esempio, application/pdf per un PDF, image/jpeg per un’immagine JPEG). Se il tipo MIME non è corretto, il browser potrebbe non visualizzare o gestire il file come previsto.
  • Nome del File per il Download (Opzionale): Si può suggerire un nome per il download tramite il parametro fileDownloadName. Questo nome verrà utilizzato dal browser del client quando il file viene scaricato, sovrascrivendo l’eventuale nome del file nel percorso URL.

Esempio Pratico

Si immagini di voler esporre un endpoint che permetta il download di un file PDF chiamato “rapporto.pdf” che risiede in una cartella “Documenti” sul server.

Un controller potrebbe implementare la logica nel seguente modo:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Hosting; // Necessario per IWebHostEnvironment
using System.IO;

[ApiController]
[Route("api/[controller]")]
public class DocumentiController : ControllerBase
{
    private readonly IWebHostEnvironment _hostingEnvironment;

    public DocumentiController(IWebHostEnvironment hostingEnvironment)
    {
        _hostingEnvironment = hostingEnvironment;
    }

    /// <summary>
    /// Permette il download di un file PDF specifico.
    /// </summary>
    /// <param name="nomeFile">Il nome del file PDF da scaricare.</param>
    /// <returns>Il file PDF richiesto o un errore 404 se non trovato.</returns>
    [HttpGet("scarica/{nomeFile}")]
    public IActionResult ScaricaDocumento(string nomeFile)
    {
        // Costruisce il percorso completo del file
        // Si assume che i file siano nella sottocartella 'Documenti' del progetto.
        var percorsoFile = Path.Combine(_hostingEnvironment.ContentRootPath, "Documenti", nomeFile);

        // Verifica che il file esista prima di tentare di servirlo
        if (!System.IO.File.Exists(percorsoFile))
        {
            return NotFound($"Il documento '{nomeFile}' non è stato trovato.");
        }

        // Definisce il tipo MIME per i file PDF
        const string tipoMime = "application/pdf";

        // Suggerisce un nome per il download al client
        string nomePerDownload = nomeFile;

        // Restituisce il file fisico
        return PhysicalFile(percorsoFile, tipoMime, nomePerDownload);
    }
}

In questo esempio, il controller DocumentiController utilizza l’interfaccia IWebHostEnvironment per accedere al percorso radice del contenuto dell’applicazione (ContentRootPath), costruendo dinamicamente il percorso verso il file. Prima di restituire il file, viene effettuato un controllo per assicurarsi che esista. Infine, il metodo PhysicalFile() viene invocato con il percorso del file, il tipo MIME (application/pdf) e il nome suggerito per il download.

Considerazioni sulla Sicurezza

È fondamentale prestare attenzione alla sicurezza quando si serve file direttamente dal file system. Il path traversal è una vulnerabilità comune, in cui un attaccante potrebbe manipolare il percorso del file per accedere a risorse non autorizzate (ad esempio, usando ../). È altamente raccomandato:

  • Validare l’input dell’utente: Non fidarsi mai ciecamente del nome del file fornito dal client. Pulire e convalidare stringhe per prevenire inclusioni di caratteri potenzialmente dannosi.
  • Limita l’accesso: Mantenere i file da servire in una directory specifica e controllata, non direttamente accessibile tramite URL pubblici se non attraverso la Web API.

L’utilizzo di PhysicalFileResult offre un modo efficiente e chiaro per gestire la restituzione di file statici o generati dinamicamente da una Web API in ASP.NET Core, mantenendo un buon controllo sul processo di consegna dei file.