Inclusione di un'opzione per il caricamento di file durante l'aggiunta di un nuovo record (VB)
Questa esercitazione illustra come creare un'interfaccia Web che consente all'utente di immettere i dati di testo e caricare file binari. Per illustrare le opzioni disponibili per archiviare i dati binari, un file verrà salvato nel database mentre l'altro viene archiviato nel file system.
Introduzione
Nelle due esercitazioni precedenti sono state esaminate le tecniche per l'archiviazione di dati binari associati al modello di dati dell'applicazione, è stato illustrato come usare il controllo FileUpload per inviare file dal client al server Web e vedere come presentare questi dati binari in un controllo Web dati. Abbiamo ancora parlato di come associare i dati caricati al modello di dati, anche se.
In questa esercitazione verrà creata una pagina Web per aggiungere una nuova categoria. Oltre a TextBoxes per il nome e la descrizione della categoria, questa pagina dovrà includere due controlli FileUpload uno per la nuova immagine della categoria e una per la brochure. L'immagine caricata verrà archiviata direttamente nella colonna del nuovo record Picture
, mentre la brochure verrà salvata ~/Brochures
nella cartella con il percorso del file salvato nella colonna del nuovo record BrochurePath
.
Prima di creare questa nuova pagina Web, sarà necessario aggiornare l'architettura. La CategoriesTableAdapter
query principale s non recupera la Picture
colonna. Di conseguenza, il metodo generato Insert
automaticamente include solo input per i CategoryName
campi , Description
e BrochurePath
. Pertanto, è necessario creare un metodo aggiuntivo nel TableAdapter che richiede tutti e quattro Categories
i campi. È necessario aggiornare anche la CategoriesBLL
classe nel livello della logica di business.
Passaggio 1: Aggiunta di unInsertWithPicture
metodo all'oggettoCategoriesTableAdapter
Quando è stato creato il back nell'esercitazione CategoriesTableAdapter
Creazione di un livello di accesso ai dati , è stato configurato per generare INSERT
automaticamente istruzioni , UPDATE
e DELETE
in base alla query principale. Inoltre, è stato indicato a TableAdapter di usare l'approccio DB Direct, che ha creato i metodi Insert
, Update
e Delete
. Questi metodi eseguono le istruzioni , e UPDATE
DELETE
generate INSERT
automaticamente e, di conseguenza, accettano parametri di input in base alle colonne restituite dalla query principale. Nell'esercitazione Caricamento file è stata aumentata la CategoriesTableAdapter
query principale dell'oggetto per usare la BrochurePath
colonna.
Poiché la CategoriesTableAdapter
query principale non fa riferimento alla Picture
colonna, non è possibile aggiungere un nuovo record né aggiornare un record esistente con un valore per la Picture
colonna. Per acquisire queste informazioni, è possibile creare un nuovo metodo nell'oggetto TableAdapter usato in modo specifico per inserire un record con dati binari oppure personalizzare l'istruzione generata INSERT
automaticamente. Il problema della personalizzazione dell'istruzione generata INSERT
automaticamente è che si rischia di avere le personalizzazioni sovrascritte dalla procedura guidata. Si supponga, ad esempio, di aver personalizzato l'istruzione per includere l'uso INSERT
della Picture
colonna. Verrà aggiornato il metodo TableAdapter Insert
per includere un parametro di input aggiuntivo per i dati binari dell'immagine della categoria. È quindi possibile creare un metodo nel livello della logica di business per usare questo metodo DAL e richiamare questo metodo BLL tramite il livello presentazione e tutto funzionerebbe in modo meraviglioso. Ovvero, fino alla successiva configurazione di TableAdapter tramite la configurazione guidata TableAdapter. Non appena completata la procedura guidata, le personalizzazioni dell'istruzione INSERT
verranno sovrascritte, il metodo verrà ripristinato nel formato precedente e il Insert
codice non verrà più compilato.
Nota
Questa annotazione è un problema non corretto quando si usano stored procedure anziché istruzioni SQL ad hoc. Un'esercitazione futura esaminerà l'uso di stored procedure in sostituzione delle istruzioni SQL ad hoc nel livello di accesso ai dati.
Per evitare questo potenziale mal di testa, anziché personalizzare le istruzioni SQL generate automaticamente, consente di creare invece un nuovo metodo per TableAdapter. Questo metodo, denominato InsertWithPicture
, accetterà i valori per le colonne , Description
, BrochurePath
e Picture
e eseguirà un'istruzione CategoryName
INSERT
che archivia tutti e quattro i valori in un nuovo record.
Aprire Typed DataSet e, dal Designer, fare clic con il pulsante destro del mouse sull'intestazione CategoriesTableAdapter
s e scegliere Aggiungi query dal menu di scelta rapida. In questo modo viene avviata la Configurazione guidata query TableAdapter, che inizia chiedendoci come la query TableAdapter deve accedere al database. Scegliere Usa istruzioni SQL e fare clic su Avanti. Il passaggio successivo richiede la generazione del tipo di query. Poiché si sta creando una query per aggiungere un nuovo record alla Categories
tabella, scegliere INSERT e fare clic su Avanti.
Figura 1: Selezionare l'opzione INSERT (Fare clic per visualizzare l'immagine full-size)
È ora necessario specificare l'istruzione INSERT
SQL. La procedura guidata suggerisce automaticamente un'istruzione INSERT
corrispondente alla query principale di TableAdapter. In questo caso, è un'istruzione INSERT
che inserisce i CategoryName
valori , Description
e BrochurePath
. Aggiornare l'istruzione in modo che la Picture
colonna sia inclusa insieme a un @Picture
parametro, ad esempio:
INSERT INTO [Categories]
([CategoryName], [Description], [BrochurePath], [Picture])
VALUES
(@CategoryName, @Description, @BrochurePath, @Picture)
La schermata finale della procedura guidata chiede di assegnare un nome al nuovo metodo TableAdapter. Immettere InsertWithPicture
e fare clic su Fine.
Figura 2: Assegnare un nome al nuovo metodo InsertWithPicture
TableAdapter (Fare clic per visualizzare l'immagine full-size)
Passaggio 2: Aggiornamento del livello di logica di business
Poiché il livello di presentazione deve essere interfacciato solo con il livello di logica di business anziché ignorarlo per passare direttamente al livello di accesso ai dati, è necessario creare un metodo BLL che richiama il metodo DAL appena creato (InsertWithPicture
). Per questa esercitazione, creare un metodo nella CategoriesBLL
classe denominata InsertWithPicture
che accetta come input tre String
s e una Byte
matrice. I String
parametri di input sono per il nome, la descrizione e il percorso del file della brochure della categoria, mentre la Byte
matrice è per il contenuto binario dell'immagine della categoria. Come illustrato nel codice seguente, questo metodo BLL richiama il metodo DAL corrispondente:
<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
Nota
Assicurarsi di aver salvato Il set di dati tipizzato prima di aggiungere il InsertWithPicture
metodo al BLL. Poiché il CategoriesTableAdapter
codice di classe viene generato automaticamente in base al dataset tipizzato, se non si salvano prima le modifiche apportate al set di dati Typed, la Adapter
proprietà non conoscerà il InsertWithPicture
metodo.
Passaggio 3: Elencare le categorie esistenti e i relativi dati binari
In questa esercitazione verrà creata una pagina che consente a un utente finale di aggiungere una nuova categoria al sistema, fornendo un'immagine e una brochure per la nuova categoria. Nell'esercitazione precedente è stato usato GridView con un ModelloField e ImageField per visualizzare ogni nome, descrizione, immagine e un collegamento per scaricare la relativa brochure. È possibile replicare tale funzionalità per questa esercitazione, creando una pagina che elenca tutte le categorie esistenti e consente la creazione di nuovi elementi.
Iniziare aprendo la DisplayOrDownload.aspx
pagina dalla BinaryData
cartella. Passare alla visualizzazione Origine e copiare la sintassi dichiarativa GridView e ObjectDataSource, incollandola all'interno dell'elemento <asp:Content>
in UploadInDetailsView.aspx
. Inoltre, non dimenticare di copiare il GenerateBrochureLink
metodo dalla classe code-behind di DisplayOrDownload.aspx
a UploadInDetailsView.aspx
.
Figura 3: Copiare e incollare la sintassi dichiarativa da DisplayOrDownload.aspx
a UploadInDetailsView.aspx
(fare clic per visualizzare l'immagine a dimensioni complete)
Dopo aver copiato la sintassi dichiarativa e GenerateBrochureLink
il metodo nella UploadInDetailsView.aspx
pagina, visualizzare la pagina tramite un browser per assicurarsi che tutto sia stato copiato correttamente. Verrà visualizzato un elenco di GridView delle otto categorie che includono un collegamento per scaricare la brochure e l'immagine della categoria.
Figura 4: è ora necessario visualizzare ogni categoria insieme ai relativi dati binari (fare clic per visualizzare l'immagine full-size)
Passaggio 4: Configurazione dell'oggetto per l'inserimentoCategoriesDataSource
del supporto
ObjectDataSource CategoriesDataSource
usato da Categories
GridView attualmente non offre la possibilità di inserire dati. Per supportare l'inserimento tramite questo controllo origine dati, è necessario eseguire il Insert
mapping del metodo a un metodo nel relativo oggetto sottostante, CategoriesBLL
. In particolare, si vuole eseguire il mapping al CategoriesBLL
metodo aggiunto di nuovo nel passaggio 2, InsertWithPicture
.
Iniziare facendo clic sul collegamento Configura origine dati dallo smart tag di ObjectDataSource. La prima schermata mostra l'oggetto con cui l'origine dati è configurata per l'uso, CategoriesBLL
. Lasciare questa impostazione come è e fare clic su Avanti per passare alla schermata Definisci metodi dati. Passare alla scheda INSERT e selezionare il InsertWithPicture
metodo dall'elenco a discesa. Fare clic su Fine per completare la procedura guidata.
Figura 5: Configurare ObjectDataSource per usare il InsertWithPicture
metodo (fare clic per visualizzare l'immagine a dimensioni complete)
Nota
Al termine della procedura guidata, Visual Studio può chiedere se si vogliono aggiornare campi e chiavi, che rigenerano i campi dei controlli Web dei dati. Scegliere No, perché scegliere Sì sovrascriverà le personalizzazioni dei campi apportate.
Dopo aver completato la procedura guidata, ObjectDataSource includerà ora un valore per la relativa InsertMethod
proprietà e InsertParameters
per le quattro colonne di categoria, come illustrato nel markup dichiarativo seguente:
<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>
Passaggio 5: Creazione dell'interfaccia di inserimento
Come illustrato per la prima volta in Panoramica dell'inserimento, dell'aggiornamento e dell'eliminazione dei dati, il controllo DetailsView fornisce un'interfaccia di inserimento predefinita che può essere usata quando si usa un controllo origine dati che supporta l'inserimento. Consente di aggiungere un controllo DetailsView a questa pagina sopra GridView che eseguirà il rendering permanente dell'interfaccia di inserimento, consentendo a un utente di aggiungere rapidamente una nuova categoria. Quando si aggiunge una nuova categoria in DetailsView, GridView viene aggiornata automaticamente e visualizzata la nuova categoria.
Iniziare trascinando un oggetto DetailsView dalla casella degli strumenti nella Designer sopra GridView, impostandone la ID
proprietà su e cancellando i Height
valori delle proprietà NewCategory
eWidth
. Dallo smart tag DetailsView, associarlo all'esistente CategoriesDataSource
e quindi selezionare la casella di controllo Abilita inserimento.
Figura 6: Associare DetailsView all'oggetto e Abilitare l'inserimento CategoriesDataSource
(fare clic per visualizzare l'immagine a dimensioni complete)
Per eseguire il rendering permanente di DetailsView nell'interfaccia di inserimento, impostare la relativa DefaultMode
proprietà su Insert
.
Si noti che DetailsView ha cinque BoundFields CategoryID
, , , NumberOfProducts
CategoryName
Description
e BrochurePath
anche se il rendering di BoundField non viene eseguito nell'interfaccia di inserimento perché la CategoryID
relativa InsertVisible
proprietà è impostata su .False
Questi BoundField sono presenti perché sono le colonne restituite dal GetCategories()
metodo, ovvero ciò che viene richiamato da ObjectDataSource per recuperare i dati. Per l'inserimento, tuttavia, non si vuole consentire all'utente di specificare un valore per NumberOfProducts
. Inoltre, è necessario consentire loro di caricare un'immagine per la nuova categoria e caricare un PDF per la brochure.
Rimuovere completamente BoundField NumberOfProducts
da DetailsView e quindi aggiornare rispettivamente le HeaderText
proprietà di CategoryName
e BoundFields in Category e BrochurePath
Brochure. Successivamente, convertire BoundField BrochurePath
in un ModelloField e aggiungere un nuovo TemplateField per l'immagine, dando a questo nuovo ModelloField un HeaderText
valore di Picture. Picture
Spostare TemplateField in modo che sia compreso tra BrochurePath
TemplateField e CommandField.
Figura 7: Associare DetailsView all'oggetto e abilitare l'inserimento CategoriesDataSource
Se l'oggetto BoundField è stato convertito in un oggetto TemplateField tramite la BrochurePath
finestra di dialogo Modifica campi, templateField include un ItemTemplate
oggetto , EditItemTemplate
e InsertItemTemplate
. Solo l'oggetto InsertItemTemplate
è necessario, tuttavia, quindi è possibile rimuovere gli altri due modelli. A questo punto la sintassi dichiarativa di DetailsView dovrebbe essere simile alla seguente:
<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>
Aggiunta di controlli FileUpload per i campi della brochure e dell'immagine
Attualmente, l'oggetto BrochurePath
TemplateField contiene InsertItemTemplate
una casella di testo, mentre Picture
TemplateField non contiene modelli. Per usare i controlli FileUpload, è necessario aggiornare questi due modelli.InsertItemTemplate
Nella smart tag DetailsView scegliere l'opzione Modifica modelli e quindi selezionare BrochurePath
TemplateField InsertItemTemplate
dall'elenco a discesa. Rimuovere TextBox e quindi trascinare un controllo FileUpload dalla casella degli strumenti nel modello. Impostare il controllo FileUpload su ID
BrochureUpload
. Analogamente, aggiungere un controllo FileUpload a Picture
TemplateField s InsertItemTemplate
. Impostare questo controllo FileUpload su ID
PictureUpload
.
Figura 8: Aggiungere un controllo FileUpload all'oggetto InsertItemTemplate
(fare clic per visualizzare l'immagine full-size)
Dopo aver effettuato queste aggiunte, la sintassi dichiarativa dei due TemplateField sarà:
<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>
Quando un utente aggiunge una nuova categoria, si vuole assicurarsi che la brochure e l'immagine siano del tipo di file corretto. Per la brochure, l'utente deve fornire un PDF. Per l'immagine è necessario che l'utente carica un file di immagine, ma sia consentito qualsiasi file di immagine o solo file di immagine di un tipo specifico, ad esempio GIF o JPG? Per consentire diversi tipi di file, è necessario estendere lo schema per includere una colonna che acquisisce il Categories
tipo di file in modo che questo tipo possa essere inviato al client tramite Response.ContentType
.DisplayCategoryPicture.aspx
Poiché non è disponibile una colonna di questo tipo, è consigliabile limitare gli utenti solo a fornire un tipo di file di immagine specifico. Le Categories
immagini esistenti della tabella sono bitmap, ma i gruppi di sicurezza di rete sono un formato di file più appropriato per le immagini gestite sul Web.
Se un utente carica un tipo di file non corretto, è necessario annullare l'inserimento e visualizzare un messaggio che indica il problema. Aggiungere un controllo Web Etichetta sotto DetailsView. Impostare la ID
proprietà su UploadWarning
, cancellare Text
la proprietà, impostare la CssClass
proprietà su Avviso e le Visible
proprietà e EnableViewState
su False
. La Warning
classe CSS è definita in Styles.css
e esegue il rendering del testo in un carattere grande, rosso, corsivo, grassetto.
Nota
Idealmente, i CategoryName
e Description
BoundFields verranno convertiti in TemplateFields e le relative interfacce di inserimento personalizzate. L'interfaccia Description
di inserimento, ad esempio, potrebbe essere più adatta tramite una casella di testo a più righe. E poiché la CategoryName
colonna non accetta NULL
i valori, deve essere aggiunto un oggetto RequiredFieldValidator per assicurarsi che l'utente fornisca un valore per il nome della nuova categoria. Questi passaggi vengono lasciati come esercizio per il lettore. Fare riferimento alla personalizzazione dell'interfaccia di modifica dei dati per un'analisi approfondita sull'aumento delle interfacce di modifica dei dati.
Passaggio 6: Salvataggio della brochure caricata nel file system del server Web
Quando l'utente immette i valori per una nuova categoria e fa clic sul pulsante Inserisci, si verifica un postback e viene aperto il flusso di lavoro di inserimento. In primo luogo, viene generato l'evento DetailsView.ItemInserting
Viene quindi richiamato il metodo ObjectDataSource Insert()
, che comporta l'aggiunta di un nuovo record alla Categories
tabella. In seguito, viene generato l'evento DetailsView.ItemInserted
Prima di richiamare il metodo ObjectDataSource Insert()
, è necessario prima assicurarsi che i tipi di file appropriati siano stati caricati dall'utente e quindi salvare il PDF della brochure nel file system del server Web. Creare un gestore eventi per l'evento DetailsView e ItemInserting
aggiungere il codice seguente:
' 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
Il gestore eventi inizia facendo riferimento al BrochureUpload
controllo FileUpload dai modelli di DetailsView. Se quindi è stata caricata una brochure, viene esaminata l'estensione del file caricato. Se l'estensione non è .PDF, viene visualizzato un avviso, l'inserimento viene annullato e l'esecuzione del gestore eventi termina.
Nota
L'estensione del file caricato non è una tecnica sicura per garantire che il file caricato sia un documento PDF. L'utente potrebbe avere un documento PDF valido con l'estensione o potrebbe aver preso un documento non PDF e dato un'estensione.Brochure
.pdf
. Il contenuto binario del file deve essere esaminato a livello di codice per verificare in modo più definitivo il tipo di file. Questi approcci approfonditi, anche se, spesso sono eccessivamente qualificati; controllare che l'estensione sia sufficiente per la maggior parte degli scenari.
Come illustrato nell'esercitazione Caricamento file , è necessario prestare attenzione quando si salvano file nel file system in modo che un utente non sovrascriva un altro s. Per questa esercitazione si tenterà di usare lo stesso nome del file caricato. Se esiste già un file nella ~/Brochures
directory con lo stesso nome di file, tuttavia, si aggiungerà un numero alla fine fino a quando non viene trovato un nome univoco. Ad esempio, se l'utente carica un file di brochure denominato Meats.pdf
, ma esiste già un file denominato Meats.pdf
nella ~/Brochures
cartella, verrà modificato il nome del file salvato in Meats-1.pdf
. Se esiste, si proverà Meats-2.pdf
e così via finché non viene trovato un nome di file univoco.
Il codice seguente usa il File.Exists(path)
metodo per determinare se esiste già un file con il nome del file specificato. In tal caso, continua a provare nuovi nomi di file per la brochure fino a quando non viene trovato alcun conflitto.
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
Dopo aver trovato un nome file valido, il file deve essere salvato nel file system e il valore di ObjectDataSource deve brochurePath``InsertParameter
essere aggiornato in modo che questo nome file venga scritto nel database. Come illustrato di nuovo nell'esercitazione Caricamento file , il file può essere salvato usando il metodo del SaveAs(path)
controllo FileUpload. Per aggiornare il parametro ObjectDataSource, brochurePath
usare la e.Values
raccolta.
' Save the file to disk and set the value of the brochurePath parameter
BrochureUpload.SaveAs(Server.MapPath(brochurePath))
e.Values("brochurePath") = brochurePath
Passaggio 7: Salvataggio dell'immagine caricata nel database
Per archiviare l'immagine caricata nel nuovo Categories
record, è necessario assegnare il contenuto binario caricato al parametro ObjectDataSource nell'evento picture
DetailsView.ItemInserting
Prima di effettuare questa assegnazione, tuttavia, dobbiamo prima assicurarsi che l'immagine caricata sia un'immagine JPG e non un altro tipo di immagine. Come nel passaggio 6, consente di usare l'estensione file dell'immagine caricata per verificare il relativo tipo.
Mentre la Categories
tabella consente NULL
valori per la colonna, tutte le categorie attualmente hanno un'immagine Picture
. Forzare l'utente a fornire un'immagine quando si aggiunge una nuova categoria tramite questa pagina. Il codice seguente verifica che un'immagine sia stata caricata e che abbia un'estensione appropriata.
' 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
Questo codice deve essere inserito prima del codice del passaggio 6 in modo che, se si verifica un problema con il caricamento dell'immagine, il gestore eventi termina prima che il file della brochure venga salvato nel file system.
Supponendo che sia stato caricato un file appropriato, assegnare il contenuto binario caricato al valore del parametro immagine con la riga di codice seguente:
' Set the value of the picture parameter
e.Values("picture") = PictureUpload.FileBytes
Gestore eventi completoItemInserting
Per la completezza, ecco il ItemInserting
gestore eventi nella relativa interezza:
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
Passaggio 8: Correzione dellaDisplayCategoryPicture.aspx
pagina
È possibile testare l'interfaccia di inserimento e ItemInserting
il gestore eventi creati negli ultimi passaggi. Visitare la pagina tramite un browser e tentare di aggiungere una categoria, ma omettere l'immagine UploadInDetailsView.aspx
o specificare un'immagine non JPG o una brochure non PDF. In uno di questi casi verrà visualizzato un messaggio di errore e il flusso di lavoro di inserimento annullato.
Figura 9: viene visualizzato un messaggio di avviso se viene caricato un tipo di file non valido (fare clic per visualizzare l'immagine a dimensioni complete)
Dopo aver verificato che la pagina richiede il caricamento di un'immagine e non accetta file NON PDF o non JPG, aggiungere una nuova categoria con un'immagine JPG valida, lasciando vuoto il campo Brochure. Dopo aver fatto clic sul pulsante Inserisci, la pagina postbackerà e verrà aggiunto un nuovo record alla Categories
tabella con il contenuto binario dell'immagine caricato archiviato direttamente nel database. GridView viene aggiornato e mostra una riga per la categoria appena aggiunta, ma, come illustrato nella figura 10, la nuova immagine della categoria non viene eseguita correttamente.
Figura 10: l'immagine della nuova categoria non viene visualizzata (fare clic per visualizzare l'immagine a dimensioni complete)
Il motivo per cui la nuova immagine non viene visualizzata è perché la DisplayCategoryPicture.aspx
pagina che restituisce un'immagine della categoria specificata è configurata per elaborare le bitmap con un'intestazione OLE. Questa intestazione di byte di 78 byte viene rimossa dal contenuto binario della Picture
colonna prima che vengano inviate al client. Ma il file JPG appena caricato per la nuova categoria non ha questa intestazione OLE; pertanto, i byte validi e necessari vengono rimossi dai dati binari dell'immagine.
Poiché sono ora presenti entrambe le bitmap con intestazioni OLE e JPG nella Categories
tabella, è necessario aggiornare in modo da eseguire la rimozione delle intestazioni OLE per le otto categorie originali e ignorare DisplayCategoryPicture.aspx
questa rimozione per i record di categoria più recenti. Nell'esercitazione successiva si esaminerà come aggiornare un'immagine del record esistente e si aggiorneranno tutte le immagini di categoria precedenti in modo che siano GPG. Per il momento, tuttavia, usare il codice seguente in DisplayCategoryPicture.aspx
per stripare le intestazioni OLE solo per queste otto categorie originali:
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
Con questa modifica, l'immagine JPG viene ora sottoposta a rendering corretto in GridView.
Figura 11: Le immagini JPG per le nuove categorie vengono visualizzate correttamente (fare clic per visualizzare l'immagine a dimensioni complete)
Passaggio 9: Eliminazione della brochure in faccia di un'eccezione
Una delle sfide per l'archiviazione dei dati binari nel file system del server Web consiste nel fatto che introduce una disconnessione tra il modello di dati e i relativi dati binari. Pertanto, ogni volta che viene eliminato un record, è necessario rimuovere anche i dati binari corrispondenti nel file system. Questo può entrare in gioco anche durante l'inserimento. Si consideri lo scenario seguente: un utente aggiunge una nuova categoria, specificando un'immagine e una brochure validi. Quando si fa clic sul pulsante Inserisci, si verifica un postback e viene generato l'evento DetailsView, ItemInserting
salvando la brochure nel file system del server Web. Viene quindi richiamato il metodo ObjectDataSourceInsert()
, che chiama il CategoriesBLL
metodo della classe, che chiama il CategoriesTableAdapter
metodo s InsertWithPicture
InsertWithPicture
.
Cosa accade ora se il database è offline o se si verifica un errore nell'istruzione INSERT
SQL? Chiaramente l'istruzione INSERT avrà esito negativo, pertanto non verrà aggiunta alcuna nuova riga di categoria al database. Ma abbiamo ancora il file brochure caricato seduto sul file system del server Web! Questo file deve essere eliminato in caso di eccezione durante il flusso di lavoro di inserimento.
Come illustrato in precedenza nell'esercitazione Sulla gestione di BLL- e DAL-Level eccezioni in un'esercitazione sulla pagina di ASP.NET , quando viene generata un'eccezione dalle profondità dell'architettura, viene inserita tra i vari livelli. A livello di presentazione è possibile determinare se si è verificata un'eccezione dall'evento DetailsView.ItemInserted
Questo gestore eventi fornisce anche i valori di ObjectDataSource s InsertParameters
. È quindi possibile creare un gestore eventi per l'evento ItemInserted
che controlla se si è verificata un'eccezione e, in tal caso, elimina il file specificato dal parametro ObjectDataSource s brochurePath
:
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
Riepilogo
Esistono diversi passaggi da eseguire per fornire un'interfaccia basata sul Web per l'aggiunta di record che includono dati binari. Se i dati binari vengono archiviati direttamente nel database, è probabile che sia necessario aggiornare l'architettura, aggiungendo metodi specifici per gestire il caso in cui vengono inseriti dati binari. Dopo aver aggiornato l'architettura, il passaggio successivo consiste nel creare l'interfaccia di inserimento, che può essere eseguita usando un controllo DetailsView personalizzato per includere un controllo FileUpload per ogni campo dati binario. I dati caricati possono quindi essere salvati nel file system del server Web o assegnati a un parametro di origine dati nel gestore eventi detailsView.ItemInserting
Il salvataggio dei dati binari nel file system richiede una pianificazione maggiore rispetto al salvataggio dei dati direttamente nel database. È necessario scegliere uno schema di denominazione per evitare il caricamento di un utente sovrascrivendo un altro. Inoltre, è necessario eseguire ulteriori passaggi per eliminare il file caricato se l'inserimento del database ha esito negativo.
Ora abbiamo la possibilità di aggiungere nuove categorie al sistema con una brochure e un'immagine, ma abbiamo ancora esaminato come aggiornare i dati binari di una categoria esistente o come rimuovere correttamente i dati binari per una categoria eliminata. Questi due argomenti verranno esaminati nell'esercitazione successiva.
Buon programmatori!
Informazioni sull'autore
Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, lavora con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto all'indirizzo mitchell@4GuysFromRolla.com. o tramite il suo blog, disponibile all'indirizzo http://ScottOnWriting.NET.
Grazie speciale a
Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali di questa esercitazione erano Dave Gardner, Teresa Murphy e Bernadette Leigh. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciami una riga in mitchell@4GuysFromRolla.com.