Inclusion d’une option de chargement de fichier lors de l’ajout d’un nouvel enregistrement (C#)
par Scott Mitchell
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, nous avons examiné comment utiliser le contrôle FileUpload pour envoyer des fichiers du client au serveur web et nous avons vu comment présenter ces données binaires dans un contrôle Web de données. 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. Outre les zones de texte pour le nom et la description de la catégorie, cette page doit inclure deux contrôles FileUpload, l’un pour la nouvelle image de catégorie et l’autre pour la brochure. L’image chargée est stockée directement dans la nouvelle colonne d’enregistrement Picture
, tandis que la brochure est enregistrée dans le ~/Brochures
dossier avec le chemin d’accès au fichier enregistré dans la nouvelle colonne 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 CategoryName
champs , Description
et BrochurePath
. Par conséquent, nous devons créer une méthode supplémentaire dans TableAdapter qui vous invite à entrer les quatre Categories
champs. La CategoriesBLL
classe de la couche logique métier doit également être mise à jour.
Étape 1 : Ajout d’uneInsertWithPicture
méthode auCategoriesTableAdapter
Lorsque nous avons créé le CategoriesTableAdapter
dans le didacticiel Création d’une couche d’accès aux données, nous l’avons configuré pour générer INSERT
automatiquement des instructions , UPDATE
et 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
, Update
et Delete
. Ces méthodes exécutent les instructions , UPDATE
et DELETE
générées automatiquement et, par conséquent, acceptent les paramètres d’entrée en fonction des colonnes retournées INSERT
par la requête main. Dans le didacticiel 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 le 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 d’avoir 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 pour Insert
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 de 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 se compile plus !
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 problème potentiel, plutôt que de personnaliser les instructions SQL générées automatiquement, nous allons plutôt créer une méthode pour TableAdapter. Cette méthode, nommée InsertWithPicture
, accepte les valeurs pour les CategoryName
colonnes , Description
, BrochurePath
et Picture
et 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
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 demande le type de requête à générer. Étant donné que nous créons une requête pour ajouter un nouvel enregistrement à la Categories
table, choisissez INSERT, puis cliquez sur Suivant.
Figure 1 : Sélectionnez l’option INSERT (Cliquer 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 main TableAdapter. Dans ce cas, il s’agit d’une INSERT
instruction qui insère les CategoryName
valeurs , Description
et 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.
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 de logique métier
Étant donné que la couche de présentation ne doit s’interfacer qu’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 tutoriel, 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 sont pour le nom de catégorie, la description et le chemin du fichier de brochure, tandis que le byte
tableau concerne le 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 void InsertWithPicture(string categoryName, string description,
string brochurePath, byte[] picture)
{
Adapter.InsertWithPicture(categoryName, description, brochurePath, picture);
}
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 dans le 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 un Champ de modèle et un Champ d’image pour afficher le nom, la description, l’image et un lien de chaque catégorie pour télécharger sa brochure. Nous allons répliquer cette fonctionnalité pour ce tutoriel, en créant une page qui répertorie toutes les catégories existantes et permet de créer de nouvelles catégories.
Commencez par ouvrir la DisplayOrDownload.aspx
page à partir du BinaryData
dossier. Accédez à la vue Source et copiez la syntaxe déclarative 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
.
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.
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 pour prendre en charge l’insertionCategoriesDataSource
L’ObjetDataSource CategoriesDataSource
utilisé par GridView Categories
n’offre actuellement pas la possibilité 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 CategoriesBLL
méthode que nous avons ajoutée à l’étape 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 qu’il est et cliquez sur Suivant pour passer à l’écran Définir des méthodes de données. Accédez à l’onglet INSERT et choisissez la InsertWithPicture
méthode dans la liste déroulante. Cliquez sur Terminer pour terminer l'Assistant.
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 le choix de Oui remplacera 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 indiqué 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. Nous allons ajouter un contrôle DetailsView à cette page au-dessus de GridView qui restitue définitivement son interface d’insertion, ce qui permet à 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 du GridView, en définissant sa ID
propriété NewCategory
sur et en effaçant 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.
Figure 6 : Lier l’objet DetailsView à et Activer l’insertion CategoriesDataSource
(cliquer pour afficher l’image en taille réelle)
Pour afficher définitivement detailsView dans son interface d’insertion, définissez sa DefaultMode
propriété sur Insert
.
Notez que DetailsView a cinq BoundFields CategoryID
, CategoryName
, Description
NumberOfProducts
, et 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 , qui est 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 télécharger une image pour la nouvelle catégorie ainsi que de télécharger un FICHIER PDF pour la brochure.
Supprimez complètement l’objet NumberOfProducts
BoundField du DetailsView, puis mettez à jour les HeaderText
propriétés de CategoryName
et BrochurePath
de BoundFields en Catégorie et Brochure, respectivement. Ensuite, convertissez l’objet BrochurePath
BoundField en templateField et ajoutez un nouveau TemplateField pour l’image, ce qui donne à ce nouveau TemplateField la HeaderText
valeur Picture. Déplacez le Picture
TemplateField de sorte qu’il se trouve entre templateField BrochurePath
et CommandField.
Figure 7 : Lier l’objet DetailsView à et Activer l’insertion CategoriesDataSource
Si vous avez converti l’objet BrochurePath
BoundField en templateField via la boîte de dialogue Modifier les champs, le Champ de modèle inclut , ItemTemplate
EditItemTemplate
et InsertItemTemplate
. Seul est InsertItemTemplate
nécessaire, cependant, n’hésitez pas à supprimer les deux autres modèles. À ce stade, votre 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 de brochure et d’image
Actuellement, le BrochurePath
TemplateField contient InsertItemTemplate
un TextBox, tandis que le Picture
TemplateField ne contient aucun modèle. Nous devons mettre à jour ces deux TemplateField s InsertItemTemplate
pour utiliser les contrôles FileUpload.
Dans la balise active DetailsAfficher, choisissez l’option Modifier les modèles, puis sélectionnez templateField BrochurePath
dans InsertItemTemplate
la liste déroulante. Supprimez le contrôle TextBox, puis faites glisser un contrôle FileUpload de la boîte à outils vers le modèle. Définissez le contrôle FileUpload sur ID
BrochureUpload
. De même, ajoutez un contrôle FileUpload à TemplateField Picture
de InsertItemTemplate
. Définissez ce contrôle FileUpload sur ID
PictureUpload
.
Figure 8 : Ajouter un contrôle FileUpload à (InsertItemTemplate
Cliquer pour afficher l’image en taille réelle)
Après avoir effectué ces ajouts, les deux syntaxes 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 est-ce que nous autorisons n’importe quel fichier image ou uniquement les fichiers image d’un type particulier, tels que les fichiers GIF ou JPG ? Pour 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 propriétés et EnableViewState
sur Visible
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
boundFields et Description
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 les valeurs, un RequiredFieldValidator doit être ajouté pour s’assurer que l’utilisateur fournit une valeur pour le nom de la nouvelle catégorie. Ces étapes sont laissées comme un exercice au lecteur. Reportez-vous à Personnalisation de l’interface de modification des données pour une présentation détaillée 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 ObjectDataSource est Insert()
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 ObjectDataSource Insert()
, 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 control
FileUpload BrochureUpload =
(FileUpload)NewCategory.FindControl("BrochureUpload");
if (BrochureUpload.HasFile)
{
// Make sure that a PDF has been uploaded
if (string.Compare(System.IO.Path.GetExtension
(BrochureUpload.FileName), ".pdf", true) != 0)
{
UploadWarning.Text =
"Only PDF documents may be used for a category's brochure.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
}
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 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 didacticiel Chargement de fichiers , vous devez prendre soin de l’enregistrement des fichiers dans le système de fichiers afin que le chargement d’un utilisateur ne remplace pas les autres fichiers. Pour ce tutoriel, nous allons essayer d’utiliser le même nom que le fichier chargé. S’il existe déjà un fichier dans le ~/Brochures
répertoire portant ce même nom de fichier, nous ajouterons un nombre à 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 changeons le nom du fichier enregistré en 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 string BrochureDirectory = "~/Brochures/";
string brochurePath = BrochureDirectory + BrochureUpload.FileName;
string fileNameWithoutExtension =
System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName);
int iteration = 1;
while (System.IO.File.Exists(Server.MapPath(brochurePath)))
{
brochurePath = string.Concat(BrochureDirectory,
fileNameWithoutExtension, "-", iteration, ".pdf");
iteration++;
}
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 didacticiel 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 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 ObjectDataSource dans picture
l’événement ItemInserting
DetailsView. 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 de l’image chargée pour déterminer son type.
Bien que la Categories
table autorise NULL
les 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 a une extension appropriée.
// Reference the FileUpload controls
FileUpload PictureUpload = (FileUpload)NewCategory.FindControl("PictureUpload");
if (PictureUpload.HasFile)
{
// Make sure that a JPG has been uploaded
if (string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName),
".jpg", true) != 0 &&
string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName),
".jpeg", true) != 0)
{
UploadWarning.Text =
"Only JPG documents may be used for a category's picture.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
}
else
{
// No picture uploaded!
UploadWarning.Text =
"You must provide a picture for the new category.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
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 l’enregistrement du fichier de brochure dans le système de fichiers.
En supposant qu’un fichier approprié a été chargé, affectez 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 CompleteItemInserting
Pour l’exhaustivité, voici le ItemInserting
gestionnaire d’événements dans son intégralité :
protected void NewCategory_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
// Reference the FileUpload controls
FileUpload PictureUpload = (FileUpload)NewCategory.FindControl("PictureUpload");
if (PictureUpload.HasFile)
{
// Make sure that a JPG has been uploaded
if (string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName),
".jpg", true) != 0 &&
string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName),
".jpeg", true) != 0)
{
UploadWarning.Text =
"Only JPG documents may be used for a category's picture.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
}
else
{
// No picture uploaded!
UploadWarning.Text =
"You must provide a picture for the new category.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
// Set the value of the picture parameter
e.Values["picture"] = PictureUpload.FileBytes;
// Reference the FileUpload controls
FileUpload BrochureUpload =
(FileUpload)NewCategory.FindControl("BrochureUpload");
if (BrochureUpload.HasFile)
{
// Make sure that a PDF has been uploaded
if (string.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName),
".pdf", true) != 0)
{
UploadWarning.Text =
"Only PDF documents may be used for a category's brochure.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
const string BrochureDirectory = "~/Brochures/";
string brochurePath = BrochureDirectory + BrochureUpload.FileName;
string fileNameWithoutExtension =
System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName);
int iteration = 1;
while (System.IO.File.Exists(Server.MapPath(brochurePath)))
{
brochurePath = string.Concat(BrochureDirectory, fileNameWithoutExtension,
"-", iteration, ".pdf");
iteration++;
}
// Save the file to disk and set the value of the brochurePath parameter
BrochureUpload.SaveAs(Server.MapPath(brochurePath));
e.Values["brochurePath"] = brochurePath;
}
}
Étape 8 : Correction de laDisplayCategoryPicture.aspx
page
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 essayez 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 workflow d’insertion est annulé.
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 Categories
table avec le 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, l’image de la nouvelle catégorie n’est pas affichée correctement.
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 due au fait 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 existe désormais des bitmaps avec des en-têtes OLE et des JPG dans la Categories
table, nous devons effectuer la mise à jour DisplayCategoryPicture.aspx
afin qu’elle effectue le stripping d’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 afin 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 ces huit catégories d’origine :
protected void Page_Load(object sender, EventArgs e)
{
int categoryID = Convert.ToInt32(Request.QueryString["CategoryID"]);
// Get information about the specified category
CategoriesBLL categoryAPI = new CategoriesBLL();
Northwind.CategoriesDataTable categories =
categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID);
Northwind.CategoriesRow category = categories[0];
if (categoryID <= 8)
{
// For older categories, we must strip the OLE header... images are bitmaps
// 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 int OleHeaderLength = 78;
int strippedImageLength = category.Picture.Length - OleHeaderLength;
byte[] strippedImageData = new byte[strippedImageLength];
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);
}
}
Avec cette modification, l’image JPG est désormais restituée correctement dans GridView.
Figure 11 : Les images JPG pour les nouvelles catégories sont correctement rendues (cliquer pour afficher l’image en taille réelle)
Étape 9 : Suppression de la brochure dans le visage d’une exception
L’un des défis du stockage des 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 ObjectDataSource est Insert()
appelée, qui appelle la méthode s InsertWithPicture
de la CategoriesBLL
classe, qui appelle la CategoriesTableAdapter
méthode sInsertWithPicture
.
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 void NewCategory_ItemInserted
(object sender, DetailsViewInsertedEventArgs e)
{
if (e.Exception != null)
{
// Need to delete brochure file, if it exists
if (e.Values["brochurePath"] != null)
System.IO.File.Delete(Server.MapPath(
e.Values["brochurePath"].ToString()));
}
}
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.