Partager via


Inclusion d’une option de chargement de fichier lors de l’ajout d’un nouvel enregistrement (VB)

par Scott Mitchell

Télécharger le PDF

Ce tutoriel montre comment créer une interface web qui permet à l’utilisateur d’entrer des données texte et de charger des fichiers binaires. Pour illustrer les options disponibles pour stocker des données binaires, un fichier est enregistré dans la base de données tandis que l’autre est stocké dans le système de fichiers.

Introduction

Dans les deux tutoriels précédents, nous avons exploré les techniques de stockage des données binaires associées au modèle de données de l’application, examiné comment utiliser le contrôle FileUpload pour envoyer des fichiers du client au serveur web et vu comment présenter ces données binaires dans un contrôle Web de données. Toutefois, nous n’avons pas encore parlé de la façon d’associer des données chargées au modèle de données.

Dans ce tutoriel, nous allons créer une page web pour ajouter une nouvelle catégorie. En plus des zones de texte pour le nom et la description de la catégorie, cette page doit inclure deux contrôles FileUpload pour l’image de la nouvelle catégorie et l’autre pour la brochure. L’image chargée est stockée directement dans la colonne s du Picture nouvel enregistrement, tandis que la brochure est enregistrée dans le ~/Brochures dossier avec le chemin d’accès au fichier enregistré dans la nouvelle colonne s d’enregistrement BrochurePath .

Avant de créer cette page web, nous devons mettre à jour l’architecture. La CategoriesTableAdapter requête s main ne récupère pas la Picture colonne. Par conséquent, la méthode générée automatiquement Insert a uniquement des entrées pour les CategoryNamechamps , Descriptionet BrochurePath . Par conséquent, nous devons créer une méthode supplémentaire dans tableAdapter qui invite les quatre Categories champs. La CategoriesBLL classe de la couche logique métier doit également être mise à jour.

Étape 1 : Ajout d’uneInsertWithPictureméthode auCategoriesTableAdapter

Lorsque nous avons créé le CategoriesTableAdapter retour dans le didacticiel Création d’une couche d’accès aux données, nous l’avons configuré pour générer INSERTautomatiquement des instructions , UPDATEet DELETE en fonction de la requête main. En outre, nous avons demandé à TableAdapter d’utiliser l’approche DB Direct, qui a créé les méthodes Insert, Updateet Delete. Ces méthodes exécutent les instructions , UPDATEet DELETE générées INSERTautomatiquement et, par conséquent, acceptent les paramètres d’entrée en fonction des colonnes retournées par la requête main. Dans le tutoriel Chargement de fichiers, nous avons augmenté la CategoriesTableAdapter requête s main pour utiliser la BrochurePath colonne.

Étant donné que la CategoriesTableAdapter requête s main ne fait pas référence à la Picture colonne, nous ne pouvons ni ajouter un nouvel enregistrement ni mettre à jour un enregistrement existant avec une valeur pour la Picture colonne. Pour capturer ces informations, nous pouvons soit créer une nouvelle méthode dans tableAdapter qui est utilisée spécifiquement pour insérer un enregistrement avec des données binaires, soit personnaliser l’instruction générée automatiquement INSERT . Le problème avec la personnalisation de l’instruction générée automatiquement INSERT est que nous risquons de voir nos personnalisations remplacées par l’Assistant. Par exemple, imaginez que nous avons personnalisé l’instruction pour inclure l’utilisation INSERT de la Picture colonne. Cela met à jour la méthode TableAdapter s Insert pour inclure un paramètre d’entrée supplémentaire pour les données binaires de l’image de catégorie. Nous pourrions ensuite créer une méthode dans la couche logique métier pour utiliser cette méthode DAL et appeler cette méthode BLL via la couche de présentation, et tout fonctionnerait à merveille. Autrement dit, jusqu’à la prochaine fois que nous avons configuré TableAdapter via l’Assistant Configuration de TableAdapter. Dès que l’Assistant est terminé, nos personnalisations de l’instruction INSERT sont remplacées, la Insert méthode revient à son ancienne forme et notre code ne sera plus compilé !

Notes

Cette gêne n’est pas un problème lors de l’utilisation de procédures stockées au lieu d’instructions SQL ad hoc. Un prochain tutoriel explorera l’utilisation de procédures stockées au lieu d’instructions SQL ad hoc dans la couche d’accès aux données.

Pour éviter ce casse-tête potentiel, plutôt que de personnaliser les instructions SQL générées automatiquement, créez une méthode pour tableAdapter. Cette méthode, nommée InsertWithPicture, accepte les valeurs pour les CategoryNamecolonnes , Description, BrochurePathet Picture et exécute une INSERT instruction qui stocke les quatre valeurs dans un nouvel enregistrement.

