Condividi tramite


Inclusione di un'opzione per il caricamento di file durante l'aggiunta di un nuovo record (VB)

di Scott Mitchell

Scarica il PDF

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 CategoryNamecampi , Descriptione 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 unInsertWithPicturemetodo all'oggettoCategoriesTableAdapter

Quando è stato creato il back nell'esercitazione CategoriesTableAdapterCreazione di un livello di accesso ai dati , è stato configurato per generare INSERTautomaticamente istruzioni , UPDATEe DELETE in base alla query principale. Inoltre, è stato indicato a TableAdapter di usare l'approccio DB Direct, che ha creato i metodi Insert, Updatee Delete. Questi metodi eseguono le istruzioni , e UPDATEDELETE generate INSERTautomaticamente 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, BrochurePathe Picture e eseguirà un'istruzione CategoryNameINSERT 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.

Selezionare l'opzione INSERT

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 CategoryNamevalori , Descriptione 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.

Assegnare un nome al nuovo metodo TableAdapter InsertWithPicture

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.

Copiare e incollare la sintassi dichiarativa da 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.

È ora necessario visualizzare ogni categoria insieme ai relativi dati binari

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'inserimentoCategoriesDataSourcedel 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.

Configurare ObjectDataSource per usare il metodo InsertWithPicture

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.

Screenshot di DetailsView con la proprietà CategoryID impostata su NewCategory, i valori delle proprietà Height e Width sono vuoti e la casella di controllo Abilita inserimento selezionata.

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, , , NumberOfProductsCategoryNameDescriptione 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.

Screenshot che mostra la finestra dei campi con TemplateField, Picture e HeaderText evidenziato.

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 ItemTemplateoggetto , EditItemTemplatee 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 IDBrochureUpload. Analogamente, aggiungere un controllo FileUpload a Picture TemplateField s InsertItemTemplate. Impostare questo controllo FileUpload su IDPictureUpload.

Aggiungere un controllo FileUpload all'elemento InsertItemTemplate

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.pdfe 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.aspxpagina

È 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.

Viene visualizzato un messaggio di avviso se viene caricato un tipo di file non valido

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.

L'immagine della nuova categoria non viene visualizzata

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.

Le immagini JPG per le nuove categorie vengono visualizzate correttamente

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 InsertWithPictureInsertWithPicture.

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.