Megosztás a következőn keresztül:


Fájlfeltöltési lehetőség hozzáadása új rekord hozzáadásakor (C#)

által Scott Mitchell

PDF letöltése

Ez az oktatóanyag bemutatja, hogyan hozhat létre olyan webes felületet, amely lehetővé teszi a felhasználó számára, hogy szöveges adatokat adjon meg és bináris fájlokat töltsön fel. A bináris adatok tárolására rendelkezésre álló lehetőségek szemléltetéséhez az egyik fájl az adatbázisban lesz mentve, míg a másik a fájlrendszerben lesz tárolva.

Bevezetés

Az előző két oktatóanyagban megvizsgáltuk az alkalmazás adatmodelljéhez társított bináris adatok tárolásának technikáit, megvizsgáltuk, hogyan lehet a FileUpload vezérlővel fájlokat küldeni az ügyfélről a webkiszolgálóra, és láttuk, hogyan jeleníthetők meg ezek a bináris adatok egy adat-webvezérlőben. Még nem beszéltünk arról, hogyan társíthatók a feltöltött adatok az adatmodellhez.

Ebben az oktatóanyagban létrehozunk egy weblapot egy új kategória hozzáadásához. A kategória nevéhez és leírásához tartozó Szövegdobozok mellett ennek a lapnak tartalmaznia kell két FileUpload vezérlőt, egyet az új kategória képéhez, egyet pedig a brosúrához. A feltöltött kép közvetlenül az új rekord Picture oszlopában lesz tárolva, míg a brosúra az ~/Brochures új rekord BrochurePath oszlopában mentett fájl elérési útját tartalmazó mappába kerül.

Az új weblap létrehozása előtt frissíteni kell az architektúrát. Az CategoriesTableAdapter fő lekérdezése nem adja vissza a Picture oszlopot. Következésképpen az automatikusan létrehozott Insert metódus csak a , CategoryNameés Description a BrochurePathmezők bemeneteit adja meg. Ezért létre kell hoznunk egy további metódust a TableAdapterben, amely mind a négy Categories mezőt kéri. Az CategoriesBLL üzleti logikai réteg osztályát is frissíteni kell.

1. lépés: Egy metódus hozzáadásaInsertWithPictureCategoriesTableAdapter

Amikor az CategoriesTableAdapter oktatóanyagban létrehoztuk a hátoldalt, úgy konfiguráltuk, hogy automatikusan generáljon INSERT, UPDATEés DELETE utasításokat a fő lekérdezés alapján. Továbbá utasítottuk a TableAdaptert, hogy alkalmazza a DB Direct megközelítést, amely létrehozta a metódusokat Insert, Updateés Delete. Ezek a metódusok végrehajtják az automatikusan létrehozott INSERT, UPDATEés DELETE utasításokat, és következésképpen elfogadják a bemeneti paramétereket a fő lekérdezés által visszaadott oszlopok alapján. A Fájlok feltöltése oktatóanyagban bővítettük a CategoriesTableAdapter fő lekérdezést az BrochurePath oszlop használatához.

Mivel az CategoriesTableAdapter s fő lekérdezés nem hivatkozik az Picture oszlopra, nem adhatunk hozzá új rekordot, és nem frissíthetünk meglévő rekordot az Picture oszlop értékével. Az információk rögzítéséhez létrehozhatunk egy új metódust a TableAdapterben, amely kifejezetten bináris adatokat tartalmazó rekord beszúrására szolgál, vagy testre szabhatjuk az automatikusan létrehozott utasítást INSERT . Az automatikusan létrehozott INSERT utasítás testreszabásával az a probléma, hogy azt kockáztatjuk, hogy a testreszabásokat felülírja a varázsló. Tegyük fel például, hogy az INSERT utasítást úgy szabtuk testre, hogy az tartalmazza az Picture oszlop használatát. Ez frissíti a TableAdapter s Insert metódust, hogy egy további bemeneti paramétert is tartalmazzon a kategória képének bináris adataihoz. Ezután létrehozhatunk egy metódust az üzleti logikai rétegben a DAL metódus használatára, és meghívhatjuk ezt a BLL-metódust a bemutató rétegen keresztül, és minden csodálatosan működik. Vagyis amíg a TableAdapter konfigurációs varázslóval legközelebb nem konfiguráltuk a TableAdaptert. Amint a varázsló befejeződött, az utasítás testreszabása INSERT felülíródik, a metódus visszaáll a Insert régi formájára, és a kód már nem fordítható le!

Megjegyzés:

Ez a bosszúság nem jelent problémát, ha tárolt eljárásokat használ az alkalmi SQL-utasítások helyett. Egy jövőbeli oktatóanyag bemutatja a tárolt eljárások használatát az alkalmi SQL-utasítások helyett az adatelérési rétegben.

A lehetséges fejfájás elkerülése érdekében az automatikusan létrehozott SQL-utasítások testreszabása helyett hozzon létre egy új módszert a TableAdapterhez. Ez a névvel ellátott InsertWithPicturemetódus elfogadja a CategoryName, Description, BrochurePathés Picture oszlopok értékeit, és végrehajt egy utasítást INSERT , amely mind a négy értéket egy új rekordban tárolja.

Nyissa meg a Gépelt adathalmazt, és a Tervezőben kattintson jobb gombbal az CategoriesTableAdapter s fejlécre, és válassza a Lekérdezés hozzáadása lehetőséget a helyi menüben. Ezzel elindítja a TableAdapter Lekérdezéskonfiguráció varázslót, amely azzal kezdődik, hogy megkérdezi, hogyan férhet hozzá a TableAdapter-lekérdezés az adatbázishoz. Válassza az SQL-utasítások használata lehetőséget, majd kattintson a Tovább gombra. A következő lépés a létrehozandó lekérdezés típusát kéri. Mivel létrehozunk egy lekérdezést, amely új rekordot ad hozzá a táblához, válassza az INSERT elemet, majd kattintson a Categories Tovább gombra.

Válassza az INSERT (BESZÚRÁS) lehetőséget

1. ábra: Válassza az INSERT lehetőséget (kattintson ide a teljes méretű kép megtekintéséhez)

Most meg kell adnunk az SQL-utasítást INSERT . A varázsló automatikusan javasol egy INSERT , a TableAdapter fő lekérdezésének megfelelő utasítást. Ebben az esetben ez egy INSERT utasítás, amely beszúrja a CategoryName, Descriptionés BrochurePath az értékeket. Frissítse az utasítást úgy, hogy az Picture oszlop egy @Picture paraméterrel együtt szerepeljön, például:

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

A varázsló utolsó képernyője arra kéri, hogy nevezzük el az új TableAdapter metódust. Adja meg InsertWithPicture , majd kattintson a Befejezés gombra.

Az InsertWithPicture új TableAdapter metódus elnevezése

2. ábra: Nevezze el az Új TableAdapter metódust InsertWithPicture (kattintson ide a teljes méretű kép megtekintéséhez)

2. lépés: Az üzleti logikai réteg frissítése

Mivel a bemutató rétegnek csak az üzleti logikai réteghez kell csatlakoznia ahelyett, hogy megkerülte volna, hogy közvetlenül az adatelérési rétegre lépjen, létre kell hoznunk egy BLL-metódust, amely meghívja az imént létrehozott DAL metódust (InsertWithPicture). Ebben az oktatóanyagban hozzon létre egy metódust az CategoriesBLL osztályban a InsertWithPicture néven, amely három string-t és egy byte tömböt fogad. A string bemeneti paraméterek a kategória neve, leírása és brosúrafájl elérési útja, míg a byte tömb a kategória képének bináris tartalmához tartozik. Ahogy az alábbi kód is mutatja, ez a BLL-metódus meghívja a megfelelő DAL metódust:

[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);
}