Ouvrez le DataSet typé et, à partir du Designer, cliquez avec le bouton droit sur l’en-tête CategoriesTableAdapter s et choisissez Ajouter une requête dans le menu contextuel. Cela lance l’Assistant Configuration de requête TableAdapter, qui commence par nous demander comment la requête TableAdapter doit accéder à la base de données. Choisissez Utiliser des instructions SQL, puis cliquez sur Suivant. L’étape suivante invite à générer le type de requête. Étant donné que nous créons une requête pour ajouter un nouvel enregistrement à la Categories table, choisissez INSERT, puis cliquez sur Suivant.

Sélectionnez l’option INSERT

Figure 1 : Sélectionnez l’option INSERT (Cliquez pour afficher l’image en taille réelle)

Nous devons maintenant spécifier l’instruction INSERT SQL. L’Assistant suggère automatiquement une INSERT instruction correspondant à la requête de main TableAdapter. Dans ce cas, il s’agit d’une INSERT instruction qui insère les CategoryNamevaleurs , Descriptionet .BrochurePath Mettez à jour l’instruction afin que la Picture colonne soit incluse avec un @Picture paramètre, comme suit :

INSERT INTO [Categories] 
    ([CategoryName], [Description], [BrochurePath], [Picture]) 
VALUES 
    (@CategoryName, @Description, @BrochurePath, @Picture)

Le dernier écran de l’Assistant nous demande de nommer la nouvelle méthode TableAdapter. Entrez InsertWithPicture et cliquez sur Terminer.

Nommez la nouvelle méthode TableAdapter InsertWithPicture

Figure 2 : Nommez la nouvelle méthode InsertWithPicture TableAdapter (cliquez pour afficher l’image en taille réelle)

Étape 2 : Mise à jour de la couche logique métier

Étant donné que la couche de présentation doit uniquement s’interfacer avec la couche logique métier au lieu de la contourner pour accéder directement à la couche d’accès aux données, nous devons créer une méthode BLL qui appelle la méthode DAL que nous venons de créer (InsertWithPicture). Pour ce didacticiel, créez une méthode dans la CategoriesBLL classe nommée InsertWithPicture qui accepte comme entrée trois String s et un Byte tableau. Les String paramètres d’entrée concernent le nom de catégorie, la description et le chemin du fichier de brochure, tandis que le Byte tableau correspond au contenu binaire de l’image de catégorie. Comme le montre le code suivant, cette méthode BLL appelle la méthode DAL correspondante :

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Insert, False)> _
Public Sub InsertWithPicture(categoryName As String, description As String, _
    brochurePath As String, picture() As Byte)
    
    Adapter.InsertWithPicture(categoryName, description, brochurePath, picture)
End Sub

Notes

Vérifiez que vous avez enregistré le DataSet typé avant d’ajouter la InsertWithPicture méthode à la BLL. Étant donné que le CategoriesTableAdapter code de classe est généré automatiquement en fonction du DataSet typé, si vous n’enregistrez pas d’abord vos modifications apportées au DataSet typé, la Adapter propriété ne connaîtra pas la InsertWithPicture méthode.

Étape 3 : Répertorier les catégories existantes et leurs données binaires

Dans ce tutoriel, nous allons créer une page qui permet à un utilisateur final d’ajouter une nouvelle catégorie au système, en fournissant une image et une brochure pour la nouvelle catégorie. Dans le tutoriel précédent , nous avons utilisé un GridView avec templateField et ImageField pour afficher le nom, la description et l’image de chaque catégorie, ainsi qu’un lien pour télécharger sa brochure. Répliquer cette fonctionnalité pour ce didacticiel, en créant une page qui répertorie toutes les catégories existantes et permet d’en créer de nouvelles.

Commencez par ouvrir la DisplayOrDownload.aspx page à partir du BinaryData dossier. Accédez à la vue Source et copiez la syntaxe déclarative de GridView et ObjectDataSource, en la collant dans l’élément <asp:Content> dans UploadInDetailsView.aspx. En outre, n’oubliez pas de copier la GenerateBrochureLink méthode de la classe code-behind de DisplayOrDownload.aspx vers UploadInDetailsView.aspx.

Copiez et collez la syntaxe déclarative de DisplayOrDownload.aspx vers UploadInDetailsView.aspx

Figure 3 : Copier et coller la syntaxe déclarative de DisplayOrDownload.aspx à UploadInDetailsView.aspx (Cliquer pour afficher l’image en taille réelle)

Après avoir copié la syntaxe déclarative et GenerateBrochureLink la méthode sur la UploadInDetailsView.aspx page, affichez la page via un navigateur pour vous assurer que tout a été copié correctement. Vous devriez voir un GridView répertoriant les huit catégories qui incluent un lien pour télécharger la brochure ainsi que l’image de catégorie.

