Sdílet prostřednictvím


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

Scott Mitchell

Stáhnout PDF

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

Úvod

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

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

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

Krok 1: PřidáníInsertWithPicturemetody doCategoriesTableAdapter

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

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

Poznámka

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

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

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

Vyberte možnost VLOŽIT.

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

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

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

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

Pojmenujte novou metodu TableAdapter InsertWithPicture.

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

Krok 2: Aktualizace vrstvy obchodní logiky

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

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Insert, false)] 
public void InsertWithPicture(string categoryName, string description, 
    string brochurePath, byte[] picture)
{
    Adapter.InsertWithPicture(categoryName, description, brochurePath, picture);
}

Poznámka

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

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

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

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

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

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

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

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

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

Krok 4: KonfiguraceCategoriesDataSourcepro podporu vkládání

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

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

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

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

Poznámka

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

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

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories" 
    TypeName="CategoriesBLL" InsertMethod="InsertWithPicture">
    <InsertParameters>
        <asp:Parameter Name="categoryName" Type="String" />
        <asp:Parameter Name="description" Type="String" />
        <asp:Parameter Name="brochurePath" Type="String" />
        <asp:Parameter Name="picture" Type="Object" />
    </InsertParameters>
</asp:ObjectDataSource>

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

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

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

Snímek obrazovky s otevřeným zobrazením DetailsView s vlastností CategoryID nastavenou na NewCategory, prázdnými hodnotami vlastností Height a Width a zaškrtnutým zaškrtávacím políkem 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, NumberOfProductsa BrochurePath ačkoli CategoryID BoundField není vykreslen v rozhraní vkládání, protože jeho InsertVisible vlastnost je nastavena na false. Tyto BoundFields existují, protože se jedná o sloupce vrácené metodou GetCategories() , což je to, co ObjectDataSource vyvolá k načtení svých dat. Pro vložení však nechceme, aby uživatel zadal hodnotu pro NumberOfProducts. Kromě toho jim musíme umožnit nahrání obrázku pro novou kategorii a také nahrát PDF pro brožuru.

NumberOfProducts Odeberte BoundField z DetailsView úplně a potom aktualizujte HeaderText vlastnosti CategoryName a BrochurePath BoundFields na Category 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, čímž tomuto novému TemplateField HeaderText udělíte hodnotu Picture. Picture Přesuňte pole TemplateField tak, aby bylo mezi polem BrochurePath TemplateField a CommandField.

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

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

Pokud jste boundField převedli BrochurePath na TemplateField prostřednictvím dialogového okna Upravit pole, templateField obsahuje ItemTemplate, EditItemTemplatea InsertItemTemplate. InsertItemTemplate Je však potřeba pouze to, 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ů FileUpload pro pole brožury a obrázku

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

Z inteligentní značky DetailsView s zvolte možnost Upravit šablony a pak v rozevíracím seznamu vyberte BrochurePath TemplateField s InsertItemTemplate . Odeberte textové pole a přetáhněte ovládací prvek FileUpload z panelu 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 s ID na PictureUpload.

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

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

Po provedení těchto sčítání 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 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 soubory JPG? Abychom umožnili použití různých typů 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 .DisplayCategoryPicture.aspx Vzhledem k tomu, že takový sloupec nemáme, bylo by vhodné omezit uživatele pouze na poskytování konkrétního typu souboru obrázku. Existující Categories obrázky tabulky jsou rastrové obrázky, ale soubory JPG jsou vhodnějším formátem souboru 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 její 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, kurzívou a tučným písmem.

Poznámka

V ideálním CategoryName případě by se objekty a Description BoundFields převely na TemplateFields a jejich vkládání rozhraní byla přizpůsobena. Například Description rozhraní pro vkládání by bylo pravděpodobně vhodnější prostřednictvím víceřádkového textového pole. A protož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 úpravu 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() , což vede k přidání nového záznamu Categories do tabulky. Poté se aktivuje událost DetailsView sItemInserted.

Před vyvoláním metody ObjectDataSource s Insert() musíme nejprve zajistit, aby uživatel nahrál příslušné typy souborů, a poté uložit pdf brožuru do systému souborů webového serveru. Vytvořte obslužnou rutinu události pro událost DetailsView s 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á odkazem na BrochureUpload ovládací prvek FileUpload ze šablon DetailsView s. Pokud se pak nahraje brožura, prozkoumá se nahraná přípona souboru. Pokud rozšíření není .PDF, zobrazí se upozornění, vložení se zruší a spuštění obslužné rutiny události se ukončí.