Megjegyzés:

Mielőtt hozzáadja a InsertWithPicture metódust a BLL-hez, győződjön meg arról, hogy mentette a Gépelt Adatkészletet. Mivel az CategoriesTableAdapter osztálykód automatikusan jön létre a Gépelt adatkészlet alapján, ha nem menti először a módosításokat a Gépelt adathalmazba, a Adapter tulajdonság nem fog tudni a InsertWithPicture metódusról.

3. lépés: A meglévő kategóriák és azok bináris adatainak felsorolása

Ebben az oktatóanyagban létrehozunk egy oldalt, amely lehetővé teszi a végfelhasználó számára, hogy új kategóriát adjon hozzá a rendszerhez, és képet és brosúrát biztosít az új kategóriához. Az előző oktatóanyagban egy GridView-t használtunk egy TemplateField és ImageField használatával az egyes kategóriák nevének, leírásának, képének és hivatkozásának megjelenítéséhez a brosúra letöltéséhez. Replikáljuk ezt a funkciót ebben az oktatóanyagban, és hozzunk létre egy lapot, amely felsorolja az összes meglévő kategóriát, és lehetővé teszi az újak létrehozását.

Először nyissa meg a DisplayOrDownload.aspx lapot a BinaryData mappából. Lépjen a Forrás nézetre, és másolja a GridView és az ObjectDataSource deklaratív szintaxisát, majd illessze be a <asp:Content> elembe UploadInDetailsView.aspx. Emellett ne felejtse el átmásolni a GenerateBrochureLink metódust a háttérkód fájlból a DisplayOrDownload.aspx-be.