Vous devez maintenant voir chaque catégorie avec ses données binaires

Figure 4 : Vous devez maintenant voir chaque catégorie avec ses données binaires (cliquez pour afficher l’image en taille réelle)

Étape 4 : Configuration de pourCategoriesDataSourceprendre en charge l’insertion

L’ObjetDataSource CategoriesDataSource utilisé par GridView Categories ne permet pas actuellement d’insérer des données. Pour prendre en charge l’insertion via ce contrôle de source de données, nous devons mapper sa Insert méthode à une méthode dans son objet sous-jacent, CategoriesBLL. En particulier, nous voulons le mapper à la méthode que nous avons ajoutée à l’étape CategoriesBLL 2, InsertWithPicture.

Commencez par cliquer sur le lien Configurer la source de données à partir de la balise active ObjectDataSource. Le premier écran montre l’objet avec lequel la source de données est configurée pour fonctionner, CategoriesBLL. Laissez ce paramètre tel quels, puis cliquez sur Suivant pour passer à l’écran Définir les méthodes de données. Accédez à l’onglet INSERT et sélectionnez la InsertWithPicture méthode dans la liste déroulante. Cliquez sur Terminer pour terminer l'Assistant.

Configurer ObjectDataSource pour utiliser la méthode InsertWithPicture

Figure 5 : Configurer ObjectDataSource pour utiliser la InsertWithPicture méthode (Cliquer pour afficher l’image en taille réelle)

Notes

À la fin de l’Assistant, Visual Studio peut vous demander si vous souhaitez actualiser les champs et les clés, ce qui régénérera les champs des contrôles web de données. Choisissez Non, car si vous choisissez Oui, vous remplacez toutes les personnalisations de champ que vous avez effectuées.

Une fois l’Assistant terminé, ObjectDataSource inclut désormais une valeur pour sa InsertMethod propriété ainsi que InsertParameters pour les quatre colonnes de catégorie, comme l’illustre le balisage déclaratif suivant :

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories" 
    TypeName="CategoriesBLL" InsertMethod="InsertWithPicture">
    <InsertParameters>
        <asp:Parameter Name="categoryName" Type="String" />
        <asp:Parameter Name="description" Type="String" />
        <asp:Parameter Name="brochurePath" Type="String" />
        <asp:Parameter Name="picture" Type="Object" />
    </InsertParameters>
</asp:ObjectDataSource>

Étape 5 : Création de l’interface d’insertion

Comme décrit dans La vue d’ensemble de l’insertion, de la mise à jour et de la suppression de données, le contrôle DetailsView fournit une interface d’insertion intégrée qui peut être utilisée lors de l’utilisation d’un contrôle de source de données qui prend en charge l’insertion. Ajoutons un contrôle DetailsView à cette page au-dessus de GridView qui rendra définitivement son interface d’insertion, ce qui permettra à un utilisateur d’ajouter rapidement une nouvelle catégorie. Lors de l’ajout d’une nouvelle catégorie dans DetailsView, le GridView en dessous s’actualise automatiquement et affiche la nouvelle catégorie.

Commencez par faire glisser un DetailsView de la boîte à outils vers le Designer au-dessus de GridView, en définissant sa ID propriété NewCategory sur et en supprimant les valeurs de propriété Height et .Width À partir de la balise active DetailsView, liez-la à l’existantCategoriesDataSource, puis case activée la case à cocher Activer l’insertion.

Capture d’écran de DetailsView avec la propriété CategoryID définie sur NewCategory, les valeurs des propriétés Height et Width sont vides et la case à cocher Activer l’insertion est activée.

Figure 6 : Lier l’objet DetailsView à et Activer l’insertion CategoriesDataSource (cliquer pour afficher l’image en taille réelle)

Pour restituer définitivement le DetailsView dans son interface d’insertion, définissez sa DefaultMode propriété sur Insert.

Notez que DetailsView a cinq BoundFields CategoryID, CategoryName, Description, NumberOfProductset BrochurePath bien que le CategoryID BoundField ne soit pas rendu dans l’interface d’insertion, car sa InsertVisible propriété est définie sur False. Ces BoundFields existent, car il s’agit des colonnes retournées par la GetCategories() méthode, ce que l’ObjectDataSource appelle pour récupérer ses données. Toutefois, pour l’insertion, nous ne voulons pas laisser l’utilisateur spécifier une valeur pour NumberOfProducts. De plus, nous devons leur permettre de charger une image pour la nouvelle catégorie, ainsi que de charger un FICHIER PDF pour la brochure.

