Sdílet prostřednictvím


Zahrnutí možnosti nahrání souboru při přidání nového záznamu (VB)

Scott Mitchell

Stáhnout PDF

V tomto kurzu se dozvíte, jak vytvořit webové rozhraní, které uživateli umožní jak zadat textová data, tak nahrát binární soubory. Pro ilustraci dostupných možností pro ukládání binárních dat se jeden soubor uloží do databáze, zatímco druhý v systému souborů.

Úvod

V předchozích dvou kurzech jsme prozkoumali techniky ukládání binárních dat, která jsou přidružená k datovému modelu aplikace, podívali se na to, jak pomocí ovládacího prvku FileUpload odesílat soubory z klienta na webový server, a zjistili jsme, jak tato binární data prezentovat v datovém webovém ovládacím prvku. Zatím jsme ale nemluvili o tom, jak přidružit nahraná data k datovému modelu.

V tomto kurzu vytvoříme webovou stránku, která přidá novou kategorii. Kromě textových polí pro název a popis kategorie bude tato stránka muset obsahovat dva ovládací prvky FileUpload jeden pro obrázek nové kategorie a jeden pro brožuru. Nahraný obrázek se uloží přímo do nového sloupce záznamů Picture , zatímco brožura se uloží do ~/Brochures složky s cestou k souboru uloženému ve sloupci s novým záznamem BrochurePath .

Před vytvořením této nové webové stránky budeme muset aktualizovat architekturu. Hlavní CategoriesTableAdapter dotaz s nenačte Picture sloupec. V důsledku toho má automaticky generovaná Insert metoda pouze vstupy pro CategoryNamepole , Descriptiona BrochurePath . Proto musíme v objektu TableAdapter vytvořit další metodu, která zobrazí výzvu pro všechna čtyři Categories pole. Bude CategoriesBLL také potřeba aktualizovat třídu ve vrstvě obchodní logiky.

Krok 1: PřidáníInsertWithPicturemetody doCategoriesTableAdapter

Když jsme vytvořili CategoriesTableAdapter back v kurzu Vytvoření vrstvy přístupu k datům , nakonfigurovali jsme ho tak, aby automaticky vygeneroval INSERTpříkazy , UPDATEa DELETE na základě hlavního dotazu. Kromě toho jsme instruovali objektu TableAdapter, aby použil přístup DB Direct, který vytvořil metody Insert, Updatea Delete. Tyto metody spouštějí automaticky vygenerované INSERTpříkazy , UPDATEa DELETE v důsledku toho přijímají vstupní parametry na základě sloupců vrácených hlavním dotazem. V kurzu Nahrávání souborů jsme rozšířili CategoriesTableAdapter hlavní dotaz s tak, aby používal sloupec BrochurePath .

Vzhledem k tomu, že CategoriesTableAdapter hlavní dotaz neodkazuje na Picture sloupec, nemůžeme přidat nový záznam ani aktualizovat existující záznam hodnotou sloupce Picture . Abychom tyto informace zachytili, můžeme buď vytvořit novou metodu v objektu TableAdapter, která se používá speciálně k vložení záznamu s binárními daty, nebo můžeme přizpůsobit automaticky vygenerovaný INSERT příkaz. Problém s přizpůsobením automaticky vygenerovaného INSERT příkazu spočívá v tom, že riskujeme, že naše přizpůsobení přepíše průvodce. Představte si například, že jsme příkaz přizpůsobili INSERT tak, aby zahrnoval použití Picture sloupce. Tím by se aktualizovala metoda TableAdapter s Insert tak, aby zahrnovala další vstupní parametr pro binární data obrázku s kategorie. Pak bychom mohli vytvořit metodu ve vrstvě obchodní logiky pro použití této metody DAL a vyvolat tuto metodu BLL prostřednictvím prezentační vrstvy a vše by fungovalo skvěle. To znamená, že až do příště jsme konfigurovali TableAdapter prostřednictvím Průvodce konfigurací nástroje TableAdapter. Jakmile průvodce dokončíte, naše vlastní nastavení příkazu se přepíšou INSERT , Insert metoda se vrátí do původní podoby a náš kód se už nebude kompilovat!

Poznámka