Másolja és illessze be a deklaratív szintaxist a DisplayOrDownload.aspx fájlból az UploadInDetailsView.aspx fájlba

3. ábra: Másolja és illessze be a deklaratív szintaxist a fájlba DisplayOrDownload.aspxUploadInDetailsView.aspx (kattintson ide a teljes méretű kép megtekintéséhez)

Miután átmásolta a deklaratív szintaxist és GenerateBrochureLink metódust a UploadInDetailsView.aspx lapra, tekintse meg a lapot egy böngészőben, hogy minden megfelelően legyen átmásolva. Látnia kell egy GridView-t, amely felsorolja a nyolc kategóriát, amely tartalmazza a brosúra letöltésére mutató hivatkozást, valamint a kategória képét.

Most már minden kategóriát látnia kell a bináris adatokkal együtt

4. ábra: Mostantól minden kategóriát látnia kell a bináris adatokkal együtt (ide kattintva megtekintheti a teljes méretű képet)

4. lépés: A beszúrás támogatásának konfigurálásaCategoriesDataSource

A CategoriesDataSource GridView által Categories használt ObjectDataSource jelenleg nem teszi lehetővé az adatok beszúrását. Annak érdekében, hogy támogassuk a beszúrást ezen adatforrás-vezérlőn keresztül, összekapcsolnunk kell annak Insert metódusát a mögöttes objektum egy másik metódusával, CategoriesBLL. Különösen az általunk a 2. lépésben hozzáadott CategoriesBLL metódushoz szeretnénk hozzárendelni InsertWithPicture.

Első lépésként kattintson az ObjectDataSource intelligens címkéjének Adatforrás konfigurálása hivatkozására. Az első képernyőn látható az az objektum, amellyel az adatforrás konfigurálva van, hogy működjön. CategoriesBLL Hagyja meg ezt a beállítást as-is, és a Tovább gombra kattintva lépjen tovább az Adatmetelyek definiálása képernyőre. Lépjen a BESZÚRÁS lapra, és válassza ki a InsertWithPicture metódust a legördülő listából. A varázsló befejezéséhez kattintson a Befejezés gombra.

Az ObjectDataSource konfigurálása az InsertWithPicture metódus használatára

5. ábra: Az ObjectDataSource konfigurálása a InsertWithPicture metódus használatára (kattintson ide a teljes méretű kép megtekintéséhez)

Megjegyzés:

A varázsló elvégzése után a Visual Studio megkérdezheti, hogy szeretné-e frissíteni a mezőket és kulcsokat, ami újragenerálja az adat webes vezérlőinek mezőit. Válassza a Nem lehetőséget, mert az Igen választás felülírja az esetlegesen végrehajtott mezők testreszabását.

A varázsló befejezése után az ObjectDataSource mostantól tartalmazni fog egy értéket a InsertMethod tulajdonságához, valamint InsertParameters a négy kategóriaoszlophoz, ahogy az alábbi deklaratív jelölés szemlélteti:

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