Supprimez l’objet NumberOfProducts BoundField du DetailsView, puis mettez à jour les HeaderText propriétés de BrochurePathCategoryName et de BoundFields en Catégorie et Brochure, respectivement. Ensuite, convertissez BrochurePath boundField en un TemplateField et ajoutez un nouveau TemplateField pour l’image, ce qui donne à ce nouveau TemplateField la HeaderText valeur Picture. Déplacez le Picture Champ de modèles afin qu’il se trouve entre templateField BrochurePath et CommandField.

Capture d’écran montrant la fenêtre des champs avec TemplateField, Picture et HeaderText mis en évidence.

Figure 7 : Lier l’objet DetailsView au CategoriesDataSource et activer l’insertion

Si vous avez converti boundField BrochurePath en templateField via la boîte de dialogue Modifier les champs, le champ de modèles inclut un ItemTemplate, EditItemTemplateet InsertItemTemplate. Seul le InsertItemTemplate est nécessaire, cependant, n’hésitez pas à supprimer les deux autres modèles. À ce stade, la syntaxe déclarative de DetailsView doit ressembler à ce qui suit :

<asp:DetailsView ID="NewCategory" runat="server" AutoGenerateRows="False" 
    DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource" 
    DefaultMode="Insert">
    <Fields>
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="CategoryID" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            SortExpression="CategoryName" />
        <asp:BoundField DataField="Description" HeaderText="Description" 
            SortExpression="Description" />
        <asp:TemplateField HeaderText="Brochure" SortExpression="BrochurePath">
            <InsertItemTemplate>
                <asp:TextBox ID="TextBox1" runat="server"
                    Text='<%# Bind("BrochurePath") %>'></asp:TextBox>
            </InsertItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Picture"></asp:TemplateField>
        <asp:CommandField ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

Ajout de contrôles FileUpload pour les champs Brochure et Image

Actuellement, le BrochurePath TemplateField s InsertItemTemplate contient une zone de texte, tandis que le Picture templateField ne contient aucun modèle. Nous devons mettre à jour ces deux s TemplateField pour InsertItemTemplate utiliser les contrôles FileUpload.

Dans la balise active DetailsView, choisissez l’option Modifier les modèles, puis sélectionnez templateField BrochurePath s InsertItemTemplate dans la liste déroulante. Supprimez la zone de texte, puis faites glisser un contrôle FileUpload de la boîte à outils vers le modèle. Définissez le contrôle FileUpload sur IDBrochureUpload. De même, ajoutez un contrôle FileUpload au Picture templateField s InsertItemTemplate. Définissez ce contrôle FileUpload sur IDPictureUpload.

Ajouter un contrôle FileUpload à l’objet InsertItemTemplate

Figure 8 : Ajouter un contrôle FileUpload à (InsertItemTemplateCliquer pour afficher l’image pleine taille)

Après avoir effectué ces ajouts, les deux syntaxe déclaratives de TemplateField sont les suivantes :

<asp:TemplateField HeaderText="Brochure" SortExpression="BrochurePath">
    <InsertItemTemplate>
        <asp:FileUpload ID="BrochureUpload" runat="server" />
    </InsertItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Picture">
    <InsertItemTemplate>
        <asp:FileUpload ID="PictureUpload" runat="server" />
    </InsertItemTemplate>
</asp:TemplateField>

Lorsqu’un utilisateur ajoute une nouvelle catégorie, nous voulons nous assurer que la brochure et l’image sont du type de fichier correct. Pour la brochure, l’utilisateur doit fournir un fichier PDF. Pour l’image, nous avons besoin que l’utilisateur charge un fichier image, mais n’autorise-t-on aucun fichier image ou uniquement les fichiers image d’un type particulier, tels que les GIF ou les fichiers JPG ? Afin d’autoriser différents types de fichiers, nous devons étendre le Categories schéma afin d’inclure une colonne qui capture le type de fichier afin que ce type puisse être envoyé au client via Response.ContentType dans DisplayCategoryPicture.aspx. Étant donné que nous n’avons pas de colonne de ce type, il serait prudent de restreindre les utilisateurs à fournir uniquement un type de fichier image spécifique. Les Categories images existantes de la table sont des bitmaps, mais les FICHIERS JPG sont un format de fichier plus approprié pour les images servies sur le web.

Si un utilisateur charge un type de fichier incorrect, nous devons annuler l’insertion et afficher un message indiquant le problème. Ajoutez un contrôle Label Web sous DetailsView. Définissez sa ID propriété sur UploadWarning, effacez sa Text propriété, définissez la CssClass propriété sur Avertissement et les Visible propriétés et EnableViewState sur False. La Warning classe CSS est définie dans Styles.css et restitue le texte dans une grande police, rouge, italique et en gras.

