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 k datovému modelu přidružit nahraná data.
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 dokud příště TableAdapter znovu nekonfigurujeme prostřednictvím Průvodce konfigurací TableAdapter. 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:
Používání uložených procedur místo ad hoc SQL příkazů nepředstavuje problém. 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 výrok 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
Jelikož by prezentační vrstva měla komunikovat pouze s vrstvou obchodní logiky a neměla by se vyhnout této vrstvě tím, že by šla přímo do vrstvy přístupu k datům, je potřeba vytvořit metodu BLL, která volá metodu DAL, kterou jsme právě vytvořili (InsertWithPicture). V tomto kurzu vytvořte metodu CategoriesBLL ve třídě 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 void InsertWithPicture(string categoryName, string description,
string brochurePath, byte[] picture)
{
Adapter.InsertWithPicture(categoryName, description, brochurePath, picture);
}
Poznámka:
Před přidáním metody InsertWithPicture do vrstvy BLL se ujistěte, že jste uložili typovaný DataSet. Vzhledem k tomu, že kód třídy je automaticky generován na základě Typed DataSet, pokud nejprve neuložíte změny v Typed DataSet, vlastnost CategoriesTableAdapter nebude vědět 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 z kódu podkladové 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: Konfigurace 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 ve smart tagu 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 tím, že přetáhnete DetailsView z panelu nástrojů do Návrháře nad GridView, nastavíte jeho vlastnost ID na hodnotu NewCategory a vymažete hodnoty 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í)
Chcete-li trvale vykreslit DetailsView v jeho vložené rozhraní, 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í 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 BoundField z DetailsView úplně a pak aktualizujte HeaderText vlastnosti CategoryName a BrochurePath BoundFields na Category a Brochure. V dalším kroku převeďte BrochurePath BoundField na TemplateField a přidejte nový TemplateField pro obrázek, kterému přiřaďte hodnotu HeaderText Picture.
Picture Přesuňte pole TemplateField tak, aby bylo mezi BrochurePath polem 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. Jelikož je potřeba pouze InsertItemTemplate, můžete tedy 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ů FileUpload pro pole brožury a obrázku
V současné době BrochurePath TemplateField obsahuje InsertItemTemplate TextBox, zatímco Picture TemplateField neobsahuje žá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 s ID na BrochureUpload. Podobně přidejte ovládací prvek FileUpload do Picture TemplateField s InsertItemTemplate. Nastavte tento ovládací prvek FileUpload na hodnotu IDPictureUpload.
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í syntaxe dvou TemplateField následující:
<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 poskytnout 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 tak, aby zahrnovalo sloupec, který zachytí typ souboru, aby tento typ mohl být odeslán klientovi prostřednictvím Response.ContentType v 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 tabulky Categories jsou bitové mapy, ale JPG je vhodnější formát souboru pro obrázky zobrazené na webu.
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 Visible a EnableViewState vlastnosti na false. Třída Warning CSS je definována v Styles.css a vykresluje text ve velkém, červeném, kurzívě, tučném písmu.
Poznámka:
CategoryName a Description BoundFields by byly ideálně převedeny na TemplateFields a jejich vkládací rozhraní přizpůsobena. Rozhraní Description pro vkládání by například mohlo být vhodnější ve víceliniovém textovém poli. 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á hodnoty nové kategorie a klikne na tlačítko Vložit, dojde k zpětnému odeslání a rozbalí se pracovní postup vložení. Nejprve se spustí 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 control
FileUpload BrochureUpload =
(FileUpload)NewCategory.FindControl("BrochureUpload");
if (BrochureUpload.HasFile)
{
// Make sure that a PDF has been uploaded
if (string.Compare(System.IO.Path.GetExtension
(BrochureUpload.FileName), ".pdf", true) != 0)
{
UploadWarning.Text =
"Only PDF documents may be used for a category's brochure.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
}
Obslužná rutina události začíná tím, že odkazuje na ovládací prvek BrochureUpload FileUpload ze šablon v 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 přehnané; 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 to existuje, zkusíme Meats-2.pdf a tak dále, 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 string BrochureDirectory = "~/Brochures/";
string brochurePath = BrochureDirectory + BrochureUpload.FileName;
string fileNameWithoutExtension =
System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName);
int iteration = 1;
while (System.IO.File.Exists(Server.MapPath(brochurePath)))
{
brochurePath = string.Concat(BrochureDirectory,
fileNameWithoutExtension, "-", iteration, ".pdf");
iteration++;
}
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.
Categories I když tabulka umožňuje NULL hodnoty pro Picture sloupec, 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
FileUpload PictureUpload = (FileUpload)NewCategory.FindControl("PictureUpload");
if (PictureUpload.HasFile)
{
// Make sure that a JPG has been uploaded
if (string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName),
".jpg", true) != 0 &&
string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName),
".jpeg", true) != 0)
{
UploadWarning.Text =
"Only JPG documents may be used for a category's picture.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
}
else
{
// No picture uploaded!
UploadWarning.Text =
"You must provide a picture for the new category.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
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áItemInsertingobslužná rutina události
Pro úplnost zde je ItemInserting obslužná rutina události v celé své podobě:
protected void NewCategory_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
// Reference the FileUpload controls
FileUpload PictureUpload = (FileUpload)NewCategory.FindControl("PictureUpload");
if (PictureUpload.HasFile)
{
// Make sure that a JPG has been uploaded
if (string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName),
".jpg", true) != 0 &&
string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName),
".jpeg", true) != 0)
{
UploadWarning.Text =
"Only JPG documents may be used for a category's picture.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
}
else
{
// No picture uploaded!
UploadWarning.Text =
"You must provide a picture for the new category.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
// Set the value of the picture parameter
e.Values["picture"] = PictureUpload.FileBytes;
// Reference the FileUpload controls
FileUpload BrochureUpload =
(FileUpload)NewCategory.FindControl("BrochureUpload");
if (BrochureUpload.HasFile)
{
// Make sure that a PDF has been uploaded
if (string.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName),
".pdf", true) != 0)
{
UploadWarning.Text =
"Only PDF documents may be used for a category's brochure.";
UploadWarning.Visible = true;
e.Cancel = true;
return;
}
const string BrochureDirectory = "~/Brochures/";
string brochurePath = BrochureDirectory + BrochureUpload.FileName;
string fileNameWithoutExtension =
System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName);
int iteration = 1;
while (System.IO.File.Exists(Server.MapPath(brochurePath)))
{
brochurePath = string.Concat(BrochureDirectory, fileNameWithoutExtension,
"-", iteration, ".pdf");
iteration++;
}
// Save the file to disk and set the value of the brochurePath parameter
BrochureUpload.SaveAs(Server.MapPath(brochurePath));
e.Values["brochurePath"] = brochurePath;
}
}
Krok 8: OpravaDisplayCategoryPicture.aspxstránky
Pojďme chvíli otestovat rozhraní pro vložení a ItemInserting obslužnou rutinu události, které byly vytvořeny 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ý bude 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 o velikosti 78 bajtů je odebrána z binárního obsahu Picture 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 nezbytné bajty.
Vzhledem k tomu, že v tabulce Categories jsou nyní rastrové obrázky se záhlavími OLE a JPG, musíme aktualizovat DisplayCategoryPicture.aspx tak, aby se záhlaví OLE odstranilo pro původních osm kategorií a bylo vynecháno pro novější záznamy 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 void Page_Load(object sender, EventArgs e)
{
int categoryID = Convert.ToInt32(Request.QueryString["CategoryID"]);
// Get information about the specified category
CategoriesBLL categoryAPI = new CategoriesBLL();
Northwind.CategoriesDataTable categories =
categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID);
Northwind.CategoriesRow category = categories[0];
if (categoryID <= 8)
{
// For older categories, we must strip the OLE header... images are bitmaps
// 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 int OleHeaderLength = 78;
int strippedImageLength = category.Picture.Length - OleHeaderLength;
byte[] strippedImageData = new byte[strippedImageLength];
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);
}
}
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 při výskytu výjimky
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 postbacku a aktivuje se událost ItemInserting v DetailsView, čímž se brožura uloží 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 procesu vkládání.
Jak bylo dříve probíráno v tutoriálu zpracování BLL a DAL-Level výjimek v tutoriálu ASP.NET Page, když se výjimka vyvolá z hloubky architektury, prochází 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 void NewCategory_ItemInserted
(object sender, DetailsViewInsertedEventArgs e)
{
if (e.Exception != null)
{
// Need to delete brochure file, if it exists
if (e.Values["brochurePath"] != null)
System.IO.File.Delete(Server.MapPath(
e.Values["brochurePath"].ToString()));
}
}
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 tomu, že nahrávka jednoho uživatele přepíše jinou, 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 se nezačali zabývat tím, jak aktualizovat binární data stávajících kategorií nebo jak správně odebrat binární data odstraněné kategorie. 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.