Tato nepříjemnost není problém při použití uložených procedur místo ad hoc příkazů SQL. V dalším kurzu se budeme zabývat používáním uložených procedur namísto ad hoc příkazů SQL ve vrstvě přístupu k datům.

Abyste se vyhnuli tomuto potenciálnímu bolesti hlavy, místo přizpůsobení automaticky generovaných příkazů SQL nechte místo toho vytvořit novou metodu pro TableAdapter. Tato metoda s názvem InsertWithPicturepřijme hodnoty sloupců CategoryName, Description, BrochurePatha a Picture spustí INSERT příkaz, který uloží všechny čtyři hodnoty do nového záznamu.

Otevřete sadu Typed DataSet a v Designer klikněte pravým tlačítkem na CategoriesTableAdapter záhlaví s a v místní nabídce zvolte Přidat dotaz. Tím se spustí Průvodce konfigurací dotazu TableAdapter, který začíná dotazem, jak by měl dotaz TableAdapter přistupovat k databázi. Zvolte Použít příkazy SQL a klikněte na Další. V dalším kroku se zobrazí výzva k vygenerování typu dotazu. Vzhledem k tomu, že vytváříme dotaz pro přidání nového záznamu Categories do tabulky, zvolte VLOŽIT a klikněte na Další.

Vyberte možnost VLOŽIT.

Obrázek 1: Vyberte možnost VLOŽIT (kliknutím zobrazíte obrázek v plné velikosti)

Teď musíme zadat INSERT příkaz SQL. Průvodce automaticky navrhne příkaz INSERT odpovídající hlavnímu dotazu objektu TableAdapter. V tomto případě se jedná o INSERT příkaz, který vloží CategoryNamehodnoty , Descriptiona BrochurePath . Aktualizujte příkaz tak, aby Picture byl sloupec zahrnutý spolu s parametrem @Picture , například takto:

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

Poslední obrazovka průvodce nás vyzve k pojmenování nové metody TableAdapter. Zadejte InsertWithPicture a klikněte na Dokončit.

Pojmenujte novou metodu TableAdapter InsertWithPicture.

Obrázek 2: Pojmenujte novou metodu InsertWithPicture TableAdapter (kliknutím zobrazíte obrázek v plné velikosti)

Krok 2: Aktualizace vrstvy obchodní logiky

Vzhledem k tomu, že prezentační vrstva by měla být pouze v rozhraní s vrstvou obchodní logiky a neměla by ji obcházet a přejít přímo na vrstvu přístupu k datům, musíme vytvořit metodu BLL, která vyvolá právě vytvořenou metodu DAL (InsertWithPicture). Pro účely tohoto kurzu vytvořte ve třídě metodu CategoriesBLL s názvem InsertWithPicture , která přijímá jako vstup tři String s a Byte pole. Vstupní String parametry jsou pro název kategorie, popis a cestu k souboru brožury, zatímco Byte pole je pro binární obsah obrázku kategorie. Jak ukazuje následující kód, tato metoda BLL vyvolá odpovídající metodu DAL:

<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

Poznámka

Před přidáním InsertWithPicture metody do BLL se ujistěte, že jste uložili Typed DataSet. Vzhledem k tomu, CategoriesTableAdapter že kód třídy je automaticky generován na základě Typed DataSet, pokud nejprve neuložíte změny do Typed DataSet Adapter vlastnost nebude vědět o InsertWithPicture metodě.

Krok 3: Výpis existujících kategorií a jejich binárních dat

V tomto kurzu vytvoříme stránku, která koncovému uživateli umožní přidat do systému novou kategorii a poskytnout obrázek a brožuru pro novou kategorii. V předchozím kurzu jsme použili GridView s TemplateField a ImageField k zobrazení názvu, popisu, obrázku a odkazu na stažení brožury každé kategorie. Umožňuje replikovat tuto funkci pro tento kurz a vytvořit stránku, která obsahuje seznam všech existujících kategorií a umožňuje vytváření nových kategorií.

