Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V tomto kurzu se dozvíte, jak vytvořit webové rozhraní, které uživateli umožní zadat textová data a nahrát binární soubory. Pro ilustraci možností dostupných k ukládání binárních dat se jeden soubor uloží do databáze, zatímco druhý je uložen v systému souborů.
Úvod
V předchozích dvou kurzech jsme prozkoumali techniky pro ukládání binárních dat přidružených k datovému modelu aplikace, podívali jsme se, jak pomocí ovládacího prvku FileUpload odesílat soubory z klienta na webový server a jak prezentovat tato binární data v ovládacím prvku datového webu. Ještě jsme nemluvili o tom, jak přidružit nahraná data k datovému modelu.
V tomto kurzu vytvoříme webovou stránku pro přidání nové kategorie. 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 bude uložen přímo ve sloupci nového záznamu Picture , zatímco brožura se uloží do ~/Brochures složky s cestou k souboru uloženému ve sloupci nového záznamu BrochurePath .
Před vytvořením této nové webové stránky budeme muset aktualizovat architekturu. Hlavní CategoriesTableAdapter dotaz nenačte Picture sloupec. V důsledku toho má automaticky generovaná Insert metoda pouze vstupy pro CategoryName, Descriptiona BrochurePath pole. Proto potřebujeme v objektu TableAdapter vytvořit další metodu, která zobrazí výzvu pro všechna čtyři Categories pole. Třída CategoriesBLL ve vrstvě obchodní logiky bude také potřeba aktualizovat.
Krok 1: PřidáníInsertWithPicturemetody doCategoriesTableAdapter
Když jsme vytvořili CategoriesTableAdapter zpět v kurzu Vytvoření vrstvy přístupu k datům, nakonfigurovali jsme ho tak, aby automaticky generoval INSERTUPDATE, a DELETE příkazy založené na hlavním dotazu. Kromě toho jsme instruovali Objekt TableAdapter, aby použil přímý přístup DB, který vytvořil metody Insert, Updatea Delete. Tyto metody spouští automaticky generované INSERTpříkazy , UPDATEa DELETE následně přijímají vstupní parametry na základě sloupců vrácených hlavním dotazem. V kurzu Nahrání souborů jsme rozšířili CategoriesTableAdapter hlavní dotaz tak, aby používal BrochurePath sloupec.
CategoriesTableAdapter Vzhledem k tomu, že hlavní dotaz neodkazuje na Picture sloupec, nemůžeme přidat nový záznam ani aktualizovat existující záznam o hodnotě Picture sloupce. Abychom mohli tyto informace zachytit, 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 generovaného INSERT příkazu spočívá v tom, že riskujeme, že průvodce přepíše vlastní nastavení. Představte si například, že jsme přizpůsobili INSERT příkaz tak, aby zahrnoval použití Picture sloupce. Tím by se aktualizovala metoda TableAdapter s Insert tak, aby obsahovala další vstupní parametr binárních dat s obrázkem 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šechno by fungovalo skvěle. To znamená, že až do příštího nastavení TableAdapteru prostřednictvím Průvodce konfigurací TableAdapteru. Jakmile průvodce dokončíte, naše přizpůsobení INSERT příkazu se přepíše, Insert metoda se vrátí do původního formuláře a náš kód už nebude kompilován!
Poznámka:
Tato nepříjemnost není problémem, když místo příkazů SQL ad hoc používáte uložené procedury. V dalším kurzu se seznámíte s používáním uložených procedur místo ad hoc příkazů SQL ve vrstvě přístupu k datům.
Abyste se vyhnuli této potenciální bolesti hlavy, místo přizpůsobení automaticky generovaných příkazů SQL místo toho vytvořte novou metodu pro TableAdapter. Tato metoda s názvem InsertWithPicturepřijme hodnoty pro CategoryName, Description, BrochurePatha sloupce a Picture spustí INSERT příkaz, který ukládá všechny čtyři hodnoty v novém záznamu.
Otevřete typovou datovou sadu a v Návrháři klikněte pravým tlačítkem myši na CategoriesTableAdapter záhlaví a v místní nabídce zvolte Přidat dotaz. Tím se spustí Průvodce konfigurací dotazu TableAdapter, který začíná dotazem, jak má 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 INSERT a klikněte na Další.
Obrázek 1: Výběr možnosti VLOŽIT (kliknutím zobrazíte obrázek s plnou velikostí)
Teď musíme zadat INSERT příkaz SQL. Průvodce automaticky navrhne INSERT příkaz odpovídající hlavnímu dotazu TableAdapter. V tomto případě je INSERT to příkaz, který vloží CategoryName, Descriptiona BrochurePath hodnoty. Aktualizujte prohlášení tak, aby byl sloupec Picture 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 požádá o pojmenování nové metody TableAdapter. Zadejte InsertWithPicture a klikněte na Dokončit.
Obrázek 2: Pojmenování metody InsertWithPicture New 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 pouze rozhraní s vrstvou obchodní logiky a nemělo by jít přímo do vrstvy přístupu k datům, musíme vytvořit metodu BLL, která vyvolá metodu DAL, kterou jsme právě vytvořili (InsertWithPicture). Pro účely tohoto kurzu vytvořte metodu ve třídě CategoriesBLL s názvem InsertWithPicture, která přijímá jako vstup tři String a pole Byte. Vstupní String parametry jsou určené pro název kategorie, popis a cestu k souboru brožury, zatímco Byte pole je určené 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:
Než přidáte metodu InsertWithPicture do BLL, ujistěte se, že jste uložili Typed DataSet. Vzhledem k tomu, že kód třídy je automaticky generován na základě Typed DataSet, platí, že pokud nejprve neuložíte změny do Typed DataSet, vlastnost CategoriesTableAdapter nebude informována o metodě Adapter.
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 se TemplateField a ImageField k zobrazení názvu každé kategorie, popisu, obrázku a odkazu ke stažení brožury. Pojďme tuto funkci pro účely tohoto kurzu replikovat a vytvořit stránku se seznamem všech existujících kategorií a umožnit vytvoř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 ze třídy DisplayOrDownload.aspx do UploadInDetailsView.aspx.
Obrázek 3: Kopírování a vložení deklarativní syntaxe z DisplayOrDownload.aspx do UploadInDetailsView.aspx (kliknutím zobrazíte obrázek s plnou velikostí)
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 zkopírovalo správně. Měli byste vidět GridView se seznamem osmi kategorií, které obsahují odkaz ke stažení brožury a obrázku kategorie.
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: Nastavení CategoriesDataSource pro podporu vkládání
CategoriesDataSource ObjectDataSource používaný Categories GridView v současné době neposkytuje možnost vložit data. Abychom mohli podporovat vkládání prostřednictvím této správy zdrojů dat, musíme jeho Insert metodu namapovat na metodu v jeho podkladové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. Na první obrazovce se zobrazí objekt, se kterým je zdroj dat nakonfigurován pro práci, CategoriesBLL. Toto nastavení ponechte as-is a kliknutím na Tlačítko Další přejděte na obrazovku Definovat metody dat. Přejděte na kartu INSERT a vyberte metodu InsertWithPicture z rozevíracího seznamu. Kliknutím na tlačítko Dokončit dokončete průvodce.
Obrázek 5: Konfigurace ObjectDataSource pro použití InsertWithPicture metody (kliknutím zobrazíte obrázek s plnou velikostí)
Poznámka:
Po dokončení průvodce se vás Visual Studio může zeptat, jestli chcete aktualizovat pole a klíče, což znovu vygeneruje pole ovládacích prvků datových webů. Zvolte Ne, protože když zvolíte Ano, přepíšete všechna vlastní nastavení polí, která jste udělali.
Po dokončení průvodce bude ObjectDataSource nyní obsahovat hodnotu pro jeho InsertMethod vlastnost a také 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 vložení
Jak je poprvé popsáno v části Přehled vkládání, aktualizace a odstraňování dat, poskytuje ovládací prvek DetailsView 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 na tuto stránku přidat ovládací prvek DetailsView nad GridView, který trvale vykresluje jeho vložené rozhraní, což uživateli umožní rychle přidat novou kategorii. Po přidání nové kategorie v DetailsView, GridView pod ní automaticky aktualizuje a zobrazí novou kategorii.
Začněte přetažením DetailsView z panelu nástrojů do Návrháře nad GridView, nastavením vlastnosti ID na NewCategory a vymazáním hodnot vlastností Height a Width. Z inteligentní značky DetailsView vytvořte vazbu na existující CategoriesDataSource a zaškrtněte políčko Povolit vkládání.
Obrázek 6: Vytvoření vazby DetailsView k CategoriesDataSource a povolení vkládání (kliknutím zobrazíte obrázek s plnou velikostí)
Pro trvalé zobrazení rozhraní pro vkládání v DetailsView nastavte jeho vlastnost DefaultMode 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í pro vložení, protože jeho InsertVisible vlastnost je nastavena na False. Tyto BoundFields existují, protože jsou sloupce vrácené metodou GetCategories() , což je to, co ObjectDataSource vyvolá k načtení svých dat. Pro vložení však nechceme, aby uživatel zadal hodnotu pro NumberOfProducts. Kromě toho musíme umožnit, aby nahráli obrázek pro novou kategorii a také nahráli PDF pro brožuru.
NumberOfProducts Odeberte položku BoundField z DetailsView úplně a pak aktualizujte HeaderText vlastnosti CategoryName a BrochurePath položek BoundField na Kategorie a Brožura. V dalším kroku převeďte BrochurePath BoundField na TemplateField a přidejte nový TemplateField pro obrázek, a této nové TemplateField přiřaďte hodnotu HeaderText Picture. Přesuňte pole Picture TemplateField tak, aby bylo mezi polem BrochurePath TemplateField a CommandField.
Obrázek 7: Vytvoření vazby DetailsView k CategoriesDataSource a povolení vkládání
Pokud jste převedli BrochurePath BoundField na TemplateField prostřednictvím dialogového okna Upravit pole, pole TemplateField obsahuje hodnotu ItemTemplate, EditItemTemplatea InsertItemTemplate. Jenom InsertItemTemplate je potřeba, takže klidně můžete odstranit zbývající 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ů FileUpload pro pole brožury a obrázku
V současné době BrochurePath TemplateField obsahuje InsertItemTemplate TextBox, zatímco Picture TemplateField nezahrnuje žádné šablony. Potřebujeme aktualizovat tyto dva TemplateField InsertItemTemplate 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 ze sady nástrojů do šablony. Nastavte ovládací prvek FileUpload na IDBrochureUpload hodnotu. Podobně přidejte ovládací prvek FileUpload do Picture TemplateField s InsertItemTemplate. Nastavte tento ovládací prvek typu FileUpload z ID na PictureUpload.
Obrázek 8: Přidání ovládacího prvku FileUpload do InsertItemTemplate (kliknutím zobrazíte obrázek s plnou velikostí)
Po přidání těchto doplňků bude deklarativní syntax dvou 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 PDF. U obrázku potřebujeme, aby uživatel nahrál soubor obrázku, ale povolujeme jakýkoli soubor obrázku nebo jenom soubory obrázků určitého typu, jako jsou GIFy nebo JPG? Abychom umožnili různé typy souborů, musíme rozšířit schéma Categories zahrnutím sloupce, který zachytí typ souboru, aby tento typ mohl být odeslán klientovi prostřednictvím Response.ContentType v rámci DisplayCategoryPicture.aspx. Vzhledem k tomu, že takový sloupec nemáme, bylo by vhodné omezit uživatele pouze na poskytnutí konkrétního typu souboru obrázku. Existující obrázky v tabulce Categories jsou bitmapy, ale JPG jsou vhodnější formát souboru pro obrázky poskytované přes web.
Pokud uživatel nahraje nesprávný typ souboru, musíme vložení zrušit a zobrazit zprávu s informací o problému. Pod DetailsView přidejte ovládací prvek Label Web. Nastavte jeho ID vlastnost na UploadWarning, vymažte jeho Text vlastnost, nastavte CssClass vlastnost na Upozornění a vlastnosti Visible a EnableViewState na False. Třída Warning CSS je definována v Styles.css a vykresluje text pomocí velkého, červeného, tučného kurzívního písma.
Poznámka:
Ideálně by měly být CategoryName a Description BoundFields převedeny na TemplateFields a rozhraní pro jejich vkládání by mělo být přizpůsobeno. Rozhraní Description pro vkládání by mohlo být například 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 pro čtenáře ponechány jako cvičení. Vraťte se k přizpůsobení rozhraní pro úpravu dat , abyste se podrobněji podívali na rozšíření rozhraní pro úpravy dat.
Krok 6: Uložení nahrané brožury do systému souborů webového serveru
Když uživatel zadává hodnoty pro novou kategorii a klikne na tlačítko Vložit, dojde k postbacku a zahájí se proces vkládání. Nejprve se aktivuje událost DetailsViewItemInserting. Dále je vyvolána metoda ObjectDataSource Insert() , která vede k přidání nového záznamu Categories do tabulky. Potom se událost DetailsView ItemInserted aktivuje.
Před vyvoláním metody ObjectDataSource Insert() musíme nejprve zajistit, aby uživatel nahrál příslušné typy souborů, a pak uložte brožuru PDF do systému souborů webového serveru. Vytvořte obslužnou rutinu události pro událost DetailsView ItemInserting a 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á odkazováním na BrochureUpload ovládací prvek FileUpload z šablon DetailsView. Pokud se pak nahraje brožura, prozkoumá se přípona nahraného souboru. Pokud rozšíření není .PDF, zobrazí se upozornění, vložení se zruší a spuštění obslužné rutiny události skončí.
Poznámka:
Spoléhat se na nahranou příponu souboru není jistá technika, jak zajistit, aby nahraný soubor byl dokument PDF. Uživatel může mít platný dokument PDF s příponou .Brochurenebo mohl pořídil jiný dokument než PDF a dal mu příponu .pdf . Binární obsah souboru by bylo potřeba zkoumat programově, aby bylo možné jednoznačně ověřit typ souboru. Takové důkladné přístupy jsou však často zbytečné; pro většinu scénářů stačí kontrola přípony.
Jak je popsáno v kurzu Nahrávání souborů , při ukládání souborů do systému souborů je potřeba věnovat pozornost, aby jeden uživatel nahrání nepřepsal jiné soubory. V tomto kurzu se pokusíme použít stejný název jako nahraný soubor. Pokud už v ~/Brochures adresáři existuje soubor se stejným názvem, připojíme na konec číslo, dokud se nenajde jedinečný název. Pokud například uživatel nahraje soubor brožury s názvem Meats.pdf, ale ve složce už existuje soubor s názvem Meats.pdf~/Brochures , změníme název uloženého souboru na Meats-1.pdf. Pokud daný název souboru existuje, zkusíme Meats-2.pdf a budeme pokračovat, dokud se nenajde jedinečný název souboru.
Následující kód používá metoduFile.Exists(path) k určení, zda soubor již existuje se zadaným názvem souboru. Pokud ano, bude i nadále 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 musí být soubor uložen do systému souborů a hodnota ObjectDataSource s brochurePath``InsertParameter musí být aktualizována tak, aby byl tento název souboru zapsán do databáze. Jak jsme viděli zpět v kurzu Uploading Files , soubor lze uložit pomocí Metody FileUpload ovládacího prvku SaveAs(path) . K aktualizaci parametru ObjectDataSource 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 přiřadit nahraný binární obsah k parametru ObjectDataSource picture v události DetailsView s ItemInserting . Než ale toto zadání provedeme, musíme nejprve ověřit, že nahraný obrázek je JPG, a ne nějaký jiný typ obrázku. Stejně jako v kroku 6 použijeme příponu nahraného obrázku k určení jeho typu.
I když Categories tabulka umožňuje hodnoty NULL pro sloupec Picture, všechny kategorie aktuálně mají obrázek. Pojďme vynutit, aby uživatel 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 že má odpovídající rozšíření.
' 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ód z kroku 6, aby pokud došlo k problému s nahráním obrázku, obslužná rutina události se ukončí před uložením souboru brožury do systému souborů.
Za předpokladu, že byl nahraný soubor odeslán, přiřaďte nahraný binární obsah hodnotě parametru obrázku následujícím řádkem kódu:
' Set the value of the picture parameter
e.Values("picture") = PictureUpload.FileBytes
ÚplnýItemInsertingzpracovatel událostí
Pro úplnost zde je ItemInserting obslužná rutina události v celé své podobě:
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
Pojďme si udělat chvíli na otestování rozhraní pro vkládání a obslužné rutiny události ItemInserting, která byla vytvořena v posledních několika krocích.
UploadInDetailsView.aspx Navštivte stránku v prohlížeči a pokuste se přidat kategorii, ale vynecháte obrázek nebo zadejte jiný obrázek než JPG nebo brožuru, která není PDF. V každém z těchto případů se zobrazí chybová zpráva a pracovní postup vložení byl zrušen.
Obrázek 9: Při nahrání neplatného typu souboru se zobrazí zpráva s upozorněním (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 jiné soubory než JPG, přidejte novou kategorii s platným obrázkem JPG a pole Brožura ponechte prázdné. Po kliknutí na tlačítko Vložit se stránka znovu načte a do tabulky Categories se přidá nový záznam s binárním obsahem nahraného obrázku, který je uložen přímo v databázi. Objekt GridView se aktualizuje a zobrazí řádek pro nově přidanou kategorii, ale jak ukazuje obrázek 10, nový obrázek kategorie se nevykreslí správně.
Obrázek 10: Obrázek nové kategorie se nezobrazuje (kliknutím zobrazíte obrázek v plné velikosti).
Důvodem, proč se nový obrázek nezobrazí, je to, že DisplayCategoryPicture.aspx stránka, která vrací zadaný obrázek kategorie, je nakonfigurována pro zpracování rastrových obrázků, které mají záhlaví OLE. Tato hlavička velikosti 78 bajtů je z binárního obsahu sloupce Picture odebrána před odesláním zpět ke 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 nezbytné bajty.
Vzhledem k tomu, že v tabulce jsou nyní rastrové obrázky se záhlavími OLE a JPG Categories, musíme aktualizovat DisplayCategoryPicture.aspx tak, aby záhlaví OLE bylo odebráno pro původní osm kategorií a bylo vynecháno u novějších záznamů kategorií. V dalším kurzu se podíváme, jak aktualizovat existující obrázek záznamu a aktualizujeme všechny staré obrázky kategorií tak, aby byly jpgy. Prozatím však pomocí následujícího kódu DisplayCategoryPicture.aspx odstraňte záhlaví OLE pouze pro tyto původní 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
Při této změně se teď obrázek JPG v GridView vykresluje správně.
Obrázek 11: Obrázky JPG pro nové kategorie se správně vykreslují (kliknutím zobrazíte obrázek v plné velikosti).
Krok 9: Odstranění brožury kvůli výjimce.
Jedním z problémů při ukládání binárních dat do systému souborů webového serveru je, že představuje odpojení mezi datovým modelem a jeho binárními daty. Proto se při každém odstranění záznamu musí odebrat také odpovídající binární data v systému souborů. To může mít vliv 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 vrácení a aktivuje se událost DetailsView ItemInserting a uloží se brožura do systému souborů webového serveru. Dále je vyvolána ObjectDataSource s Insert() metoda, která volá metodu CategoriesBLL třídy s InsertWithPicture , která volá metodu CategoriesTableAdapter s InsertWithPicture .
Co se stane, když je databáze offline nebo pokud dojde k chybě v INSERT příkazu SQL? Vložení bude zjevně neúspěšné, takže do databáze se nepřidá žádný nový řádek kategorií. Ale stále máme nahraný soubor brožury sedící na systému souborů webového serveru! Tento soubor je potřeba odstranit v případě výjimky během vkládání.
Jak jsme už dříve probírali v kurzu zpracování výjimek BLL a DAL-Level v ASP.NET Page, když se výjimka vyvolá z hloubky architektury, je předávána různými vrstvami. V prezentační vrstvě můžeme určit, 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 vytvořit obslužnou rutinu události pro ItemInserted událost, která zkontroluje, jestli došlo k výjimce, a pokud ano, odstraní soubor určený parametrem ObjectDataSource 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
Shrnutí
Existuje několik kroků, které je potř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, pravděpodobně budete muset aktualizovat architekturu a přidat konkrétní metody pro zpracování případu vložení binárních dat. 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 je pak možné uložit do systému souborů webového serveru nebo přiřadit parametru zdroje dat v obslužné rutině události DetailsView ItemInserting .
Ukládání binárních dat do systému souborů vyžaduje větší plánování než ukládání dat přímo do databáze. Aby se zabránilo přepsání nahrávky jednoho uživatele nahrávkou dalšího, musí být zvoleno schéma pojmenování. Navíc je potřeba provést další kroky pro odstranění nahraného souboru, pokud se vložení databáze nezdaří.
Nyní máme možnost přidat do systému nové kategorie s brožurou a obrázkem, ale ještě jsme nezvážili, jak aktualizovat binární data stávajících 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 ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, trenér a spisovatel. Jeho nejnovější kniha je Sams: Nauč se ASP.NET 2.0 za 24 hodin. Může být dosažitelný na mitchell@4GuysFromRolla.comadrese .
Zvláštní díky
Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Vedoucí recenzenti tohoto kurzu byli Dave Gardner, Teresa Murphy a Bernadette Leigh. Chcete si projít nadcházející články MSDN? Pokud ano, napište mi zprávu na mitchell@4GuysFromRolla.com.