Partage via


Téléchargements de fichiers ASP.NET Core Blazor

Note

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Avertissement

Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la Stratégie de prise en charge de .NET et .NET Core. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

Cet article explique comment télécharger des fichiers dans Blazor applications.

Téléchargements de fichiers

Cet article couvre des approches pour les scénarios suivants, où un fichier ne doit pas être ouvert par un navigateur, mais téléchargé et enregistré sur le client :

Lors du téléchargement de fichiers à partir d’une origine différente de celle de l’application, les considérations de partage des ressources cross-origin (CORS, Cross-Origin Resource Sharing) s’appliquent. Pour plus d’informations, consultez la section Partage des ressources cross-origin (CORS, Cross-Origin Resource Sharing).

Considérations relatives à la sécurité

Soyez prudent lorsque vous fournissez aux utilisateurs la possibilité de télécharger des fichiers à partir d’un serveur. Les cyberattaquants peuvent effectuer des attaques par déni de service (DoS) ou des attaques d’exploitation d’API, ou tenter de compromettre des réseaux et des serveurs en utilisant d’autres moyens.

Les étapes de sécurité qui réduisent la probabilité d’une attaque réussie sont les suivantes :

  • Téléchargez des fichiers à partir d’une zone de téléchargement de fichier dédiée sur le serveur, de préférence à partir d’un lecteur non système. L’utilisation d’un emplacement dédié facilite la prise de restrictions de sécurité sur les fichiers téléchargeables. Désactivez les autorisations d’exécution sur la zone de téléchargement de fichier.
  • Les contrôles de sécurité côté client sont faciles à contourner par des utilisateurs malveillants. De plus, effectuez toujours des vérifications de sécurité côté client sur le serveur.
  • Ne recevez pas d’utilisateurs ou d’autres sources non approuvées des fichiers que vous rendez ensuite disponibles en téléchargement immédiat sans effectuer de vérifications de sécurité sur ces fichiers. Pour plus d’informations, consultez Charger des fichiers dans ASP.NET Core.

Télécharger à partir d’un flux

Cette section s’applique aux fichiers dont la taille maximale est généralement de 250 Mo.

L’approche recommandée pour télécharger des fichiers relativement petits (< 250 Mo) consiste à diffuser en streaming du contenu de fichier dans une mémoire tampon de données binaires brutes sur le client avec l’interopérabilité JavaScript (JS). Cette approche est efficace pour les composants qui adoptent un mode de rendu interactif, mais pas pour les composants qui adoptent le rendu statique côté serveur (SSR statique).

L’approche recommandée pour télécharger des fichiers relativement petits (< 250 Mo) consiste à diffuser en streaming du contenu de fichier dans une mémoire tampon de données binaires brutes sur le client avec l’interopérabilité JavaScript (JS).

Avertissement

L’approche décrite dans cette section lit le contenu du fichier dans un JS ArrayBuffer. Cette approche charge l’ensemble du fichier dans la mémoire du client, ce qui peut nuire aux performances. Pour télécharger des fichiers relativement volumineux (>= 250 Mo), nous vous recommandons de suivre les instructions fournies dans la section Télécharger à partir d’une URL.

La fonction downloadFileFromStreamJS suivante :

  • Lit le flux fourni dans un ArrayBuffer.
  • Crée un Blob pour encapsuler le ArrayBuffer.
  • Crée une URL d’objet pour servir d’adresse de téléchargement du fichier.
  • Crée un HTMLAnchorElement (<a> élement).
  • Attribue le nom (fileName) et l’URL (url) du fichier pour le téléchargement.
  • Déclenche le téléchargement en activant un événement click sur l’élément d’ancrage.
  • Supprime l’élément d’ancrage.
  • Révoque l’URL d’objet (url) en appelant URL.revokeObjectURL. Il s’agit d’une étape importante pour garantir qu’il n’y a pas de fuite de mémoire sur le client.
<script>
  window.downloadFileFromStream = async (fileName, contentStreamReference) => {
    const arrayBuffer = await contentStreamReference.arrayBuffer();
    const blob = new Blob([arrayBuffer]);
    const url = URL.createObjectURL(blob);
    const anchorElement = document.createElement('a');
    anchorElement.href = url;
    anchorElement.download = fileName ?? '';
    anchorElement.click();
    anchorElement.remove();
    URL.revokeObjectURL(url);
  }
</script>

Remarque

Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.