Začněte otevřením DisplayOrDownload.aspx stránky ze BinaryData složky. Přejděte do zobrazení Zdroj a zkopírujte deklarativní syntaxi GridView a ObjectDataSource a vložte ji do elementu <asp:Content> v UploadInDetailsView.aspx. Nezapomeňte také zkopírovat metodu GenerateBrochureLink z třídy kódu na pozadí do DisplayOrDownload.aspxUploadInDetailsView.aspx.

Zkopírujte a vložte deklarativní syntaxi z DisplayOrDownload.aspx do UploadInDetailsView.aspx

Obrázek 3: Zkopírování a vložení deklarativní syntaxe z DisplayOrDownload.aspx do UploadInDetailsView.aspx (kliknutím zobrazíte obrázek v plné velikosti)

Po zkopírování deklarativní syntaxe a GenerateBrochureLink metody na UploadInDetailsView.aspx stránku zobrazte stránku v prohlížeči a ujistěte se, že se vše správně zkopírovalo. Měli byste vidět GridView se seznamem osmi kategorií, které obsahují odkaz ke stažení brožury a také obrázek kategorií.

Teď byste měli vidět každou kategorii spolu s binárními daty.

Obrázek 4: Teď byste měli vidět každou kategorii spolu s binárními daty (kliknutím zobrazíte obrázek v plné velikosti)

Krok 4: KonfiguraceCategoriesDataSourcepro podporu vkládání

ObjectDataSource CategoriesDataSource používaný objektem Categories GridView v současné době neumožňuje vkládat data. Aby bylo možné podporovat vkládání prostřednictvím tohoto ovládacího prvku zdroje dat, potřebujeme jeho Insert metodu namapovat na metodu v příslušném objektu CategoriesBLL. Konkrétně ho chceme namapovat na metodu CategoriesBLL , kterou jsme přidali zpět v kroku 2, InsertWithPicture.

Začněte kliknutím na odkaz Konfigurovat zdroj dat z inteligentní značky ObjectDataSource. První obrazovka ukazuje objekt, se kterým je zdroj dat nakonfigurovaný pro práci, CategoriesBLL. Ponechte toto nastavení tak, jak je, a kliknutím na Další přejděte na obrazovku Definovat metody dat. Přejděte na kartu VLOŽENÍ a vyberte metodu InsertWithPicture z rozevíracího seznamu. Dokončete průvodce kliknutím na Dokončit.

Nakonfigurujte ObjectDataSource tak, aby používal metodu InsertWithPicture.

Obrázek 5: Konfigurace objektu ObjectDataSource tak, aby používal metodu InsertWithPicture (kliknutím zobrazíte obrázek v plné velikosti)

Poznámka

Po dokončení průvodce se sada Visual Studio může zeptat, jestli chcete aktualizovat pole a klíče, čímž se znovu vygenerují pole webových ovládacích prvků dat. Zvolte Ne, protože pokud zvolíte Ano, přepíšete všechna možná vlastní nastavení polí.

Po dokončení průvodce teď ObjectDataSource bude obsahovat hodnotu pro svoji InsertMethod vlastnost i InsertParameters pro čtyři sloupce kategorií, jak ukazuje následující deklarativní kód:

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

Krok 5: Vytvoření rozhraní pro vkládání

Jak je poprvé popsáno v přehledu vkládání, aktualizací a odstraňování dat, ovládací prvek DetailsView poskytuje integrované rozhraní pro vkládání, které lze využít při práci s ovládacím prvek zdroje dat, který podporuje vkládání. Pojďme přidat ovládací prvek DetailsView na tuto stránku nad GridView, který bude trvale vykreslovat jeho vkládání rozhraní, což uživateli umožní rychle přidat novou kategorii. Po přidání nové kategorie v zobrazení DetailsView se objekt GridView pod ní automaticky aktualizuje a zobrazí novou kategorii.

Začněte přetažením DetailsView z panelu nástrojů do Designer nad GridView, nastavením jeho ID vlastnosti na NewCategory hodnotu a vymazáním Height hodnot vlastností aWidth. Z inteligentní značky DetailsView svážete ji s existující CategoriesDataSource a zaškrtněte políčko Povolit vkládání.

Snímek obrazovky DetailsView s vlastností CategoryID nastavenou na NewCategory, hodnoty vlastností Height a Width jsou prázdné a políčko Povolit vkládání zaškrtnuté