Notes

Dans l’idéal, les CategoryName et Description BoundFields seraient convertis en TemplateFields et leurs interfaces d’insertion personnalisées. L’interface Description d’insertion, par exemple, serait probablement mieux adaptée via une zone de texte multiligne. Et étant donné que la CategoryName colonne n’accepte NULL pas de valeurs, un RequiredFieldValidator doit être ajouté pour garantir que l’utilisateur fournit une valeur pour le nouveau nom s de catégorie. Ces étapes sont laissées comme un exercice pour le lecteur. Reportez-vous à Personnalisation de l’interface de modification des données pour un aperçu détaillé de l’augmentation des interfaces de modification des données.

Étape 6 : Enregistrement de la brochure chargée dans le système de fichiers du serveur web

Lorsque l’utilisateur entre les valeurs d’une nouvelle catégorie et clique sur le bouton Insérer, une publication se produit et le flux de travail d’insertion se déroule. Tout d’abord, l’événement DetailsView se ItemInserting déclenche. Ensuite, la méthode s Insert() ObjectDataSource est appelée, ce qui entraîne l’ajout d’un nouvel enregistrement à la Categories table. Après cela, l’événement DetailsView se ItemInserted déclenche.

Avant d’appeler la méthode s Insert() ObjectDataSource, nous devons d’abord nous assurer que les types de fichiers appropriés ont été chargés par l’utilisateur, puis enregistrer le FICHIER PDF de la brochure dans le système de fichiers du serveur web. Créez un gestionnaire d’événements pour l’événement ItemInserting DetailsView et ajoutez le code suivant :

' Reference the FileUpload controls
Dim BrochureUpload As FileUpload = _
    CType(NewCategory.FindControl("BrochureUpload"), FileUpload)
If BrochureUpload.HasFile Then
    ' Make sure that a PDF has been uploaded
    If String.Compare(System.IO.Path.GetExtension _
        (BrochureUpload.FileName), ".pdf", True) <> 0 Then
        UploadWarning.Text = _
            "Only PDF documents may be used for a category's brochure."
        UploadWarning.Visible = True
        e.Cancel = True
        Exit Sub
    End If
End If

Le gestionnaire d’événements commence par référencer le BrochureUpload contrôle FileUpload à partir des modèles DetailsView. Ensuite, si une brochure a été chargée, l’extension du fichier chargé est examinée. Si l’extension n’est pas .PDF, un avertissement s’affiche, l’insertion est annulée et l’exécution du gestionnaire d’événements se termine.

Notes

Le fait de s’appuyer sur l’extension du fichier chargé n’est pas une technique sûre pour garantir que le fichier chargé est un document PDF. L’utilisateur peut avoir un document PDF valide avec l’extension .Brochure, ou il peut avoir pris un document non-PDF et lui avoir donné une .pdf extension. Le contenu binaire du fichier doit être examiné par programmation afin de vérifier de manière plus concluante le type de fichier. Cependant, ces approches approfondies sont souvent excessives ; la vérification de l’extension est suffisante pour la plupart des scénarios.

Comme indiqué dans le tutoriel Chargement de fichiers , vous devez veiller à l’enregistrement des fichiers dans le système de fichiers afin que le chargement d’un utilisateur ne remplace pas d’autres fichiers. Pour ce tutoriel, nous allons essayer d’utiliser le même nom que le fichier chargé. Toutefois, s’il existe déjà un fichier dans le ~/Brochures répertoire portant ce même nom de fichier, nous ajouterons un numéro à la fin jusqu’à ce qu’un nom unique soit trouvé. Par exemple, si l’utilisateur charge un fichier de brochure nommé Meats.pdf, mais qu’il existe déjà un fichier nommé Meats.pdf dans le ~/Brochures dossier, nous allons remplacer le nom du fichier enregistré par Meats-1.pdf. Si cela existe, nous allons essayer Meats-2.pdf, et ainsi de suite, jusqu’à ce qu’un nom de fichier unique soit trouvé.

Le code suivant utilise la File.Exists(path) méthode pour déterminer si un fichier existe déjà avec le nom de fichier spécifié. Si c’est le cas, il continue d’essayer de nouveaux noms de fichiers pour la brochure jusqu’à ce qu’aucun conflit ne soit trouvé.

Const BrochureDirectory As String = "~/Brochures/"
Dim brochurePath As String = BrochureDirectory & BrochureUpload.FileName
Dim fileNameWithoutExtension As String = _
    System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName)
Dim iteration As Integer = 1
While System.IO.File.Exists(Server.MapPath(brochurePath))
    brochurePath = String.Concat(BrochureDirectory, _
        fileNameWithoutExtension, "-", iteration, ".pdf")
    iteration += 1