5. lépés: A beszúrási felület létrehozása

Az Adatok beszúrásának, frissítésének és törlésének áttekintése című cikk első része szerint a DetailsView vezérlő egy beépített beszúrási felületet biztosít, amely a beszúrást támogató adatforrás-vezérlők használatakor használható. Adjunk hozzá egy DetailsView-vezérlőt ehhez a laphoz a GridView fölött, amely véglegesen megjeleníti a beszúrási felületet, így a felhasználó gyorsan hozzáadhat egy új kategóriát. Ha új kategóriát ad hozzá a DetailsView-ban, az alatta lévő GridView automatikusan frissíti és megjeleníti az új kategóriát.

Kezdje azzal, hogy húz egy DetailsView elemet az Eszközkészletből a Tervezőre a GridView fölé, törölje a ID és NewCategory tulajdonságok értékeit, majd állítsa be a Height tulajdonságot Width értékre. A DetailsView intelligens címkéje alapján kösse hozzá a meglévőhöz CategoriesDataSource , majd jelölje be a Beszúrás engedélyezése jelölőnégyzetet.

Képernyőkép, amelyen a DetailsView megnyílik, a CategoryID tulajdonság NewCategory értékre van állítva, üres Magasság és Szélesség tulajdonságértékek, és a Beszúrás engedélyezése jelölőnégyzet be van jelölve.

6. ábra: A DetailsView kötése a CategoriesDataSource beszúráshoz és a beszúrás engedélyezése (kattintson ide a teljes méretű kép megtekintéséhez)

Ha véglegesen meg szeretné jeleníteni a DetailsView-t a beszúrási felületen, állítsa a tulajdonságát DefaultMode a következőre Insert: .

Vegye figyelembe, hogy a DetailsView öt BoundField-et tartalmaz: CategoryID, CategoryName, Description, NumberOfProducts és BrochurePath, bár a CategoryID BoundField nem jelenik meg a beszúrási felületen, mert a InsertVisible tulajdonsága false értékre van állítva. Ezek a BoundField azért létezik, mert az oszlopokat a GetCategories() metódus adja vissza, amelyet az ObjectDataSource meghív az adatok lekéréséhez. A beszúráshoz azonban nem szeretnénk engedélyezni, hogy a felhasználó megadjon egy értéket.NumberOfProducts Ezenkívül lehetővé kell tenni számukra az új kategória képének feltöltését, valamint a brosúra PDF-fájljának feltöltését.

Távolítsa el a NumberOfProducts BoundFieldet a DetailsView-ból, majd frissítse a HeaderText és CategoryName BoundFieldek tulajdonságait Kategória, illetve Brosúra értékre. Ezután alakítsa át a BrochurePath BoundFieldet sablonmezővé, és adjon hozzá egy új TemplateFieldet a képhez, így az új TemplateField HeaderText értéke Kép lesz. Helyezze át a Picture TemplateFieldet úgy, hogy a TemplateField és a BrochurePath CommandField között legyen.

Képernyőkép a mezőablakról, amelyen a TemplateField, a Picture és a HeaderText ki van emelve.

7. ábra: Kösse a DetailsView-t a CategoriesDataSource-hoz, és engedélyezze a beszúrást

Ha a BrochurePath BoundFieldet sablonmezővé alakította a Mezők szerkesztése párbeszédpanelen keresztül, a Sablonmező tartalmaz egy ItemTemplate, EditItemTemplateés InsertItemTemplate. Azonban csak a InsertItemTemplate szükséges elemekre van szükség, ezért nyugodtan távolítsa el a másik két sablont. Ezen a ponton a DetailsView deklaratív szintaxisának a következőképpen kell kinéznie:

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

FileUpload vezérlők hozzáadása a brosúrához és a képmezőkhöz

A BrochurePath TemplateField InsertItemTemplate jelenleg szövegmezőt tartalmaz, míg a Picture TemplateField nem tartalmaz sablonokat. A FileUpload vezérlők használatához frissíteni kell ezt a két TemplateField-vezérlőt InsertItemTemplate .