Obrázek 6: Vytvoření vazby DetailsView na CategoriesDataSource a Povolit vkládání (kliknutím zobrazíte obrázek v plné velikosti)

Chcete-li trvale vykreslit DetailsView v jeho rozhraní pro vložení, nastavte jeho DefaultMode vlastnost na Insert.

Všimněte si, že DetailsView má pět BoundFields CategoryID, CategoryName, Description, NumberOfProductsa BrochurePath ačkoli CategoryID BoundField není vykreslen v rozhraní vkládání, protože jeho InsertVisible vlastnost je nastavena na False. Tyto BoundFields existují, protože se jedná o sloupce vrácené metodou GetCategories() , což je to, co ObjectDataSource vyvolá k načtení svých dat. Pro vkládání ale nechceme, aby uživatel zadal hodnotu pro NumberOfProducts. Kromě toho jim musíme povolit nahrání obrázku pro novou kategorii i nahrání souboru PDF pro brožuru.

NumberOfProducts Úplně odeberte BoundField z DetailsView a potom aktualizujte HeaderText vlastnosti CategoryName objektů a BrochurePath BoundFields na Kategorie a Brožura v uvedeném pořadí. Dále převeďte BoundField na BrochurePath TemplateField a přidejte nové TemplateField pro obrázek, aby toto nové TemplateField získalo HeaderText hodnotu Picture. Picture Přesuňte pole TemplateField tak, aby bylo mezi BrochurePath ŠablonaPole a CommandField.

Snímek obrazovky s oknem polí se zvýrazněnými položkami TemplateField, Picture a HeaderText

Obrázek 7: Vytvoření vazby prvku DetailsView na objekty CategoriesDataSource a Povolit vkládání

Pokud jste boundField převedli BrochurePath na TemplateField prostřednictvím dialogového okna Upravit pole, templateField obsahuje ItemTemplate, EditItemTemplatea InsertItemTemplate. InsertItemTemplate Je však potřeba pouze , takže můžete odebrat další dvě šablony. V tomto okamžiku by deklarativní syntaxe DetailsView měla vypadat takto:

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

Přidání ovládacích prvků SouborNahrání pro pole brožury a obrázku

BrochurePath V současné době TemplateField s InsertItemTemplate obsahuje TextBox, zatímco Picture TemplateField neobsahuje žádné šablony. Tyto dvě šablony InsertItemTemplate Musíme aktualizovat tak, aby používaly ovládací prvky FileUpload.

Z inteligentní značky DetailsView zvolte možnost Upravit šablony a pak v rozevíracím seznamu vyberte BrochurePath TemplateField s InsertItemTemplate . Odeberte TextBox a přetáhněte ovládací prvek FileUpload z panelu nástrojů do šablony. Nastavte ovládací prvek FileUpload na IDBrochureUpload. Podobně přidejte ovládací prvek FileUpload do Picture TemplateField s InsertItemTemplate. Nastavte tento ovládací prvek FileUpload na IDPictureUpload.

Přidání ovládacího prvku FileUpload do InsertItemTemplate

Obrázek 8: Přidání ovládacího prvku FileUpload do InsertItemTemplate (kliknutím zobrazíte obrázek v plné velikosti)

Po přidání těchto funkcí budou dvě deklarativní syntaxe TemplateField:

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

Když uživatel přidá novou kategorii, chceme zajistit, aby brožura a obrázek byly správného typu souboru. Pro brožuru musí uživatel zadat SOUBOR PDF. U obrázku potřebujeme, aby uživatel nahrál soubor obrázku, ale povolíme nějaký soubor obrázku nebo jenom soubory obrázků určitého typu, jako jsou gify nebo jpgy? Aby bylo možné použít různé typy souborů, museli bychom schéma rozšířit Categories tak, aby zahrnovalo sloupec, který zachycuje typ souboru, aby bylo možné tento typ odeslat klientovi prostřednictvím Response.ContentType příkazu v DisplayCategoryPicture.aspx. Vzhledem k tomu, že takový sloupec nemáme, bylo by rozumné omezit uživatele tak, aby poskytovali pouze konkrétní typ souboru obrázku. Existující Categories obrázky tabulky jsou rastrové obrázky, ale soubory JPG jsou vhodnějším formátem souborů pro obrázky obsluhované přes web.