End While

Une fois qu’un nom de fichier valide a été trouvé, le fichier doit être enregistré dans le système de fichiers et la valeur de brochurePath``InsertParameter ObjectDataSource doit être mise à jour afin que ce nom de fichier soit écrit dans la base de données. Comme nous l’avons vu dans le tutoriel Chargement de fichiers , le fichier peut être enregistré à l’aide de la méthode s du SaveAs(path) contrôle FileUpload. Pour mettre à jour le paramètre s ObjectDataSource brochurePath , utilisez la e.Values collection .

' Save the file to disk and set the value of the brochurePath parameter
BrochureUpload.SaveAs(Server.MapPath(brochurePath))
e.Values("brochurePath") = brochurePath

Étape 7 : enregistrement de l’image chargée dans la base de données

Pour stocker l’image chargée dans le nouvel Categories enregistrement, nous devons affecter le contenu binaire chargé au paramètre s ObjectDataSource picture dans l’événement DetailsView.ItemInserting Toutefois, avant d’effectuer cette affectation, nous devons d’abord nous assurer que l’image chargée est une image JPG et non un autre type d’image. Comme à l’étape 6, utilisons l’extension de fichier s image chargée pour déterminer son type.

Bien que la table autorise NULL les Categories valeurs pour la Picture colonne, toutes les catégories ont actuellement une image. Forcez l’utilisateur à fournir une image lors de l’ajout d’une nouvelle catégorie via cette page. Le code suivant vérifie qu’une image a été chargée et qu’elle dispose d’une extension appropriée.

' Reference the FileUpload controls
Dim PictureUpload As FileUpload = _
    CType(NewCategory.FindControl("PictureUpload"), FileUpload)
If PictureUpload.HasFile Then
    ' Make sure that a JPG has been uploaded
    If  String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
            ".jpg", True) <> 0 AndAlso _
        String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
            ".jpeg", True) <> 0 Then
        
        UploadWarning.Text = _
            "Only JPG documents may be used for a category's picture."
        UploadWarning.Visible = True
        e.Cancel = True
        Exit Sub
    End If
Else
    ' No picture uploaded!
    UploadWarning.Text = _
        "You must provide a picture for the new category."
    UploadWarning.Visible = True
    e.Cancel = True
    Exit Sub
End If

Ce code doit être placé avant le code de l’étape 6 afin qu’en cas de problème avec le chargement de l’image, le gestionnaire d’événements se termine avant que le fichier de brochure ne soit enregistré dans le système de fichiers.

En supposant qu’un fichier approprié a été chargé, attribuez le contenu binaire chargé à la valeur du paramètre d’image avec la ligne de code suivante :

' Set the value of the picture parameter
e.Values("picture") = PictureUpload.FileBytes

Gestionnaire d’événements completItemInserting

Pour plus d’exhaustivité, voici le ItemInserting gestionnaire d’événements dans son intégralité :

Protected Sub NewCategory_ItemInserting _
    (sender As Object, e As DetailsViewInsertEventArgs) _
    Handles NewCategory.ItemInserting
    
    ' Reference the FileUpload controls
    Dim PictureUpload As FileUpload = _
        CType(NewCategory.FindControl("PictureUpload"), FileUpload)
    If PictureUpload.HasFile Then
        ' Make sure that a JPG has been uploaded
        If  String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
                ".jpg", True) <> 0 AndAlso _
            String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
                ".jpeg", True) <> 0 Then
            
            UploadWarning.Text = _
                "Only JPG documents may be used for a category's picture."
            UploadWarning.Visible = True
            e.Cancel = True
            Exit Sub
        End If
    Else
        ' No picture uploaded!
        UploadWarning.Text = _
            "You must provide a picture for the new category."
        UploadWarning.Visible = True
        e.Cancel = True
        Exit Sub
    End If
    ' Set the value of the picture parameter
    e.Values("picture") = PictureUpload.FileBytes
    ' Reference the FileUpload controls
    Dim BrochureUpload As FileUpload = _
        CType(NewCategory.FindControl("BrochureUpload"), FileUpload)
    If BrochureUpload.HasFile Then
        ' Make sure that a PDF has been uploaded
        If String.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName), _
            ".pdf", True) <> 0 Then
            
            UploadWarning.Text = _
                "Only PDF documents may be used for a category's brochure."
            UploadWarning.Visible = True
            e.Cancel = True
            Exit Sub
        End If
        Const BrochureDirectory As String = "~/Brochures/"
        Dim brochurePath As String = BrochureDirectory & BrochureUpload.FileName
        Dim fileNameWithoutExtension As String = _
            System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName)
        Dim iteration As Integer = 1
        While System.IO.File.Exists(Server.MapPath(brochurePath))
            brochurePath = String.Concat(BrochureDirectory, _
                fileNameWithoutExtension, "-", iteration, ".pdf")
            iteration += 1
        End While
        ' Save the file to disk and set the value of the brochurePath parameter
        BrochureUpload.SaveAs(Server.MapPath(brochurePath))
        e.Values("brochurePath") = brochurePath
    End If