A DetailsView intelligens címkén válassza a Sablonok szerkesztése lehetőséget, majd válassza ki a BrochurePath TemplateField s InsertItemTemplate elemet a legördülő listából. Távolítsa el a TextBoxot, majd húzza a FileUpload vezérlőt az eszközkészletből a sablonba. A FileUpload vezérlő s ID értékének beállítása a következőre BrochureUpload: . Hasonlóképpen, adjon hozzá egy FileUpload vezérlőt a Picture TemplateField s InsertItemTemplate. Állítsd be a FileUpload vezérlőt ID értékre PictureUpload.

FileUpload vezérlő hozzáadása az InsertItemTemplate-hoz

8. ábra: Fájlbetöltési vezérlő hozzáadása a InsertItemTemplate fájlhoz (kattintson ide a teljes méretű kép megtekintéséhez)

A kiegészítések elvégzése után a TemplateField két deklaratív szintaxisa a következő lesz:

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

Amikor egy felhasználó új kategóriát ad hozzá, biztosítani szeretnénk, hogy a brosúra és a kép a megfelelő fájltípusú legyen. A brosúrához a felhasználónak PDF-fájlt kell megadnia. A képhez a felhasználónak fel kell töltenie egy képfájlt, de engedélyezünk-e bármilyen képfájlt vagy csak egy adott típusú képfájlt, például GIF-eket vagy JPG-ket? A különböző fájltípusok engedélyezéséhez ki kell terjesztenünk a Categories sémát egy olyan oszlopra, amely rögzíti a fájltípust, hogy ezt a típust elküldhessük az ügyfélnek Response.ContentType keresztül DisplayCategoryPicture.aspx. Mivel nincs ilyen oszlopunk, célszerű korlátozni a felhasználókat, hogy csak egy adott képfájltípust adjanak meg. A Categories táblázat meglévő lemezképei bitképek, a JPG-k azonban a webes képekhez megfelelőbb fájlformátumot jelentenek.

Ha egy felhasználó helytelen fájltípust tölt fel, le kell szakítanunk a beszúrást, és meg kell jeleníteni a problémát jelző üzenetet. Vegyen fel egy Címke web vezérlőelemet a DetailsView alatt. Állítsa be a tulajdonságát ID a következőre UploadWarning, törölje a tulajdonságát Text , állítsa a CssClass tulajdonságot Figyelmeztetés értékre, a Visible tulajdonságokat pedig EnableViewState a következőre false. A Warning CSS-osztály a Styles.css van definiálva, és nagy, piros, dőlt, félkövér betűvel jeleníti meg a szöveget.

Megjegyzés:

Ideális esetben a CategoryName és Description BoundFields sablonmezőkké lennének átalakítva, és a beszúrási felületeik testre lennének szabva. A Description beszúrási felület például valószínűleg jobban megfelelne egy többsoros szövegdoboznak. Mivel az CategoryName oszlop nem fogad el NULL értékeket, hozzá kell adni egy RequiredFieldValidatort, hogy a felhasználó értéket adjon az új kategória nevének. Ezek a lépések gyakorlatként maradnak az olvasó számára. Az adatmódosítási felület testreszabásával kapcsolatos részletes áttekintésért tekintse meg az adatmódosítási felületek bővítését.

6. lépés: A feltöltött brosúra mentése a webkiszolgáló fájlrendszerére

Amikor a felhasználó beírja egy új kategória értékeit, és a Beszúrás gombra kattint, visszalépés történik, és a beszúrási munkafolyamat megnyílik. Először a DetailsView eseménye aktiválódikItemInserting. Ezután a rendszer meghívja Insert() az ObjectDataSource metódust, amely egy új rekord hozzáadását eredményezi a Categories táblához. Ezután a DetailsView eseményeItemInserted aktiválódik.

Az ObjectDataSource metódus meghívása Insert() előtt először meg kell győződnünk arról, hogy a felhasználó feltöltötte a megfelelő fájltípusokat, majd mentse a brosúra PDF-fájlját a webkiszolgáló fájlrendszerére. Hozzon létre egy eseménykezelőt a DetailsView eseményéhez ItemInserting , és adja hozzá a következő kódot:

// 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;
    }
}

Az eseménykezelő először a BrochureUpload FileUpload vezérlőre hivatkozik a DetailsView-sablonokból. Ezután, ha feltöltöttek egy brosúrát, a rendszer megvizsgálja a feltöltött fájl bővítményét. Ha a bővítmény nem .PDF, figyelmeztetés jelenik meg, a beszúrás megszakad, és az eseménykezelő végrehajtása véget ér.

Megjegyzés:

A feltöltött fájl kiterjesztésére való támaszkodás nem biztos módszer annak biztosítására, hogy a feltöltött fájl PDF-dokumentum legyen. A felhasználó rendelkezhet érvényes PDF-dokumentummal a kiterjesztéssel .Brochure, vagy készíthetett egy nem PDF formátumú dokumentumot, és mellékelhette .pdf . A fájl bináris tartalmát programozott módon kell megvizsgálni a fájltípus egyértelműbb ellenőrzéséhez. Az ilyen alapos megközelítések azonban gyakran túlzások; a bővítmény ellenőrzése a legtöbb forgatókönyv esetében elegendő.

A Fájlok feltöltése oktatóanyagban leírtaknak megfelelően ügyelni kell a fájlok fájlrendszerbe való mentésekor, hogy az egyik felhasználó feltöltése ne írja felül a másikat. Ebben az oktatóanyagban megpróbáljuk ugyanazt a nevet használni, mint a feltöltött fájl. Ha már létezik ilyen nevű fájl a ~/Brochures könyvtárban, a végén hozzáfűzünk egy számot, amíg egyedi név nem található. Ha például a felhasználó feltölt egy brosúrafájlt, Meats.pdfde már van egy fájl neve Meats.pdf a ~/Brochures mappában, a mentett fájl nevét a következőre Meats-1.pdfmódosítjuk. Ha ez létezik, megpróbáljuk Meats-2.pdf, és így tovább, amíg nem talál egy egyedi fájlnevet.

Az alábbi kód a File.Exists(path) metódus használatával állapítja meg, hogy létezik-e már fájl a megadott fájlnévvel. Ha igen, addig próbálkozik a brosúra új fájlnevekkel, amíg nem talál ütközést.

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++;
}

Az érvényes fájlnév megtalálása után a fájlt a fájlrendszerbe kell menteni, és frissíteni kell az ObjectDataSource brochurePath``InsertParameter értékét, hogy a fájlnév bekerüljön az adatbázisba. Ahogy a Fájlok feltöltése oktatóanyagban is láttuk, a fájl menthető a FileUpload vezérlő s SaveAs(path) metódusával. Az ObjectDataSource brochurePath paraméter frissítéséhez használja a e.Values gyűjteményt.

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

7. lépés: A feltöltött kép mentése az adatbázisba

A feltöltött kép új Categories rekordban való tárolásához a feltöltött bináris tartalmat hozzá kell rendelnünk az ObjectDataSource paraméteréhez picture a DetailsView eseményben ItemInserting . A feladat végrehajtása előtt azonban először meg kell győződnünk arról, hogy a feltöltött kép JPG formátumú, nem pedig más képtípus. A 6. lépéshez hasonlóan használjuk a feltöltött kép fájlkiterjesztését annak típusának megállapításához.

Bár a Categories táblázat lehetővé teszi a NULL oszlopban lévő Picture értékeket, jelenleg az összes kategória rendelkezik képpel. Kényszerítsük a felhasználót arra, hogy adjon meg egy képet, amikor új kategóriát ad hozzá ezen a lapon. Az alábbi kód ellenőrzi, hogy egy kép feltöltése megtörtént-e, és hogy megfelelő kiterjesztéssel rendelkezik-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;
}

Ezt a kódot a 6. lépésben kell elhelyezni a kód elé , hogy ha probléma merül fel a képfeltöltéssel kapcsolatban, az eseménykezelő leáll, mielőtt a brosúrafájlt a fájlrendszerbe mentené.