Pokud uživatel nahraje nesprávný typ souboru, musíme vložení zrušit a zobrazit zprávu o problému. Přidejte ovládací prvek Label Web pod DetailsView. Nastavte jeho ID vlastnost na UploadWarning, vymažte jeho Text vlastnost, nastavte CssClass vlastnost na Warning a Visible vlastnosti a EnableViewState na False. Třída Warning CSS je definována v Styles.css a vykreslí text velkým, červeným, tučným písmem kurzívou.

Poznámka

V ideálním CategoryName případě by se boundfields a Description převedli na TemplateFields a jejich rozhraní pro vkládání by se přizpůsobila. Například Description rozhraní pro vkládání bude pravděpodobně vhodnější prostřednictvím víceřádkového textového pole. A vzhledem k tomu, že CategoryName sloupec nepřijímá NULL hodnoty, měl by být přidán RequiredFieldValidator, aby se zajistilo, že uživatel poskytne hodnotu pro název nové kategorie. Tyto kroky jsou ponechány jako cvičení pro čtenáře. Podrobné informace o rozšíření rozhraní pro úpravu dat najdete v tématu Přizpůsobení rozhraní pro úpravy dat.

Krok 6: Uložení nahrané brožury do systému souborů webového serveru

Když uživatel zadá hodnoty pro novou kategorii a klikne na tlačítko Vložit, dojde k zpětnému odeslání a pracovní postup vložení se rozbalí. Nejprve se aktivuje událost DetailsView sItemInserting. Dále je vyvolána metoda ObjectDataSource s Insert() , která má za následek přidání nového záznamu Categories do tabulky. Poté se aktivuje událost DetailsViewItemInserted.

Před vyvoláním metody ObjectDataSource Insert() s musíme nejprve ověřit, že uživatel nahrál příslušné typy souborů, a pak uložit pdf brožuru do systému souborů webového serveru. Vytvořte obslužnou rutinu události pro událost DetailsView a ItemInserting přidejte následující kód:

' 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

Obslužná rutina události začíná odkazem na BrochureUpload ovládací prvek FileUpload ze šablon DetailsView. Pokud se pak nahraje brožura, prověří se přípona nahraného souboru. Pokud rozšíření není .PDF, zobrazí se upozornění, vložení se zruší a zpracování obslužné rutiny události skončí.

Poznámka

Spoléhat se na nahranou příponu souboru není jistá technika, jak zajistit, aby byl nahraný soubor dokument PDF. Uživatel mohl mít platný dokument PDF s příponou .Brochurenebo mohl vzít dokument, který není ve formátu PDF, a dát mu příponu .pdf . Binární obsah souboru by bylo potřeba programově prozkoumat, aby bylo možné typ souboru jednoznačněji ověřit. Takové důkladné přístupy jsou však často přehnané; kontrola rozšíření je pro většinu scénářů dostatečná.

Jak je popsáno v kurzu Nahrávání souborů , při ukládání souborů do systému souborů je potřeba dbát na to, aby nahrávání jednoho uživatele nepřepsalo jiné soubory. V tomto kurzu se pokusíme použít stejný název jako nahraný soubor. Pokud už ale v ~/Brochures adresáři existuje soubor se stejným názvem, připojíme na konec číslo, dokud nenajdete jedinečný název. Pokud například uživatel nahraje soubor brožury s názvem Meats.pdf, ale ve ~/Brochures složce už soubor s názvem Meats.pdf existuje, změníme název uloženého souboru na Meats-1.pdf. Pokud existuje, zkusíme Meats-2.pdf, a tak dále, dokud nenajdete jedinečný název souboru.

Následující kód používá metoduFile.Exists(path) k určení, jestli soubor se zadaným názvem již existuje. Pokud ano, bude dál zkoušet nové názvy souborů pro brožuru, dokud se nenajde žádný konflikt.

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