Le composant suivant :

  • Utilise l’interopérabilité de streaming d’octets native pour garantir un transfert efficace du fichier vers le client.
  • A une méthode nommée GetFileStream pour récupérer un Stream pour le fichier qui est téléchargé sur les clients. D’autres approches permettent de récupérer un fichier à partir du stockage ou de générer de façon dynamique un fichier dans du code C#. Pour cette démonstration, l’application crée un fichier de données aléatoires de 50 Ko à partir d’un nouveau tableau d’octets (new byte[]). Les octets sont wrappés avec un MemoryStream pour servir de fichier binaire généré dynamiquement de l’exemple.
  • La méthode DownloadFileFromStream :
    • Récupère le Stream partir de GetFileStream.
    • Spécifie un nom de fichier lorsque le fichier est enregistré sur la machine de l’utilisateur. L’exemple suivant nomme le fichier quote.txt.
    • Envelopper le Stream dans un DotNetStreamReference, ce qui permet de diffuser en streaming les données du fichier vers le client.
    • Appelle la fonction JS downloadFileFromStream pour accepter les données sur le client.

FileDownload1.razor:

@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS

<PageTitle>File Download 1</PageTitle>

<h1>File Download Example 1</h1>

<button @onclick="DownloadFileFromStream">
    Download File From Stream
</button>

@code {
    private Stream GetFileStream()
    {
        var randomBinaryData = new byte[50 * 1024];
        var fileStream = new MemoryStream(randomBinaryData);

        return fileStream;
    }

    private async Task DownloadFileFromStream()
    {
        var fileStream = GetFileStream();
        var fileName = "log.bin";

        using var streamRef = new DotNetStreamReference(stream: fileStream);

        await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
    }
}
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS

<PageTitle>File Download 1</PageTitle>

<h1>File Download Example 1</h1>

<button @onclick="DownloadFileFromStream">
    Download File From Stream
</button>

@code {
    private Stream GetFileStream()
    {
        var randomBinaryData = new byte[50 * 1024];
        var fileStream = new MemoryStream(randomBinaryData);

        return fileStream;
    }

    private async Task DownloadFileFromStream()
    {
        var fileStream = GetFileStream();
        var fileName = "log.bin";

        using var streamRef = new DotNetStreamReference(stream: fileStream);

        await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
    }
}
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS

<h1>File Download Example</h1>

<button @onclick="DownloadFileFromStream">
    Download File From Stream
</button>

@code {
    private Stream GetFileStream()
    {
        var randomBinaryData = new byte[50 * 1024];
        var fileStream = new MemoryStream(randomBinaryData);

        return fileStream;
    }

    private async Task DownloadFileFromStream()
    {
        var fileStream = GetFileStream();
        var fileName = "log.bin";

        using var streamRef = new DotNetStreamReference(stream: fileStream);

        await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
    }
}
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS

<h1>File Download Example</h1>

<button @onclick="DownloadFileFromStream">
    Download File From Stream
</button>

@code {
    private Stream GetFileStream()
    {
        var randomBinaryData = new byte[50 * 1024];
        var fileStream = new MemoryStream(randomBinaryData);

        return fileStream;
    }

    private async Task DownloadFileFromStream()
    {
        var fileStream = GetFileStream();
        var fileName = "log.bin";

        using var streamRef = new DotNetStreamReference(stream: fileStream);

        await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
    }
}

Pour un composant d’une application d’un côté serveur qui doit retourner un Stream pour un fichier physique, le composant peut appeler File.OpenRead, comme le montre l’exemple suivant :

private Stream GetFileStream() => File.OpenRead(@"{PATH}");

