5. Zarządzanie interfejsem użytkownika
5.1. Introduction
W relacji klient-serwer w sieci WWW klient przesyła informacje do serwera w postaci ciągu parametrów [param1=val1¶m2=val2&...]. W naszych poprzednich przykładach najczęściej tworzyliśmy ten ciąg ręcznie, wysyłając adresy URL w postaci [http://localhost/appli? param1=val1¶m2=val2&...]. W rzeczywistości informacje przekazywane przez klienta do serwera pochodzą z formularzy wypełnionych przez użytkownika. W niniejszym rozdziale omówimy sposób ich tworzenia. Przedstawimy również narzędzie WebMatrix, które pozwoli nam projektować interfejsy użytkownika. Sposób instalacji tego narzędzia opisano w załącznikach.
5.2. Język HTML
5.2.1. Przykład
Rozważmy następujący przykład, utworzony za pomocą narzędzia [Web Matrix], który przedstawia:
- tabelę
- obraz
- link

Uruchommy [WebMatrix], a następnie wybierzmy opcję [File/New File]:

Decydujemy się utworzyć stronę o nazwie HTML. Powyższe informacje spowodują utworzenie pliku [d:\data\devel\aspnet\chap4\exemple1\exemple1.htm]. [WebMatrix] oferuje dwie możliwości edycji tego pliku: tryb [Design] oraz tryb [HTML]:

Tryb [Design] umożliwia korzystanie z palety komponentów HTML oferowanej przez [WebMatrix]:

Aby wstawić element z tej palety, wystarczy dwukrotnie na niego kliknąć, a następnie umieścić go w oknie [Design]. Tryb [HTML] umożliwia tworzenie dokumentu HTML za pomocą edytora tekstu. W tym celu należy znać składnię języka HTML. W zakładce [HTML] wygenerowano szkielet dokumentu:

Okno [HTML] jest bardzo przydatne dla osób, które nie znają języka HTML. W oknie [Design] tworzy dokument i sprawdza kod HTML wygenerowany w oknie [HTML]. W ten sposób stopniowo opanowuje język HTML i dość szybko może pracować wyłącznie z edytorem tekstu, bez pomocy trybu [Design]. Pokażemy teraz, jak stworzyć dokument HTML przedstawiony na początku tej sekcji. Pracujemy w oknie [Design]. Najpierw wpisujemy bezpośrednio pierwszy wiersz tekstu:

- dodajemy komponent [Horizontal Rule] z palety komponentów:

- dodajemy komponent [Table]:

- umieszczamy kursor w trzecim wierszu tabeli, aby usunąć go za pomocą opcji [HTML/Edit Table/Delete Table Row]. Następnie wpisujemy oczekiwany tekst w każdej komórce:

- umieszczamy kursor w jednej z komórek tabeli i sprawdzamy jej właściwości. Okno właściwości wyświetla się w prawym dolnym rogu środowiska pracy:

- komórka jest reprezentowana przez tag HTML <TD>. Wyświetlane są zatem właściwości tagu <TD>. Skupiamy się na tabeli, która jest obiektem obejmującym komórkę. Klikamy na listę rozwijaną (click to see parent HTML elements) powyżej, aby wybrać obiekt <TABLE>:

- Obiekt <TABLE> posiada właściwość [border], która określa szerokość obramowania otaczającego komórki tabeli. W tym przypadku przyjmujemy wartość border=1.

- teraz edytujemy atrybuty obiektu <TD> komórki (1,2), aby ustawić align=Center i width=200 (pikseli). Tekst zostanie wyśrodkowany w komórce (align=center), a jej szerokość wyniesie 200 pikseli. Aby zobaczyć zmianę, czasami konieczne może być wybranie zakładki [HTML], a następnie powrót do zakładki [Design]:

- teraz umieszczamy tekst poprzedzający obraz:

- a następnie obraz, klikając dwukrotnie komponent [image] z palety:

- Zaznaczamy obraz, aby edytować jego właściwości:

- w atrybucie [src] wpisujemy nazwę pliku zawierającego obraz, w tym przypadku [univ01.gif]:

- umieszczamy tekst poprzedzający link:

- tworzymy z tekstu [ici] link do adresu URL [http://istia.univ-angers.fr]. W tym celu zaznaczamy go, a następnie wybieramy opcję [HTML/Insert Hyperlink]:

- otrzymujemy następujący wynik:

- już prawie gotowe. Przyjrzyjmy się kodowi HTML wygenerowanemu w zakładce [HTML]:
<html>
<head>
</head>
<body>
<p>
Le langage HTML - 1
</p>
<hr />
<table border="1">
<tbody>
<tr>
<td>
cellule(1,1)</td>
<td align="middle" width="200">
cellule(1,2)</td>
<td>
cellule(1,3)</td>
</tr>
<tr>
<td>
cellule(2,1)</td>
<td>
cellule(2,2)</td>
<td>
cellule(2,3)</td>
</tr>
</tbody>
</table>
<p>
Une image <img src="univ01.gif" />
</p>
<p>
Le site de l'istia <a href="http://istia.univ-angers.fr">ici</a>
</p>
</body>
</html>
Pozostało nam jeszcze kilka szczegółów do dopracowania. Przede wszystkim chcielibyśmy nadać tytuł naszemu dokumentowi. [WebMatrix] nie pozwala na to w trybie [Design]. W zakładce [HTML] zastępujemy sekwencję <head>..</head> następującą sekwencją:
Ponadto chcielibyśmy, aby tekst [Le langage HTML - 1] był wyświetlany większą czcionką. Sekwencja <Hi>tekst</Hi> pozwala ustawić rozmiar tekstu, gdzie i przyjmuje wartości od 1 do 6, od największego do najmniejszego. W tym przypadku wybierzemy H2. Sekwencja
przekształca się w:
Okno [Design] odzwierciedla nasze zmiany:

Pozostaje nam tylko przeprowadzić test przy użyciu opcji [View/Start] lub [F5]. Opcja [WebMatrix] wymaga podania kilku informacji w celu uruchomienia serwera WWW [Cassini]:

Możemy zaakceptować wartości domyślne. Serwer [Cassini] zostaje uruchomiony, a nasza strona wyświetla się w przeglądarce:

Z ciekawości możemy sprawdzić, z jakimi parametrami uruchomiono serwer [Cassini]:

Przedstawiliśmy podstawy tworzenia strony HTML za pomocą [WebMatrix]. Zachęcamy czytelnika do tworzenia kolejnych stron HTML i sprawdzania za każdym razem wygenerowanego kodu HTML. Stopniowo będzie w stanie stworzyć stronę bez pomocy trybu [Design]. Dokument HTML ma następującą ogólną postać:
Cały dokument jest ujęty w tagi <html>...</html>. Składa się on z dwóch części:
<head>...</head>: jest to niewidoczna część dokumentu. Zawiera informacje dla przeglądarki, która wyświetli dokument. Często znajduje się w niej tag <title>...</title>, który określa tekst wyświetlany w pasku tytułu przeglądarki. Można tam również znaleźć inne tagi, w szczególności te definiujące słowa kluczowe dokumentu, wykorzystywane następnie przez wyszukiwarki. W tej części można również znaleźć skrypty, najczęściej napisane w języku JavaScript lub VBScript, które zostaną wykonane przez przeglądarkę.
<body atrybuty>...</body>: jest to część, która zostanie wyświetlona przez przeglądarkę. Tagi zawarte w tej części wskazują przeglądarce „pożądany” wygląd dokumentu. Każda przeglądarka interpretuje te tagi na swój sposób. W związku z tym dwie przeglądarki mogą wyświetlać ten sam dokument internetowy w różny sposób. Jest to zazwyczaj jeden z problemów, z którymi borykają się projektanci stron internetowych.
Kod HTML poprzedniego dokumentu wyglądał następująco:
<html>
<head>
<title>HTML1</title>
</head>
<body>
<h2>Le langage HTML - 1
</h2>
<hr />
<table border="1">
<tbody>
<tr>
<td>
cellule(1,1)</td>
<td align="middle" width="200">
cellule(1,2)</td>
<td>
cellule(1,3)</td>
</tr>
<tr>
<td>
cellule(2,1)</td>
<td>
cellule(2,2)</td>
<td>
cellule(2,3)</td>
</tr>
</tbody>
</table>
<p>
Une image <img src="univ01.gif" />
</p>
<p>
Le site de l'istia <a href="http://istia.univ-angers.fr">ici</a>
</p>
</body>
</html>
Element | tagów i przykładów HTML |
<title>HTML1</title> HTML1 pojawi się w pasku tytułu przeglądarki wyświetlającej dokument | |
<hr>: wyświetla poziomą kreskę | |
<atrybuty tabeli>....</table>: w celu zdefiniowania tabeli <tr atrybuty>...</tr>: do zdefiniowania wiersza <td atrybuty>...</td>: do zdefiniowania komórki przykłady: <table border="1">...</table>: atrybut border określa grubość obramowania tabeli <td align="center" width="200">komórka(1,2)</td>: definiuje komórkę, której zawartością będzie cellule(1,2). Zawartość ta zostanie wyśrodkowana w poziomie (align="center"). Komórka będzie miała szerokość 200 pikseli (width="200") | |
<img src="univ01.gif" />: definiuje obraz, którego plik źródłowy znajduje się na serwerze internetowym pod nazwą univ01.gif (src="univ01.gif"). Link ten znajduje się w dokumencie internetowym uzyskanym za pomocą URL http://localhost/exemple1.htm. W związku z tym przeglądarka wyśle żądanie do serwera URL http://localhost/univ01.gif, aby pobrać obraz, do którego odwołuje się ten link. | |
<a href="http://istia.univ-angers.fr">tutaj</a>: sprawia, że tekst ici służy jako link do strony URL http://istia.univ-angers.fr. |
Na tym prostym przykładzie widać, że aby zbudować cały dokument, przeglądarka musi wysłać dwa żądania do serwera:
http://localhost/exemple1.htm, aby pobrać kod źródłowy HTML dokumentu
http://localhost/univ01.gif, aby pobrać obraz o nazwie univ01.gif
5.2.2. Tworzenie formularza
Formularz HTML ma na celu przedstawienie użytkownikowi strony służącej do wprowadzania informacji, analogicznej do formularzy spotykanych w systemie Windows. Formularz ten jest wysyłany do przeglądarki w postaci dokumentu HTML. Przeglądarka wyświetli formularz użytkownikowi, który go wypełni i zatwierdzi za pomocą odpowiedniego przycisku. Następnie przeglądarka prześle wprowadzone wartości do serwera w celu przetworzenia. Zauważymy, że nie przesyła ona do serwera całego formularza, a jedynie wprowadzone wartości. Poniższy przykład przedstawia formularz internetowy, który również został utworzony przy użyciu WebMatrix:

Kod HTML wygenerowany przez [WebMatrix] wygląda następująco:
<html>
<head>
<title>Formulaire</title>
<script language="javascript">
function effacer(){
alert("Vous avez cliqué sur le bouton [Effacer]");
}
</script>
</head>
<body>
<p>
Gestion d'un formulaire
</p>
<hr />
<form name="formulaire" method="post">
<table border="1">
<tr>
<td>
Etes-vous marié(e)</td>
<td>
<p align="center">
<input type="radio" value="oui" name="rdMarie" />Oui
<input type="radio" checked value="non" name="rdMarie" />Non
</p>
</td>
</tr>
<tr>
<td>
Cases à cocher
</td>
<td>
<p align="center">
<input type="checkbox" value="un" name="C1" />1
<input type="checkbox" checked value="deux" name="C2" />2
<input type="checkbox" value="trois" name="C3" />3
</p>
</td>
</tr>
<tr>
<td>
Champ de saisie</td>
<td>
<p align="center">
<input type="text" maxlength="30" value="qqs mots" name="txtSaisie" />
</p>
</td>
</tr>
<tr>
<td>
Mot de passe</td>
<td>
<p align="center">
<input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" />
</p>
</td>
</tr>
<tr>
<td>
Boîte de saisie</td>
<td>
<p align="center">
</p>
<textarea name="areaSaisie">ligne1
ligne2</textarea>
</td>
</tr>
<tr>
<td>
ComboBox</td>
<td>
<p align="center">
</p>
<select name="cmbValeurs">
<option value="1">choix1</option>
<option value="2" selected>choix2</option>
<option value="3">choix3</option>
</select>
</td>
</tr>
<tr>
<td>
Liste à choix simple</td>
<td>
<p align="center">
</p>
<select size="3" name="lstSimple">
<option value="1" selected>liste1</option>
<option value="2">liste2</option>
<option value="3">liste3</option>
<option value="4">liste4</option>
<option value="5">liste5</option>
</select>
</td>
</tr>
<tr>
<td>
Liste à choix multiple</td>
<td>
<p align="center">
</p>
<select multiple size="3" name="lstMultiple">
<option value="1" selected>multiple1</option>
<option value="2">multiple2</option>
<option value="3" selected>multiple3</option>
<option value="4">multiple4</option>
<option value="5">multiple5</option>
</select>
</td>
</tr>
<tr>
<td>
Bouton simple</td>
<td>
<p align="center">
<input onclick="effacer()" type="button" value="Effacer" name="btnEffacer" />
</p>
</td>
</tr>
<tr>
<td>
Bouton submit</td>
<td>
<p align="center">
<input type="submit" value="Envoyer" name="btnEnvoyer" />
</p>
</td>
</tr>
<tr>
<td>
Bouton reset</td>
<td>
<p align="center">
<input type="reset" value="Rétablir" name="btnRetablir" runat="server" />
</p>
</td>
</tr>
</table>
<input type="hidden" name="secret" value="uneValeur" />
</form>
</body>
</html>
Związek między kontrolą wizualną <--> znacznikiem HTML jest następujący:
Kontrola | tag HTML |
<form name="formularz" method="post"> | |
<input type="text" maxlength="30" value="kilka słów" name="txtSaisie" /> | |
<input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" /> | |
<textarea name="areaSaisie">wiersz1 wiersz 2</textarea> | |
<input type="radio" value="tak" name="rdMarie" />Tak <input type="radio" checked value="nie" name="rdMarie" />Nie | |
<input type="checkbox" value="jeden" name="C1" />1 <input type="checkbox" checked value="dwa" name="C2" />2 <input type="checkbox" value="trzy" name="C3" />3 | |
<select name="cmbValeurs"> <option value="1">opcja1</option> <option value="2" selected>opcja 2</option> <option value="3">opcja3</option> </select> | |
<select size="3" name="lstSimple"> <option value="1" selected>lista1</option> <option value="2">lista2</option> <option value="3">lista3</option> <option value="4">lista4</option> <option value="5">lista5</option> </select> | |
<select multiple size="3" name="lstMultiple"> <option value="1" selected>multiple1</option> <option value="2">multiple2</option> <option value="3" selected>multiple3</option> <option value="4">multiple4</option> <option value="5">multiple5</option> </select> | |
<input type="hidden" name="secret" value="uneValeur" /> | |
<input type="submit" value="Wyślij" name="btnEnvoyer" /> | |
<input type="reset" value="Przywróć" name="btnRetablir" runat="server" /> | |
<input onclick="effacer()" type="button" value="Usuń" name="btnEffacer" /> |
Przyjrzyjmy się tym różnym elementom sterującym.
5.2.2.1. Formularz
<form name="formularz" method="post"> |
<form name="..." method="..." action="...">...</form> | |
name="frmexemple": nazwa formularza method="..." : metoda używana przez przeglądarkę do wysyłania do serwera WWW wartości zebranych w formularzu action="..." : adres, na który zostaną wysłane wartości zebrane w formularzu. Formularz internetowy jest otoczony tagami <form>...</form>. Formularz może mieć nazwę (name="xx"). Dotyczy to wszystkich elementów kontrolnych, które można znaleźć w formularzu. Nazwa ta jest przydatna, jeśli dokument internetowy zawiera skrypty, które muszą odwoływać się do elementów formularza. Celem formularza jest zebranie informacji podanych przez użytkownika za pomocą klawiatury lub myszy oraz przesłanie ich do serwera internetowego o adresie URL. Którego? Tego, do którego odwołuje się atrybut action="URL". Jeśli ten atrybut nie występuje, informacje zostaną wysłane na serwer URL dokumentu, w którym znajduje się formularz. W jaki sposób klient sieciowy przekazuje informacje (zawarte w formularzu) do serwera internetowego? Omówiliśmy to szczegółowo. Może on skorzystać z dwóch różnych metod o nazwach POST i GET. Atrybut method="méthode", z metodą równą GET lub POST, w tagu <form> wskazuje przeglądarce metodę, jaką należy zastosować do wysłania informacji zebranych w formularzu do adresu URL określonego przez atrybut action="URL". Gdy atrybut method nie jest określony, domyślnie stosowana jest metoda GET. |
5.2.2.2. Pole wprowadzania danych

<input type="text" maxlength="30" value="kilka słów" name="txtSaisie" /> <input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" /> |
<input type="..." name="..." size=".." value=".."> Tag `input` służy do różnych elementów sterujących. To właśnie atrybut type pozwala odróżnić te różne elementy sterujące od siebie. | |
type="text": określa, że jest to pole wprowadzania danych type="password": znaki w polu wprowadzania danych są zastępowane znakami *. Jest to jedyna różnica w stosunku do zwykłego pola wprowadzania danych. Ten typ elementu kontrolnego nadaje się do wprowadzania haseł. size="12": liczba znaków widocznych w polu – nie uniemożliwia wprowadzenia większej liczby znaków maxlength="30": ustala maksymalną liczbę znaków na 30 – przeglądarka jest odpowiedzialna za egzekwowanie tego atrybutu name="txtSaisie": nazwa elementu kontrolnego value="kilka słów": tekst, który zostanie wyświetlony w polu wprowadzania danych. |
5.2.2.3. Pole wprowadzania wielowierszowe

<textarea name="areaSaisie">wiersz1 wiersz 2</textarea> |
<textarea ...>tekst</textarea> wyświetla wielowierszowe pole wprowadzania danych z tekstem domyślnym | |
rows="2": liczba wierszy cols="'20" : liczba kolumn name="areaSaisie": nazwa kontrolki |
5.2.2.4. Przyciski opcji
![]()
<input type="radio" value="tak" name="rdMarie" />Tak <input type="radio" checked value="nie" name="rdMarie" />Nie |
<input type="radio" attribut2="valeur2" ..../>tekst wyświetla przycisk opcji z tekstem obok. | |
name="rdMarie": nazwa elementu sterującego. Przyciski opcji o tej samej nazwie tworzą grupę przycisków wykluczających się wzajemnie: można zaznaczyć tylko jeden z nich. value="wartość": wartość przypisana do przycisku opcji. Nie należy mylić tej wartości z tekstem wyświetlanym obok przycisku opcji. Ten ostatni służy wyłącznie do wyświetlania. checked: jeśli to słowo kluczowe jest obecne, przycisk opcji jest zaznaczony, w przeciwnym razie nie jest. |
5.2.2.5. Pola wyboru
<input type="checkbox" value="jeden" name="C1" />1 <input type="checkbox" checked value="dwa" name="C2" />2 <input type="checkbox" value="trzy" name="C3" />3 |
![]()
<input type="checkbox" attribut2="valeur2" ..../>tekst wyświetla pole wyboru z tekstem obok. | |
name="C1": nazwa elementu sterującego. Pola wyboru mogą, ale nie muszą mieć tę samą nazwę. Pola o tej samej nazwie tworzą grupę powiązanych pól. value="wartość": wartość przypisana do pola wyboru. Nie należy mylić tej wartości z tekstem wyświetlanym obok przycisku opcji. Ten ostatni służy wyłącznie do wyświetlania. checked: jeśli to słowo kluczowe występuje, przycisk opcji jest zaznaczony, w przeciwnym razie nie jest. |
5.2.2.6. Lista rozwijana (combo)
<select name="cmbValeurs"> <option value="1">opcja1</option> <option value="2" selected>opcja 2</option> <option value="3">opcja 3</option> </select> |
![]()
<select size=".." name=".."> <option [selected="selected"] [value="valeur"]>tekst</option> ... </select> wyświetla na liście teksty zawarte między tagami <option>...</option> | |
name="cmbValeurs": nazwa kontrolki. size="1": liczba widocznych elementów listy. size="1" sprawia, że lista działa jak pole kombi. Jest to wartość domyślna, jeśli brakuje atrybutu [size]. selected="selected": jeśli ten atrybut występuje w elemencie listy, element ten pojawia się jako zaznaczony na liście. W naszym powyższym przykładzie element listy choix2 pojawia się jako zaznaczony element listy rozwijanej, gdy jest ona wyświetlana po raz pierwszy. value="wartość": określa wartość, która ma zostać wysłana do serwera w przypadku zaznaczenia elementu. Jeśli ten atrybut nie występuje, do serwera wysyłany jest tekst powiązany z opcją. |
5.2.2.7. Lista z jednym wyborem
<select size="3" name="lstSimple"> <option value="1" selected>lista1</option> <option value="2">lista2</option> <option value="3">lista3</option> <option value="4">lista4</option> <option value="5">lista5</option> </select> |

<select size=".." name=".."> <option [selected] [value="valeur"]>...</option> ... </select> wyświetla na liście teksty zawarte między znacznikami <option>...</option> | |
takie same jak w przypadku listy rozwijanej wyświetlającej tylko jeden element. Ten element sterujący różni się od poprzedniej listy rozwijanej jedynie atrybutem size>1. |
5.2.2.8. Lista z możliwością wielokrotnego wyboru
<select multiple size="3" name="lstMultiple"> <option value="1" selected>multiple1</option> <option value="2">multiple2</option> <option value="3" selected>multiple3</option> <option value="4">multiple4</option> <option value="5">multiple5</option> </select> |

<select size=".." name=".." multiple> <option [selected] ] [value="valeur"]>...</option> ... </select> wyświetla na liście teksty zawarte między znacznikami <option>...</option> | |
multiple: umożliwia zaznaczenie wielu elementów z listy. W powyższym przykładzie zaznaczone są zarówno elementy liste1, jak i liste3. |
5.2.2.9. Przycisk typu button
<input onclick="effacer()" type="button" value="Usuń" name="btnEffacer" /> |
![]()
<input type="button" value="..." name="..." onclick="effacer()" ....> | |
type="button": definiuje kontrolkę przycisku. Istnieją dwa inne typy przycisków: submit i reset. value="Usuń": tekst wyświetlany na przycisku onclick="funkcja()": pozwala zdefiniować funkcję, która ma zostać wykonana, gdy użytkownik kliknie przycisk. Funkcja ta jest częścią skryptów zdefiniowanych w wyświetlanym dokumencie internetowym. Powyższa składnia jest zgodna ze standardem javascript. Jeśli skrypty są napisane w języku VBScript, należy wpisać onclick="funkcja" bez nawiasów. Składnia pozostaje taka sama, jeśli do funkcji trzeba przekazać parametry: onclick="funkcja(val1, val2,...)" W naszym przykładzie kliknięcie przycisku Effacer wywołuje następującą funkcję JavaScript effacer: Funkcja effacer wyświetla komunikat: ![]() |
5.2.2.10. Przycisk typu „submit”
<input type="submit" value="Wyślij" name="btnEnvoyer" /> |
![]()
<input type="submit" value="Wyślij" name="btnEnvoyer"> | |
type="submit": definiuje przycisk jako przycisk wysyłający dane formularza do serwera internetowego. Gdy użytkownik kliknie ten przycisk, przeglądarka wyśle dane formularza do adresu URL zdefiniowanego w atrybucie action tagu <form> zgodnie z metodą określoną przez atrybut method tego samego tagu. value="Wyślij": tekst wyświetlany na przycisku |
5.2.2.11. Przycisk typu reset
<input type="reset" value="Przywróć" name="btnRetablir" runat="server" /> |
![]()
<input type="reset" value="Przywróć" name=" btnRetablir "> | |
type="reset": definiuje przycisk jako przycisk resetowania formularza. Gdy użytkownik kliknie ten przycisk, przeglądarka przywróci formularz do stanu, w jakim go otrzymała. value="Przywróć": tekst wyświetlany na przycisku |
5.2.2.12. Pole ukryte
<input type="hidden" name="secret" value="uneValeur" /> |
<input type="hidden" name="..." value="..."> | |
type="hidden": określa, że jest to pole ukryte. Pole ukryte stanowi część formularza, ale nie jest widoczne dla użytkownika. Jeśli jednak użytkownik poprosiłby przeglądarkę o wyświetlenie kodu źródłowego, zobaczyłby tag <input type="hidden" value="..."> i tym samym wartość pola ukrytego. value="uneValeur": wartość pola ukrytego. Jaka jest zaleta pola ukrytego? Pozwala to serwerowi internetowemu na przechowywanie informacji w trakcie kolejnych żądań wysyłanych przez klienta. Rozważmy przykład aplikacji do zakupów internetowych. Klient kupuje pierwszy produkt o numerze art1 w ilości q1 na pierwszej stronie katalogu, a następnie przechodzi do kolejnej strony katalogu. Aby zapamiętać, że klient kupił q1 sztuk produktu art1, serwer może umieścić te dwie informacje w ukrytym polu formularza internetowego na nowej stronie. Na tej nowej stronie klient kupuje produkty o numerach q2 i art2. Gdy dane z tego drugiego formularza zostaną wysłane na serwer (submit), serwer otrzyma nie tylko informację (q2,art2), ale także (q1,art1), które również stanowią część formularza jako ukryte pola, których użytkownik nie może modyfikować. Serwer WWW umieści wówczas w nowym ukrytym polu informacje (q1,art1) oraz (q2,art2) i wyśle nową stronę katalogu. I tak dalej. |
5.3. Przesyłanie wartości formularza z przeglądarki do serwera internetowego
Z poprzedniego rozdziału wiemy już, w jaki sposób klient przesyła informacje do serwera. Czyni to za pomocą:
- żądania o postaci HTTP GET url?param1=va1¶m2=val2&....
- żądania o postaci HTT POST url, po którym następuje dokument zawierający ciąg parametrów param1=va1¶m2=val2&....
Przeglądarka zastosuje jedną z tych dwóch metod w zależności od tego, czy atrybut [method] tagu [form] ma wartość GET czy POST. To właśnie teraz pokażemy. Strona omówiona wcześniej jest stroną statyczną. Aby uzyskać dostęp do nagłówków HTTP wysyłanych przez przeglądarkę, która zażąda tego dokumentu, przekształcamy ją w stronę dynamiczną dla serwera internetowego .NET (IIS lub Cassini). Poprzedni kod statyczny umieszczamy w pliku [formulaire_get.aspx], a jego zawartość jest następująca:
<%@ Page src="formulaire_get.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire_get" %>
<html>
<head>
<title>Formulaire</title>
<script language="javascript">
function effacer(){
alert("Vous avez cliqué sur le bouton [Effacer]");
}
</script>
</head>
<body>
.....
</body>
</html>
Powyższa strona prezentacyjna jest powiązana z kontrolerem [formulaire_get.aspx.vb]:
Public Class formulaire_get
Inherits System.Web.UI.Page
Private Sub Page_Init(ByVal Sender As Object, ByVal e As System.EventArgs) Handles MyBase.Init
' zapisuje bieżące zapytanie w request.txt w folderze strony
Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt"
Me.Request.SaveAs(requestFileName, True)
End Sub
End Class
Przy każdym wywołaniu dokumentu [formulaire_get.aspx] żądanie klienta zostanie zapisane w pliku [request.txt] przez procedurę Page_Init. Z tym sposobem działania mieliśmy już do czynienia, dlatego nie będziemy dalej omawiać tego kontrolera.
5.3.1. Metoda GET
Przeprowadźmy pierwszy test, w którym w kodzie HTML dokumentu tag FORM jest zdefiniowany w następujący sposób:
<form name="formulaire" method="get">
Umieszczamy pliki [formulaire_get.aspx] i [formulaire_get.aspx.vb] w folderze <application-path> i uruchamiamy serwer Cassini z parametrami (<application-path>,/form2). Wprowadzamy adres URL http://localhost/form2/formulaire_get.aspx:

Przeglądarka właśnie wysłała żądanie i wiemy, że zostało ono zapisane w pliku [request.txt]. Przyjrzyjmy się jego zawartości:
GET /form2/formulaire_get.aspx HTTP/1.1
Cache-Control: max-age=0
Connection: keep-alive
Keep-Alive: 300
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316
Przeglądarka użyła zapytania HTTP GET, aby uzyskać adres URL [http://localhost/form2/formulaire_get.aspx]. Dzieje się tak zawsze, gdy adres URL jest podawany przez użytkownika. Formularz wypełniamy w następujący sposób:

Korzystamy z powyższego przycisku [Envoyer]. Jego kod HTML wygląda następująco:
Po kliknięciu przycisku typu [Submit] przeglądarka wysyła parametry formularza (tag <form>) do adresu URL wskazanego w atrybucie [action] tagu <form action="URL">, o ile taki istnieje. Jeśli ten atrybut nie istnieje, parametry formularza są wysyłane do adresu URL, z którego pochodzi formularz. Tak jest w tym przypadku. Przycisk [Envoyer] powinien zatem spowodować wysłanie przez przeglądarkę żądania do serwera URL [http://localhost/form2/formulaire_get.aspx] wraz z przekazaniem parametrów formularza. Ponieważ strona [formulaire_get.aspx] zapamiętuje otrzymane żądanie, powinniśmy wiedzieć, w jaki sposób klient przesłał te parametry. Spróbujmy. Klikamy przycisk [Envoyer]. Otrzymujemy następującą odpowiedź z przeglądarki:

Jest to strona początkowa, ale można zauważyć, że wartość URL w polu [Adresse] przeglądarki uległa zmianie. Przybrała następującą postać:
http://localhost/form2/formulaire_get.aspx?rdMarie=tak&C1=jeden&C2=dwa&txtSaisie=programowanie+asp.net&txtMdp=unMotDePasse&areaSaisie=podstawy+programowania+0D%0Aprogramowanie+stron+internetowych%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=Wyślij&secret=uneValeur
Widać, że wybory dokonane w formularzu znajdują się w polu URL. Przyjrzyjmy się zawartości pliku [request.txt], który zapisał żądanie klienta:
GET /form2/formulaire_get.aspx?rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0,1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
Referer: http://localhost/form2/formulaire_get.aspx
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316
Widać zapytanie HTTP, dość podobne do tego, które pierwotnie wysłała przeglądarka, gdy żądała dokumentu bez przekazywania parametrów. Istnieją dwie różnice:
Parametry formularza zostały dodane po adresie URL dokumentu w postaci ?param1=val1¶m2=val2&... | |
Klient wskazuje za pomocą tego nagłówka HTTP numer URL dokumentu, który wyświetlał w momencie wysłania żądania |
Przyjrzyjmy się bliżej, w jaki sposób parametry zostały przekazane w poleceniu GET URL?param1=wartość1¶m2=wartość2&... HTTP/1.1, gdzie parami to nazwy elementów sterujących formularza internetowego, a valeuri to przypisane do nich wartości. Poniżej przedstawiamy tabelę z trzema kolumnami:
- kolumna 1: zawiera definicję elementu sterującego HTML z przykładu
- kolumna 2: przedstawia wygląd tego elementu w przeglądarce
- kolumna 3: przedstawia wartość wysyłaną do serwera przez przeglądarkę dla elementu z kolumny 1 w postaci, jaką ma ona w zapytaniu GET z przykładu
element sterujący HTML | wygląd przed zatwierdzeniem | zwracana(-e) wartość(-i) |
<input type="radio" value="tak" name="rdMarie" />Tak <input type="radio" checked value="nie" name="rdMarie" />Nie | rdMarie=tak – wartość atrybutu value przycisku zaznaczonego przez użytkownika. | |
<input type="checkbox" value="un" name="C1" />1 <input type="checkbox" checked value="deux" name="C2" />2 <input type="checkbox" value="trzy" name="C3" />3 | C1=jeden C2=dwa – wartości atrybutów value pól zaznaczonych przez użytkownika | |
<input type="text" maxlength="30" value="qqs słów" name="txtSaisie" /> | txtSaisie=programowanie+asp.net – tekst wpisany przez użytkownika w polu wprowadzania danych. Spacje zostały zastąpione znakiem + | |
<input type="password" maxlength="12" size="12" value="hasło" name="txtMdp" /> | txtMdp=tojesttajemnica – tekst wpisany przez użytkownika w polu wprowadzania danych. Tekst faktycznie wpisany brzmiał „tojesttajemnica”. Ostatni znak został utracony, ponieważ atrybut maxlength="12" ograniczał liczbę znaków do 12. | |
<textarea name="areaSaisie"> wiersz1 wiersz2</textarea> | ![]() | poleWprowadź=podstawy+ %0D%0A programowania+stron+internetowych – tekst wpisany przez użytkownika w polu wprowadzania danych. %OD%OA to znak końca linii. Spacje zostały zastąpione znakiem + |
<select name="cmbValeurs"> <option value="1">opcja1 </option> <option value="2" selected>opcja 2 </option> <option value="3">opcja 3 </option> </select> | cmbWartości=3 - wartość wybrana przez użytkownika z liście z jedną opcją do wyboru | |
<select size="3" name="lstSimple"> <option value="1" selected>lista1</option> <option value="2">lista2 </option> <option value="3">lista3 </option> <option value="4">lista4 </option> <option value="5">lista5 </option> </select> | ![]() | lstSimple=3 - wartość wybrana przez użytkownika z liście z jednym wyborem |
<select multiple size="3" name="lstMultiple"> <option value="1" selected>multiple1 </option> <option value="2">multiple2 </option> <option value="3" selected>multiple3 </option> <option value="4">multiple4 </option> <option value="5">multiple5 </option> </select> | ![]() | lstMultiple=2 lstMultiple=4 - wartości wybrane przez użytkownika z liście z możliwością wielokrotnego wyboru |
<input type="submit" value="Wyślij" name="btnEnvoyer" /> | btnEnvoyer=Wyślij – nazwa i atrybut value przycisku, który służył do wysłania danych formularza na serwer | |
<input type="hidden" name="secret" value="uneValeur" /> | secret=uneValeur – atrybut value pola ukrytego |
Można się zastanawiać, co serwer zrobił z przekazanymi mu parametrami. W rzeczywistości nic. Po otrzymaniu polecenia
GET /form2/formulaire_get.aspx?rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur HTTP/1.1
serwer WWW przekazał parametry do pliku URL, [http://localhost/form2/formulaire_get.aspx] oraz c.a.d, czyli do dokumentu, który stworzyliśmy na początku. Nie napisaliśmy żadnego kodu do pobierania i przetwarzania parametrów przesyłanych przez klienta. Dlatego wszystko przebiega tak, jakby żądanie klienta brzmiało po prostu:
Z tego powodu w odpowiedzi na nasze wywołanie przycisku [Envoyer] otrzymaliśmy tę samą stronę, co początkowo przy wywołaniu URL i [http://localhost/form2/formulaire_get.aspx] bez parametrów.
5.3.2. Metoda POST
Dokument HTML jest teraz skonfigurowany tak, aby przeglądarka korzystała z metody POST do wysyłania wartości formularza na serwer WWW. W tym celu kopiujemy plik [formulaire_get.aspx] do pliku [formulaire_post.aspx] i modyfikujemy wyłącznie tag <form> w pliku [formulaire_post.aspx]:
<%@ Page src="formulaire_get.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire_get" %>
<html>
<head>
...
</head>
<body>
<p>
Gestion d'un formulaire
</p>
<hr />
<form name="formulaire" method="post">
<table border="1">
Nie ma potrzeby zmiany kontrolera [formulaire_get.aspx.vb], więc pozostawiamy go bez zmian. Żądamy nowego dokumentu za pomocą URL [http://localhost/form2/formulaire_post.aspx], wypełniamy formularz tak samo jak w przypadku metody GET i przesyłamy parametry do serwera za pomocą przycisku [Envoyer]. Otrzymujemy z serwera następującą stronę odpowiedzi:

Otrzymujemy zatem ten sam wynik, co w przypadku metod GET i c.a.d – stronę początkową. Warto zwrócić uwagę na jedną różnicę: w polu [Adresse] przeglądarki nie pojawiają się przesłane parametry. Przyjrzyjmy się teraz żądaniu wysłanemu przez klienta, które zostało zapisane w pliku [request.txt]:
POST /form2/formulaire_post.aspx HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Content-Length: 222
Content-Type: application/x-www-form-urlencoded
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0,1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
Referer: http://localhost/form2/formulaire_post.aspx
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316
rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=3&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur
W zapytaniu klienta HTTP pojawiają się nowe pozycje:
Zapytanie GET zostało zastąpione zapytaniem POST. Parametry nie występują już w pierwszym wierszu zapytania. Można zauważyć, że znajdują się one teraz za zapytaniem HTTP, po pustym wierszu. Ich kodowanie jest identyczne jak w zapytaniu GET. | |
liczba „wysłanych” znaków, c.a.d. Liczba znaków, które serwer WWW będzie musiał odczytać po otrzymaniu nagłówków HTTP, aby pobrać dokument wysłany przez klienta. Dokumentem tym jest w tym przypadku lista wartości z formularza. | |
określa typ dokumentu, który klient wyśle po nagłówkach HTTP. Typ [application/x-www-form-urlencoded] wskazuje, że jest to dokument zawierający wartości z formularza. |
Istnieją dwie metody przesyłania danych do serwera WWW: GET i POST. Czy jedna z tych metod jest lepsza od drugiej? Widzieliśmy, że jeśli wartości formularza były wysyłane przez przeglądarkę metodą GET, przeglądarka wyświetlała w polu Adresse żądaną wartość URL w postaci URL?param1=val1¶m2=val2&.... Można to postrzegać jako zaletę lub wadę:
- zaletą, jeśli chcemy umożliwić użytkownikowi dodanie tego skonfigurowanego adresu URL do ulubionych
- wadą, jeśli nie chcemy, aby użytkownik miał dostęp do niektórych informacji zawartych w formularzu, takich jak na przykład pola ukryte
W dalszej części będziemy stosować w naszych formularzach niemal wyłącznie metodę POST.
5.4. Przetwarzanie wartości formularza po stronie serwera
5.4.1. Przedstawienie przykładu
Teraz, gdy ustaliliśmy związek między tagiem HTML <form method="GET/POST" ...> a sposobem, w jaki przeglądarka wysyła wartości formularza, wiemy już, jak pobrać je po stronie serwera. Odpowiedź znaleźliśmy w poprzednim rozdziale:
- jeśli metodą tagu <form> jest GET, wartości parametrów zostaną pobrane z kolekcji [Request.QueryString]
- jeśli metodą tagu <form> jest POST, wartości „wysłanych” parametrów zostaną pobrane z kolekcji [Request.Form]. Należy tu wprowadzić pewne wyjaśnienie. Tag <form> może określać za pomocą atrybutu [action] docelowy adres URL GET lub POST. Adres ten można z łatwością skonfigurować niezależnie od tego, czy mamy do czynienia z elementem GET, czy POST, w postaci action="url?param1=val1¶m2=val2&..". Parametry te są następnie dodawane do tych zawartych między tagami <form> i </form>, które zostaną przesłane na serwer za pomocą GET lub POST. Ponieważ stanowią one część docelowego adresu URL, zostaną one pobrane z kolekcji [Request.QueryString], niezależnie od tego, czy mamy do czynienia z GET, czy z POST.
Teraz tworzymy aplikację MVC z dwoma widokami:
- pierwszy widok to poprzedni formularz. Nazwiemy go [vue_formulaire].
- Drugi widok to strona informacyjna zawierająca listę wartości wprowadzonych na pierwszej stronie. Link umożliwia powrót do formularza. Nazwiemy ten widok [vue_confirmation].
Widok [vue_formulaire] jest wysyłany do użytkownika, który go wypełnia i zatwierdza. Tuż przed zatwierdzeniem może wyglądać następująco:

Użytkownik korzysta z przycisku [Envoyer], aby zatwierdzić wprowadzone dane. W odpowiedzi otrzymuje następujący widok [vue_validation]:

5.4.2. Kontroler aplikacji
W poprzednim rozdziale widzieliśmy, że rolę kontrolera aplikacji MVC możemy powierzyć plikowi [global.asax], przez który przechodzą wszystkie żądania klientów. Przedstawiliśmy już aplikację MVC zbudowaną w ten sposób i w tym miejscu kierujemy się modelem programowania przedstawionym wówczas. Plik [global.asax] będzie wyglądał następująco:
Składa się on z jednego wiersza odwołującego się do kontrolera umieszczonego w pliku [global.asax.vb]:
Imports System
Imports System.Web
Imports System.Web.SessionState
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
' pobieramy akcję do wykonania
Dim action As String
If Request.QueryString("action") Is Nothing Then
action = "init"
Else
action = Request.QueryString("action").ToString.ToLower
End If
' wykonujemy akcję
Select Case action
Case "init"
Server.Transfer("formulaire.aspx", False)
Case "validation"
Server.Transfer("validation.aspx", True)
Case Else
Server.Transfer("formulaire.aspx", True)
End Select
End Sub
End Class
Zasada działania kontrolera jest następująca:
- kontroler oczekuje w docelowym adresie URL ciągu parametrów zawierającego parametr [action]. Jeśli ten parametr nie występuje, traktuje się to tak, jakby w ciągu parametrów znajdował się parametr [action=init].
- Rozpoznawane są tylko dwie akcje:
- init: wysyłamy do klienta wstępnie wypełniony formularz
- validation: klient otrzymuje stronę potwierdzającą wprowadzone dane
- jeśli akcja nie jest jedną z powyższych, traktuje się to tak, jakby w łańcuchu parametrów znajdował się parametr [action=init]. Można również wyświetlić stronę błędu.
5.4.3. Obsługa akcji „init”
Gdy kontroler przetwarza akcję „init”, musi wygenerować wstępnie wypełniony formularz. Zadaniem strony [formulaire.aspx] jest wykonanie tej czynności. Jej kod wygląda następująco:
<HTML>
<HEAD>
<title>Formulaire</title>
<script language="javascript">
function effacer(){
alert("Vous avez cliqué sur le bouton [Effacer]");
}
function raz(liste){
liste.selectedIndex=-1
}
</script>
</HEAD>
<body>
<p>
Gestion d'un formulaire
</p>
<hr>
<form name="formulaire" method="post" action="?action=validation">
<table border="1">
<tr>
<td>
Etes-vous marié(e)</td>
<td>
<p align="center">
<input type="radio" value="oui" name="rdMarie">Oui <input type="radio" checked value="non" name="rdMarie">Non
</p>
</td>
</tr>
....
<td>
<select size="3" name="lstSimple">
<option value="1" selected>liste1</option>
<option value="2">liste2</option>
<option value="3">liste3</option>
<option value="4">liste4</option>
<option value="5">liste5</option>
</select>
<INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
</td>
....
<td>
<select multiple size="3" name="lstMultiple">
<option value="1" selected>multiple1</option>
<option value="2">multiple2</option>
<option value="3" selected>multiple3</option>
<option value="4">multiple4</option>
<option value="5">multiple5</option>
</select>
<INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
</td>
...
</table>
<input type="hidden" name="secret" value="uneValeur">
</form>
</body>
</HTML>
Ponownie spotykamy kod HTML z omówionego wcześniej formularza, z kilkoma niewielkimi różnicami. Kod tagu <form> został zmieniony:
<form name="formulaire" method="post" action="?action=validation">
- post: wartości wprowadzone przez użytkownika, a następnie wysłane na serwer po naciśnięciu przycisku typu [submit], będą przesyłane metodą HTTP POST
- akcja: składnia action="url" służy do określenia adresu URL, na który mają zostać wysłane wartości formularza. Adres ten może zawierać ciąg parametrów w postaci param1=val1¶m2=val2&... Tak właśnie postępujemy w tym przypadku, przekazując parametr [action=validation], aby wskazać kontrolerowi, jaką akcję ma wykonać. Należy zauważyć, że ten ciąg parametrów nie jest poprzedzony adresem internetowym. Przeglądarka wyśle zatem parametry formularza na adres, z którego pochodzi ten formularz. W naszym przykładzie przedstawionym powyżej adres ten to [http://localhost/mvcform1]. Przeglądarka wyśle zatem żądanie [POST /mvcform1?action=validation] do serwera [localhost].
Dodano przyciski, aby umożliwić użytkownikowi odznaczenie elementów z list [lstSimple] i [lstMultiple]:

Przekłada się to na następujący kod HTML:
<td>
<select size="3" name="lstSimple">
<option value="1" selected>liste1</option>
<option value="2">liste2</option>
<option value="3">liste3</option>
<option value="4">liste4</option>
<option value="5">liste5</option>
</select>
<INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
</td>
....
<td>
<select multiple size="3" name="lstMultiple">
<option value="1" selected>multiple1</option>
<option value="2">multiple2</option>
<option value="3" selected>multiple3</option>
<option value="4">multiple4</option>
<option value="5">multiple5</option>
</select>
<INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
</td>
Kliknięcie przycisku [Raz] powoduje odznaczenie wszystkich elementów listy, z którą jest powiązany. Weźmy na przykład listę [lstMultiple]. Kliknięcie odpowiedniego przycisku [Raz] powoduje wykonanie funkcji JavaScript [raz(lstMultiple)]. Należy pamiętać, że kod JavaScript dokumentu HTML wyświetlanego przez przeglądarkę jest wykonywany przez tę samą przeglądarkę, a nie przez serwer. JavaScript jest bardzo wszechstronnym językiem, który pozwala nadać stronom dynamiczny charakter bez udziału serwera. Funkcja [raz] wygląda następująco:
Funkcja ta przyjmuje parametr, którym jest obiekt JavaScript reprezentujący listę HTML. Obiekt ten posiada właściwości i metody. Jedną z jego właściwości jest [selectedIndex], której wartością jest numer pierwszej opcji wybranej z listy HTML. Jeśli nie ma żadnej opcji, wartość tej właściwości wynosi -1. Z drugiej strony, nadanie wartości tej właściwości powoduje wybranie nowego elementu z listy HTML, a nadanie jej wartości -1 oznacza, że żaden element nie jest zaznaczony. Właśnie to ma miejsce w tym przypadku.
Na koniec należy zauważyć, że kod prezentacji [formulaire.aspx] nie jest powiązany z kontrolerem [formulaire.aspx.vb]. W dokumencie HTML nie ma bowiem żadnej części dynamicznej generowanej przez serwer, więc nie ma potrzeby stosowania kontrolera.
5.4.4. Obsługa akcji „walidacja”
Gdy kontroler przetwarza akcję „walidacja”, musi wygenerować stronę zawierającą listę wartości wprowadzonych przez użytkownika. Zadaniem strony [validation.aspx] jest wykonanie tej czynności. Wizualnie strona wygląda następująco:

Jej kod HTML wygląda następująco:
<%@ Page src="validation.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="validation" %>
<HTML>
<HEAD>
<title>validation</title>
</HEAD>
<body>
<P>Valeurs saisies</P>
<HR width="100%" SIZE="1">
<TABLE id="Table1" cellSpacing="1" cellPadding="1" width="300" border="1">
<TR>
<TD width="84">rdMarie</TD>
<TD><% =rdMarie%></TD>
</TR>
<TR>
<TD width="84">C1</TD>
<TD><%=C1%></TD>
</TR>
<TR>
<TD width="84">C2</TD>
<TD><%=C2%></TD>
</TR>
<TR>
<TD width="84">C3</TD>
<TD><%=C3%></TD>
</TR>
<TR>
<TD width="84">txtSaisie</TD>
<TD><%=txtSaisie%></TD>
</TR>
<TR>
<TD width="84">txtMdp</TD>
<TD><%=txtMdp%></TD>
</TR>
<TR>
<TD width="84">areaSaisie</TD>
<TD><%=areaSaisie%></TD>
</TR>
<TR>
<TD width="84">cmbValeurs</TD>
<TD><%=cmbValeurs%></TD>
</TR>
<TR>
<TD width="84">lstSimple</TD>
<TD><%=lstSimple%></TD>
</TR>
<TR>
<TD width="84">lstMultiple</TD>
<TD><%=lstMultiple%></TD>
</TR>
<TR>
<TD width="84">secret</TD>
<TD><%=secret%></TD>
</TR>
</TABLE>
</body>
</HTML>
Dynamiczne fragmenty dokumentu <%=zmienna%> są obliczane przez powiązany kontroler [validation.aspx.vb]:
Imports System.Text.RegularExpressions
Public Class validation
Inherits System.Web.UI.Page
Protected rdMarie As String
Protected C1 As String
Protected C2 As String
Protected C3 As String
Protected txtSaisie As String
Protected txtMdp As String
Protected areaSaisie As String
Protected cmbValeurs As String
Protected lstSimple As String
Protected lstMultiple As String
Protected secret As String
Protected delimiteur As New Regex("\r\n")
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'pobieramy parametry przesłane metodą POST
rdMarie = getValue("rdMarie")
C1 = getValue("C1")
C2 = getValue("C2")
C3 = getValue("C3")
txtSaisie = getValue("txtSaisie")
txtMdp = getValue("txtMdp")
areaSaisie = String.Join(",", delimiteur.Split(getValue("areaSaisie")))
cmbValeurs = getValue("cmbValeurs")
lstSimple = getValue("lstSimple")
lstMultiple = getValue("lstMultiple")
secret = getValue("secret")
End Sub
Private Function getValue(ByVal champ As String) As String
' pobiera wartość pola [champ] z przesłanego żądania
' coś tam?
If Request.Form(champ) Is Nothing Then Return ""
' pobieramy wartość lub wartości pola
Dim valeurs() As String = Request.Form.GetValues(champ)
Dim valeur As String = ""
Dim i As Integer
For i = 0 To valeurs.Length - 1
valeur += "[" + valeurs(i) + "]"
Next
Return valeur
End Function
End Class
Obliczanie wartości do wyświetlenia odbywa się w procedurze [Form_Load]. Wartość „przesłanego” pola uzyskuje się za pomocą funkcji getValue(C), gdzie C to nazwa pola. Najważniejsze cechy tej funkcji są następujące:
- jeśli C nie występuje w przekazanym ciągu parametrów, wówczas jako wartość C zwracany jest pusty ciąg
- w przeciwnym razie pobiera się tablicę wartości pola C za pomocą funkcji [Request.Form.GetValues(C)]. Wartości te są łączone w ciąg znaków w postaci [val1][val2]...[valn], gdzie [vali] jest wartością nr i pola C
Pole [areaSaisie] jest przetwarzane w szczególny sposób. Jego wartość jest wysyłana przez przeglądarkę w postaci areaSaisie=wiersz1\r\nwiersz2\r\n... gdzie \r to znak o kodzie ASCII 13 (powrót karetki), a \n to znak o kodzie ASCII 10 (przejście do nowego wiersza). Funkcja getValue(areaSaisie) jest zatem ciągiem znaków „linia1\r\nlinia2\r\n...”. Ciąg ten jest dzielony na linie za pomocą metody [Regex.Split]. W ten sposób otrzymujemy tablicę ciągów znaków {linia1,linia2,...}. Tablica ta jest przekształcana w ciąg znaków „linia1,linia2,...” za pomocą metody [String.Join]. To właśnie ten ostatni ciąg znaków zostanie wyświetlony jako wartość pola [areaSaisie]. Celem tego przykładu było pokazanie, w jaki sposób można uzyskać poszczególne wiersze pola HTML typu [TextArea].
5.4.5. Testy
Umieszczamy wszystkie pliki (global.asax, global.asax.vb, formulaire.aspx, validation.aspx, validation.aspx.vb) w folderze <application-path>. Uruchamiamy serwer Cassini z parametrami (<application-path>,/mvcform1). W folderze <application-path> tworzymy pusty plik o nazwie [default.aspx], a następnie wywołujemy adres URL [http://localhost/mvcform1]. Ponieważ [/mvcform1] jest wirtualną ścieżką do folderu, a nie do dokumentu, serwer WWW wyświetli dokument [default.aspx], jeśli taki istnieje. Właśnie dlatego go utworzyliśmy. Przed wyświetleniem zostanie uruchomiony skrypt [global.asax], który ostatecznie spowoduje wyświetlenie strony [formulaire.aspx]. Dlatego plik [default.aspx] może być pusty.
Załóżmy, że zatwierdzony formularz wygląda następująco:

Kliknięcie przycisku [Envoyer] powoduje wyświetlenie następującej strony:

Zwróćmy najpierw uwagę na adres URL odpowiedzi: [http://localhost/mvcform1/?action=validation]. Jest to URL z atrybutu [action] w tagu <form> formularza [formulaire.aspx]:
<form name="formulaire" method="post" action="?action=validation">
Przyjrzyjmy się po kolei wartościom uzyskanym dla poszczególnych pól formularza:
pole | wartość | HTML | uwagi |
rdMarie | tak | <input type="radio" value="tak" name="rdMarie">Tak <input type="radio" checked value="nie" name="rdMarie">Nie | uzyskaną wartością jest atrybut [value] przycisku zaznaczonego |
C1 | jeden | <input type="checkbox" value="un" name="C1">1 | to samo |
C2 | dwa | <input type="checkbox" zaznaczone value="dwa" name="C2">2 | to samo |
C3 | <input type="checkbox" value="trzy" name="C3">3 | ten przycisk nie został zaznaczony przez użytkownika. Jego wartość nie została zatem przesłana przez przeglądarkę. W kodzie warunek [Request.Form("C3") is Nothing] był zatem spełniony. | |
txtSaisie | Programowanie asp.net | <input type="text" ... name="txtSaisie"> | uzyskaną wartością jest tekst znajdujący się w polu wprowadzania danych w momencie zatwierdzenia |
txtMdp | mdp | <input type="password" ...name="txtMdp"> | to samo |
areaSaisie | podstawy programowania stron internetowych | <textarea name="areaSaisie"> ...</textarea> | to samo |
cmbValeurs | 3 | <select name="cmbValeurs"> ... <option value="3">opcja3</option> </select> | uzyskaną wartością jest atrybut [value] wybranej opcji |
lstSimple | 3 | <select size="3" name="lstSimple"> .... <option value="3">lista3</option> ... </select> | to samo |
lstMultiple | 2 4 | <select multiple size="3" name="lstMultiple"> ... <option value="2">multiple2 </option> ... <option value="4">multiple4 </option> ... </select> | uzyskane wartości odpowiadają atrybutom [value] wybranych opcji |
secret | uneValeur | <input type="hidden" name="secret" value="uneValeur"> | uzyskana wartość to atrybut [value] pola ukrytego |
Zajmijmy się teraz listami. Załóżmy, że w momencie walidacji stan formularza jest następujący:

- opcja [choix1] jest zaznaczona w comboBox
- w pozostałych dwóch listach nie jest zaznaczona żadna opcja. Aby to osiągnąć, użyto przycisków [Raz].
Oto strona wyświetlona po zatwierdzeniu:

Gdy w liście nie wybrano żadnej wartości, przeglądarka nie wysyła parametru dla tej listy. W kodzie [validation.aspx.vb] wyrażenia [Request.Form("lstSimple")] i [Request.Form("lstMultiple")] są zatem równe stałej [Nothing], stąd wynik wyświetlony powyżej.
5.5. Zachowanie stanu strony
5.5.1. Zachowanie stanu strony za pomocą sesji
Kopiujemy całą poprzednią aplikację do nowego folderu. Na stronie [validation.aspx] dodajemy link umożliwiający użytkownikowi powrót do formularza:

Zmianą, jaką należy wprowadzić na stronie [validation.aspx], jest dodanie linku:
.....
<TR>
<TD width="84">secret</TD>
<TD><%=secret%></TD>
</TR>
</TABLE>
<P>
<a href="?action=formulaire">Retour au formulaire</a>
</P>
</body>
</HTML>
Atrybut [href] linku ma wartość adresu URL z jednym parametrem: [action=formulaire], co pozwala serwerowi rozpoznać, że ma wyświetlić formularz w stanie, w jakim znajdował się w momencie zatwierdzenia. Istnieje zatem różnica w stosunku do akcji [init], która wyświetla formularz predefiniowany. Adres URL z parametrem [?action=formulaire] w rzeczywistości nie ma adresu URL. Będzie on zatem taki sam jak ten, który umożliwił wyświetlenie strony walidacji. Jeśli przypomnimy sobie poprzednią analizę, jest to adres URL katalogu aplikacji. Żądanie przejdzie zatem przez kontroler. Kontroler musi teraz przetworzyć akcję [formulaire]. Kod akcji [global.asax.vb] zostaje zmodyfikowany w następujący sposób:
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
' pobieramy czynność do wykonania
Dim action As String
If Request.QueryString("action") Is Nothing Then
action = "init"
Else
action = Request.QueryString("action").ToString.ToLower
End If
' wykonuje się działanie
Select Case action
Case "init"
Server.Transfer("formulaire.aspx", False)
Case "validation"
Server.Transfer("validation.aspx", True)
Case "formulaire"
Server.Transfer("formulaire.aspx", True)
Case Else
Server.Transfer("formulaire.aspx", True)
End Select
End Sub
W przypadku, gdy akcją jest „formularz”, wystarczy przekazać żądanie do strony [formulaire.aspx]. Wiemy, że strona ta wyświetla predefiniowany formularz, w którym nie ma żadnych zmiennych elementów. Strona ta nie może zatem wyświetlić formularza z wartościami, jakie posiadał w momencie zatwierdzenia. Chcemy tutaj podkreślić tę kwestię. Jeśli wszystkie pliki aplikacji zostały umieszczone w <application-path>, uruchamiamy Cassini z parametrami (<application-path>,/mvcform2), a następnie wywołujemy adres URL [http://localhost/mvcform2]. Otrzymujemy następującą stronę (fragment):

Wypełniamy formularz w następujący sposób, a następnie go zatwierdzamy:

Otrzymujemy następującą stronę potwierdzenia:

Korzystamy z linku [Retour au formulaire], który znajduje się (ale nie jest widoczny) na powyższej stronie. Otrzymujemy następującą odpowiedź z serwera:

Stwierdzamy, że:
- żądany adres URL zawiera parametr action=formularz, zgodnie z oczekiwaniami
- wyświetlony formularz utracił wprowadzone wartości.
Wiemy, dlaczego nie odzyskujemy wprowadzonych wartości. Jeśli przyjrzymy się kodowi dokumentu [formulaire.aspx], zauważymy, że wszystko jest statyczne i w związku z tym za każdym razem wyświetlana jest ta sama strona. Wyraźnie widać, że musimy uczynić ten kod dynamicznym. Musi on wyświetlać wartości zatwierdzone przez użytkownika. Ale gdzie je zapisać?
Przypomnijmy żelazną zasadę protokołu bezstanowego HTTP:
- adres URL [http://localhost/mvcform2] jest wywoływany – otrzymana zostaje odpowiedź. Połączenie TCP-IP zostało otwarte między klientem a serwerem na początku żądania i zamknięte po zakończeniu odpowiedzi.
- Użytkownik wprowadza, a następnie zatwierdza dane. Wysyłane jest żądanie adresu URL [http://localhost/mvcform2/?action=validation] – otrzymana zostaje odpowiedź. Między obydwoma partnerami otwarto, a następnie zamknięto nowe połączenie o numerze TCP-IP.
- Użytkownik korzysta z linku [Retour au formulaire]. Wysyłane jest żądanie do adresu URL [http://localhost/mvcform2/?action=formulaire] – otrzymana zostaje odpowiedź. Pomiędzy obydwoma partnerami ponownie otwarto, a następnie zamknięto nowe połączenie o numerze TCP-IP.
Cykle żądania-odpowiedzi są od siebie niezależne, ponieważ każdy z nich wykorzystuje nowe połączenie o numerze TCP-IP. Gdy aplikacja klient-serwer wykorzystuje jedno połączenie TCP-IP do serii wymian danych, serwer może zidentyfikować klienta na podstawie jego połączenia. Może zatem zapamiętać informacje, które powiąże z konkretnym połączeniem, i w ten sposób śledzić przebieg wymiany danych. Gdy wymiana danych odbywa się za pośrednictwem różnych połączeń, serwer nie jest w stanie zidentyfikować klienta na podstawie połączenia. Potrzebne jest inne rozwiązanie. Jedno z nich przedstawiliśmy w poprzednim rozdziale: mechanizm sesji. Pozwala on cyklom żądania-odpowiedzi na zapisywanie informacji w obiekcie [Session], dostępnym dla wszystkich kolejnych cykli.
Teraz, gdy mamy aplikację MVC z sesją, nie możemy już używać pliku [global.asax] jako kontrolera, tak jak pokazano w poprzednim rozdziale. Rolę kontrolera aplikacji musi pełnić specjalna strona przeznaczona do tego celu. W tym przypadku będzie to strona [main.aspx]. Postąpimy w następujący sposób:
- gdy użytkownik zatwierdzi swoje dane (akcja=walidacja), kontroler [main.aspx.vb] zapisze je w bieżącej sesji, a następnie wyświetli stronę walidacji.
- gdy konieczne będzie wyświetlenie formularza z wprowadzonymi wartościami (action=formularz), kontroler [main.aspx.vb] pobierze je z sesji i umieści w kontekście przed wyświetleniem formularza.
5.5.2. Nowy kontroler aplikacji
Kontroler aplikacji składa się z dwóch plików [main.aspx, main.aspx.vb]:
[main.aspx]
[main.aspx.vb]
Imports System.Collections.Specialized
Imports Microsoft.VisualBasic
Public Class main
Inherits System.Web.UI.Page
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' pobieramy czynność do wykonania
Dim action As String
If Request.QueryString("action") Is Nothing Then
action = "init"
Else
action = Request.QueryString("action").ToString.ToLower
End If
' wykonuje się działanie
Select Case action
Case "init"
' wyświetla się wstępnie wypełniony formularz
Context.Items("formulaire") = initForm()
Server.Transfer("formulaire.aspx", True)
Case "validation"
' wyświetla stronę potwierdzenia po zapisaniu wartości przesłanych w sesji
Session.Item("formulaire") = Request.Form
Server.Transfer("validation.aspx", True)
Case "formulaire"
' wyświetla się formularz z wartościami pobranymi z sesji
Context.Items("formulaire") = Session.Item("formulaire")
Server.Transfer("formulaire.aspx", True)
Case Else
' wyświetla się wstępnie wypełniony formularz
Context.Items("formulaire") = initForm()
Server.Transfer("formulaire.aspx", True)
End Select
End Sub
Private Function initForm() As NameValueCollection
' formularz jest inicjowany
Dim form As New NameValueCollection
form.Set("rdMarie", "non")
form.Set("C2", "deux")
form.Set("txtSaisie", "qqs mots")
form.Set("txtMdp", "ceciestsecret")
form.Set("areasaisie", "ligne1" + ControlChars.CrLf + "ligne2" + ControlChars.CrLf)
form.Set("cmbValeurs", "2")
form.Set("lstSimple", "1")
form.Set("lstMultiple", "1")
form.Add("lstMultiple", "3")
Return form
End Function
End Class
Znajdujemy tu istotę struktury kontrolera aplikacji omówionego wcześniej, z następującymi różnicami:
- praca kontrolera odbywa się w procedurze [Form_Load]
- w przypadku akcji [validation] wartości formularza obecne w [Request.Form] są zapisywane w sesji powiązanej z kluczem „formularz”. Następnie wykonanie jest przekazywane do strony [validation.aspx], która wyświetli te wartości.
- W przypadku pozostałych akcji wykonanie jest zawsze przekazywane do strony [formulaire.aspx]. Strona ta oczekuje w swoim kontekście klucza „formularz”, który będzie powiązany z obiektem typu [Request.form], c.a.d lub typu [NameValueCollection]. Obiekt ten musi zawierać zbiór wartości pól formularza.
- W przypadku, gdy akcją jest [init] lub akcja nierozpoznana, zbiór wartości jest tworzony arbitralnie przez funkcję [initForm].
- W przypadku, gdy akcją jest [formulaire], zbiorem tym jest zbiór [Request.Form], który został umieszczony w sesji przez akcję [validation]
5.5.3. Nowy formularz
Ponieważ aplikacja nie wyświetla już tej samej treści w formularzu, musi on być generowany dynamicznie. Nowa strona [formulaire.aspx] wygląda następująco:
<%@ Page src="formulaire.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire" %>
<HTML>
<HEAD>
<title>Formulaire</title>
<script language="javascript">
function effacer(){
alert("Vous avez cliqué sur le bouton [Effacer]");
}
function raz(liste){
liste.selectedIndex=-1
}
</script>
</HEAD>
<body>
<p>
Gestion d'un formulaire
</p>
<hr>
<form name="formulaire" method="post" action="main.aspx?action=validation">
<table border="1">
<tr>
<td>
Etes-vous marié(e)</td>
<td>
<p align="center">
<INPUT type="radio" value="oui" name="rdMarie" <%=rdouichecked%>>Oui
<INPUT type="radio" value="non" name="rdMarie" <%=rdnonchecked%>>Non
</p>
</td>
</tr>
<TR>
<TD>Cases à cocher
</TD>
<TD>
<P align="center">
<INPUT type="checkbox" value="un" name="C1" <%=c1checked%>>1
<INPUT type="checkbox" value="deux" name="C2" <%=c2checked%>>2
<INPUT type="checkbox" value="trois" name="C3" <%=c3checked%>>3
</P>
</TD>
</TR>
<TR>
<TD>Champ de saisie</TD>
<TD>
<P align="center">
<INPUT type="text" maxLength="30" value="<%=txtSaisie%>" name="txtSaisie">
</P>
</TD>
</TR>
<tr>
<td>
Mot de passe</td>
<td>
<p align="center">
<input type="password" maxlength="12" size="12" value="<%=txtMdp%>" name="txtMdp">
</p>
</td>
</tr>
<tr>
<td>
Boîte de saisie</td>
<td>
<textarea name="areaSaisie"><%=areaSaisie%></textarea>
</td>
</tr>
<tr>
<td>
ComboBox</td>
<td>
<select name="cmbValeurs">
<%=cmbValeursOptions%>
</select>
</td>
</tr>
<tr>
<td>
Liste à choix simple</td>
<td>
<select size="3" name="lstSimple">
<%=lstSimpleOptions%>
</select>
<INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
</td>
</tr>
<tr>
<td>
Liste à choix multiple</td>
<td>
<select multiple size="3" name="lstMultiple">
<%=lstMultipleOptions%>
</select>
<INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
</td>
</tr>
<tr>
<td>
Bouton simple</td>
<td>
<p align="center">
<input onclick="effacer()" type="button" value="Effacer" name="btnEffacer">
</p>
</td>
</tr>
<tr>
<td>
Bouton submit</td>
<td>
<p align="center">
<input type="submit" value="Envoyer" name="btnEnvoyer">
</p>
</td>
</tr>
<tr>
<td>
Bouton reset</td>
<td>
<p align="center">
<input type="reset" value="Rétablir" name="btnRetablir" runat="server">
</p>
</td>
</tr>
</table>
<input type="hidden" name="secret" value="uneValeur">
</form>
</body>
</HTML>
Omówmy zmienne dynamiczne występujące w kodzie HTML:
zmienna | rola |
będzie miała wartość „checked”, jeśli przycisk opcji [oui] ma być zaznaczony, w przeciwnym razie wartość „” | |
to samo dotyczy przycisku opcji [non] | |
to samo dotyczy pola wyboru [C1] | |
to samo dotyczy pola wyboru [C2] | |
to samo dotyczy pola wyboru [C3] | |
tekst, który ma zostać umieszczony w polu [txtSaisie] | |
tekst, który ma zostać umieszczony w polu [txtMdp] | |
tekst do umieszczenia w polu [areaSaisie] | |
tekst HTML z opcji listy rozwijanej [cmbValeurs] | |
tekst HTML z opcji listy rozwijanej [lstSimple] | |
tekst HTML z opcji listy rozwijanej [lstMultiple] | |
Wartości tych zmiennych są obliczane przez kontroler strony [formulaire.aspx.vb]:
Imports Microsoft.VisualBasic
Imports System.Collections.Specialized
Public Class formulaire
Inherits System.Web.UI.Page
' stałe pola formularza
Private libellésCmbValeurs() As String = {"choix1", "choix2", "choix3"}
Private valeursCmbValeurs() As String = {"1", "2", "3"}
Private libellésLstSimple() As String = {"liste1", "liste2", "liste3"}
Private valeursLstSimple() As String = {"1", "2", "3"}
Private libellésLstMultiple() As String = {"multiple1", "multiple2", "multiple3", "multiple4", "multiple5"}
Private valeursLstMultiple() As String = {"1", "2", "3", "4", "5"}
' dynamiczne pola formularza
Protected rdouichecked As String
Protected rdnonchecked As String
Protected c1checked As String
Protected c2checked As String
Protected c3checked As String
Protected txtSaisie As String
Protected txtMdp As String
Protected areaSaisie As String
Protected cmbValeursOptions As String
Protected lstSimpleOptions As String
Protected lstMultipleOptions As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' pobieramy poprzednie zapytanie z sesji
Dim form As NameValueCollection
If Not Context.Items("formulaire") Is Nothing Then
form = Context.Items("formulaire")
Else
form = New NameValueCollection
End If
' przygotowuje się stronę do wyświetlenia
' przyciski opcji
rdouichecked = ""
rdnonchecked = "checked"
If isEqual(form("rdMarie"), "oui") Then
rdouichecked = "checked"
rdnonchecked = ""
End If
' pola wyboru
c1checked = ""
If isEqual(form("C1"), "un") Then c1checked = "checked"
c2checked = ""
If isEqual(form("C2"), "deux") Then c2checked = "checked"
c3checked = ""
If isEqual(form("C3"), "trois") Then c3checked = "checked"
' pola wprowadzania danych
txtSaisie = ""
If Not form("txtSaisie") Is Nothing Then txtSaisie = form("txtSaisie").ToString
txtMdp = ""
If Not form("txtMdp") Is Nothing Then txtMdp = form("txtMdp").ToString
areaSaisie = ""
If Not form("areaSaisie") Is Nothing Then areaSaisie = form("areaSaisie").ToString
' listy
Dim sélections() As String = {}
If Not form("cmbValeurs") Is Nothing Then sélections = form.GetValues("cmbValeurs")
cmbValeursOptions = getOptions(valeursCmbValeurs, libellésCmbValeurs, sélections)
sélections = New String() {}
If Not form("lstSimple") Is Nothing Then sélections = form.GetValues("lstSimple")
lstSimpleOptions = getOptions(valeursLstSimple, libellésLstSimple, sélections)
sélections = New String() {}
If Not form("lstMultiple") Is Nothing Then sélections = form.GetValues("lstMultiple")
lstMultipleOptions = getOptions(valeursLstMultiple, libellésLstMultiple, sélections)
End Sub
Private Function getOptions(ByRef valeurs() As String, ByRef libelles() As String, ByRef sélections() As String) As String
' zwraca kod HTML opcji tagu <select>
' wartości: tabela wartości opcji tagu
' nazwy: tabela nazw opcji tagu
' wybory: opcje do wyboru
Dim iValeur As Integer
Dim iSelection As Integer
Dim selected As String
Dim toString As String = ""
' przeglądamy listę wartości opcji
For iValeur = 0 To valeurs.Length - 1
' sprawdza się, czy bieżąca wartość ma zostać zaznaczona
selected = "" : iSelection = 0
Do While iSelection < sélections.Length And selected = ""
If valeurs(iValeur) = sélections(iSelection) Then selected = "selected"
iSelection += 1
Loop
' wstawia się kod HTML opcji
toString += "<option " + selected + " value='" + valeurs(iValeur) + "'> " _
+ libelles(iValeur) + "</option>" + ControlChars.CrLf
Next
' zwracamy wynik
Return toString
End Function
Private Function isEqual(Byval champ As Object, ByVal valeur As String) As Boolean
' zwraca wartość „prawda”, jeśli pole jest równe wartości
If champ Is Nothing OrElse champ.ToString <> valeur Then
Return false
Else
Return true
End If
end function
End Class
Gdy strona [formulaire.aspx] rozpocznie działanie, znajdzie w swoim kontekście klucz „formularz” powiązany z zbiorem wartości pól, które ma wyświetlić.
' pobieramy poprzednie zapytanie z sesji
Dim form As NameValueCollection
If Not Context.Items("formulaire") Is Nothing Then
form = Context.Items("formulaire")
Else
form = New NameValueCollection
End If
Można się zastanawiać, dlaczego sprawdzane jest, czy obiekt [Context.Items("formulaire")] istnieje. W rzeczywistości kontroler przypisuje wartość do tego obiektu w każdym przypadku. Nic jednak nie stoi na przeszkodzie, aby klient zażądał bezpośrednio strony [formulaire.aspx], omijając kontroler. W takim przypadku powyższy kod będzie działał z pustą kolekcją wartości, ale nie dojdzie do „zawieszenia”.
Kod przegląda otrzymaną kolekcję wartości w celu obliczenia wszystkich zmiennych dynamicznych strony HTML, która jest z nią powiązana. Chociaż kod ten jest długi, nie jest szczególnie skomplikowany i pozostawiamy czytelnikowi możliwość samodzielnego zapoznania się z nim, aby nie przedłużać niniejszego wyjaśnienia. Skupimy się jednak na sposobie generowania kodu HTML z trzech list typu [select]. Kod ten jest generowany przez następującą funkcję:
Private Function getOptions(ByRef valeurs() As String, ByRef libelles() As String, ByRef sélections() As String) As String
' zwraca kod HTML z opcji tagu <select>
' wartości: tablica wartości opcji tagu
' nazwy: tablica nazw opcji tagu
' wybory: opcje do wyboru
Dim iValeur As Integer
Dim iSelection As Integer
Dim selected As String
Dim toString As String = ""
' przeglądamy listę wartości opcji
For iValeur = 0 To valeurs.Length - 1
' sprawdza się, czy bieżąca wartość ma zostać zaznaczona
selected = "" : iSelection = 0
Do While iSelection < sélections.Length And selected = ""
If valeurs(iValeur) = sélections(iSelection) Then selected = "selected"
iSelection += 1
Loop
' wstawia się kod HTML opcji
toString += "<option " + selected + " value='" + valeurs(iValeur) + "'> " _
+ libelles(iValeur) + "</option>" + ControlChars.CrLf
Next
' zwracamy wynik
Return toString
End Function
Przypomnijmy, że opcje tagu <select> odpowiadają następującemu kodowi HTML:
Dla każdej opcji należy zatem wygenerować trzy informacje:
- wartość opcji w atrybucie [value]
- tekst opcji pomiędzy tagami <option> i </option>
- słowo kluczowe [selected], jeśli opcja ma zostać zaznaczona na liście
Aby wygenerować te trzy informacje dla każdej z opcji, funkcja [getOptions] otrzymuje trzy wartości:
- tabela wartości opcji w [valeurs]
- tablicę tekstów opcji w [libelles]
- tabela wartości do wyboru w [sélections]
5.5.4. Strona zatwierdzania
Strona walidacji pozostaje bez zmian:
[validation.aspx]
<%@ Page src="validation.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="validation" %>
<HTML>
<HEAD>
<title>validation</title>
</HEAD>
<body>
<P>Valeurs saisies</P>
<HR width="100%" SIZE="1">
<TABLE id="Table1" cellSpacing="1" cellPadding="1" width="300" border="1">
<TR>
<TD width="84">rdMarie</TD>
<TD><% =rdMarie%></TD>
</TR>
<TR>
<TD width="84">C1</TD>
<TD><%=C1%></TD>
</TR>
<TR>
<TD width="84">C2</TD>
<TD><%=C2%></TD>
</TR>
<TR>
<TD width="84">C3</TD>
<TD><%=C3%></TD>
</TR>
<TR>
<TD width="84">txtSaisie</TD>
<TD><%=txtSaisie%></TD>
</TR>
<TR>
<TD width="84">txtMdp</TD>
<TD><%=txtMdp%></TD>
</TR>
<TR>
<TD width="84">areaSaisie</TD>
<TD><%=areaSaisie%></TD>
</TR>
<TR>
<TD width="84">cmbValeurs</TD>
<TD><%=cmbValeurs%></TD>
</TR>
<TR>
<TD width="84">lstSimple</TD>
<TD><%=lstSimple%></TD>
</TR>
<TR>
<TD width="84">lstMultiple</TD>
<TD><%=lstMultiple%></TD>
</TR>
<TR>
<TD width="84">secret</TD>
<TD><%=secret%></TD>
</TR>
</TABLE>
<P>
<a href="main.aspx?action=formulaire">Retour au formulaire</a>
</P>
</body>
</HTML>
[validation.aspx.vb]
Imports Microsoft.VisualBasic
Imports System.Text.RegularExpressions
Public Class validation
Inherits System.Web.UI.Page
Protected rdMarie As String
Protected C1 As String
Protected C2 As String
Protected C3 As String
Protected txtSaisie As String
Protected txtMdp As String
Protected areaSaisie As String
Protected cmbValeurs As String
Protected lstSimple As String
Protected lstMultiple As String
Protected secret As String
Protected delimiteur As New Regex("\r\n")
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'pobieramy przesłane parametry
rdMarie = getValue("rdMarie")
C1 = getValue("C1")
C2 = getValue("C2")
C3 = getValue("C3")
txtSaisie = getValue("txtSaisie")
txtMdp = getValue("txtMdp")
areaSaisie = String.Join(",", delimiteur.Split(getValue("areaSaisie")))
cmbValeurs = getValue("cmbValeurs")
lstSimple = getValue("lstSimple")
lstMultiple = getValue("lstMultiple")
secret = getValue("secret")
' zapisujemy je w sesji
'Session("formularz") = Request.Form
End Sub
Private Function getValue(ByVal champ As String) As String
' pobieramy wartość pola [champ] z przesłanego żądania
' coś tam?
If Request.Form(champ) Is Nothing Then Return ""
' pobiera wartość lub wartości z pola
Dim valeurs() As String = Request.Form.GetValues(champ)
Dim valeur As String = ""
Dim i As Integer
For i = 0 To valeurs.Length - 1
valeur += "[" + valeurs(i) + "]"
Next
Return valeur
End Function
End Class
5.5.5. Testy
Pliki [main.aspx, main.aspx.vb,formulaire.aspx,formulaire.aspx.vb, validation.aspx, validation.aspx.vb] umieszczamy w katalogu <application-path>, a Casini uruchamiamy z parametrami (<application-path>,/mvcform3). Następnie wywołujemy adres URL [http://localhost/mvcform3/main.aspx]. Otrzymujemy wstępnie zainicjowany formularz:

Wypełniamy formularz w następujący sposób:

Korzystamy z przycisku [Envoyer] znajdującego się powyżej. Otrzymujemy następującą odpowiedź z serwera:

Korzystamy z powyższego linku [Retour au formulaire], aby powrócić do formularza. Otrzymujemy następującą nową odpowiedź:

Formularz wyświetla się dokładnie tak, jak go zatwierdziliśmy.
5.5.6. Wniosek
Poprzedni przykład pokazał nam, że możliwe jest zachowanie stanu strony w trakcie cykli żądania-odpowiedzi między klientem a serwerem. Nie jest to jednak zadanie proste. W kolejnym rozdziale zobaczymy, że za pomocą ASP.NET można pozwolić serwerowi samodzielnie przywrócić stan strony.