Poznámka

Spoléhat se na příponu nahraného souboru není jistá technika, která zajistí, že nahraný soubor je dokument PDF. Uživatel mohl mít platný dokument PDF s příponou .Brochurenebo mohl vzít dokument, který není pdf, a dát mu příponu .pdf . Binární obsah souboru s by bylo nutné programově prozkoumat, aby bylo možné jednoznačněji ověřit typ souboru. Takové důkladné přístupy jsou však často příliš kvalifikovaná; 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 věnovat pozornost tomu, 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ž v ~/Brochures adresáři existuje soubor se stejným názvem, připojíme na konec číslo, dokud nenajdeme jedinečný název. Pokud například uživatel nahraje soubor brožury s názvem Meats.pdf, ale soubor s názvem Meats.pdf ve ~/Brochures složce už existuje, změníme název uloženého souboru na Meats-1.pdf. Pokud existuje, zkusíme Meats-2.pdfa tak dále, dokud nenajdete 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 dál 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 je třeba soubor uložit do systému souborů a hodnotu ObjectDataSource brochurePath``InsertParameter je třeba aktualizovat tak, aby byl tento název souboru zapsán do databáze. Jak jsme viděli v kurzu Nahrávání souborů , soubor se dá uložit pomocí metody FileUpload control s SaveAs(path) . 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 nejprve ujistit, že nahraný obrázek je JPG a ne nějaký jiný typ obrázku. Stejně jako v kroku 6 pojďme použít příponu nahraného obrázku s ke zjištění jeho typu.

Categories I když tabulka umožňuje NULL hodnoty pro Picture sloupec, všechny kategorie mají aktuálně 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 byl obrázek nahrán a jestli 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, takže pokud dojde k problému s nahrává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 nahrán příslušný soubor, přiřaďte nahraný binární obsah hodnotě parametru obrázku pomocí následujícího řádku kódu:

// Set the value of the picture parameter
e.Values["picture"] = PictureUpload.FileBytes;

Kompletní obslužnáItemInsertingrutina události

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

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

Chvíli si zabereme, než otestujeme rozhraní pro vkládání a ItemInserting obslužnou rutinu události, 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 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í se zruší.

V případě nahrání neplatného typu souboru se zobrazí zpráva s upozorněním.

Obrázek 9: V případě 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 vrátí zpět a do Categories tabulky se přidá nový záznam s binárním obsahem nahraného obrázku uloženého přímo v databázi. Objekt GridView se aktualizuje a zobrazí řádek pro nově přidanou kategorii, ale jak ukazuje obrázek 10, obrázek nové kategorie se nevykreslí správně.

Obrázek nové kategorie se nezobrazuje.

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

Důvodem, proč se nový obrázek nezobrazuje, je to, DisplayCategoryPicture.aspx že stránka, která vrací obrázek zadané kategorie s, je nakonfigurována pro zpracování rastrových obrázků, 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 se z binárních dat obrázku odeberou platné potřebné bajty.

Vzhledem k tomu, že v Categories tabulce jsou nyní rastrové obrázky se záhlavími OLE a soubory JPG, musíme provést aktualizaci DisplayCategoryPicture.aspx tak, aby prokláněla záhlaví OLE pro původních osm kategorií a obchávala toto prokládání u novějších záznamů kategorií. V dalším kurzu prozkoumáme, jak aktualizovat existující obrázek záznamu, a všechny staré obrázky kategorií aktualizujeme tak, aby byly soubory JPG. Prozatím však pomocí následujícího kódu v souboru DisplayCategoryPicture.aspx odstraňte hlavičky OLE pouze pro těchto původních 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);
    }
}

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

Obrázky JPG pro nové kategorie jsou správně vykresleny

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 ve výjimce

Jedním z výzev při ukládání binárních dat do systému souborů webového serveru je, že zavádí odpojení mezi datovým modelem a binárními daty. Proto při každém odstranění záznamu musí být odebrána také odpovídající binární data v systému souborů. To může přijít do hry také 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 událost DetailsView s ItemInserting se aktivuje a uloží se brožura do systému souborů s 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 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()));
    }
}

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 .