Feltételezve, hogy a megfelelő fájl feltöltése megtörtént, rendelje hozzá a feltöltött bináris tartalmat a képparaméter s értékéhez a következő kódsor használatával:

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

A TeljesItemInsertingeseménykezelő

A teljesség kedvéért itt található az ItemInserting-eseménykezelő teljes terjedelmében:

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

8. lépés: AzDisplayCategoryPicture.aspxoldal javítása

Szánjunk egy kis időt a beszúrási felület és ItemInserting az eseménykezelő tesztelésére, amely az elmúlt néhány lépésben jött létre. Látogasson el a UploadInDetailsView.aspx lapra egy böngészőben, és próbáljon meg hozzáadni egy kategóriát, de hagyja ki a képet, vagy adjon meg egy nem JPG formátumú képet vagy egy nem PDF-brosúrát. Ezen esetek bármelyikében megjelenik egy hibaüzenet, és a beszúrási munkafolyamat megszakad.

Figyelmeztető üzenet jelenik meg, ha érvénytelen fájltípus van feltöltve

9. ábra: Érvénytelen fájltípus feltöltése esetén figyelmeztető üzenet jelenik meg (ide kattintva megtekintheti a teljes méretű képet)

Miután meggyőződött arról, hogy a laphoz fel kell tölteni egy képet, és nem fogad el nem PDF vagy nem JPG formátumú fájlokat, adjon hozzá egy új kategóriát érvényes JPG-képpel, és hagyja üresen a Brosúra mezőt. Miután a Beszúrás gombra kattintott, a lap visszakerül, és egy új rekordot ad hozzá a Categories táblázathoz, amelyben a feltöltött kép bináris tartalma közvetlenül az adatbázisban van tárolva. A GridView frissül, és megjeleníti az újonnan hozzáadott kategória sorát, de ahogy a 10. ábrán látható, az új kategória képe nem jelenik meg megfelelően.

Az Új kategória képe nem jelenik meg

10. ábra: Az Új kategória képe nem jelenik meg (kattintson ide a teljes méretű kép megtekintéséhez)

Az új kép azért nem jelenik meg, mert a DisplayCategoryPicture.aspx megadott kategóriaképet visszaadó lap úgy van konfigurálva, hogy feldolgozhassa az OLE fejlécet tartalmazó bitképeket. Ezt a 78 bájtos fejlécet a rendszer eltávolítja az Picture oszlop bináris tartalmából, mielőtt visszaküldené őket az ügyfélnek. Az új kategóriához most feltöltött JPG-fájl azonban nem rendelkezik ezzel az OLE fejléccel; ezért a rendszer eltávolítja az érvényes, szükséges bájtokat a kép bináris adataiból.

Mivel a táblázatban most már mind az OLE-fejléceket, mind a JPG-ket tartalmazó bitképek találhatók, frissítenünk kell Categories-t, hogy az eltávolítsa az OLE fejlécet az eredeti nyolc kategóriánál, és mellőzze ezt az eltávolítást az újabb kategóriarekordoknál. A következő oktatóanyagban megvizsgáljuk, hogyan frissíthet egy meglévő rekord képét, és frissítjük az összes régi kategóriaképet, hogy azok JPG-k legyenek. Egyelőre azonban az alábbi kóddal DisplayCategoryPicture.aspx távolítsa el az OLE-fejléceket, csak az eredeti nyolc kategóriára korlátozva:

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);
    }
}

Ezzel a módosítással a JPG-rendszerkép helyesen jelenik meg a GridView-ban.

Az új kategóriák JPG-képei megfelelően jelennek meg

11. ábra: Az új kategóriák JPG-képei megfelelően renderelve vannak (ide kattintva megtekintheti a teljes méretű képet)

9. lépés: A brosúra törlése kivétel esetén

