Aller au contenu principal

30-3 Préparation du téléversement et lecture du contenu du fichier

Maintenant que nous avons un endroit central où stocker les fichiers, on peut entamer le téléversement de fichiers.

La première étape est d'avoir un champ de formulaire pour ajouter un fichier.

Blazor offre un composant <InputFile> pour afficher un input de type file

Ajouter un champ InputFile au formulaire

Dans le composant pour créer un nouvel événement (New), ajoutez un nouveau champ InputFile (ici, il est directement dans le haut du formulaire):

Snowfall.Web.ClientAdmin/Pages/Evenements/New.razor
<!-- ... -->

<div class="col-lg-6">
<EditForm Model="evenementDto" OnValidSubmit="@CreerEvenement">
<DataAnnotationsValidator />

<div class="mb-3">
<label for="image" class="form-label">@LocalizerEvenementDto["Image"]</label>
<InputFile id="image" class="form-control" accept=".jpg, .jpeg, .png" />
</div>

<!-- ... -->
info

Il est possible de spécifier les types de fichiers acceptés via accept=.

Comme on veut une image, on indique les extensions d'images standards.

Détecter les changements au InputFile

Lorsqu'une image sera sélectionnée, on procédera immédiatement à l'envoi du fichier pour stockage.

La stratégie est différente de si on avait un formulaire rendu serveur un peu plus classique comme MVC où on pourrait faire l'envoi du fichier en même temps que le reste du formulaire.

Ici, si on voulait faire cela, il faudrait convertir le contenu de l'image en base64, assigner ce contenu à une propriété du DTO et poursuivre la sauvegarde côté serveur. Cela est fonctionnel, mais rend la requête très grosse en plus de ne pas être très flexible dans le cas où plusieurs fichiers seraient à téléverser en même temps.

Une approche fréquente est de simplement téléverser le fichier et si jamais il n'est pas utilisé (parce que le formulaire n'a pas été soumis), un processus de "ménage" passe en arrière-plan quelques fois par jour ou par semaine pour faire le ménage des fichiers inutilisé. Cependant, on ne s'occupera pas trop de cet aspect pour l'instant.

Pour détecter les changements, on vient lier la propriété onchange à une fonction de la composante dans la portion @code:

Snowfall.Web.ClientAdmin/Pages/Evenements/New.razor
<!-- ... -->

<div class="mb-3">
<label for="image" class="form-label">Image</label>
<InputFile id="image" class="form-control" accept=".jpg, .jpeg, .png" OnChange="@OnInputFileChange" />
</div>

<!-- ... -->

private async Task OnInputFileChange(InputFileChangeEventArgs e)
{
// Un fichier a été sélectionné à partir du champ image
}

Lire le contenu du fichier et préparer la requête

Lorsqu'on envoie un fichier, on l'envoie en format binaire. Pour ce faire, il est nécessaire de lire le contenu du fichier.

Pour l'envoi du fichier en format binaire, on utilisera un type d'encodage particulier: multipart/form-data

info

Le format multipart/form-data est un type d'encodage utilisé pour transmettre des données de formulaire, y compris des fichiers binaires, à travers des requêtes HTTP. Il est souvent utilisé pour le téléchargement de fichiers dans les applications Web.

Pour envoyer des données multipart/form-data à l'aide de HttpClient, vous pouvez utiliser la classe MultipartFormDataContent et ajouter des instances de ByteArrayContent, StringContent ou StreamContent pour représenter les données des champs de formulaire.

Dans le cas qui nous occupe, on utilise StreamContent qui correspond à la sortie de la lecture du fichier.

  1. On créera dans un premier temps deux variables: une pour spécifier la taille maximale des fichiers acceptés et une deuxième qui servira à valider que le fichier est prêt à être envoyé vers le serveur.
    Snowfall.Web.ClientAdmin/Pages/Evenements/New.razor
    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
    // La taille maximale acceptés pour les fichiers (5 Mo)
    long tailleFichierMax = 1024 * 1024 * 5;

    // Variable permettant de contrôler si on procède ou non au téléversement
    bool estPretPourUpload = false;
    }

  2. Un objet de type MultipartFormDataContent est créé pour concenir le contenu du fichier.
    Snowfall.Web.ClientAdmin/Pages/Evenements/New.razor
    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
    // La taille maximale acceptés pour les fichiers (5 Mo)
    long tailleFichierMax = 1024 * 1024 * 5;

    // Variable permettant de contrôler si on procède ou non au téléversement
    bool estPretPourUpload = false;

    // On crée le contenu du "formulaire" (body) envoyé
    using var content = new MultipartFormDataContent();
    }

  3. Finalement, on fait la lecture du fichier et on l'assigne à la variable content de type MultipartFormDataContent.
    Snowfall.Web.ClientAdmin/Pages/Evenements/New.razor
    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
    // La taille maximale acceptés pour les fichiers (5 Mo)
    long tailleFichierMax = 1024 * 1024 * 5;

    // Variable permettant de contrôler si on procède ou non au téléversement
    var estPretPourUpload = false;

    // On crée le contenu du "formulaire" (body) envoyé
    using var content = new MultipartFormDataContent();
    try
    {
    // Le fichier est récupéré à partir de l'événement
    IBrowserFile file = e.File;

    // Le contenu du fichier est récupéré, avec comme limite tailleFichierMax
    var fileContent =
    new StreamContent(file.OpenReadStream(tailleFichierMax));

    // On assigne le bon type de fichier au contenu
    fileContent.Headers.ContentType =
    new MediaTypeHeaderValue(file.ContentType);

    // Le body de la requête qui sera envoyée
    content.Add(
    content: fileContent,
    name: "\"file\"",
    fileName: file.Name);

    // Aucune erreur, on peut procéder à l'upload
    estPretPourUpload = true;
    }
    catch (Exception ex)
    {
    ToastService.Notify(new(ToastType.Danger, "Impossible de lire le fichier. Vérifiez qu'il correspond bien à la taille maximale."));
    }
    }

Cela devrait nous permettre de lire le contenu du fichier, mais pas encore de l'envoyer. C'est pourquoi on assigne à la variable estPretPourUpload la valeur de true.

Pour envoyer le fichier et le stocker sur le serveur, un point de terminaison (action) d'API sera nécéssaire.