Po nalezení platného názvu souboru je třeba soubor uložit do systému souborů a hodnotu ObjectDataSource brochurePath``InsertParameter je potřeba aktualizovat tak, aby se tento název souboru zapisoval do databáze. Jak jsme viděli v kurzu Nahrávání souborů , soubor se dá uložit pomocí metody ovládacího prvku SaveAs(path) FileUpload. Pokud chcete aktualizovat parametr ObjectDataSource s brochurePath , použijte kolekci e.Values .

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

Krok 7: Uložení nahraného obrázku do databáze

K uložení nahraného obrázku do nového Categories záznamu musíme nahraný binární obsah přiřadit parametru ObjectDataSource s picture v události DetailsView s ItemInserting . Než ale toto zadání provedeme, musíme se nejdřív ujistit, že nahraný obrázek je jpg, a ne nějaký jiný typ obrázku. Stejně jako v kroku 6 pomocí nahrané přípony souboru obrázku zjistíme jeho typ.

Categories I když tabulka umožňuje NULL hodnoty pro Picture sloupec, všechny kategorie aktuálně mají obrázek. Vynutíme uživatele, aby při přidávání nové kategorie prostřednictvím této stránky zadal obrázek. Následující kód zkontroluje, jestli je obrázek nahraný a jestli má odpovídající příponu.

' 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

Tento kód by měl být umístěn před kódem z kroku 6, aby se v případě problému s nahráváním obrázku obslužná rutina události ukončila před uložením souboru brožury do systému souborů.

Za předpokladu, že byl nahrán příslušný soubor, přiřaďte nahraný binární obsah hodnotě parametru obrázku s následujícím řádkem kódu:

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

KompletníItemInsertingobslužná rutina události

Pro úplnost tady je ItemInserting celá obslužná rutina události:

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

Krok 8: OpravaDisplayCategoryPicture.aspxstránky

Chvíli si zabereme, než otestujeme rozhraní pro vkládání a ItemInserting obslužnou rutinu události, které byly vytvořeny v několika posledních krocích. Přejděte na UploadInDetailsView.aspx stránku v prohlížeči a pokuste se přidat kategorii, ale vynechat obrázek, nebo zadat jiný obrázek než JPG nebo brožuru bez PDF. V každém z těchto případů se zobrazí chybová zpráva a pracovní postup vložení bude zrušen.

Pokud se nahraje neplatný typ souboru, zobrazí se zpráva upozornění.

Obrázek 9: V případě nahrání neplatného typu souboru se zobrazí zpráva upozornění (kliknutím zobrazíte obrázek v plné velikosti).

Jakmile ověříte, že stránka vyžaduje nahrání obrázku, a nebude přijímat jiné soubory než PDF nebo JPG, přidejte novou kategorii s platným obrázkem JPG a pole Brožura nechte prázdné. Po kliknutí na tlačítko Vložit se stránka odešle zpět a do Categories tabulky se přidá nový záznam s nahraným binárním obsahem obrázku uloženým přímo v databázi. Objekt GridView se aktualizuje a zobrazí řádek pro nově přidanou kategorii, ale jak ukazuje obrázek na obrázku 10, obrázek nové kategorie se nevykreslí správně.

Nový obrázek kategorie se nezobrazuje.

Obrázek 10: Nový obrázek kategorie se nezobrazuje (kliknutím zobrazíte obrázek v plné velikosti)

Nový obrázek se nezobrazuje DisplayCategoryPicture.aspx proto, že stránka, která vrací obrázek zadané kategorie, je nakonfigurovaná tak, aby zpracovávala rastrové obrázky, které mají záhlaví OLE. Tato hlavička 78 bajtů je odstraněna z binárního Picture obsahu sloupce před odesláním zpět klientovi. Ale soubor JPG, který jsme právě nahráli pro novou kategorii, nemá tuto hlavičku OLE; proto jsou z binárních dat obrázku odebrány platné nezbytné bajty.

Vzhledem k tomu, že v Categories tabulce jsou nyní oba rastrové obrázky se záhlavími OLE a jpgy, musíme provést aktualizaci DisplayCategoryPicture.aspx tak, aby pro původních osm kategorií provedlo odkládání záhlaví OLE a obcházení pro novější záznamy kategorií. V dalším kurzu prozkoumáme, jak aktualizovat existující obrázek záznamu, a všechny staré obrázky kategorie aktualizujeme tak, aby se jedná o soubory JPG. Prozatím ale použijte následující kód v nástroji DisplayCategoryPicture.aspx k odebrání hlaviček OLE pouze pro těchto původních osm kategorií:

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