A bináris adatok webkiszolgáló fájlrendszeren való tárolásának egyik kihívása, hogy leválasztja az adatmodellt és a bináris adatokat. Ezért egy rekord törlésekor a fájlrendszer megfelelő bináris adatait is el kell távolítani. Ez a beszúráskor is szerepet játszhat. Fontolja meg a következő forgatókönyvet: a felhasználó új kategóriát ad hozzá, megjelölve egy megfelelő képet és brosúrát. Amikor a Beszúrás gombra kattint, postback történik, és a DetailsView ItemInserting esemény aktiválódik, amely a brosúrát a webkiszolgáló fájlrendszerére menti. Ezután az ObjectDataSource Insert() metódusa kerül meghívásra, amely meghívja az CategoriesBLL osztály InsertWithPicture metódusát, amely meghívja a CategoriesTableAdapter osztály InsertWithPicture metódusát.

Mi történik, ha az adatbázis offline állapotban van, vagy ha az SQL-utasítás hibát INSERT jelez? Nyilvánvaló, hogy az INSERT sikertelen lesz, ezért a program nem ad hozzá új kategóriasort az adatbázishoz. De a feltöltött brosúrafájl továbbra is a webkiszolgáló fájlrendszerén található! Ezt a fájlt kivétel miatt törölni kell a beszúrási munkafolyamat során.

A BLL- és DAL-Level-kivételek kezelése egy ASP.NET-lap oktatóanyagában már korábban megvitatottak szerint, amikor egy kivételt az architektúra mélyebb részéből dobnak ki, az felfelé halad a különböző rétegeken keresztül. A Bemutató rétegben megállapíthatjuk, hogy történt-e kivétel a DetailsView eseményéből ItemInserted . Ez az eseménykezelő az ObjectDataSource-ok InsertParametersértékeit is biztosítja. Ezért létrehozhatunk egy eseménykezelőt az ItemInserted eseményhez, amely ellenőrzi, hogy volt-e kivétel, és ha igen, törli az ObjectDataSource brochurePath paraméter által megadott fájlt:

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()));
    }
}

Összefoglalás

Számos lépést kell végrehajtani annak érdekében, hogy webes felületet biztosítson a bináris adatokat tartalmazó rekordok hozzáadásához. Ha a bináris adatok közvetlenül az adatbázisba vannak tárolva, valószínűleg frissítenie kell az architektúrát, és adott metódusokat kell hozzáadnia a bináris adatok beszúrási eseteinek kezeléséhez. Az architektúra frissítését követően a következő lépés a beszúrási felület létrehozása, amely egy testre szabott DetailsView használatával valósítható meg, amely minden bináris adatmezőhöz tartalmaz egy FileUpload vezérlőt. A feltöltött adatok ezután menthetők a webkiszolgáló fájlrendszerére, vagy hozzárendelhetők egy adatforrásparaméterhez a DetailsView ItemInserting eseménykezelőjében.

A bináris adatok fájlrendszerbe való mentése több tervezést igényel, mint az adatok közvetlenül az adatbázisba való mentése. Annak érdekében, hogy egy felhasználó feltöltése ne írjon felül egy másikét, megfelelő elnevezési sémát kell választani. Emellett további lépéseket kell tenni a feltöltött fájl törléséhez, ha az adatbázis beszúrása sikertelen.

Mostantól brosúrával és képpel új kategóriákat adhatunk hozzá a rendszerhez, de még nem foglalkoztunk azzal, hogyan frissíthetjük a meglévő kategória bináris adatait, vagy hogyan távolíthatjuk el helyesen a törölt kategóriák bináris adatait. Ezt a két témakört a következő oktatóanyagban ismertetjük.

Boldog programozást!

Tudnivalók a szerzőről

Scott Mitchell, hét ASP/ASP.NET-könyv szerzője és a 4GuysFromRolla.com alapítója, 1998 óta dolgozik a Microsoft webtechnológiáival. Scott független tanácsadóként, edzőként és íróként dolgozik. Legújabb könyve Sams Tanuld meg ASP.NET 2.0 24 óra alatt. Ő itt elérhető mitchell@4GuysFromRolla.com.

Külön köszönet

Ezt az oktatóanyag-sorozatot sok hasznos véleményező áttekintette. Az oktatóanyag fő véleményezői Dave Gardner, Teresa Murphy és Bernadette Leigh voltak. Szeretné áttekinteni a közelgő MSDN-cikkeimet? Ha igen, írj egy sort a mitchell@4GuysFromRolla.com-ra.