Dołączanie opcji przekazywania pliku podczas dodawania nowego rekordu (C#)
W tym samouczku pokazano, jak utworzyć interfejs internetowy, który umożliwia użytkownikowi wprowadzanie danych tekstowych i przekazywanie plików binarnych. Aby zilustrować opcje dostępne do przechowywania danych binarnych, jeden plik zostanie zapisany w bazie danych, podczas gdy drugi jest przechowywany w systemie plików.
Wprowadzenie
W dwóch poprzednich samouczkach omówiliśmy techniki przechowywania danych binarnych skojarzonych z modelem danych aplikacji, przyjrzeliśmy się sposobom wysyłania plików z klienta do serwera internetowego za pomocą kontrolki FileUpload. Jeszcze nie rozmawialiśmy o tym, jak skojarzyć przekazane dane z modelem danych.
W tym samouczku utworzymy stronę internetową, aby dodać nową kategorię. Oprócz pola TextBoxes dla nazwy i opisu kategorii ta strona będzie musiała zawierać dwie kontrolki FileUpload jeden dla nowego obrazu kategorii i jeden dla broszury. Przekazany obraz będzie przechowywany bezpośrednio w nowej kolumnie rekordu Picture
, natomiast broszura zostanie zapisana w ~/Brochures
folderze ze ścieżką do pliku zapisanego w nowej kolumnie rekordu BrochurePath
.
Przed utworzeniem nowej strony internetowej musimy zaktualizować architekturę. Główne CategoriesTableAdapter
zapytanie nie pobiera kolumny Picture
. W związku z tym metoda wygenerowana Insert
automatycznie ma tylko dane wejściowe dla CategoryName
pól , Description
i BrochurePath
. W związku z tym musimy utworzyć dodatkową metodę w tableAdapter, która wyświetli monit o podanie wszystkich czterech Categories
pól. Należy CategoriesBLL
również zaktualizować klasę w warstwie logiki biznesowej.
Krok 1. DodawanieInsertWithPicture
metody do elementuCategoriesTableAdapter
Po utworzeniu CategoriesTableAdapter
z powrotem w samouczku Tworzenie warstwy dostępu do danych skonfigurowaliśmy ją do automatycznego generowania INSERT
instrukcji , UPDATE
i na DELETE
podstawie głównego zapytania. Ponadto poinstruowaliśmy metodę TableAdapter, aby zastosować metodę DB Direct, która utworzyła metody Insert
, Update
i Delete
. Te metody wykonują automatycznie wygenerowane INSERT
instrukcje , UPDATE
i DELETE
, w związku z tym akceptują parametry wejściowe na podstawie kolumn zwracanych przez zapytanie główne. W samouczku Przekazywanie plików rozszerzyliśmy CategoriesTableAdapter
główne zapytanie, aby użyć kolumny BrochurePath
.
CategoriesTableAdapter
Ponieważ główne zapytanie nie odwołuje się do Picture
kolumny, nie możemy dodać nowego rekordu ani zaktualizować istniejącego rekordu z wartością dla kolumnyPicture
. Aby przechwycić te informacje, możemy utworzyć nową metodę w tabeli TableAdapter, która jest używana specjalnie do wstawiania rekordu z danymi binarnymi lub możemy dostosować instrukcję wygenerowaną INSERT
automatycznie. Problem z dostosowywaniem automatycznie wygenerowanej INSERT
instrukcji polega na tym, że ryzyko, że nasze dostosowania zostaną zastąpione przez kreatora. Załóżmy na przykład, że dostosowano instrukcję INSERT
tak, aby zawierała użycie kolumny Picture
. Spowoduje to zaktualizowanie metody TableAdapter w Insert
celu uwzględnienia dodatkowego parametru wejściowego dla danych binarnych obrazu kategorii. Następnie możemy utworzyć metodę w warstwie logiki biznesowej, aby użyć tej metody DAL i wywołać tę metodę BLL za pośrednictwem warstwy prezentacji, a wszystko będzie działać cudownie. Oznacza to, że do następnego momentu skonfigurowaliśmy narzędzie TableAdapter za pośrednictwem Kreatora konfiguracji tableAdapter. Po zakończeniu działania kreatora nasze dostosowania instrukcji INSERT
zostaną zastąpione, Insert
metoda powróci do starego formularza, a nasz kod nie będzie już kompilowany.
Uwaga
Ta irytacja jest problemem podczas korzystania z procedur składowanych zamiast instrukcji AD-hoc SQL. W przyszłym samouczku omówiono używanie procedur składowanych zamiast instrukcji AD-hoc SQL w warstwie dostępu do danych.
Aby uniknąć tego potencjalnego bólu głowy, zamiast dostosowywać automatycznie wygenerowane instrukcje SQL, zamiast tego utwórzmy nową metodę dla klasy TableAdapter. Ta metoda o nazwie InsertWithPicture
, akceptuje wartości dla CategoryName
kolumn , Description
, BrochurePath
i Picture
wykonuje instrukcję INSERT
, która przechowuje wszystkie cztery wartości w nowym rekordzie.
Otwórz typowy zestaw danych i w Projektant kliknij prawym przyciskiem myszy CategoriesTableAdapter
nagłówek s, a następnie wybierz polecenie Dodaj zapytanie z menu kontekstowego. Spowoduje to uruchomienie Kreatora konfiguracji zapytań TableAdapter, który zaczyna się od pytania, w jaki sposób zapytanie TableAdapter powinno uzyskać dostęp do bazy danych. Wybierz pozycję Użyj instrukcji SQL i kliknij przycisk Dalej. W następnym kroku zostanie wyświetlony monit o wygenerowanie typu zapytania. Ponieważ tworzymy zapytanie w celu dodania nowego rekordu Categories
do tabeli, wybierz pozycję INSERT i kliknij przycisk Dalej.
Rysunek 1. Wybierz opcję INSERT (Kliknij, aby wyświetlić obraz pełnowymiarowy)
Teraz musimy określić instrukcję INSERT
SQL. Kreator automatycznie sugeruje instrukcję odpowiadającą INSERT
głównemu zapytaniu TableAdapter. W tym przypadku jest INSERT
to instrukcja, która wstawia CategoryName
wartości , Description
i BrochurePath
. Zaktualizuj instrukcję tak, aby kolumna Picture
została dołączona wraz z parametrem @Picture
, w następujący sposób:
INSERT INTO [Categories]
([CategoryName], [Description], [BrochurePath], [Picture])
VALUES
(@CategoryName, @Description, @BrochurePath, @Picture)
Na ostatnim ekranie kreatora zostanie wyświetlony monit o nadenie nazwy nowej metody TableAdapter. Wprowadź InsertWithPicture
i kliknij przycisk Zakończ.
Rysunek 2. Nadaj nazwę nowej metodzie InsertWithPicture
TableAdapter (kliknij, aby wyświetlić obraz pełnowymiarowy)
Krok 2. Aktualizowanie warstwy logiki biznesowej
Ponieważ warstwa prezentacji powinna być interfejsem tylko z warstwą logiki biznesowej, a nie pomijając ją bezpośrednio do warstwy dostępu do danych, musimy utworzyć metodę BLL, która wywołuje właśnie utworzoną metodę DAL (InsertWithPicture
). Na potrzeby tego samouczka utwórz metodę w CategoriesBLL
klasie o nazwie InsertWithPicture
, która przyjmuje jako dane wejściowe trzy string
s i tablicę byte
. string
Parametry wejściowe są przeznaczone dla nazwy, opisu i ścieżki pliku broszury kategorii, podczas gdy byte
tablica jest przeznaczona dla zawartości binarnej obrazu kategorii. Jak pokazano w poniższym kodzie, ta metoda BLL wywołuje odpowiednią metodę 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);
}
Uwaga
Przed dodaniem metody do biblioteki InsertWithPicture
BLL upewnij się, że zapisano typowy zestaw danych. CategoriesTableAdapter
Ponieważ kod klasy jest generowany automatycznie na podstawie typu zestawu danych, jeśli nie najpierw zapiszesz zmian w typowym zestawie danychAdapter
, właściwość nie będzie wiedzieć o metodzieInsertWithPicture
.
Krok 3. Wyświetlanie listy istniejących kategorii i ich danych binarnych
W tym samouczku utworzymy stronę, która pozwala użytkownikowi końcowemu dodać nową kategorię do systemu, udostępniając obraz i broszurę dla nowej kategorii. W poprzednim samouczku użyliśmy elementu GridView z elementem TemplateField i ImageField w celu wyświetlenia nazwy, opisu, obrazu i linku do pobrania broszury. Zreplikujmy tę funkcję dla tego samouczka, tworząc stronę zawierającą listę wszystkich istniejących kategorii i umożliwiającą utworzenie nowych.
Zacznij od otwarcia DisplayOrDownload.aspx
strony z BinaryData
folderu. Przejdź do widoku Źródło i skopiuj składnię deklaratywną GridView i ObjectDataSource, wklejając ją w <asp:Content>
elemecie w elemecie .UploadInDetailsView.aspx
Nie zapomnij również skopiować GenerateBrochureLink
metody z klasy code-behind do DisplayOrDownload.aspx
UploadInDetailsView.aspx
klasy .
Rysunek 3. Kopiowanie i wklejanie składni deklaratywnej z DisplayOrDownload.aspx
do UploadInDetailsView.aspx
(kliknij, aby wyświetlić obraz pełnowymiarowy)
Po skopiowaniu składni deklaratywnej UploadInDetailsView.aspx
i GenerateBrochureLink
metody na stronę wyświetl stronę za pośrednictwem przeglądarki, aby upewnić się, że wszystko zostało skopiowane poprawnie. Powinna zostać wyświetlona lista gridview zawierająca osiem kategorii, które zawierają link do pobrania broszury, a także obrazu kategorii.
Rysunek 4. Powinna być teraz widoczna każda kategoria wraz z danymi binarnymi (kliknij, aby wyświetlić obraz pełnowymiarowy)
Krok 4. KonfigurowanieCategoriesDataSource
elementu do obsługi wstawiania
Obiekt CategoriesDataSource
ObjectDataSource używany przez Categories
obiekt GridView obecnie nie zapewnia możliwości wstawiania danych. Aby umożliwić wstawianie za pośrednictwem tej kontroli źródła danych, musimy zamapować jej Insert
metodę na metodę w jego obiekcie bazowym. CategoriesBLL
W szczególności chcemy zamapować ją na metodę CategoriesBLL
dodaną z powrotem w kroku 2. InsertWithPicture
Zacznij od kliknięcia linku Konfiguruj źródło danych z tagu inteligentnego ObjectDataSource. Pierwszy ekran przedstawia obiekt skonfigurowany do pracy ze źródłem danych. CategoriesBLL
Pozostaw to ustawienie zgodnie z rzeczywistym ustawieniem i kliknij przycisk Dalej, aby przejść do ekranu Definiowanie metod danych. Przejdź do karty INSERT i wybierz metodę InsertWithPicture
z listy rozwijanej. Kliknij przycisk Zakończ, aby zakończyć kreatora.
Rysunek 5. Konfigurowanie obiektu ObjectDataSource do użycia InsertWithPicture
metody (kliknij, aby wyświetlić obraz pełnowymiarowy)
Uwaga
Po ukończeniu pracy kreatora program Visual Studio może zapytać, czy chcesz odświeżyć pola i klucze, co spowoduje ponowne wygenerowanie pól kontrolek sieci Web danych. Wybierz pozycję Nie, ponieważ wybranie pozycji Tak spowoduje zastąpienie wszelkich dostosowań pól, które mogły zostać wprowadzone.
Po ukończeniu pracy kreatora źródło ObjectDataSource będzie teraz zawierać wartość jej InsertMethod
właściwości, a także InsertParameters
dla czterech kolumn kategorii, jak pokazano w poniższym deklaratywnej adiustacji:
<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. Tworzenie interfejsu wstawiania
Zgodnie z opisem w temacie Omówienie wstawiania, aktualizowania i usuwania danych kontrolka DetailsView udostępnia wbudowany interfejs wstawiania, który można wykorzystać podczas pracy z kontrolką źródła danych, która obsługuje wstawianie. Dodajmy kontrolkę DetailsView do tej strony powyżej kontrolki GridView, która trwale renderuje interfejs wstawiania, umożliwiając użytkownikowi szybkie dodawanie nowej kategorii. Po dodaniu nowej kategorii w widoku DetailsView element GridView będzie automatycznie odświeżyć i wyświetlić nową kategorię.
Zacznij od przeciągnięcia kontrolki DetailsView z przybornika na Projektant powyżej kontrolki GridView, ustawiając jej ID
właściwość na NewCategory
i usuwając Height
wartości właściwości iWidth
. Z tagu inteligentnego DetailsView powiąż go z istniejącym CategoriesDataSource
, a następnie zaznacz pole wyboru Włącz wstawianie.
Rysunek 6. Powiąż widok DetailsView z elementem CategoriesDataSource
i Włącz wstawianie (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Aby trwale renderować element DetailsView w interfejsie wstawiania, ustaw jej DefaultMode
właściwość na Insert
.
Należy pamiętać, że element DetailsView ma pięć elementów BoundFieldsCategoryID
, , Description
, NumberOfProducts
i BrochurePath
chociaż pole CategoryID
BoundField nie jest renderowane w interfejsie wstawiania, CategoryName
ponieważ jego InsertVisible
właściwość jest ustawiona na false
. Te pola granic istnieją, ponieważ są to kolumny zwracane przez metodę GetCategories()
, która jest wywoływana przez obiekt ObjectDataSource w celu pobrania danych. W przypadku wstawiania nie chcemy jednak zezwalać użytkownikowi na określenie wartości .NumberOfProducts
Ponadto musimy zezwolić im na przekazanie obrazu dla nowej kategorii, a także przekazanie pliku PDF dla broszury.
Usuń pole NumberOfProducts
BoundField z widoku DetailsView, a następnie zaktualizuj HeaderText
odpowiednio właściwości CategoryName
pola i BrochurePath
BoundFields do kategorii i broszury. Następnie przekonwertuj pole BrochurePath
BoundField na pole szablonu i dodaj nowe pole szablonu dla obrazu, dając temu nowemu pola szablonu HeaderText
wartość Obraz. Przenieś pole szablonu, Picture
aby było między BrochurePath
polami TemplateField i CommandField.
Rysunek 7. Powiązanie widoku DetailsView z elementem CategoriesDataSource
i włączanie wstawiania
Jeśli pole BoundField przekonwertowano BrochurePath
na pole szablonu za pomocą okna dialogowego Edytowanie pól, pole TemplateField zawiera element ItemTemplate
, EditItemTemplate
i InsertItemTemplate
. Tylko te InsertItemTemplate
elementy są potrzebne, więc możesz usunąć pozostałe dwa szablony. W tym momencie składnia deklaratywna elementu DetailsView powinna wyglądać następująco:
<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>
Dodawanie kontrolek FileUpload dla pól broszury i obrazów
Obecnie pole BrochurePath
TemplateField InsertItemTemplate
zawiera pole tekstowe, a pole Picture
szablonu nie zawiera żadnych szablonów. Musimy zaktualizować te dwa obiekty TemplateField s InsertItemTemplate
, aby używać kontrolek FileUpload.
Z tagu inteligentnego DetailsView wybierz opcję Edytuj szablony, a następnie wybierz pozycję BrochurePath
TemplateField s InsertItemTemplate
z listy rozwijanej. Usuń kontrolkę TextBox, a następnie przeciągnij kontrolkę FileUpload z przybornika do szablonu. Ustaw kontrolkę FileUpload s ID
na BrochureUpload
. Podobnie dodaj kontrolkę FileUpload do elementu Picture
TemplateField s InsertItemTemplate
. Ustaw tę kontrolkę FileUpload s ID
na PictureUpload
.
Rysunek 8. Dodawanie kontrolki FileUpload do elementu InsertItemTemplate
(kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Po dodaniu tych dodatków składnia deklaratywna pola szablonu będzie następująca:
<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>
Gdy użytkownik doda nową kategorię, chcemy mieć pewność, że broszura i obraz są poprawnego typu pliku. W przypadku broszury użytkownik musi podać plik PDF. W przypadku obrazu potrzebujemy użytkownika do przekazania pliku obrazu, ale czy zezwalamy na dowolny plik obrazu lub tylko pliki obrazów określonego typu, takie jak pliki GIF lub JPG? Aby umożliwić korzystanie z różnych typów plików, musimy rozszerzyć Categories
schemat, aby zawierał kolumnę, która przechwytuje typ pliku, aby ten typ mógł zostać wysłany do klienta za pośrednictwem Response.ContentType
programu w DisplayCategoryPicture.aspx
programie . Ponieważ nie mamy takiej kolumny, rozsądnie byłoby ograniczyć użytkowników tylko do podawania określonego typu pliku obrazu. Istniejące Categories
obrazy tabeli to mapy bitowe, ale pliki JPG są bardziej odpowiednim formatem plików dla obrazów obsługiwanych w Internecie.
Jeśli użytkownik przekaże nieprawidłowy typ pliku, musimy anulować wstawianie i wyświetlić komunikat wskazujący problem. Dodaj kontrolkę Sieć Web Etykieta pod kontrolką DetailsView. Ustaw jej ID
właściwość na UploadWarning
, wyczyść jej Text
właściwość, ustaw CssClass
właściwość na Ostrzeżenie, a właściwości i Visible
EnableViewState
na false
wartość . Klasa Warning
CSS jest definiowana w pliku Styles.css
i renderuje tekst w dużej, czerwonej, kursywie, pogrubionej czcionki.
Uwaga
W idealnym przypadku obiekty CategoryName
i Description
BoundFields zostaną przekonwertowane na pola szablonów i dostosowane do ich interfejsów wstawiania. Na Description
przykład interfejs wstawiania prawdopodobnie lepiej nadaje się za pomocą wielowierszowego pola tekstowego. Ponieważ kolumna CategoryName
nie akceptuje NULL
wartości, należy dodać element RequiredFieldValidator, aby upewnić się, że użytkownik udostępnia wartość nowej nazwy kategorii. Te kroki są pozostawione jako ćwiczenie dla czytelnika. Zapoznaj się z tematem Dostosowywanie interfejsu modyfikacji danych , aby uzyskać szczegółowe informacje na temat rozszerzania interfejsów modyfikacji danych.
Krok 6. Zapisanie przekazanej broszury do systemu plików serwera sieci Web
Gdy użytkownik wprowadzi wartości nowej kategorii i kliknie przycisk Wstaw, nastąpi powrót i zostanie rozwinięty wstawiony przepływ pracy. Najpierw zostanie wyzwolony zdarzenie DetailsViewItemInserting
. Następnie wywoływana jest metoda ObjectDataSource Insert()
, która powoduje dodanie nowego rekordu Categories
do tabeli. Następnie zostanie wyzwolony zdarzenie DetailsViewItemInserted
.
Przed wywołaniem metody ObjectDataSource Insert()
należy najpierw upewnić się, że odpowiednie typy plików zostały przekazane przez użytkownika, a następnie zapisać broszurę PDF w systemie plików serwera internetowego. Utwórz procedurę obsługi zdarzeń dla zdarzenia DetailsView i ItemInserting
dodaj następujący kod:
// 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;
}
}
Procedura obsługi zdarzeń rozpoczyna się od odwoływania się do BrochureUpload
kontrolki FileUpload z szablonów elementu DetailsView. Następnie, jeśli broszura została przekazana, rozszerzenie przekazanego pliku zostanie zbadane. Jeśli rozszerzenie nie jest .PDF, zostanie wyświetlone ostrzeżenie, wstawianie zostanie anulowane, a wykonanie programu obsługi zdarzeń zakończy się.
Uwaga
Poleganie na przekazanym rozszerzeniu pliku nie jest techniką zapewnienia, że przekazany plik jest dokumentem PDF. Użytkownik może mieć prawidłowy dokument PDF z rozszerzeniem .Brochure
lub mógł pobrać dokument inny niż PDF i nadać mu .pdf
rozszerzenie. Zawartość binarna pliku musiałaby zostać zbadana programowo, aby bardziej jednoznacznie zweryfikować typ pliku. Takie dokładne podejścia są jednak często przesadne; sprawdzanie rozszerzenia jest wystarczające w przypadku większości scenariuszy.
Zgodnie z opisem w samouczku Przekazywanie plików należy zachować ostrożność podczas zapisywania plików w systemie plików, aby przekazywanie jednego użytkownika nie zastępowało innego elementu. W tym samouczku spróbujemy użyć tej samej nazwy co przekazany plik. Jeśli istnieje już plik w ~/Brochures
katalogu o tej samej nazwie pliku, jednak dołączymy liczbę na końcu do momentu znalezienia unikatowej nazwy. Jeśli na przykład użytkownik przekaże plik broszury o nazwie , ale istnieje już plik o nazwie Meats.pdf
Meats.pdf
w ~/Brochures
folderze, zmienimy zapisaną nazwę pliku na Meats-1.pdf
. Jeśli tak istnieje, spróbujemy użyć Meats-2.pdf
metody i tak dalej, dopóki nie zostanie znaleziona unikatowa nazwa pliku.
Poniższy kod używa File.Exists(path)
metody do określenia, czy plik już istnieje o określonej nazwie pliku. Jeśli tak, nadal spróbuje nowych nazw plików dla broszury, dopóki nie zostanie znaleziony 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 znalezieniu prawidłowej nazwy pliku należy zapisać plik w systemie plików, a wartość ObjectDataSource brochurePath``InsertParameter
musi zostać zaktualizowana, aby ta nazwa pliku została zapisana w bazie danych. Jak widzieliśmy już w samouczku Przekazywanie plików , plik można zapisać przy użyciu metody s kontrolki SaveAs(path)
FileUpload. Aby zaktualizować parametr objectDataSource brochurePath
, użyj kolekcji 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. Zapisywanie przekazanego obrazu do bazy danych
Aby zapisać przekazany obraz w nowym Categories
rekordzie, musimy przypisać przekazaną zawartość binarną do parametru ObjectDataSource picture
w zdarzeniu DetailsView.ItemInserting
Zanim jednak wykonamy to przypisanie, musimy najpierw upewnić się, że przekazany obraz jest obrazem JPG, a nie innym typem obrazu. Podobnie jak w kroku 6, użyjmy rozszerzenia pliku przekazanego obrazu, aby ustalić jego typ.
Categories
Chociaż tabela zezwala NULL
na wartości dla Picture
kolumny, wszystkie kategorie mają obecnie obraz. Wymusimy, aby użytkownik podał obraz podczas dodawania nowej kategorii za pośrednictwem tej strony. Poniższy kod sprawdza, czy obraz został przekazany i czy ma odpowiednie rozszerzenie.
// 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;
}
Ten kod powinien zostać umieszczony przed kodem z kroku 6, aby w przypadku wystąpienia problemu z przekazywaniem obrazu program obsługi zdarzeń zakończył się przed zapisaniem pliku broszury w systemie plików.
Przy założeniu, że został przekazany odpowiedni plik, przypisz przekazaną zawartość binarną do wartości parametru obrazu z następującym wierszem kodu:
// Set the value of the picture parameter
e.Values["picture"] = PictureUpload.FileBytes;
KompletnaItemInserting
procedura obsługi zdarzeń
Aby uzyskać kompletność, poniżej przedstawiono procedurę obsługi zdarzeń ItemInserting
w całości:
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. NaprawianieDisplayCategoryPicture.aspx
strony
Poświęćmy chwilę na przetestowanie interfejsu wstawiania i ItemInserting
procedury obsługi zdarzeń utworzonej w ciągu ostatnich kilku kroków. UploadInDetailsView.aspx
Odwiedź stronę za pośrednictwem przeglądarki i spróbuj dodać kategorię, ale pominąć obraz lub określić obraz inny niż JPG lub broszurę inną niż PDF. W każdym z tych przypadków zostanie wyświetlony komunikat o błędzie i anulowany przepływ pracy wstawiania.
Rysunek 9. Komunikat ostrzegawczy jest wyświetlany, jeśli przekazano nieprawidłowy typ pliku (kliknij, aby wyświetlić obraz pełnowymiarowy)
Po sprawdzeniu, czy strona wymaga przekazania obrazu i nie zaakceptuje plików innych niż PDF lub innych niż JPG, dodaj nową kategorię z prawidłowym obrazem JPG, pozostawiając pole Broszura puste. Po kliknięciu przycisku Wstaw strona zostanie wycofana, a nowy rekord zostanie dodany do Categories
tabeli z przekazaną zawartością binarną obrazu przechowywaną bezpośrednio w bazie danych. Widok GridView jest aktualizowany i pokazuje wiersz dla nowo dodanej kategorii, ale jak pokazano na rysunku 10, nowy obraz kategorii nie jest poprawnie renderowany.
Rysunek 10. Obraz nowej kategorii nie jest wyświetlany (kliknij, aby wyświetlić obraz pełnowymiarowy)
Powodem, dla którego nowy obraz nie jest wyświetlany, jest to, że DisplayCategoryPicture.aspx
strona zwracająca obraz określonej kategorii jest skonfigurowany do przetwarzania map bitowych, które mają nagłówek OLE. Ten nagłówek 78 bajtów jest usuwany z zawartości binarnej Picture
kolumny, zanim zostaną one wysłane z powrotem do klienta. Ale plik JPG, który właśnie przekazaliśmy dla nowej kategorii, nie ma tego nagłówka OLE; dlatego prawidłowe, niezbędne bajty są usuwane z danych binarnych obrazu.
Ponieważ istnieją teraz mapy bitowe z nagłówkami OLE i grupami JPG w Categories
tabeli, musimy zaktualizować DisplayCategoryPicture.aspx
tak, aby nagłówek OLE usuwał oryginalne osiem kategorii i pomija ten usuwanie dla nowszych rekordów kategorii. W następnym samouczku sprawdzimy, jak zaktualizować istniejący obraz rekordu i zaktualizujemy wszystkie stare obrazy kategorii, tak aby były to pliki JPG. Na razie jednak użyj następującego kodu, DisplayCategoryPicture.aspx
aby usunąć nagłówki OLE tylko dla tych oryginalnych ośmiu kategorii:
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);
}
}
Dzięki tej zmianie obraz JPG jest teraz poprawnie renderowany w elemecie GridView.
Rysunek 11. Obrazy JPG dla nowych kategorii są poprawnie renderowane (kliknij, aby wyświetlić obraz pełnowymiarowy)
Krok 9. Usunięcie broszury w obliczu wyjątku
Jednym z wyzwań związanych z przechowywaniem danych binarnych w systemie plików serwera internetowego jest wprowadzenie rozłączenia między modelem danych a danymi binarnymi. Dlatego za każdym razem, gdy rekord zostanie usunięty, należy również usunąć odpowiednie dane binarne w systemie plików. Może to również być w grę podczas wstawiania. Rozważmy następujący scenariusz: użytkownik dodaje nową kategorię, określając prawidłowy obraz i broszurę. Po kliknięciu przycisku Wstaw nastąpi powrót, a zdarzenie DetailsView zostanie ItemInserting
wyzwolony, zapisując broszurę w systemie plików serwera internetowego. Następnie wywoływana jest metoda ObjectDataSourceInsert()
, która wywołuje metodę s InsertWithPicture
klasy, która wywołuje CategoriesBLL
metodę CategoriesTableAdapter
sInsertWithPicture
.
Teraz co się stanie, jeśli baza danych jest w trybie offline lub jeśli w instrukcji INSERT
SQL występuje błąd? Oczywiście wstawianie zakończy się niepowodzeniem, więc do bazy danych nie zostanie dodany żaden nowy wiersz kategorii. Ale nadal mamy przekazany plik broszury siedzący w systemie plików serwera internetowego! Ten plik musi zostać usunięty w obliczu wyjątku podczas wstawiania przepływu pracy.
Jak wspomniano wcześniej w samouczku Obsługa wyjątków BLL i DAL-Level w samouczku dotyczącym strony ASP.NET , gdy wyjątek jest zgłaszany z poziomu głębi architektury, jest bąbelkowany przez różne warstwy. W warstwie prezentacji możemy określić, czy wystąpił wyjątek z zdarzenia DetailsView.ItemInserted
Ta procedura obsługi zdarzeń udostępnia również wartości obiektu ObjectDataSource s InsertParameters
. W związku z tym możemy utworzyć procedurę obsługi zdarzeń, ItemInserted
która sprawdza, czy wystąpił wyjątek, a jeśli tak, usuwa plik określony przez parametr 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()));
}
}
Podsumowanie
Istnieje kilka kroków, które należy wykonać w celu zapewnienia internetowego interfejsu do dodawania rekordów zawierających dane binarne. Jeśli dane binarne są przechowywane bezpośrednio w bazie danych, prawdopodobieństwo, że konieczne będzie zaktualizowanie architektury, dodanie określonych metod do obsługi przypadku wstawiania danych binarnych. Po zaktualizowaniu architektury następnym krokiem jest utworzenie interfejsu wstawiania, który można wykonać przy użyciu kontrolki DetailsView dostosowanej do uwzględnienia kontrolki FileUpload dla każdego pola danych binarnych. Przekazane dane można następnie zapisać w systemie plików serwera internetowego lub przypisać do parametru źródła danych w procedurze obsługi zdarzeń elementu DetailsView ItemInserting
.
Zapisywanie danych binarnych w systemie plików wymaga więcej planowania niż zapisywanie danych bezpośrednio w bazie danych. Aby uniknąć zastąpienia innego użytkownika, należy wybrać schemat nazewnictwa. Ponadto należy wykonać dodatkowe kroki w celu usunięcia przekazanego pliku, jeśli wstawianie bazy danych zakończy się niepowodzeniem.
Teraz mamy możliwość dodawania nowych kategorii do systemu z broszurą i obrazem, ale jeszcze nie przyjrzeliśmy się, jak zaktualizować istniejące dane binarne kategorii lub jak poprawnie usunąć dane binarne dla usuniętej kategorii. Zapoznamy się z tymi dwoma tematami w następnym samouczku.
Szczęśliwe programowanie!
Informacje o autorze
Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można do niego dotrzeć pod adresem mitchell@4GuysFromRolla.com. Lub za pośrednictwem swojego bloga, który można znaleźć na stronie http://ScottOnWriting.NET.
Specjalne podziękowania
Ta seria samouczków została sprawdzona przez wielu pomocnych recenzentów. Recenzenci na potrzeby tego samouczka to Dave Gardner, Teresa Murphy i Bernadette Leigh. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresem mitchell@4GuysFromRolla.com.