End Sub

Étape 8 : Correction de laDisplayCategoryPicture.aspxpage

Prenons un moment pour tester l’interface d’insertion et ItemInserting le gestionnaire d’événements qui ont été créés au cours des dernières étapes. Visitez la UploadInDetailsView.aspx page via un navigateur et tentez d’ajouter une catégorie, mais omettez l’image, ou spécifiez une image non-JPG ou une brochure non PDF. Dans l’un de ces cas, un message d’erreur s’affiche et le flux de travail d’insertion est annulé.

Un message d’avertissement s’affiche si un type de fichier non valide est chargé

Figure 9 : Un message d’avertissement s’affiche si un type de fichier non valide est chargé (cliquez pour afficher l’image en taille réelle)

Une fois que vous avez vérifié que la page nécessite le chargement d’une image et que vous n’acceptez pas les fichiers non-PDF ou non JPG, ajoutez une nouvelle catégorie avec une image JPG valide, en laissant le champ Brochure vide. Après avoir cliqué sur le bouton Insérer, la page est publiée et un nouvel enregistrement est ajouté à la table avec le Categories contenu binaire de l’image chargée stocké directement dans la base de données. GridView est mis à jour et affiche une ligne pour la catégorie nouvellement ajoutée, mais, comme le montre la figure 10, la nouvelle image de catégorie n’est pas affichée correctement.

L’image de la nouvelle catégorie n’est pas affichée

Figure 10 : L’image de la nouvelle catégorie n’est pas affichée (cliquez pour afficher l’image en taille réelle)

La raison pour laquelle la nouvelle image n’est pas affichée est que la DisplayCategoryPicture.aspx page qui retourne une image de catégorie spécifiée est configurée pour traiter les bitmaps qui ont un en-tête OLE. Cet en-tête de 78 octets est supprimé du contenu binaire de la Picture colonne avant d’être renvoyé au client. Mais le fichier JPG que nous venons de charger pour la nouvelle catégorie n’a pas cet en-tête OLE ; par conséquent, les octets nécessaires et valides sont supprimés des données binaires de l’image.

Étant donné qu’il y a maintenant des bitmaps avec des en-têtes OLE et des JPGs dans la Categories table, nous devons mettre à jour DisplayCategoryPicture.aspx afin qu’il effectue le décapage de l’en-tête OLE pour les huit catégories d’origine et contourne cette suppression pour les enregistrements de catégorie plus récents. Dans notre prochain tutoriel, nous allons examiner comment mettre à jour une image d’enregistrement existante, et nous allons mettre à jour toutes les anciennes images de catégorie pour qu’elles soient DES JPG. Pour l’instant, cependant, utilisez le code suivant dans DisplayCategoryPicture.aspx pour supprimer les en-têtes OLE uniquement pour les huit catégories d’origine :

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim categoryID As Integer = Convert.ToInt32(Request.QueryString("CategoryID"))
    ' Get information about the specified category
    Dim categoryAPI As New CategoriesBLL()
    Dim categories As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = categories(0)
    If categoryID <= 8 Then
        ' Output HTTP headers providing information about the binary data
        Response.ContentType = "image/bmp"
        ' Output the binary data
        ' But first we need to strip out the OLE header
        Const OleHeaderLength As Integer = 78
        Dim strippedImageLength As Integer = _
            category.Picture.Length - OleHeaderLength
        Dim strippedImageData(strippedImageLength) As Byte
        Array.Copy(category.Picture, OleHeaderLength, _
            strippedImageData, 0, strippedImageLength)
        Response.BinaryWrite(strippedImageData)
    Else
        ' For new categories, images are JPGs...
        ' Output HTTP headers providing information about the binary data
        Response.ContentType = "image/jpeg"
        ' Output the binary data
        Response.BinaryWrite(category.Picture)
    End If
End Sub

Avec cette modification, l’image JPG est désormais affichée correctement dans gridView.

Les images JPG pour les nouvelles catégories sont correctement rendues

Figure 11 : Les images JPG pour les nouvelles catégories sont correctement rendues (cliquer pour afficher l’image de taille réelle)

Étape 9 : Suppression de la brochure dans la face d’une exception

