Zahrnutí možnosti nahrání souboru při přidání nového záznamu (VB)
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 CategoryName
pole , Description
a 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íInsertWithPicture
metody doCategoriesTableAdapter
Když jsme vytvořili CategoriesTableAdapter
back v kurzu Vytvoření vrstvy přístupu k datům , nakonfigurovali jsme ho tak, aby automaticky vygeneroval INSERT
příkazy , UPDATE
a 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
, Update
a Delete
. Tyto metody spouštějí automaticky vygenerované INSERT
příkazy , UPDATE
a 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 InsertWithPicture
přijme hodnoty sloupců CategoryName
, Description
, BrochurePath
a 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ší.
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ží CategoryName
hodnoty , Description
a 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.
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.aspx
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í.
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: KonfiguraceCategoriesDataSource
pro 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.
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í.
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
, NumberOfProducts
a 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.
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
, EditItemTemplate
a 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 ID
BrochureUpload
. Podobně přidejte ovládací prvek FileUpload do Picture
TemplateField s InsertItemTemplate
. Nastavte tento ovládací prvek FileUpload na ID
PictureUpload
.
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 .Brochure
nebo 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íItemInserting
obsluž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.aspx
strá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.
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ě.
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á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 .