Dans l’exemple précédent, l’espace réservé {PATH} est le chemin du fichier. Le préfixe @ indique que la chaîne est un littéral de chaîne verbatim, ce qui permet d’utiliser des barres obliques inverses (\) dans un chemin du système d’exploitation Windows et des guillemets doubles incorporés ("") pour un guillemet simple dans le chemin. Vous pouvez également éviter le littéral de chaîne (@) et utiliser l’une des approches suivantes :

  • Utilisez des barres obliques inverses dans une séquence d’échappement (\\) et des guillemets (\") dans une séquence d’échappement.
  • Utilisez des barres obliques (/) dans le chemin : elles sont prises en charge sur toutes les plateformes dans les applications ASP.NET Core, et des guillemets dans une séquence d’échappement (\").

Télécharger à partir d’une URL

Cette section s’applique aux fichiers relativement volumineux, d’une taille généralement supérieure ou égale à 250 Mo.

L’approche recommandée pour le téléchargement de fichiers relativement volumineux (> = 250 Mo) avec des composants ou des fichiers rendus de manière interactive de toute taille pour des composants rendus de manière statique consiste à utiliser JS pour déclencher un élément d’ancrage avec le nom et l’URL du fichier.

L’approche recommandée pour le téléchargement de fichiers relativement volumineux (> = 250 Mo) consiste à utiliser JS pour déclencher un élément d’ancrage avec le nom et l’URL du fichier.

L’exemple de cette section utilise un fichier de téléchargement nommé quote.txt, qui est placé dans un dossier nommé files à la racine web de l’application (dossier wwwroot). Le dossier files est utilisé uniquement à des fins de démonstration. Vous pouvez organiser les fichiers téléchargeables dans n’importe quelle disposition de dossier au sein de la racine web (dossier wwwroot) de votre choix, ce qui inclut de traiter les fichiers directement à partir du dossier wwwroot.

wwwroot/files/quote.txt:

When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"

- General Ravon (Guy Siner, http://guysiner.com/)
  Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00vd5g2)
  Copyright 1975 BBC (https://www.bbc.co.uk/)
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"

- General Ravon (Guy Siner, http://guysiner.com/)
  Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00vd5g2)
  Copyright 1975 BBC (https://www.bbc.co.uk/)
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"

- General Ravon (Guy Siner, http://guysiner.com/)
  Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00vd5g2)
  Copyright 1975 BBC (https://www.bbc.co.uk/)
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"

- General Ravon (Guy Siner, http://guysiner.com/)
  Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00vd5g2)
  Copyright 1975 BBC (https://www.bbc.co.uk/)

La fonction triggerFileDownloadJS suivante :

  • Crée un HTMLAnchorElement (<a> élement).
  • Attribue le nom (fileName) et l’URL (url) du fichier pour le téléchargement.
  • Déclenche le téléchargement en activant un événement click sur l’élément d’ancrage.
  • Supprime l’élément d’ancrage.
<script>
  window.triggerFileDownload = (fileName, url) => {
    const anchorElement = document.createElement('a');
    anchorElement.href = url;
    anchorElement.download = fileName ?? '';
    anchorElement.click();
    anchorElement.remove();
  }
</script>

Remarque

Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.

L’exemple de composant suivant télécharge le fichier à partir de la même origine que celle utilisée par l’application. Si le téléchargement de fichier est tenté à partir d’une autre origine, configurez le partage des ressources cross-origin (CORS, Cross-Origin Resource Sharing). Pour plus d’informations, consultez la section Partage des ressources cross-origin (CORS).

FileDownload2.razor:

@page "/file-download-2"
@inject IJSRuntime JS

<PageTitle>File Download 2</PageTitle>

<h1>File Download Example 2</h1>

<button @onclick="DownloadFileFromURL">
    Download File From URL
</button>

@code {
    private async Task DownloadFileFromURL()
    {
        var fileName = "quote.txt";
        var fileURL = "/files/quote.txt";
        await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
    }
}

Pour les composants interactifs, le bouton de l’exemple précédent appelle le gestionnaire DownloadFileFromURL pour appeler la fonction JavaScript triggerFileDownload (JS).

Si le composant adopte le rendu statique côté serveur (SSR statique), ajoutez un gestionnaire d’événements pour le bouton (addEventListener (documentation MDN)) pour appeler triggerFileDownload en suivant les instructions de JavaScript Blazor ASP.NET Core avec rendu statique côté serveur (SSR statique).

@page "/file-download-2"
@inject IJSRuntime JS

<PageTitle>File Download 2</PageTitle>

<h1>File Download Example 2</h1>

<button @onclick="DownloadFileFromURL">
    Download File From URL
</button>

@code {
    private async Task DownloadFileFromURL()
    {
        var fileName = "quote.txt";
        var fileURL = "/files/quote.txt";
        await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
    }
}

Pour les composants interactifs, le bouton de l’exemple précédent appelle le gestionnaire DownloadFileFromURL pour appeler la fonction JavaScript triggerFileDownload (JS).

Si le composant adopte le rendu statique côté serveur (SSR statique), ajoutez un gestionnaire d’événements pour le bouton (addEventListener (documentation MDN)) pour appeler triggerFileDownload en suivant les instructions de JavaScript Blazor ASP.NET Core avec rendu statique côté serveur (SSR statique).

@page "/file-download-2"
@inject IJSRuntime JS

<h1>File Download Example 2</h1>

<button @onclick="DownloadFileFromURL">
    Download File From URL
</button>

@code {
    private async Task DownloadFileFromURL()
    {
        var fileName = "quote.txt";
        var fileURL = "https://localhost:5001/files/quote.txt";
        await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
    }
}

Modifiez le port dans l’exemple précédent pour qu’il corresponde au port de développement localhost de votre environnement.

@page "/file-download-2"
@inject IJSRuntime JS

<h1>File Download Example 2</h1>

<button @onclick="DownloadFileFromURL">
    Download File From URL
</button>

@code {
    private async Task DownloadFileFromURL()
    {
        var fileName = "quote.txt";
        var fileURL = "https://localhost:5001/files/quote.txt";
        await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
    }
}

Modifiez le port dans l’exemple précédent pour qu’il corresponde au port de développement localhost de votre environnement.

CORS (Cross Origin Resource Sharing)

Si vous n’effectuez pas d’étapes supplémentaires pour activer le partage de ressources cross-origin (CORS) pour les fichiers qui n’ont pas la même origine que l’application, le téléchargement de fichiers ne réussira pas les vérifications CORS effectuées par le navigateur.

Pour plus d’informations sur le partage CORS avec des applications ASP.NET Core et d’autres produits et services Microsoft qui hébergent des fichiers à télécharger, consultez les ressources suivantes :

Ressources supplémentaires