L’un des défis du stockage de données binaires sur le système de fichiers du serveur web est qu’il introduit une déconnexion entre le modèle de données et ses données binaires. Par conséquent, chaque fois qu’un enregistrement est supprimé, les données binaires correspondantes sur le système de fichiers doivent également être supprimées. Cela peut également entrer en jeu lors de l’insertion. Considérez le scénario suivant : un utilisateur ajoute une nouvelle catégorie, en spécifiant une image et une brochure valides. Lorsque vous cliquez sur le bouton Insérer, une publication se produit et l’événement DetailsView se ItemInserting déclenche, ce qui enregistre la brochure dans le système de fichiers du serveur web. Ensuite, la méthode s Insert() ObjectDataSource est appelée, ce qui appelle la méthode de classe CategoriesBLL s InsertWithPicture , qui appelle la CategoriesTableAdapter méthode s InsertWithPicture .

Maintenant, que se passe-t-il si la base de données est hors connexion ou s’il y a une erreur dans l’instruction INSERT SQL ? Il est clair que l’insertion échoue, de sorte qu’aucune nouvelle ligne de catégorie n’est ajoutée à la base de données. Mais nous avons toujours le fichier de brochure chargé se trouve sur le système de fichiers du serveur web ! Ce fichier doit être supprimé en face d’une exception pendant le flux de travail d’insertion.

Comme indiqué précédemment dans le didacticiel Gestion des exceptions BLL- et DAL-Level dans un ASP.NET Page , lorsqu’une exception est levée à partir des profondeurs de l’architecture, elle est mise en bulles à travers les différentes couches. Au niveau de la couche de présentation, nous pouvons déterminer si une exception s’est produite à partir de l’événement DetailsView.ItemInserted Ce gestionnaire d’événements fournit également les valeurs de ObjectDataSource s InsertParameters. Par conséquent, nous pouvons créer un gestionnaire d’événements pour l’événement ItemInserted qui vérifie s’il existe une exception et, le cas échéant, supprime le fichier spécifié par le paramètre s brochurePath ObjectDataSource :

Protected Sub NewCategory_ItemInserted _
    (sender As Object, e As DetailsViewInsertedEventArgs) _
    Handles NewCategory.ItemInserted
    
    If e.Exception IsNot Nothing Then
        ' Need to delete brochure file, if it exists
        If e.Values("brochurePath") IsNot Nothing Then
            System.IO.File.Delete(Server.MapPath _
                (e.Values("brochurePath").ToString()))
        End If
    End If
End Sub

Résumé

Un certain nombre d’étapes doivent être effectuées afin de fournir une interface web permettant d’ajouter des enregistrements qui incluent des données binaires. Si les données binaires sont stockées directement dans la base de données, il est probable que vous deviez mettre à jour l’architecture, en ajoutant des méthodes spécifiques pour gérer le cas où les données binaires sont insérées. Une fois l’architecture mise à jour, l’étape suivante consiste à créer l’interface d’insertion, qui peut être effectuée à l’aide d’un DetailsView qui a été personnalisé pour inclure un contrôle FileUpload pour chaque champ de données binaires. Les données chargées peuvent ensuite être enregistrées dans le système de fichiers du serveur web ou affectées à un paramètre de source de données dans le gestionnaire d’événements DetailsView.ItemInserting

L’enregistrement de données binaires dans le système de fichiers nécessite plus de planification que l’enregistrement de données directement dans la base de données. Un schéma de nommage doit être choisi afin d’éviter qu’un chargement d’un utilisateur ne remplace un autre s. En outre, des étapes supplémentaires doivent être effectuées pour supprimer le fichier chargé si l’insertion de base de données échoue.

Nous avons maintenant la possibilité d’ajouter de nouvelles catégories au système avec une brochure et une image, mais nous n’avons pas encore examiné comment mettre à jour les données binaires d’une catégorie existante ou comment supprimer correctement les données binaires d’une catégorie supprimée. Nous allons explorer ces deux rubriques dans le tutoriel suivant.

Bonne programmation !

À propos de l’auteur

Scott Mitchell, auteur de sept livres ASP/ASP.NET et fondateur de 4GuysFromRolla.com, travaille avec les technologies Web Microsoft depuis 1998. Scott travaille comme consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 2.0 in 24 Heures. Il est accessible à l’adressemitchell@4GuysFromRolla.com . ou via son blog, qui peut être trouvé à l’adresse http://ScottOnWriting.NET.

Un merci spécial à

Cette série de tutoriels a été examinée par de nombreux réviseurs utiles. Les principaux réviseurs de ce tutoriel étaient Dave Gardner, Teresa Murphy et Bernadette Leigh. Vous souhaitez consulter mes prochains articles MSDN ? Si c’est le cas, déposez-moi une ligne à mitchell@4GuysFromRolla.com.