Díky této změně se teď obrázek JPG v GridView vykreslí správně.

Obrázky JPG pro nové kategorie se vykreslují správně.

Obrázek 11: Obrázky JPG pro nové kategorie jsou správně vykresleny (kliknutím zobrazíte obrázek v plné velikosti)

Krok 9: Odstranění brožury v okně s výjimkou

Jedním z problémů při ukládání binárních dat do systému souborů webového serveru je to, že zavádí odpojení mezi datovým modelem a jeho binárními daty. Proto je při každém odstranění záznamu nutné odebrat také odpovídající binární data v systému souborů. To může přijít v úvahu i při vkládání. Představte si následující scénář: Uživatel přidá novou kategorii a zadá platný obrázek a brožuru. Po kliknutí na tlačítko Vložit dojde k zpětnému odeslání a aktivuje se událost DetailsView s ItemInserting , která uloží brožuru do systému souborů webového serveru. Dále je vyvolána metoda ObjectDataSource s Insert() , která volá metodu CategoriesBLL třídy s InsertWithPicture , která volá metodu CategoriesTableAdapter s InsertWithPicture .

Co se stane, když je databáze offline nebo pokud je v INSERT příkazu SQL chyba? Je zřejmé, že funkce INSERT selže, takže do databáze nebude přidán žádný nový řádek kategorie. Ale stále máme nahraný soubor brožury sedí v systému souborů webového serveru! Tento soubor je potřeba odstranit kvůli výjimce během pracovního postupu vkládání.

Jak bylo popsáno dříve v kurzu Zpracování výjimek BLL a DAL-Level v kurzu ASP.NET Page , pokud je výjimka vyvolána z hloubky architektury, probubluje se v různých vrstvách. Na prezentační vrstvě můžeme zjistit, jestli došlo k výjimce z události DetailsView s ItemInserted . Tato obslužná rutina události také poskytuje hodnoty ObjectDataSource s InsertParameters. Proto můžeme pro událost vytvořit obslužnou rutinu ItemInserted události, která zkontroluje, jestli nedošlo k výjimce, a pokud ano, odstraní soubor určený parametrem 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

Souhrn

Existuje několik kroků, které je třeba provést, aby bylo možné poskytnout webové rozhraní pro přidání záznamů, které obsahují binární data. Pokud se binární data ukládají přímo do databáze, je pravděpodobné, že budete muset aktualizovat architekturu a přidat konkrétní metody pro zpracování případu, kdy se binární data vkládají. Po aktualizaci architektury je dalším krokem vytvoření rozhraní pro vkládání, které lze provést pomocí DetailsView, který byl přizpůsoben tak, aby zahrnoval fileUpload ovládací prvek pro každé binární datové pole. Nahraná data pak mohou být uložena do systému souborů webového serveru nebo přiřazena k parametru zdroje dat v obslužné rutině události DetailsView s ItemInserting .

Ukládání binárních dat do systému souborů vyžaduje více plánování než ukládání dat přímo do databáze. Je třeba zvolit schéma pojmenování, aby se zabránilo tomu, že jeden uživatel nahraje jiný s. V případě selhání vložení databáze je také nutné provést další kroky k odstranění nahraného souboru.

Teď máme možnost přidat do systému nové kategorie pomocí brožury a obrázku, ale zatím jsme se nezabížili na to, jak aktualizovat existující binární data kategorií nebo jak správně odebrat binární data pro odstraněnou kategorii. Tato dvě témata prozkoumáme v dalším kurzu.

Šťastné programování!

O autorovi

Scott Mitchell, autor sedmi knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Můžete ho najít na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na http://ScottOnWriting.NETadrese .

Zvláštní poděkování

Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavními recenzenty tohoto kurzu byli Dave Gardner, Teresa Murphy a Bernadette Leigh. Chcete si projít moje nadcházející články na WEBU MSDN? Pokud ano, dejte mi čáru na mitchell@4GuysFromRolla.comadresu .