Documente Academic
Documente Profesional
Documente Cultură
<appSettings> <!-- Setările personalizate ale aplicației merg aici. --> </appSettings> <system.web> <!-- ASP.NET
Secțiunile de configurare merg aici. --> </system.web> </configuration>
Notă: acest exemplu adaugă un comentariu în locul în care ați găsi în mod normal setări suplimentare. Comentariile XML sunt puse între paranteze cu secvențele de caractere <!-- și -->. De asemenea, puteți utiliza comentarii XML pentru a dezactiva temporar o setare dintr-un fișier de configurare.
Setările particularizate pe care le adăugați sunt scrise ca variabile șir simple. Este posibil să doriți să
utilizați o setare specială web.config din mai multe motive:
Pentru a centraliza o setare importantă care trebuie utilizată în mai multe pagini diferite: De exemplu,
puteți crea o variabilă care stochează o interogare a bazei de date. Orice pagină care trebuie să
utilizeze această interogare poate apoi să regăsească această valoare și să o utilizeze.
Pentru a facilita comutarea rapidă între diferite moduri de funcționare: De exemplu, puteți crea o
variabilă specială de depanare. Paginile dvs. web ar putea verifica această variabilă și, dacă este
setată la o valoare specificată, să emită informații suplimentare pentru a vă ajuta să testați aplicația.
Pentru a seta unele valori inițiale: În funcție de operație, utilizatorul poate modifica aceste valori,
dar fișierul web.config ar putea furniza valorile implicite.
Puteți introduce setări personalizate utilizând un element <add> care identifică un nume unic al variabilei
(cheie) și conținutul variabilei (valoare). Următorul exemplu adaugă o variabilă care definește o cale de fișier
în care sunt stocate informații importante:
<Setări aplicație>
<add key="DataFilePath" value="e:\NetworkShare\Documents\WebApp\Shared" />
Setări </app>
Puteți adăuga câte setări de aplicație doriți, deși acest exemplu definește doar una. Puteți crea o pagină de test simplă pentru a
interoga aceste informații și pentru a afișa rezultatele, așa cum se arată în exemplul următor (care este furnizat cu exemplul de
cod ca ShowSettings.aspx și ShowSettings.aspx.cs). Regăsiți setările de aplicație particularizate de la web.config după numele
cheii, utilizând clasa WebConfigurationManager, care se găsește în spațiul de nume System.Web.Configuration. Această clasă
166
CAPITOLUL FUNDAMENTELE FORMULARELOR WEB
5 •
Sfat: Observați că acest cod formatează textul inserând etichete HTML în etichetă alături de conținutul textului, inclusiv etichete aldine (<b>) pentru a sublinia anumite cuvinte și un sfârșit de linie (<br />) pentru a împărți ieșirea pe mai multe linii. Aceasta este o tehnică comună.
Mai târziu, în capitolul 17, veți învăța cum să obțineți informații despre fișiere și directoare și să citiți și să
scrieți fișiere. Pentru moment, aplicația simplă afișează doar setarea web.config personalizată, așa cum se
arată în Figura 5-12.
167
CAPITOLUL FUNDAMENTELE FORMULARELOR WEB
5 •
ASP.NET este configurat, în mod implicit, să refuze orice solicitări pentru fișiere .config. Aceasta înseamnă că
utilizatorii de la distanță nu vor putea accesa fișierul. În schimb, vor primi mesajul de eroare afișat în Figura 5-13.
Descărcați de la Wow! eBook <www.wowebook.com>
168
CAPITOLUL FUNDAMENTELE FORMULARELOR WEB
5 •
Puteți utiliza WAT pentru a automatiza modificările web.config pe care le-ați făcut în exemplul anterior.
Pentru a încerca acest lucru, faceți clic pe fila Aplicație. Utilizând această filă, puteți crea o setare nouă
(faceți clic pe legătura Creare setări aplicație). Dacă faceți clic pe Gestionare setări aplicație, veți vedea o
listă cu toate setările aplicațiilor definite în aplicație (Figura 5-15). Apoi puteți alege să eliminați sau să
editați oricare dintre ele.
169
CAPITOLUL FUNDAMENTELE FORMULARELOR WEB
5 •
Aceasta este ideea esențială din spatele WAT. Efectuați modificările utilizând o interfață grafică (o pagină
web), iar WAT generează setările de care aveți nevoie și le adaugă la fișierul web.config pentru aplicația dvs.
din culise. Desigur, WAT are o serie de setări pentru configurarea setărilor ASP.NET mai complexe și le veți
folosi pe tot parcursul acestei cărți.
Notă WAT funcționează numai în timp ce dezvoltați o aplicație web. Cu alte cuvinte, nu puteți implementa un site web pe un server web live și apoi să încercați să utilizați WAT. Cu toate acestea, dacă trebuie să reconfigurați o aplicație deja implementată, puteți utiliza instrumentul grafic IIS Manager, care oferă unele dintre aceleași caracteristici ca WAT (și multe altele suplimentare). Veți afla mai multe despre configurația IIS în capitolul 26.
Ultimul cuvânt
Acest capitol v-a prezentat prima privire asupra aplicațiilor web, paginilor web și configurației. Acum ar trebui să
înțelegeți cum să creați o pagină web ASP.NET și să utilizați controale de server HTML. Controalele HTML sunt
un compromis între controalele web ASP.NET și HTML tradițional. Acestea folosesc elementele HTML familiare,
dar oferă o interfață limitată orientată pe obiecte. În esență, controalele HTML sunt concepute pentru a fi simple,
170
CAPITOLUL FUNDAMENTELE FORMULARELOR WEB
5 •
previzibile și compatibile automat cu programele existente. Cu controale HTML, pagina HTML finală care este
trimisă clientului seamănă foarte mult cu pagina .aspx originală.
În capitolul următor, veți afla despre controalele web, care oferă o interfață obiect mai sofisticată care
abstractizează HTML-ul de bază. Dacă începeți un proiect nou sau trebuie să adăugați unele dintre cele mai
puternice controale ASP.NET, controalele web sunt cea mai bună opțiune.
171
CAPITOLUL6
•■■
Controale web
Capitolul anterior a introdus modelul de programare bazat pe evenimente și control al ASP.NET. Acest model vă
permite să creați programe pentru Web utilizând aceleași tehnici orientate pe obiecte pe care le-ați utiliza pentru a
scrie o aplicație Windows.
Cu toate acestea, controalele serverului HTML arată într-adevăr doar o privire asupra a ceea ce este posibil cu
modelul de control al serverului ASP.NET. Pentru a vedea unele dintre avantajele reale, trebuie să vă scufundați în
controalele web mai bogate și mai extensibile. În acest capitol, veți explora controalele web de bază și ierarhia lor
de clasă. De asemenea, veți aprofunda gestionarea evenimentelor ASP.NET, veți afla detaliile ciclului de viață al
paginii web și vă veți pune cunoștințele la lucru prin crearea unei pagini web care permite utilizatorului să proiecteze
o felicitare.
Ele oferă un model de obiect consistent: HTML este plin de ciudățenii și idiosincrazii. De exemplu, o casetă
text simplă poate apărea ca unul dintre cele trei elemente, inclusiv <textarea>, <input type="text"> și <input
type="password">. Cu controalele web, aceste trei elemente sunt consolidate ca un singur control TextBox. În
funcție de proprietățile pe care le setați, elementul HTML subiacent redat de ASP.NET poate diferi. În mod
similar, numele proprietăților nu urmează numele atributelor HTML. De exemplu, controalele care afișează
text, indiferent dacă este o legendă sau o casetă text care poate fi editată de utilizator, expun o proprietate
Text.
Acestea își adaptează automat rezultatele: ASP.NET controale de server pot detecta tipul de browser și pot ajusta
automat codul HTML pe care îl scriu pentru a profita de caracteristici precum suportul pentru JavaScript. Nu trebuie să
știți despre client, deoarece ASP.NET gestionează acel strat și utilizează automat cel mai bun set posibil de entități.
Această caracteristică este cunoscută sub numele de redare adaptivă. Acestea oferă funcții de nivel înalt: veți vedea că
173
CAPITOLUL CONTROALE WEB
6 •
controalele web vă permit să accesați evenimente, proprietăți și metode suplimentare care nu corespund direct
controalelor HTML tipice. ASP.NET implementează aceste caracteristici utilizând o combinație de trucuri.
De-a lungul acestei cărți, veți vedea exemple care utilizează setul complet de controale web. Pentru a
stăpâni dezvoltarea ASP.NET, trebuie să vă simțiți confortabil cu aceste ingrediente ale interfeței cu
utilizatorul și să le înțelegeți abilitățile. Controalele serverului HTML, pe de altă parte, sunt mai puțin
importante pentru dezvoltarea formularelor web. Le veți utiliza numai dacă migrați o pagină HTML existentă
în lumea ASP.NET sau dacă trebuie să aveți un control fin asupra codului HTML care va fi generat și trimis
clientului.
Tabelul 6-1 listează clasele de control de bază și elementele HTML pe care le generează. Unele controale
(cum ar fi Buton și Casetă text) pot fi redate ca elemente HTML diferite. În acest caz, ASP.NET utilizează
elementul care corespunde proprietăților pe care le-ați setat. De asemenea, unele controale nu au
echivalent HTML real. De exemplu, atunci când controalele CheckBoxList și RadioButtonList se redau
singure, acestea pot afișa un <tabel> care conține mai multe casete de selectare HTML sau butoane radio.
ASP.NET le expune ca un singur obiect pe partea serverului pentru programare convenabilă, ilustrând astfel
unul dintre punctele forte principale ale controalelor web.
Tabelul 6-1. Controale web de bază
Etichetă <span>
Hyperlink <a>
Imagine <IMG>
Casetă listă <select size="X"> unde X este numărul de rânduri care sunt vizibile simultan
174
CAPITOLUL CONTROALE WEB
6 •
Lista casetelor de selectare O listă sau <tabel> cu mai multe etichete <input type="checkbox">
Lista cu marcatori O listă ordonată <ol> (numerotată) sau <ul> listă neordonată (cu marcatori)
Panou <div>
Acest tabel omite unele dintre controalele mai specializate utilizate pentru date, navigare, securitate și
portaluri web. Veți vedea aceste controale pe măsură ce aflați despre caracteristicile lor pe parcursul
acestei cărți.
HTML-ul rezultat utilizează elementul <textarea> și setează toate atributele necesare (cum ar fi rândurile și
numai în citire) și atributul de stil (cu culoarea de fundal). De asemenea, setează atributul cols cu lățimea
implicită de 20 de coloane, chiar dacă nu ați setat explicit proprietatea TextBox.Columns:
175
CAPITOLUL CONTROALE WEB
6 •
În mod clar, este ușor să creați o etichetă de control web. Nu necesită nicio înțelegere a HTML. Cu toate
acestea, va trebui să înțelegeți clasa de control și proprietățile care vă sunt disponibile.
Porțiunea de aspect .aspx a unei pagini web tolerează scrierea cu majuscule diferite pentru numele
etichetelor, numele proprietăților și valorile enumerării. De exemplu, următoarele două etichete sunt
echivalente și ambele vor fi interpretate corect de motorul ASP.NET, chiar dacă cazul lor diferă:
<asp:Button ID="button1" runat="server" enabled="false"
text="button" font-size="XX-small" /> <asp:button ID="button2"
runat="server" enabled="false" tExT="button" font-size="xx-small"
/>
Acest design a fost adoptat pentru a face .aspx pagini să se comporte mai mult ca paginile web
HTML obișnuite, care ignoră complet majusculele. Cu toate acestea, nu puteți utiliza aceeași
slăbiciune în etichetele care aplică setările în fișierul web.config sau fișierul machine.config. Aici,
cazul trebuie să se potrivească exact.
176
CAPITOLUL CONTROALE WEB
6 •
Această diagramă moștenire include unele controale pe care nu le veți studia în acest capitol, inclusiv
controalele de date, cum ar fi GridView, DetailsView și FormView și controalele de validare. Veți explora
aceste controale în capitolele următoare.
Proprietate Descriere
Cheie de acces Specifică scurtătura de la tastatură ca o singură literă. De exemplu, dacă setați această
opțiune la Y, combinația de tastatură Alt+Y își va schimba automat focalizarea pe acest
control web. Această caracteristică este acceptată numai pe Internet Explorer 4.0 și
versiuni ulterioare.
BackColor, ForeColor Setează culorile utilizate pentru fundalul, prim-planul și bordura controlului. În
și BorderColor majoritatea controalelor, culoarea planului frontal setează culoarea textului.
177
CAPITOLUL CONTROALE WEB
6 •
Proprietate Descriere
BorderStyle Una dintre valorile din enumerarea BorderStyle, inclusiv Dashed, Dotted,
Double, Groove, Ridge, Inset, Outset, Solid și None.
Activat Când este setat la false, controlul va fi vizibil, dar nu va putea primi informații
de la utilizator sau focalizare.
EnableViewState Setați acest lucru la false pentru a dezactiva gestionarea automată a stării pentru
acest control. În acest caz, controlul va fi resetat la proprietățile și formatarea
specificate în eticheta de control (în pagina .aspx) de fiecare dată când pagina
este postată înapoi. Dacă aceasta este setată la true (implicit), controlul utilizează
Descărcați de la Wow! eBook <www.wowebook.com>
Înălțime și lățime Specifică lățimea și înălțimea comenzii. Pentru unele controale, aceste
proprietăți vor fi ignorate atunci când sunt utilizate cu browsere mai vechi.
ID Specifică numele pe care îl utilizați pentru a interacționa cu controlul din cod (și,
de asemenea, servește drept bază pentru ID-ul utilizat pentru a denumi
elementul de nivel superior din codul HTML redat).
Părinte Furnizează o referință la controlul care conține acest control. Dacă controlul este
plasat direct pe pagină (nu în interiorul altui control), acesta va returna o
referință la obiectul paginii.
TabIndex Un număr care vă permite să controlați ordinea filelor. Controlul cu un TabIndex de 0 este
focalizat la prima încărcare a paginii. Apăsarea tastei Tab mută utilizatorul la controlul cu
următorul cel mai mic TabIndex, cu condiția ca acesta să fie activat. Această proprietate
este acceptată numai în Internet Explorer 4.0 și versiuni ulterioare.
Sfat ecran Afișează un mesaj text atunci când utilizatorul plasează mouse-ul deasupra
controlului. Multe browsere mai vechi nu acceptă această proprietate.
Vizibil Când este setat la false, controlul va fi ascuns și nu va fi redat la pagina HTML
finală care este trimisă clientului.
178
CAPITOLUL CONTROALE WEB
6 •
Următoarele câteva secțiuni descriu unele dintre conceptele comune pe care le veți utiliza cu aproape
orice control web, inclusiv modul de setare a proprietăților care utilizează unități și enumerări și modul
de utilizare a culorilor și fonturilor.
Unităţi
Toate proprietățile care utilizează măsurători, inclusiv BorderWidth, Height și Width, necesită structura Unității, care
combină o valoare numerică cu un tip de măsurare (pixeli, procentaj etc.). Aceasta înseamnă că atunci când setați aceste
proprietăți într-o etichetă de control, trebuie să vă asigurați că adăugați px (pixel) sau % (pentru procent) la număr pentru
a indica tipul de unitate.
Iată un exemplu cu un control al panoului care are o înălțime de 300 de pixeli și o lățime egală cu 50% din
fereastra curentă a browserului:
<asp:Înălțimea panoului = "300px" width = "50%" ID = "pnl" runat = "server" / >
Dacă atribuiți o proprietate bazată pe unitate prin cod, trebuie să utilizați una dintre metodele statice
ale tipului de unitate. Utilizați Pixel() pentru a furniza o valoare în pixeli și utilizați Percent() pentru a
furniza o valoare procentuală:
Convertiți numărul 300 într-un obiect unitate //
reprezentând pixeli și atribuiți-l. PNL. înălțime =
unitate.pixel(300);
Convertiți numărul 50 într-un obiect unitate //
reprezentând procentul și atribuiți-l. PNL. lățime
= unitate.procent(50);
De asemenea, puteți crea manual un obiect Unit și îl puteți inițializa utilizând unul dintre constructorii furnizați
și enumerarea UnitType. Acest lucru necesită câțiva pași suplimentari, dar vă permite să atribuiți cu ușurință
aceeași unitate mai multor controale:
Creați un obiect Unitate.
Unit myUnit = unitate nouă (300, UnitType.Pixel);
Enumerări
Enumerările sunt utilizate intens în biblioteca de clase .NET pentru a grupa un set de constante asociate. De
exemplu, când setați proprietatea BorderStyle a unui control, puteți alege una dintre mai multe valori
predefinite din enumerarea BorderStyle. În cod, setați o enumerare utilizând sintaxa punct:
Ctrl. BorderStyle = BorderStyle.Dashed;
În fișierul .aspx, setați o enumerare specificând una dintre valorile permise ca șir. Nu includeți numele
tipului de enumerare, care este presupus automat.
179
CAPITOLUL CONTROALE WEB
6 •
Culori
Proprietatea Culoare se referă la un obiect Culoare din spațiul de nume System.Drawing. Puteți crea
obiecte color în mai multe moduri:
Utilizarea unei valori de culoare ARGB (alfa, roșu, verde, albastru): Specificați fiecare valoare ca
număr întreg de la 0 la 255. Componenta alfa reprezintă transparența unei culori și, de obicei, veți
utiliza 255 pentru a face culoarea complet opacă.
Utilizarea unui nume de culoare .NET predefinit: Alegeți proprietatea denumită corespunzător doar în
citire din structura de culori. Aceste proprietăți includ cele 140 de nume de culori HTML.
Utilizarea unui nume de culoare HTML: Specificați această valoare ca șir utilizând clasa ColorTranslator.
Pentru a utiliza oricare dintre aceste tehnici, probabil că veți dori să începeți prin importul spațiului de
nume System.Drawing, după cum urmează:
folosind System.Drawing;
Următorul cod prezintă mai multe moduri de a specifica o culoare în cod:
180
CAPITOLUL CONTROALE WEB
6 •
Când definiți o culoare în fișierul .aspx, puteți utiliza oricare dintre numele de culori cunoscute:
<asp:TextBox Text="Test"
ForeColor="#ff50ff"
ID="txt" runat="server" />
Fonturi
Proprietatea Font face referire de fapt la un obiect FontInfo complet, care este definit în spațiul de nume
System.Web.UI.WebControls. Fiecare obiect FontInfo are mai multe proprietăți care îi definesc numele,
dimensiunea și stilul (consultați tabelul 6-3).
Tabelul 6-3. Proprietăți FontInfo
Proprietate Descriere
aldine, cursive, tăiate, Proprietăți booleene care aplică atributul stil dat.
Subliniere și supraliniere
În cod, puteți atribui un font setând diferitele proprietăți ale fontului utilizând sintaxa familiară a punctelor:
În fișierul .aspx, trebuie să utilizați o sintaxă specială "obiect walker" pentru a specifica proprietățile obiectului,
cum ar fi Font. Sintaxa umblătorului de obiecte utilizează o cratimă (-) pentru a separa proprietățile. De
exemplu, puteți seta un control cu un anumit font (Tahoma) și dimensiunea fontului (40 de puncte) astfel:
<asp:TextBox font-name="Tahoma" font-size="40" text=" test de dimensiune"
ID="txt" runat="server" />
181
CAPITOLUL CONTROALE WEB
6 •
O setare a fontului este într-adevăr doar o recomandare. În cazul în care computerul client nu are fontul solicitat, acesta
revine la un font standard. Pentru a rezolva această problemă, este obișnuit să specificați o listă de fonturi, în ordinea
preferințelor. Pentru aceasta, utilizați proprietatea Font.Names în loc de Font.Name, așa cum se arată aici:
<asp:TextBox
nume-fonturi="Verdana, Tahoma, Arial"
text="Test de dimensiune" ID="txt" runat="server" />
Aici, browserul va folosi fontul Verdana (dacă îl are). Dacă nu, va cădea înapoi pe Tahoma sau, dacă nu este
prezent, pe Arial.
Când specificați fonturi, este o idee bună să încheiați cu unul dintre următoarele fonturi, care sunt acceptate
în toate browserele:
• Ori
• Arial și Helvetica
• Curierat
Următoarele fonturi se găsesc pe aproape toate computerele Windows și Mac, dar nu neapărat pe alte
sisteme de operare, cum ar fi Unix:
• Verdana
• Georgia
• Tahoma
• Benzi desenate
• Negru Arial
• Impactul
182
CAPITOLUL CONTROALE WEB
6 •
Focar
Spre deosebire de controalele serverului HTML, fiecare control web oferă o metodă Focus(). Metoda Focus() afectează
numai controalele de intrare (controale care pot accepta apăsări de taste de la utilizator). Când pagina este redată în
browserul client, utilizatorul pornește în controlul focalizat.
De exemplu, dacă aveți un formular care permite utilizatorului să editeze informațiile despre clienți, puteți apela metoda
Focalizare() în prima casetă text din acel formular. În acest fel, cursorul apare în această casetă de text imediat când
pagina se încarcă pentru prima dată în browser. În cazul în care caseta text se află parțial în jos în formular, pagina chiar
defilează automat în jos. Utilizatorul poate trece apoi de la control la control folosind tasta Tab onorată de timp.
Dacă sunteți un dezvoltator HTML experimentat, știți că nu există nicio modalitate încorporată de a focaliza un control de
intrare. În schimb, trebuie să vă bazați pe JavaScript. Acesta este secretul implementării ASP.NET. Când codul este
procesat și pagina este redată, ASP.NET adaugă un bloc suplimentar de cod JavaScript la sfârșitul paginii. Acest cod
JavaScript setează pur și simplu focalizarea la ultimul control care a folosit metoda Focus(). Dacă nu ați apelat deloc
Focus(), acest cod nu este adăugat la pagină.
În loc să apelați metoda Focus() prin programare, puteți seta un control care ar trebui să fie întotdeauna
focalizat setând proprietatea DefaultFocus a etichetei <formular>:
<form DefaultFocus="TextBox2" runat="server">
Puteți înlocui focalizarea implicită apelând metoda Focalizare() din codul dvs.
O altă modalitate de a gestiona focalizarea este utilizarea tastelor de acces. De exemplu, dacă setați proprietatea
AccessKey a unei casete text la A, apăsarea focalizării Alt+A va comuta la TextBox. Etichetele pot intra, de asemenea, în
joc, chiar dacă nu pot accepta concentrarea. Trucul este să setați proprietatea Label.AssociatedControlID pentru a
specifica un control de intrare legat. În acest fel, eticheta transferă focalizarea asupra controlului asociat.
De exemplu, următoarea etichetă focalizează TextBox2 atunci când este apăsată combinația de
tastatură Alt+2:
Tastele de focalizare și acces sunt, de asemenea, acceptate în browserele non-Microsoft, inclusiv Firefox.
Butonul implicit
Împreună cu focalizarea controlului, ASP.NET vă permite, de asemenea, să desemnați un buton implicit pe o pagină
web. Butonul implicit este butonul pe care se face clic atunci când utilizatorul apasă tasta Enter. De exemplu, dacă
pagina web include un formular, poate doriți să transformați butonul de trimitere într-un buton implicit. În acest fel, dacă
utilizatorul apasă Enter în orice moment, pagina este postată înapoi și evenimentul Button.Click este declanșat pentru
acel buton.
Pentru a desemna un buton implicit, trebuie să setați proprietatea HtmlForm.DefaultButton cu ID-ul
controlului respectiv, așa cum se arată aici:
<form DefaultButton="cmdSubmit" runat="server">
Butonul implicit trebuie să fie un control care implementează interfața IButtonControl. Interfața este implementată
de controalele web Button, LinkButton și ImageButton, dar nu de niciunul dintre controalele serverului HTML.
În unele cazuri, este logic să aveți mai multe butoane implicite. De exemplu, puteți crea o pagină web cu două
grupuri de controale de intrare. Ambele grupuri pot avea nevoie de un buton implicit diferit. Puteți gestiona
acest lucru plasând grupurile în panouri separate. Controlul Panou expune, de asemenea, proprietatea
DefaultButton, care funcționează atunci când orice control de intrare pe care îl conține este focalizat.
183
CAPITOLUL CONTROALE WEB
6 •
PREFIXE DE CONTROL
Când lucrați cu controale web, este adesea util să utilizați un prefix de trei litere mici pentru a identifica tipul
de control. Exemplul precedent (și cele din restul acestei cărți) urmează această convenție pentru a face
codul interfeței cu utilizatorul cât mai clar posibil. Unele prefixe de control recomandate sunt următoarele:
• Buton: cmd
• Casetă de selectare: chk
• Imagine: img
• Etichetă: lbl
• Controlul listei: lst
• Panou: pnl
• RadioButton: optați
• Casetă text: txt
Dacă sunteți un programator veteran, veți observa, de asemenea, că această carte nu
folosește prefixe pentru a identifica tipurile de date. Acest lucru este în conformitate cu noua
filozofie a .NET, care recunoaște că tipurile de date se pot schimba adesea liber și fără
consecințe și că variabilele indică adesea obiecte cu funcții complete în loc de variabile
simple de date.
Controale listă
Controalele listei includ ListBox, DropDownList, CheckBoxList, RadioButtonList și BulletedList. Toate funcționează
în esență în același mod, dar sunt redate diferit în browser. ListBox, de exemplu, este o listă dreptunghiulară care
afișează mai multe intrări, în timp ce Lista verticală afișează numai elementul selectat. CheckBoxList și
RadioButtonList sunt similare cu ListBox, dar fiecare element este redat ca o casetă de selectare sau, respectiv,
un buton de opțiune. În cele din urmă, BulletedList este cel ciudat - este singurul control de listă care nu poate fi
selectat. În schimb, se redă ca o secvență de elemente numerotate sau marcate.
Toate controalele de listă selectabile furnizează o proprietate SelectedIndex care indică rândul selectat ca index
bazat pe zero (la fel ca controlul HtmlSelect pe care l-ați utilizat în capitolul anterior). De exemplu, dacă este
selectat primul element din listă, SelectedIndex va fi 0. Controalele de listă selectabile furnizează, de asemenea, o
proprietate SelectedItem suplimentară, care permite codului să regăsească obiectul ListItem care reprezintă
elementul selectat. Obiectul ListItem oferă trei proprietăți importante: Text (conținutul afișat), Valoare (valoarea
ascunsă din marcajul HTML) și Selectat (adevărat sau fals, în funcție de selectarea elementului).
În capitolul anterior, ați utilizat cod ca acesta pentru a prelua obiectul ListItem selectat dintr-un control
HtmlSelect numit Monedă, după cum urmează:
184
CAPITOLUL CONTROALE WEB
6 •
Dacă ați utilizat controlul web ListBox, puteți simplifica acest cod cu o sintaxă mai clară:
Proprietățile SelectedIndex și SelectedItem nu sunt de mare ajutor cu o listă care acceptă mai multe selecții,
deoarece vor returna pur și simplu primul element selectat. În schimb, puteți găsi toate elementele selectate
iterând prin colecția Elemente a controlului listă și verificând proprietatea ListItem.Selected a fiecărui
element. (Dacă este adevărat, acel element este unul dintre elementele selectate.) Figura 6-5 prezintă un
exemplu simplu de pagină web. Acesta oferă o listă de limbi de calculator și indică ce selecții a făcut
utilizatorul atunci când se face clic pe butonul OK.
Fișierul .aspx pentru această pagină definește controalele CheckListBox, Button și Label, așa cum se arată aici:
185
CAPITOLUL 6 CONTROALE WEB
•
Codul adaugă elemente în CheckListBox la pornire și iterează prin colecție atunci când se face clic pe
buton:
}
}
186
CAPITOLUL CONTROALE WEB
6 •
Controlul BulletedList
Controlul BulletedList este un echivalent pe partea de server a elementelor <ul> (listă neordonată) și <ol>
(listă ordonată). Ca și în cazul tuturor controalelor de listă, setați colecția de elemente care ar trebui să fie
afișate prin proprietatea Elemente. În plus, utilizați proprietățile din tabelul 6-4 pentru a configura modul de
afișare a elementelor.
Tabelul 6-4. S-au adăugat proprietăți BulletedList
Proprietate Descriere
Stil glonț Determină tipul de listă. Alegeți dintre Numerotate (1, 2, 3, . . .), LowerAlpha
(a, b, c, . . .) și UpperAlpha (A, B, C, . .), LowerRoman (i, ii, iii, ; . . .) și
Romana superioară (I, II, III, . .) și simbolurile marcatorilor Disc, Cerc, Pătrat sau
CustomImage (caz în care trebuie să setați proprietatea BulletImageUrl).
BulletImageUrl Dacă BulletStyle este setat la CustomImage, aceasta indică spre imaginea plasată
în partea stângă a fiecărui element sub forma unui marcator.
Modul DisplayMode Stabilește dacă textul fiecărui element este redat ca text (utilizați Text, pictograma
implicit) sau un hyperlink (utilizați LinkButton sau HyperLink). Diferența dintre
LinkButton și HyperLink este modul în care tratează clicurile. Când utilizați LinkButton,
Lista cu marcatori declanșează un eveniment Click la care puteți reacționa pe server
Efectuați navigarea. Când utilizați HyperLink, BulletedList nu se declanșează
evenimentul Faceți clic - în schimb, tratează textul fiecărui element din listă ca relativ sau
URL absolut și le redă ca hyperlink-uri HTML obișnuite. Când utilizatorul
dă clic pe un element, browserul încearcă să navigheze la adresa URL respectivă.
Dacă setați DisplayMode la LinkButton, puteți reacționa la evenimentul Button.Click pentru a determina
pe ce element s-a făcut clic. Iată un exemplu:
Figura 6-6 prezintă toate valorile BulletStyle acceptate de BulletList. Când faceți clic pe unul dintre
elemente, lista se modifică pentru a utiliza acel BulletStyle. Puteți încerca această pagină exemplu cu
exemplul de proiect WebControls pentru acest capitol.
187
CAPITOLUL CONTROALE WEB
6 •
Descărcați de la Wow! eBook <www.wowebook.com>
Controale tabel
În esență, controlul Tabel este construit dintr-o ierarhie de obiecte. Fiecare obiect Tabel conține unul sau
mai multe obiecte TableRow. La rândul său, fiecare obiect TableRow conține unul sau mai multe obiecte
TableCell. Fiecare obiect TableCell conține alte controale ASP.NET sau conținut HTML care afișează
informații. Dacă sunteți familiarizat cu etichetele tabelului HTML, această relație (prezentată în Figura 6-7)
va părea destul de logică.
188
CAPITOLUL CONTROALE WEB
6 •
Pentru a crea un tabel dinamic, urmați aceeași filozofie ca și pentru orice alt control web. Mai întâi, creați și configurați
obiectele ASP.NET necesare. Apoi, ASP.NET convertește aceste obiecte la reprezentarea HTML finală înainte ca
pagina să fie trimisă clientului.
Luați în considerare exemplul prezentat în figura 6-8. Permite utilizatorului să specifice un număr de
rânduri și coloane, precum și dacă celulele ar trebui să aibă borduri.
189
CAPITOLUL CONTROALE WEB
6 •
Când utilizatorul face clic pe butonul Creare, tabelul este completat dinamic cu date eșantion în conformitate cu
opțiunile selectate, așa cum se arată în figura 6-9.
190
CAPITOLUL 6 CONTROALE WEB
•
Veți observa că controlul Tabel nu conține rânduri sau celule reale. Pentru a crea un tabel valid, va trebui
să imbricați mai multe straturi de etichete. Următorul exemplu creează un tabel cu o singură celulă care
conține textul Un rând de test:
<asp:Table ID="tbl" runat="server">
<asp:TableRow ID="row" runat="server">
A ID="cell" runat="server">A Sample Value</asp:TableCell> </asp:TableRow>
</asp:Table>
Pagina web de testare a tabelului nu are elemente imbricate. Aceasta înseamnă că tabelul va fi creat ca obiect de
control pe partea serverului, dar dacă codul nu adaugă rânduri și celule, tabelul nu va fi redat în pagina HTML finală.
Clasa TableTest utilizează două rutine de tratare a evenimentelor. Când pagina este încărcată pentru prima
dată, aceasta adaugă o bordură în jurul tabelului. Când se face clic pe buton, acesta creează dinamic
obiectele TableRow și TableCell necesare într-o buclă.
clasa publică parțială TableTest : System.Web.UI.Page
{
vid protejat Page_Load(expeditor obiect, EventArgs e)
{
Configurați aspectul tabelului.
Acest lucru poate fi efectuat și în fișierul .aspx // sau în
cmdCreate_Click event handler. TBL. BorderStyle =
BorderStyle.Inset; } tbl. BorderWidth = Unit.Pixel(1);
CAPITOLUL CONTROALE WEB
6 •
if (chkBorder.Checked) { cellNew.BorderStyle =
BorderStyle.Inset; cellNew.BorderWidth =
Unit.Pixel(1); }
Acest cod utilizează colecția Controale pentru a adăuga controale fiu. Fiecare control al containerului oferă
această proprietate. De asemenea, puteți utiliza colecția TableCell.Controls pentru a adăuga controale web la
fiecare TableCell. De exemplu, puteți plasa un control Imagine și un control Etichetă în fiecare celulă. În acest
caz, nu puteți seta proprietatea TableCell.Text. Următorul fragment de cod utilizează această tehnică, iar
Figura 6-10 afișează rezultatele:
Creați un nou obiect TableCell.
cellNew = nou TableCell();
192
CAPITOLUL CONTROALE WEB
6 •
Flexibilitatea reală a paginii de test a tabelului este că fiecare tabel, rând de tabel și celulă de tabel este un
obiect cu caracteristici complete. Dacă doriți, puteți da fiecărei celule un stil diferit de bordură, culoare de
bordură și culoare de text, setând proprietățile corespunzătoare.
193
CAPITOLUL CONTROALE WEB
6 •
ASP.NET controalele serverului sunt într-adevăr o iluzie ingenioasă. Vă veți aminti că codul dintr-o pagină
de ASP.NET este procesat pe server. Apoi este trimis utilizatorului ca HTML obișnuit. Figura 6-11
ilustrează ordinea evenimentelor în procesarea paginilor.
Acest lucru este același în ASP.NET ca și în programarea tradițională ASP. Întrebarea este, cum puteți scrie cod
de server care să reacționeze imediat la un eveniment care apare pe client?
Unele evenimente, cum ar fi evenimentul Faceți clic pe un buton, apar imediat. Asta pentru că atunci când faceți clic,
butonul postează înapoi pagina. Aceasta este o convenție de bază a formularelor HTML. Cu toate acestea, alte acțiuni
provoacă evenimente, dar nu declanșează o postare. Un exemplu este atunci când utilizatorul modifică textul dintr-o
casetă text (care declanșează evenimentul TextChanged) sau alege un element nou dintr-o listă (evenimentul
SelectedIndexChanged). S-ar putea să doriți să răspundeți la aceste evenimente, dar fără o postback, codul dvs. nu are
cum să ruleze.
ASP.NET gestionează acest lucru oferindu-vă două opțiuni:
• Puteți aștepta până la următoarea postback pentru a reacționa la eveniment. De exemplu,
imaginați-vă că doriți să reacționați la evenimentul SelectedIndexChanged dintr-o listă. Dacă utilizatorul
selectează un element dintr-o listă, nu se întâmplă nimic imediat. Cu toate acestea, dacă utilizatorul
face clic apoi pe un buton pentru a posta înapoi pagina, se declanșează două evenimente: Button.Click
urmat de ListBox.SelectedIndexChanged. Și dacă aveți mai multe controale, este foarte posibil ca un
194
CAPITOLUL CONTROALE WEB
6 •
singur postback să ducă la mai multe evenimente de schimbare, care se declanșează unul după
altul, într-o ordine nedeterminată.
• Puteți utiliza funcția de postback automat pentru a forța un control să posteze înapoi
pagina imediat ce detectează o anumită acțiune a utilizatorului. În acest scenariu,
când utilizatorul face clic pe un element nou din listă, pagina este postat înapoi, codul
se execută și se returnează o nouă versiune a paginii.
Opțiunea pe care o alegeți depinde de rezultatul dorit. Dacă trebuie să reacționați imediat (de exemplu, doriți să
actualizați un alt control atunci când are loc o anumită acțiune), trebuie să utilizați postback-uri automate. Pe de altă parte,
postback-urile automate pot face uneori pagina mai puțin receptivă, deoarece fiecare postback și reîmprospătare a paginii
adaugă o întârziere scurtă, dar vizibilă, și o reîmprospătare a paginii. (Veți învăța cum să creați pagini care se
actualizează singure fără o reîmprospătare vizibilă a paginii atunci când luați în considerare ASP.NET AJAX în capitolul
25.)
Toate controalele web de intrare acceptă postback-uri automate. Tabelul 6-5 oferă o listă de bază a
controalelor web și a evenimentelor acestora.
Dacă doriți să capturați imediat un eveniment de modificare (cum ar fi TextChanged, CheckedChanged sau
SelectedIndexChanged), trebuie să setați proprietatea AutoPostBack a controlului la true. În acest fel, pagina va fi trimisă
automat atunci când utilizatorul interacționează cu controlul (de exemplu, alege o selecție din listă, face clic pe un buton
radio sau pe o casetă de selectare sau modifică textul dintr-o casetă de text și apoi trece la un control nou).
Când pagina este postată înapoi, ASP.NET va examina pagina, va încărca toate informațiile curente și apoi
va permite codului să efectueze o procesare suplimentară înainte de a returna pagina înapoi utilizatorului (a
se vedea figura 6-12). În funcție de rezultatul dorit, este posibil să aveți o pagină care are unele controale
care postează înapoi automat și altele care nu.
195
CAPITOLUL CONTROALE WEB
6 •
Acest sistem postback nu este ideal pentru toate evenimentele. De exemplu, unele evenimente cu care este
posibil să fiți familiarizat din programele Windows, cum ar fi evenimentele de mișcare a mouse-ului sau
evenimentele de presă cheie, nu sunt practice într-o aplicație ASP.NET. Retrimiterea paginii de fiecare dată
când este apăsată o tastă sau mouse-ul este mutat ar face ca aplicația să fie insuportabil de lentă și să nu
răspundă.
196
CAPITOLUL CONTROALE WEB
6 •
ASP.NET adaugă, de asemenea, două câmpuri de intrare ascunse suplimentare care sunt utilizate pentru a
transmite informații înapoi la server. Aceste informații constau în ID-ul controlului care a generat evenimentul și
orice informații suplimentare care ar putea fi relevante. Aceste câmpuri sunt inițial goale, după cum se arată aici:
Funcția __doPostBack() are responsabilitatea de a seta aceste valori cu informațiile corespunzătoare despre
eveniment și apoi de a trimite formularul. Funcția __doPostBack() este prezentată aici:
}
</scenariu>
Rețineți, ASP.NET generează automat funcția __doPostBack(), cu condiția ca cel puțin un control de pe pagină să
utilizeze postback-uri automate.
În cele din urmă, orice control care are proprietatea AutoPostBack setată la true este conectat la funcția
__doPostBack() utilizând atributele onclick sau onchange. Aceste atribute indică ce acțiune trebuie să
întreprindă browserul ca răspuns la evenimentele JavaScript onclick și onchange din partea clientului.
Următorul exemplu afișează eticheta pentru un control listă numit lstBackColor, care postează înapoi
automat. Ori de câte ori utilizatorul modifică selecția din listă, evenimentul onchange din partea clientului se
declanșează. Browserul apelează apoi funcția __doPostBack(), care trimite pagina înapoi la server.
<select ID="lstBackColor" onchange="__doPostBack('lstBackColor','')" language="javascript">
Cu alte cuvinte, ASP.NET transformă automat un eveniment JavaScript pe partea client într-un eveniment
ASP.NET pe partea de server, utilizând funcția __doPostBack() ca intermediar. Figura 6-13 prezintă acest
proces.
197
CAPITOLUL CONTROALE WEB
6 •
Pentru a înțelege cum funcționează evenimentele de control web, trebuie să aveți o înțelegere solidă a
ciclului de viață al paginii. Luați în considerare ce se întâmplă atunci când un utilizator modifică un control
care are proprietatea AutoPostBack setată la true:
1. Pe partea clientului, funcția JavaScript __doPostBack este invocată, iar pagina
este retrimisă către server.
2. ASP.NET recreează obiectul Page utilizând fișierul .aspx.
3. ASP.NET preia informațiile de stare din câmpul de stare a vizualizării
ascunse și actualizează controalele în consecință.
4. Evenimentul Page.Load este declanșat.
5. Evenimentul de schimbare corespunzător este declanșat pentru control. (Dacă au fost
modificate mai multe controale, ordinea evenimentelor de modificare este nedeterminată.)
198
CAPITOLUL 6 CONTROALE WEB
•
Listarea 6-1 arată codul de marcare pentru trackerul de evenimente, iar Listarea 6-2 arată clasa din
spatele codului care îl face să funcționeze.
protejat void Page_PreRender(expeditor obiect, EventArgs e) { // Când apare evenimentul Page.PreRender, este prea târziu
// pentru a schimba lista.
} Jurnal("Page_PreRender");
Acest lucru necesită conversia tipului de obiect într-o clasă Control. șir ctrlName
= ((Control)sender).ID; } log(ctrlName + " schimbat");
Selectați ultimul element pentru a derula lista, astfel încât cele mai recente
intrări // să fie vizibile.
lstEvents.SelectedIndex = lstEvents.Items.Count - 1;
}
}
200
CAPITOLUL CONTROALE WEB
6 •
Disecarea codului . . .
Următoarele puncte sunt demne de remarcat despre acest cod:
• Codul scrie în ListBox folosind o metodă privată Log(). Metoda Log() adaugă
textul și derulează automat în partea de jos a listei de fiecare dată când se adaugă
o nouă intrare, asigurându-se astfel că cele mai recente intrări rămân vizibile.
• Toate evenimentele de modificare sunt gestionate prin aceeași metodă,
CtrlChanged(). Dacă vă uitați cu atenție la fișierul .aspx, veți observa că fiecare control
de intrare conectează evenimentul monitorizat la metoda CtrlChanged(). Codul de
tratare a evenimentelor din metoda CtrlChanged() utilizează parametrul sursă pentru a
afla ce control a trimis evenimentul și încorporează aceste informații în șirul jurnal.
• Pagina include rutine de tratare a evenimentelor pentru evenimentele Page.Load și
Page.PreRender. La fel ca în cazul tuturor evenimentelor de pagină, acești rutine de
tratare a evenimentelor sunt conectați prin numele metodei. Asta înseamnă că pentru
a adăuga rutina de tratare a evenimentelor pentru evenimentul Page.PreRender,
trebuie doar să adăugați o metodă numită Page_PreRender(), ca cea prezentată aici.
201
CAPITOLUL CONTROALE WEB
6 •
Sfat: elementul <div> este util atunci când doriți să grupați textul și controalele și să le aplicați tuturor un set de proprietăți de formatare (cum ar fi o culoare sau un font). Elementul <div> este, de asemenea, un instrument esențial pentru poziționarea blocurilor de conținut într-o pagină. Din aceste motive, elementul <div> este folosit în multe dintre exemplele din această carte. Veți afla mai multe despre utilizarea <div> pentru aspect și formatare în capitolul
12.
Ori de câte ori utilizatorul face clic pe butonul Actualizare, pagina este postată înapoi și "cardul" este
actualizat (a se vedea figura 6-16).
202
CAPITOLUL• CONTROALE
6 WEB
Codul de aspect .aspx este simplu. Desigur, lungimea mare a acestuia face dificilă lucrul eficient. Iată
marcajul, cu detaliile de formatare reduse la elementele esențiale:
Pentru a obține aspectul cu două coloane în acest exemplu, aveți două opțiuni. Puteți utiliza tabele HTML
(care sunt o tehnică oarecum de modă veche) sau puteți utiliza poziționarea absolută cu stiluri CSS (ca în
acest exemplu). Esența poziționării absolute este ușor de înțeles. Uitați-vă doar la atributul de stil din controlul
Panou, care specifică o coordonată fixă de sus și o coordonată stângă pe pagina web. Când panoul este
randat în HTML, acest punct devine colțul din stânga sus.
Notă Poziționarea absolută este o caracteristică a CSS, standardul Cascading Style Sheets. Ca atare, funcționează în orice element XHTML, nu doar ASP.NET controale. Poziționarea absolută este descrisă în detaliu în capitolul 12.
Codul urmează modelul familiar, cu accent pe două evenimente: evenimentul Page.Load, unde sunt setate
valorile inițiale, și evenimentul Button.Click, unde este generat cardul.
204
CAPITOLUL CONTROALE WEB
6 •
} lstBackColor.Items.Add ("Alb");
lstBackColor.Items.Add ("Roșu");
lstBackColor.Items.Add ("Verde");
lstBackColor.Items.Add ("Albastru");
lstBackColor.Items.Add ("Galben");
Adăugați elementul.
lstBorder.Items.Add(articol);
Setați imaginea.
imgDefault.ImageUrl = "defaultpic.png";
Actualizați fontul.
205
CAPITOLUL CONTROALE WEB
6 •
lblGreeting.Font.Name = lstFontName.SelectedItem.Text;
Actualizați stilul de bordură. Acest lucru necesită doi pași de conversie. În primul
rând, valoarea elementului de listă este convertită dintr-un șir // într-un întreg. Apoi,
numărul întreg este convertit într-o valoare în // enumerarea BorderStyle.
Setați textul.
lblGreeting.Text = txtGreeting.Text;
}
}
După cum puteți vedea, acest exemplu limitează utilizatorul la câteva opțiuni presetate de font și culoare.
Codul pentru opțiunea BorderStyle este deosebit de interesant. Controlul lstBorder are o listă care afișează
numele text al uneia dintre valorile enumerate BorderStyle. Vă veți aminti din capitolele introductive că fiecare
valoare enumerată este de fapt un număr întreg cu un nume atribuit. De asemenea, lstBorder stochează în
secret numărul corespunzător, astfel încât codul să poată prelua numărul și să seteze enumerarea cu
ușurință atunci când utilizatorul face o selecție și operatorul de evenimente cmdUpdate_Click se
declanșează.
Îmbunătățirea generatorului de felicitări
ASP.NET pagini au acces la biblioteca completă de clase .NET. Cu puțină explorare, veți găsi cursuri care ar putea ajuta
producătorul de felicitări, cum ar fi instrumente care vă permit să recuperați toate numele de culori cunoscute și toate
fonturile instalate pe serverul web.
De exemplu, puteți completa controlul lstFontName cu o listă de fonturi utilizând clasa InstalledFontCollection.
Pentru a-l accesa, trebuie să importați spațiul de nume System.Drawing.Text. De asemenea, trebuie să
importați spațiul de nume System.Drawing, deoarece definește clasa FontFamily care reprezintă fonturile
individuale instalate pe serverul web:
folosind System.Drawing;
folosind
System.Drawing.Text;
206
CAPITOLUL CONTROALE WEB
6 •
Iată codul care primește lista de fonturi și o folosește pentru a completa lista:
Pentru a obține o listă cu numele culorilor, trebuie să recurgeți la un truc mai avansat. Deși ați putea codifica greu o
listă de culori comune, .NET oferă de fapt o listă lungă de nume de culori în enumerarea
System.Drawing.KnownColor. Cu toate acestea, extragerea efectivă a numelor din această enumerare necesită
ceva muncă.
Trucul este de a utiliza o caracteristică de bază a tuturor enumerărilor: metoda statică Enum.GetNames(),
care inspectează o enumerare și oferă o serie de șiruri, cu un șir pentru fiecare valoare din enumerare.
Pagina web poate utiliza apoi legarea datelor pentru a completa automat controlul listei cu informațiile din
ColorArray. (Veți explora legarea datelor mult mai detaliat în capitolul 15.)
Notă: Nu vă faceți griji dacă acest exemplu introduce câteva caracteristici care arată complet extraterestru! Aceste caracteristici sunt mai avansate (și nu sunt legate în mod specific de ASP.NET). Cu toate acestea, vă arată o parte din aroma pe care biblioteca completă de clasă .NET o poate oferi pentru o aplicație matură.
207
CAPITOLUL CONTROALE WEB
6 •
O problemă minoră cu această abordare este că include culori de mediu de sistem (de exemplu,
ActiveBorder) în listă. Este posibil să nu fie evident pentru utilizator ce culori reprezintă aceste valori.
Totuși, această abordare funcționează bine pentru această aplicație simplă. Puteți utiliza o tehnică
similară pentru a completa opțiunile BorderStyle:
Setați opțiunile pentru stilul de bordură.
string[] borderStyleArray = Enum.GetNames(typeof(BorderStyle));
lstBorder.DataSource = borderStyleArray; lstBorder.DataBind();
Acest cod ridică o nouă provocare: cum convertiți valoarea pe care utilizatorul o selectează în constanta
corespunzătoare pentru enumerare? Când utilizatorul alege un stil de bordură din listă, proprietatea SelectedItem va
avea un șir de text precum "Groove". Dar pentru a aplica acest stil de bordură controlului, aveți nevoie de o modalitate
Descărcați de la Wow! eBook <www.wowebook.com>
208
CAPITOLUL CONTROALE WEB
6 •
AutoPostBack="true"
Width="194px" Height="22px"/>
Apoi, modificați etichetele de control astfel încât evenimentul modificat al fiecărui control de intrare să fie
conectat la o rutină de tratare a evenimentelor numită ControlChanged. Iată un exemplu cu evenimentul
SelectedIndexChanged sau lista verticală:
Alegeți o culoare de fundal: <br /> <asp:DropDownList ID="lstBackColor"
AutoPostBack="true" runat="server" width="194px" height="22px"/>
OnSelectedIndexChanged="ControlChanged"
Veți observa că numele evenimentului de modificare depinde de control. De exemplu, TextBox furnizează un
eveniment TextChanged, ListBox furnizează un eveniment SelectedIndexChanged și așa mai departe. În cele din
urmă, trebuie să creați un manipulator de evenimente care să poată gestiona evenimentele de modificare. Pentru a
salva câțiva pași, puteți utiliza aceeași rutină de tratare a evenimentelor pentru toate controalele de intrare. Tot ce
trebuie să facă rutina de tratare a evenimentelor este să apeleze rutina de actualizare care regenerează felicitarea.
Cu aceste modificări, este ușor să perfecționați programul mai extins de generare a cardurilor
prezentat în Figura 6-18. Codul complet pentru această aplicație este furnizat împreună cu mostrele
online.
209
CAPITOLUL CONTROALE WEB
6 •
Sfat
Postback-ul automat nu este întotdeauna cel mai bun. Uneori, un postback automat poate deranja un utilizator, mai ales atunci când utilizatorul lucrează printr-o conexiune lentă sau când serverul trebuie să efectueze o opțiune consumatoare de timp. Din acest motiv, uneori este mai bine să utilizați un buton explicit de trimitere și să nu activați AutoPostBack pentru majoritatea controalelor de intrare. Alternativ, vă puteți îmbunătăți pagina web cu cele ASP.NET caracteristici AJAX descrise în capitolul 25, care vă permit să creați interfețe de
utilizator care se simt mai receptive și se pot actualiza fără o reîmprospătare a paginii complete.
210
CAPITOLUL CONTROALE WEB
6 •
Ultimul cuvânt
Acest capitol v-a prezentat controalele web și interfața lor obiect. Pe măsură ce continuați prin această
carte, veți afla despre mai multe controale web. Următoarele momente importante urmează să apară:
• În capitolul 10, veți afla despre controalele avansate, cum ar fi AdRotator, Calendar și
comenzile de validare. Veți afla, de asemenea, despre controalele specializate ale
containerelor, cum ar fi MultiView și Wizard.
• În capitolul 13, veți afla despre comenzile de navigare, cum ar fi TreeView și
Menu.
• În capitolul 16, veți afla despre GridView, DetailsView și FormView - controale web
de nivel înalt care vă permit să manipulați un tabel complex de date din orice sursă de
date.
Pentru o referință bună care afișează fiecare control Web și listează proprietățile sale importante,
consultați Ajutorul Visual Studio.
211
CAPITOLUL7
• ■■
Tratarea erorilor,
înregistrarea în jurnal și
urmărirea
Niciun software nu poate rula fără erori, iar aplicațiile ASP.NET nu fac excepție. Mai devreme sau mai târziu, codul dvs. va fi
întrerupt de o greșeală de programare, date nevalide, circumstanțe neașteptate sau chiar defecțiuni hardware. Programatorii
începători petrec nopți nedormite îngrijorându-se de erori. Dezvoltatorii profesioniști recunosc că bug-urile sunt o parte
inerentă a aplicațiilor software și a codului defensiv, testând ipoteze, înregistrând probleme și scriind cod de manipulare a
erorilor pentru a face față neașteptatului. În acest capitol, veți afla practicile de gestionare și depanare a erorilor pe care le
puteți utiliza pentru a vă apăra aplicațiile ASP.NET împotriva erorilor comune, pentru a urmări problemele utilizatorilor și
pentru a rezolva probleme misterioase. Veți învăța cum să utilizați gestionarea structurată a excepțiilor, cum să păstrați o
evidență a erorilor nerecuperabile cu jurnalele și cum să configurați pagini web cu mesaje de eroare personalizate pentru
erorile HTTP comune. De asemenea, veți afla cum să utilizați urmărirea paginilor pentru a vedea informații de diagnosticare
despre ASP.NET pagini.
Erori comune
Erorile pot apărea într-o varietate de situații. Unele dintre cele mai frecvente cauze ale erorilor includ încercările de
împărțire la zero (cauzate de obicei de intrări nevalide sau de informații lipsă) și încercările de conectare la o resursă
limitată, cum ar fi un fișier sau o bază de date (care pot eșua dacă fișierul nu există, conexiunea bazei de date expiră
sau codul are acreditări de securitate insuficiente).
Un tip infam de eroare este excepția de referință nulă, care apare de obicei atunci când un program încearcă să
utilizeze un obiect neinițializat. Ca programator .NET, veți învăța rapid să recunoașteți și să rezolvați această greșeală
comună, dar enervantă. Următorul exemplu de cod arată problema în acțiune, cu două obiecte SqlConnection care
reprezintă conexiuni la baza de date:
public void cmdDoSomething_Click(object sender, EventArgs e) { // Acest lucru funcționează, deoarece obiectul a fost creat // cu
noul cuvânt cheie.
...
213
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
214
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Chiar dacă o eroare este rezultatul unei intrări nevalide sau al eșecului unei componente terțe, o pagină de
eroare poate distruge aspectul profesional al oricărei aplicații. Utilizatorii aplicației ajung să aibă sentimentul
că aplicația este instabilă, nesigură sau de slabă calitate - și sunt cel puțin parțial corecte.
Dacă o aplicație ASP.NET este proiectată și construită cu atenție, o pagină de eroare nu va apărea aproape
niciodată. Erorile pot apărea în continuare din cauza unor circumstanțe neprevăzute, dar acestea vor fi
prinse în cod și identificate. Dacă eroarea este una critică pe care aplicația nu o poate rezolva singură, va
raporta o pagină mai utilă (și mai ușor de utilizat) de informații care ar putea include un link către un e-mail
de asistență sau un număr de telefon unde clientul poate primi asistență suplimentară. Veți analiza aceste
tehnici în acest capitol.
Tratarea excepțiilor
Majoritatea limbajelor .NET acceptă tratarea excepțiilor structurate. În esență, atunci când apare o eroare în aplicația dvs.,
.NET Framework creează un obiect de excepție care reprezintă problema. Puteți prinde acest obiect folosind un
manipulator de excepții. Dacă nu reușiți să utilizați un rutină de tratare a excepțiilor, codul va fi anulat și utilizatorul va
vedea o pagină de eroare.
Gestionarea structurată a excepțiilor oferă mai multe caracteristici cheie:
Excepțiile sunt bazate pe obiecte: Fiecare excepție furnizează o cantitate semnificativă de informații de
diagnosticare înfășurate într-un obiect îngrijit, în locul unui mesaj simplu și a unui cod de eroare. Aceste obiecte de
excepție acceptă, de asemenea, o proprietate InnerException care vă permite să înfășurați o eroare generică peste
eroarea mai specifică care a provocat-o. Puteți chiar să creați și să aruncați propriile obiecte de excepție.
Excepțiile sunt prinse în funcție de tipul lor: Acest lucru vă permite să simplificați codul de gestionare a
erorilor fără a fi nevoie să treceți prin coduri de eroare obscure.
Gestionarii de excepții utilizează o structură modernă de blocuri: Acest lucru facilitează activarea și dezactivarea
diferitelor gestionare a erorilor pentru diferite secțiuni de cod și gestionarea individuală a erorilor.
Gestionarii de excepții sunt multistrat: Puteți suprapune cu ușurință gestionarii de excepții peste
alte rutine de tratare a excepțiilor, dintre care unele pot verifica doar un set specializat de erori.
Excepțiile sunt o parte generică a .NET Framework: Aceasta înseamnă că sunt complet compatibile
între limbi. Astfel, o componentă .NET scrisă în C# poate arunca o excepție pe care o puteți prinde într-o
pagină web scrisă în VB.
Notă
Gestionarii de excepții sunt o tehnică cheie de programare. Acestea vă permit să reacționați la problemele care apar în timpul rulării din cauza unor factori în afara controlului dvs. Cu toate acestea, evident că nu ar trebui să utilizați gestionari de excepții pentru a ascunde erorile care ar putea apărea în codul dvs.! În schimb, trebuie să urmăriți aceste greșeli ale programatorului la momentul dezvoltării și să le corectați. Caracteristicile de depanare ale Visual
Clasa de excepție
Fiecare clasă de excepție derivă din clasa de bază System.Exception. .NET Framework este plin de clase
de excepții predefinite, cum ar fi NullReferenceException, IOException, SqlException și așa mai departe.
215
CAPITOLUL 7 GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
Clasa Excepție include funcționalitatea esențială pentru identificarea oricărui tip de eroare. Tabelul 7-1
enumeră cei mai importanți membri ai săi.
Membru Descriere
Link de ajutor Un link către un document de ajutor, care poate fi o uniformă relativă sau complet calificată
localizator de resurse (URL) sau nume uniform de resurse (URN), cum ar fi
file:///C:/ACME/MyApp/help.html#Err42. .NET Framework nu utilizează
această proprietate, dar o puteți seta în excepțiile personalizate dacă doriți să o utilizați
în codul paginii dvs.
Sursă Numele cererii sau al obiectului pentru care a fost ridicată excepția.
StackTrace Un șir care conține o listă cu toate apelurile metodei curente pe stivă, în
ordinea de la cele mai recente la cele mai puțin recente. Acest lucru este util pentru a determina unde
a apărut problema.
GetBaseException() O metodă utilă pentru excepțiile imbricate care pot avea mai mult de un strat. El
Recuperează excepția originală (cea mai adânc imbricată) deplasându-se la baza butonului
Lanțul InnerException.
Când prindeți o excepție într-o pagină ASP.NET, aceasta nu va fi o instanță a clasei generice System.Exception. În schimb,
va fi un obiect care reprezintă un anumit tip de eroare. Acest obiect se va baza pe una dintre multele clase care moștenesc
de la System.Exception. Acestea includ diverse clase, cum ar fi DivideByZeroException, ArithmeticException, IOException,
SecurityException și multe altele. Unele dintre aceste clase oferă detalii suplimentare despre eroarea din proprietățile
suplimentare. Visual Studio oferă un instrument util pentru a naviga prin excepțiile din biblioteca de clasă .NET. Pur și simplu
selectați Excepții de depanare din meniu (va trebui să aveți un proiect deschis pentru ca acest lucru să
216
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Caseta de dialog Excepții vă permite să specificați ce excepții ar trebui să fie tratate de codul dvs. atunci când depanare
și ce excepții vor determina Visual Studio să intre imediat în modul de întrerupere. Aceasta înseamnă că nu trebuie să
dezactivați codul de tratare a erorilor pentru a depana o problemă. De exemplu, puteți alege să permiteți programului să
gestioneze un FileNotFoundException comun (care poate fi cauzat de o selecție de utilizator nevalidă), dar instruiți
Visual Studio să întrerupă executarea dacă apare o excepție neașteptată DivideByZero.
Pentru a configura acest lucru, adăugați un marcaj de selectare în coloana Aruncat de lângă intrarea pentru
excepția System.DivideByZero. În acest fel, veți fi avertizat imediat ce apare problema. Dacă nu adăugați o
bifă la coloana Aruncat, codul va continua, va rula orice rutine de tratare a excepțiilor pe care le-a definit și
va încerca să rezolve problema. Veți primi o notificare numai dacă apare o eroare și nu este disponibil un
handler de excepții adecvat.
Lanțul de excepții
Figura 7-3 arată cum funcționează proprietatea InnerException. În scenariul specific afișat aici, un
FileNotFoundException a condus la un NullReferenceException, care a condus la o particularizare
UpdateFailedException. Folosind un bloc de tratare a excepțiilor, aplicația poate prinde
UpdateFailedException. Apoi poate obține mai multe informații despre sursa problemei urmând proprietatea
InnerException la NullReferenceException, care la rândul său face referire la FileNotFoundException original.
217
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Proprietatea InnerException este un instrument extrem de util pentru programarea bazată pe componente. În general,
Descărcați de la Wow! eBook <www.wowebook.com>
nu este de mare ajutor dacă o componentă raportează o problemă de nivel scăzut, cum ar fi o referință nulă sau o
eroare de împărțire la zero. În schimb, trebuie să comunice un mesaj mai detaliat despre operațiunea care a eșuat și ce
intrare ar fi putut fi nevalidă. Codul de apelare poate corecta adesea problema și poate reîncerca operațiunea.
Pe de altă parte, uneori depanați un bug care se ascunde adânc în interiorul componentei în sine. În acest
caz, trebuie să știți exact ce a cauzat eroarea - nu doriți să o înlocuiți cu o excepție de nivel superior care ar
putea ascunde problema rădăcină. Utilizarea unui lanț de excepții gestionează ambele scenarii: primiți
oricâte obiecte de excepție legate sunt necesare, ceea ce poate specifica informații de la cea mai mică la
cea mai specifică condiție de eroare.
Excepții de manipulare
Prima linie de apărare într-o aplicație este de a verifica condițiile potențiale de eroare înainte de a efectua o
operație. De exemplu, un program poate verifica în mod explicit dacă divizorul este 0 înainte de a efectua un
calcul sau dacă există un fișier înainte de a încerca să îl deschidă:
dacă (divizor != 0)
{
Este sigur să împărțiți un anumit număr după divizor.
}
Cu toate acestea, ar trebui să utilizați în continuare gestionarea excepțiilor, deoarece pot interveni
Chiar dacă efectuați acest nivel de bază de "asigurare a calității", aplicația dvs. este încă vulnerabilă. De exemplu, nu aveți nicio
modalitate de a vă proteja împotriva tuturor problemelor posibile de acces la fișiere care apar, inclusiv defecțiuni hardware sau
probleme de rețea care ar putea apărea spontan în mijlocul unei operații. În mod similar, nu aveți nicio modalitate de a valida un
ID de utilizator și o parolă pentru o bază de date înainte de a încerca să deschideți o conexiune - și chiar dacă ați face-o, acea
218
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
tehnică ar fi supusă propriului set de erori potențiale. În unele cazuri, este posibil să nu fie practic să efectuați întreaga gamă
de verificări defensive, deoarece acestea pot impune o rezistență notabilă asupra performanței aplicației dvs. Din toate
aceste motive, aveți nevoie de o modalitate de a detecta și de a face față erorilor atunci când apar.
Soluția este gestionarea structurată a excepțiilor. Pentru a utiliza tratarea structurată a excepțiilor,
încadrați codul potențial problematic în structura specială de blocuri prezentată aici:
încercați { // Codul riscant merge aici (deschiderea unui fișier, conectarea la o bază de date și
așa mai departe). } captură { // A fost detectată o eroare. Vă puteți ocupa de asta aici. } în
concluzie { // Este timpul să curățați, indiferent dacă a existat sau nu o eroare. }
Instrucțiunea de încercare permite tratarea erorilor. Orice excepții care apar în rândurile următoare pot fi "prinse"
automat. Codul din blocul de captură va fi executat atunci când este detectată o eroare. Și oricum, indiferent dacă
apare sau nu o eroare, blocul final al codului va fi executat ultimul. Acest lucru vă permite să efectuați o curățare de
bază, cum ar fi închiderea unei conexiuni la baza de date. În cele din urmă, codul este important deoarece se va
executa chiar dacă a apărut o eroare care va împiedica continuarea programului. Cu alte cuvinte, dacă o excepție
nerecuperabilă vă oprește cererea, veți avea în continuare șansa de a elibera resurse.
Actul de a prinde o excepție o neutralizează. Dacă tot ce doriți să faceți este să faceți inofensivă o anumită
eroare, nici măcar nu trebuie să adăugați niciun cod în blocul de captură al gestionarului de erori. De obicei,
totuși, această porțiune a codului va fi utilizată pentru a raporta eroarea utilizatorului sau pentru a o înregistra
pentru referințe viitoare. Într-o componentă separată (cum ar fi un obiect de afaceri), acest cod poate
gestiona excepția, poate efectua o curățare și apoi o poate rearunca în codul de apelare, care va fi în cea
mai bună poziție pentru a-l remedia sau pentru a alerta utilizatorul. Sau ar putea crea de fapt un nou obiect
de excepție cu informații suplimentare și să le arunce.
219
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
O excepție va fi prinsă atâta timp cât este o instanță a clasei indicate sau dacă este derivată din acea
clasă. Cu alte cuvinte, dacă utilizați această afirmație:
captură (excepție de eroare)
veți prinde orice excepție, deoarece fiecare obiect de excepție este derivat din clasa de bază
System.Exception.
Blocurile de excepție funcționează puțin ca un cod condiționat. De îndată ce se găsește un manipulator de
excepții corespunzător, se invocă codul de captură corespunzător. Prin urmare, trebuie să vă organizați
declarațiile de captură de la cele mai specifice la cele mai puțin specifice:
încercați { // Codul bazei de date riscante
merge aici.
Încheind cu o declarație de captură pentru clasa de excepție de bază este adesea o idee bună pentru a vă
asigura că nu se strecoară erori. Cu toate acestea, în programarea bazată pe componente, ar trebui să vă
asigurați că interceptați numai acele excepții pe care le puteți trata sau recupera. În caz contrar, este mai
bine să lăsați codul de apelare să prindă eroarea inițială.
Când utilizați clase din .NET Framework, este posibil să nu știți ce excepții trebuie să
prindeți. Din fericire, Ajutorul Visual Studio vă poate completa.
Trucul este să căutați metoda sau constructorul pe care îl utilizați în referința bibliotecii clasei. O modalitate
rapidă de a trece la o anumită metodă este să utilizați indexul Ajutor - trebuie doar să tastați numele clasei,
urmat de un punct, urmat de numele metodei, ca în File.Open (care este o metodă pe care o veți utiliza pentru
a deschide fișiere în capitolul 17). Dacă există mai multe versiuni supraîncărcate ale metodei, veți vedea o
pagină care le listează pe toate și va trebui să faceți clic pe cea care are parametrii doriți.
După ce găsiți metoda potrivită, parcurgeți documentația metodei până când găsiți o
secțiune numită Excepții. Această secțiune enumeră toate excepțiile posibile pe care
această metodă le poate arunca. De exemplu, dacă căutați metoda File.Open(), veți găsi
că excepțiile posibile includ DirectoryNotFoundException, FileNotFoundException,
UnauthorizedAccessException și așa mai departe. Probabil că nu veți scrie un bloc de
captură pentru fiecare excepție posibilă. Cu toate acestea, ar trebui să știți în continuare
despre toate, astfel încât să puteți decide ce excepții doriți să gestionați separat.
220
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
În acest exemplu, metoda DivideNumbers() nu are niciun fel de rutină de tratare a excepțiilor. Cu toate
acestea, apelul metodei DivideNumbers() se face în interiorul unui bloc de încercare, ceea ce înseamnă că
problema va fi prinsă mai în amonte în codul de apelare. Aceasta este o abordare bună, deoarece rutina
DivideNumbers() ar putea fi utilizată într-o varietate de circumstanțe (sau, dacă face parte dintr-o
componentă, într-o varietate de tipuri diferite de aplicații). Chiar nu are acces la niciun fel de interfață cu
utilizatorul și nu poate raporta direct o eroare. Numai codul de apelare este în măsură să determine dacă
problema este una gravă sau minoră și numai codul de apelare poate solicita utilizatorului mai multe
informații sau poate raporta detaliile erorii în pagina web.
Notă În acest exemplu, se acordă o atenție deosebită utilizării tipului de date zecimale, mai degrabă decât dublului mai comun
• tip de date. Asta pentru că, spre deosebire de ceea ce v-ați putea aștepta, este acceptabil să
împărțiți un dublu la 0. Rezultatul este valoarea specială Double.PositiveInfinity (sau
Double.NegativeInfinity dacă împărțiți un număr negativ la 0).
De asemenea, puteți suprapune rutinele de tratare a excepțiilor în așa fel încât diferite rutine de tratare a
excepțiilor să filtreze diferite tipuri de probleme. Iată un astfel de exemplu:
221
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
zecimal privat GetAverageCost(DateTime saleDateDate) { încercați { // Utilizați codul de acces la baza de date aici pentru a prelua
toate înregistrările de vânzare // pentru această dată și pentru a calcula media.
}}
Disecarea codului . . .
Ar trebui să fiți conștienți de următoarele puncte:
• Dacă apare un SqlException în timpul operației bazei de date, acesta va fi prins în
metoda GetAverageCost().
• Dacă apare o excepție DivideByZero(de exemplu, metoda nu primește înregistrări,
dar încearcă totuși să calculeze o medie), excepția va fi prinsă în rutina de tratare a
evenimentelor Page.Load.
• Dacă apare o altă problemă (cum ar fi o excepție de referință nulă), nu există un
handler de excepții activ pentru a o detecta. În acest caz, .NET va căuta prin întreaga
stivă de apeluri fără a găsi o declarație de captură corespunzătoare într-o rutină activă
de tratare a excepțiilor și va genera o eroare de execuție, va încheia programul și va
returna o pagină cu informații despre excepție.
222
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Evident, puteți preveni cu ușurință apariția acestei excepții utilizând verificări suplimentare de siguranță a codului sau o
puteți rezolva elegant folosind controalele de validare. Cu toate acestea, acest cod oferă un bun exemplu despre modul în
care puteți face față proprietăților unui obiect de excepție. De asemenea, vă oferă o idee bună despre ce fel de informații
vor fi returnate.
Iată codul clasei de pagini pentru acest exemplu:
a = Decimal.Parse(txtA.Text);
b = Decimal.Parse (txtB.Text); rezultat = a/b; lblResult.Text =
rezultat. ToString(); } lblResult.ForeColor =
System.Drawing.Color.Black; catch (Exception err) {
lblResult.Text = "<b>Message:</b> " + err. Mesaj;
lblResult.Text += "<br /><br />"; lblResult.Text +=
"<b>Sursa:</b> " + eroare. Sursă; lblResult.Text += "<br /><br
/>"; } } lblResult.Text += "<b>Stack Trace:</b> " + err. Stivuire;
lblResult.ForeColor = System.Drawing.Color.Red;
223
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
}
Rețineți că, imediat ce apare eroarea, execuția este transferată unui rutină de tratare a excepțiilor. Codul din blocul de
încercare nu este finalizat. Din acest motiv, rezultatul etichetei este setat în blocul de încercare. Aceste linii vor fi
executate numai dacă codul de divizare rulează fără erori.
Veți vedea multe alte exemple de tratare a excepțiilor pe parcursul acestei cărți. Capitolele privind
accesul la date din partea 4 a acestei cărți prezintă cele mai bune practici pentru tratarea excepțiilor
la accesarea unei baze de date.
Excepții de stăpânire
Rețineți aceste puncte atunci când lucrați cu tratarea structurată a excepțiilor:
Împărțiți codul în mai multe blocuri de încercare/captură: dacă puneți tot codul într-un singur rutină de tratare a
excepțiilor, veți avea probleme la determinarea locului în care a apărut problema. Nu aveți nicio modalitate de
a "relua" codul într-un bloc de încercare. Aceasta înseamnă că, dacă apare o eroare la începutul unui bloc de
încercare lung, veți omite o cantitate mare de cod. Regula generală este să utilizați o rutină de tratare a
excepțiilor pentru o activitate asociată (cum ar fi deschiderea unui fișier și regăsirea informațiilor).
Raportați toate erorile: În timpul depanării, porțiuni din codul aplicației de gestionare a erorilor pot
masca greșelile ușor de corectat din aplicație. Pentru a preveni acest lucru, asigurați-vă că raportați
toate erorile și luați în considerare omiterea unei logici de gestionare a erorilor în compilările timpurii.
Nu utilizați rutine de tratare a excepțiilor pentru fiecare instrucțiune: Instrucțiunile simple de cod
(atribuirea unei valori constante unei variabile, interacțiunea cu un control etc.) pot provoca erori în timpul
testării dezvoltării, dar nu vor cauza probleme viitoare odată perfecționate. Gestionarea erorilor trebuie
utilizată atunci când accesați o resursă externă sau aveți de-a face cu date furnizate asupra cărora nu
aveți control (și, prin urmare, pot fi nevalide).
224
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
zecimal privat DivideNumbers(număr zecimal, divizor zecimal) { if (divizor == 0) { DivideByZeroException err = nou
DivideByZeroException(); aruncă eroare; } else { număr returnat/divizor; } }
Alternativ, aveți posibilitatea să creați un obiect de excepție .NET și să specificați un mesaj de eroare
particularizat utilizând un alt constructor:
zecimal privat DivideNumbers(număr zecimal, divizor zecimal) { if (divizor == 0) { DivideByZeroException err = nou
DivideByZeroException( "Ați furnizat 0 pentru parametrul divizor. Trebuie să fii oprit."); aruncă eroare; } else { număr
returnat/divizor; } }
225
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Aruncarea unei excepții este cea mai utilă în programarea bazată pe componente. În programarea bazată pe
componente, pagina dvs. ASP.NET creează obiecte și metode de apelare dintr-o clasă definită într-un ansamblu
compilat separat. În acest caz, clasa din componentă trebuie să poată notifica codul de apelare (aplicația web) cu
privire la orice erori. Componenta ar trebui să gestioneze erorile recuperabile în liniște și să nu le transmită codului
de apelare. Pe de altă parte, dacă apare o eroare nerecuperabilă, aceasta trebuie indicată întotdeauna cu o
excepție și niciodată printr-un alt mecanism (cum ar fi un cod de returnare). Pentru mai multe informații despre
programarea bazată pe componente, consultați capitolul 22. Dacă puteți găsi o excepție în biblioteca de clasă care
reflectă cu exactitate problema care a apărut, ar trebui să o aruncați. Dacă trebuie să returnați informații
suplimentare sau specializate, vă puteți crea propria clasă de excepții particularizată.
Clasele de excepții particularizate ar trebui să moștenească întotdeauna de la System.ApplicationException, care la
rândul său derivă din clasa de excepție de bază. Acest lucru permite .NET să facă distincția între două clase largi de
excepții - cele pe care le creați și cele care sunt native pentru .NET Framework.
Când creați o clasă de excepții, puteți adăuga proprietăți pentru a înregistra informații suplimentare. De
exemplu, iată o clasă specială care înregistrează informații despre încercarea eșuată de împărțire la zero:
226
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Notă Putețiorganizată
• Abordarea defini clasa
constă
de excepții
în utilizarea
particularizată
unui fișierdirect
de cod
în fișierul
separat.codului
Pentru.aspx.cs.
aceasta,Cu
faceți
toateclic
acestea, mai mult
dreapta pe aplicație în Exploratorul de soluții și alegeți Adăugare element nou. Apoi, alegeți Clasă
din lista de șabloane, introduceți un nume de fișier și faceți clic pe Adăugare. Visual Studio va
plasa un nou fișier de cod în subfolderul App_Code al site-ului web. (Depinde de dvs. dacă creați
un fișier de cod separat pentru fiecare clasă sau puneți mai multe clase în același fișier de cod.
Ambele abordări au același efect.)
private zecimal DivideNumbers(număr zecimal, divizor zecimal) { if (divizor == 0) { CustomDivideByZeroException err = new
CustomDivideByZeroException(); err. DividingNumber = număr; aruncă eroare; } else { număr returnat/divizor; } }
Pentru a perfecționa excepția personalizată, trebuie să o furnizați cu cei trei constructori standard. Acest
lucru permite crearea clasei de excepții în modurile standard pe care le acceptă fiecare excepție:
• Pe cont propriu, fără argumente
• Cu un mesaj personalizat
• Cu un mesaj personalizat și un obiect de excepție de utilizat ca excepție internă
Acești constructori nu trebuie să conțină niciun cod. Tot ce trebuie să facă acești constructori este să
transmită parametrii către clasa de bază (constructorii din clasa moștenită ApplicationException) folosind
cuvântul cheie de bază, așa cum se arată aici:
clasa publică CustomDivideByZeroException : ApplicationException { // Adăugați o variabilă pentru a specifica numărul "altele".
împărțirea zecimală privatăNumăr; public zecimal DividingNumber { get { return dividingNumber; } set { dividingNumber = value; } }
227
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Al treilea constructor este deosebit de util pentru programarea componentelor. Vă permite să setați
proprietatea InnerException cu obiectul excepției care a cauzat problema inițială. Următorul exemplu arată
cum puteți utiliza acest constructor cu o clasă de componente numită ArithmeticUtility:
clasa publică ArithmeticUtilityException : ApplicationException { public
ArithmeticUtilityException() : base() {}
clasa publică ArithmeticUtility { private zecimal Divide (număr zecimal, divizor zecimal) { try { return number/divisor; } catch
(Exception err) {
Creați o instanță a clasei de excepții specializate, // și plasați obiectul de excepție original (de exemplu, un //
DivideByZeroException) în proprietatea InnerException. ArithmeticUtilityException errNew = new
ArithmeticUtilityException("Eroare de calcul", err);
Amintiți-vă, clasele de excepții personalizate sunt într-adevăr doar o modalitate standardizată pentru o clasă
de a comunica o eroare unei alte porțiuni de cod. Dacă nu utilizați componente sau propriile clase de
utilitare, probabil că nu trebuie să creați clase de excepții particularizate.
228
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Sfat
În multe cazuri, este logic să se utilizeze mai mult de o tehnică de înregistrare. De exemplu, puteți decide să înregistrați majoritatea erorilor într-un tabel ErrorLog dintr-o bază de date, dar să înregistrați erorile bazei de date în alt loc, cum ar fi Jurnalul de evenimente Windows.
Unul dintre cele mai sigure instrumente de înregistrare este sistemul de înregistrare a evenimentelor
Windows , care este încorporat în sistemul de operare Windows și disponibil pentru orice aplicație. Utilizând
jurnalele de evenimente Windows, site-ul dvs. web poate scrie mesaje text care înregistrează erori sau
evenimente neobișnuite. Jurnalele de evenimente Windows stochează mesajele dvs., precum și diverse alte
detalii, cum ar fi tipul mesajului (informații, eroare etc.) și ora la care a fost lăsat mesajul.
Aplicație Folosit pentru a urmări erorile sau notificările din orice aplicație. În general, veți
utiliza acest jurnal atunci când efectuați înregistrarea în jurnal a evenimentelor
sau veți crea propriul jurnal personalizat.
Securitate Folosit pentru a urmări problemele legate de securitate, dar utilizat în general
exclusiv de sistemul de operare.
229
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Utilizând Vizualizatorul de evenimente, puteți efectua o varietate de activități de gestionare cu jurnalele. De exemplu,
dacă faceți clic dreapta pe unul dintre jurnalele din lista Vizualizator evenimente, veți vedea opțiuni care vă permit să
goliți evenimentele din jurnal, să salvați intrările de jurnal în alt fișier și să importați un fișier jurnal extern.
Fiecare înregistrare de eveniment dintr-un jurnal de evenimente identifică sursa (în general, aplicația sau
serviciul care a creat înregistrarea), tipul de notificare (eroare, informații, avertisment) și ora la care a fost
inserată intrarea în jurnal. Pentru a vedea aceste informații, trebuie doar să selectați o intrare în jurnal, iar
detaliile vor apărea într-o zonă de afișare sub lista de intrări (a se vedea figura 7-6).
De asemenea, aveți posibilitatea să revizuiți jurnalele de evenimente în Visual Studio, cu excepția cazului în care executați ediția
puțin mai puțin puternică Visual Studio Web Developer Express, care nu include această caracteristică. Mai întâi, afișați fereastra
Server Explorer (dacă nu este deja vizibilă) alegând Vizualizare Server Explorer. (Exploratorul serverului
→ fereastra apare de obicei în partea stângă a ferestrei Visual Studio, unde partajează spațiul cu Trusa de instrumente.) Utilizând Server Explorer, extindeți serverele
→ grupul [ComputerName] Jurnale de evenimente pentru a vedea o listă de jurnale de evenimente pe computer. Această
listă este puțin mai lungă decât ceea ce ați văzut în Vizualizatorul de evenimente, deoarece include atât jurnalele de evenimente
Windows pe care le-ați văzut, cât și jurnalele de evenimente particularizate pentru anumite aplicații (pe care veți învăța să le
creați mai târziu în acest capitol).
Dacă extindeți un jurnal de evenimente în fereastra Server Explorer, veți găsi toate intrările din jurnalul de
evenimente, grupate în funcție de sursa care a făcut intrarea în jurnal. Figura 7-7 prezintă unele dintre
jurnalele de evenimente lăsate în Jurnalul de aplicații pe computerul curent de sursa de evenimente .NET
Runtime Optimization Source. După ce selectați o intrare de jurnal, puteți vizualiza detaliile sale specifice
(cum ar fi mesajul jurnalului de evenimente și ora la care a fost lăsat) în fereastra Proprietăți.
230
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Una dintre problemele potențiale cu jurnalele de evenimente este că intrările vechi sunt eliminate automat atunci când
jurnalul de evenimente atinge o dimensiune maximă (implicit, 20 MB). Cu toate acestea, veți descoperi că buștenii cresc
rapid. Aceasta înseamnă că, dacă nu utilizați un jurnal de evenimente personalizat care are mult spațiu, este posibil ca
intrările de jurnal să nu dureze o perioadă lungă de timp. În mod ideal, ar trebui să utilizați jurnalele de evenimente pentru a
înregistra informații care sunt revizuite și acționate într-o perioadă relativ scurtă de timp. De exemplu, jurnalele de
evenimente sunt o alegere bună dacă intenționați să înregistrați erorile aplicației și să le revizuiți pentru a diagnostica
comportamentul ciudat imediat după ce se întâmplă. Jurnalele de evenimente nu au la fel de mult sens dacă doriți să
obțineți o imagine detaliată a activității aplicației șase luni mai târziu, deoarece Windows (sau altcineva) poate șterge
intrările vechi de jurnal. În acest scenariu, o bază de date particularizată are mai mult sens.
Dacă doriți să adăugați puțin mai mult spațiu de respirație la un jurnal existent, puteți modifica dimensiunea
maximă. Pentru aceasta, faceți clic dreapta pe jurnal și alegeți Proprietăți. Veți vedea fereastra Proprietăți
aplicație prezentată în Figura 7-8, unde puteți modifica dimensiunea maximă.
231
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Sfat: Puteți mări dimensiunea jurnalului, dar chiar nu ar trebui să dezactivați complet ștergerea automată a jurnalului, deoarece ați putea ajunge să consumați o cantitate imensă de spațiu în timp dacă informațiile nu sunt eliminate în mod regulat.
folosind System.Diagnostics;
Următorul exemplu rescrie pagina simplă ErrorTest pentru a utiliza înregistrarea în jurnal a evenimentelor:
232
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
a = Decimal.Parse(txtA.Text);
b = Decimal.Parse (txtB.Text); rezultat = a / b;
lblResult.Text = rezultat. ToString(); lblResult.ForeColor
= System.Drawing.Color.Black;
catch (Exception err) { lblResult.Text = "<b>Message:</b> " + err. Mesaj + "<br /><br />"; lblResult.Text +=
"<b>Sursa:</b> " + eroare. Sursa + "<br /><br />"; lblResult.Text += "<b>Stack Trace:</b> " + err. Stivuire;
lblResult.ForeColor = System.Drawing.Color.Red;
}
}
Înregistrarea jurnalului de evenimente va apărea acum în utilitarul Vizualizator evenimente, așa cum se arată în
Figura 7-9. Rețineți că înregistrarea în jurnal este destinată administratorului sau dezvoltatorului de sistem. Nu
înlocuiește codul pe care îl utilizați pentru a notifica utilizatorul și a explica faptul că a apărut o problemă.
233
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Există o potențială problemă cu acest exemplu. În mod obișnuit, Windows nu vă va permite să accesați jurnalul
de evenimente și veți primi o excepție atunci când încercați să rulați acest exemplu. Modul corect de a rezolva
această problemă depinde dacă testați aplicația web sau o implementați pe un server web live.
Dacă doar testați codul de înregistrare în jurnal, cea mai simplă opțiune este să rulați Visual Studio ca
administrator. Pentru aceasta, faceți clic dreapta pe comanda rapidă Visual Studio și alegeți Executare ca
administrator. Acest pas este necesar din cauza sistemului de siguranță Control cont utilizator (UAC) din Windows.
CCU vă împiedică să utilizați privilegiile de administrator, cu excepția cazului în care le solicitați în mod specific,
totul în încercarea de a restricționa virușii, programele malware și hackerii care vă pot ataca computerul.
Când implementați aplicația pe un server web, procesul nu este la fel de simplu. În mod obișnuit, contul care
rulează aplicațiile dvs. web are un set atent limitat de permisiuni. Cu siguranță nu va fi un cont de
administrator. Dacă doriți ca aplicația web să poată utiliza jurnalul de evenimente, trebuie să acordați contului
respectiv permisiunile de care are nevoie pentru a crea intrări în jurnalul de evenimente. Iată pașii pe care dvs.
(sau un administrator) trebuie să îi urmați pe computerul server web:
1. Executați regedit.exe, fie utilizând un prompt de linie de comandă, fie
alegând Executare din meniul Start.
2. Navigați la secțiunea
HKEY_Local_Machine\SYSTEM\CurrentControlSet\Services\EventLog din registry.
3. Selectați folderul EventLog dacă doriți să acordați permisiunea ASP.NET tuturor
zonelor jurnalului de evenimente. Sau selectați un anumit folder care corespunde
jurnalului de evenimente pe care ASP.NET trebuie să îl acceseze.
4. Faceți clic dreapta pe folder și alegeți Permisiuni.
5. Adăugați contul pe care îl utilizează ASP.NET în listă (sau într-un grup din care face parte
acest cont). Dacă utilizați IIS în Windows 7, Windows Vista sau Windows Server 2008, trebuie
să adăugați permisiuni la grupul de IIS_IUSRS. (Pentru a afla mai multe despre modul în care
ASP.NET aplicații sunt mapate la conturile de utilizator, consultați capitolul 26.)
Jurnale personalizate
De asemenea, puteți înregistra erorile într-un jurnal particularizat. De exemplu, puteți crea un jurnal cu numele firmei și
puteți adăuga înregistrări la acesta pentru toate aplicațiile ASP.NET. Este posibil să doriți chiar să creați un jurnal
individual pentru o aplicație deosebit de mare și să utilizați proprietatea Sursă a fiecărei intrări pentru a indica pagina (sau
metoda serviciului web) care a cauzat problema.
Accesarea unui jurnal personalizat este ușoară - trebuie doar să utilizați un constructor diferit pentru clasa EventLog
pentru a specifica numele jurnalului particularizat. De asemenea, trebuie să înregistrați o sursă de evenimente pentru
jurnal. Acest pas inițial trebuie efectuat o singură dată - de fapt, veți primi o eroare dacă încercați să creați aceeași sursă
de evenimente. De obicei, veți utiliza numele aplicației ca sursă de evenimente.
Iată un exemplu care utilizează un jurnal personalizat numit ProseTech și înregistrează sursa
evenimentului DivideByZeroApp:
234
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Puteți utiliza acest tip de cod oriunde în aplicația dvs. De obicei, veți utiliza codul de înregistrare atunci
când răspundeți la o excepție care ar putea fi un simptom al unei probleme mai profunde.
235
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
→, alegeți Clasă, alegeți un nume de fișier adecvat, apoi faceți clic pe Adăugare.
Iată un exemplu de clasă numită MyLogger care gestionează detaliile înregistrării evenimentelor:
{
RegistruLog();
}}
Odată ce aveți o clasă în folderul App_Code, este ușor să o utilizați oriunde pe site-ul dvs. Iată cum puteți
utiliza clasa MyLogger într-o pagină web pentru a înregistra o excepție:
Înregistrați eroarea utilizând clasa de înregistrare în jurnal. MyLogger logger = nou MyLogger(); Logger.
LogError(Request.Path, eroare);
Dacă scrieți frecvent intrări de jurnal, este posibil să nu doriți să verificați dacă jurnalul există de fiecare dată
când doriți să scrieți o intrare. În schimb, puteți crea sursa de evenimente o singură dată - când aplicația
pornește pentru prima dată - utilizând o rutină de tratare a evenimentelor aplicației din fișierul global.asax.
Această tehnică este descrisă în capitolul 5.
236
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Sfat: înregistrarea în jurnal a evenimentelor utilizează spațiu pe disc și ia timpul procesorului departe de aplicațiile web. Nu stocați informații neimportante, cantități mari de date sau informații care ar fi mai bine într-un alt tip de stocare (cum ar fi o bază de date relațională). În general, ar trebui să utilizați un jurnal de evenimente pentru a înregistra condiții sau erori neașteptate, nu acțiuni ale clienților sau informații de urmărire a performanței.
237
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
}}
}
Dacă alegeți să afișați toate intrările din jurnalul de aplicații, pagina va funcționa lent. Doi factori sunt în acțiune aici. În primul
rând, este nevoie de timp pentru a prelua fiecare intrare în jurnalul de evenimente; Un jurnal tipic de aplicații poate conține cu
238
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
ușurință câteva mii de intrări. În al doilea rând, codul utilizat pentru a adăuga text la controlul Etichetă este ineficient. De
fiecare dată când adăugați o informație nouă la proprietatea Label.Text, .NET trebuie să genereze un nou obiect String. O
soluție mai bună este utilizarea clasei specializate System.Text.StringBuilder, care este concepută pentru a gestiona
procesarea intensivă a șirurilor cu o cheltuială mai mică prin gestionarea unui tampon intern sau a unei memorii.
Iată modul mai eficient în care puteți scrie codul de procesare a șirurilor:
{
Sb. Adăugare("<b>Tip intrare:</b>"); Sb.
Apend(intrare. EntryType.ToString()); Sb.
Adăugare("<br /><b>Message:</b> "); Sb.
Apend(intrare. Mesaj); Sb. Adăugare("<br
/><b>Timp generat:</b>"); Sb. Apend(intrare.
Generată în timp); Sb. Anexă("<br /><br />");
}
Copiați textul complet pe pagina web.
lblResult.Text = sb. ToString();
}
Sfat: Puteți ocoli unele dintre limitările jurnalului de evenimente utilizând propriul sistem de înregistrare personalizat. Toate ingredientele de care aveți nevoie sunt încorporate în biblioteca comună a clasei. De exemplu, puteți stoca informații despre erori într-o bază de date utilizând tehnicile de acces la date descrise în capitolul 14.
Urmărirea paginilor
Instrumentele de depanare ale Visual Studio și paginile de eroare detaliate ale ASP.NET sunt extrem de utile atunci
când testați o aplicație. Cu toate acestea, uneori aveți nevoie de o modalitate de a identifica problemele după ce ați
implementat o aplicație, atunci când nu aveți Visual Studio pe care să vă bazați.
Puteți încerca să identificați aceste erori înregistrând informații de diagnosticare într-un jurnal de
evenimente, dar acest lucru presupune că cineva va revizui jurnalul în mod regulat. Mai agresiv, puteți afișa
unele informații direct în pagina web. Problema cu această strategie este că trebuie să eliminați (sau cel
puțin să comentați) tot acest cod suplimentar înainte de a implementa aplicația web. În caz contrar,
utilizatorii site-ului dvs. web ar putea vedea mesaje ciudate de depanare atunci când se așteaptă cel mai
puțin.
239
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Din fericire, există o modalitate mai ușoară de a rezolva problema fără a recurge la o soluție autohtonă.
ASP.NET oferă o caracteristică numită urmărire, care vă oferă o modalitate mult mai convenabilă și mai
flexibilă de a raporta informațiile de diagnosticare.
Activarea urmăririi
Pentru a utiliza urmărirea, trebuie să o activați în mod explicit. Există mai multe moduri de a activa urmărirea.
Una dintre cele mai simple modalități este adăugarea unui atribut la directiva Page în fișierul .aspx:
<%@ Pagina trace="true" ... %>
De asemenea, puteți activa vectorizarea utilizând obiectul Urmărire încorporat (care este o instanță a clasei
System.Web.TraceContext). Iată un exemplu de activare a urmăririi în rutina de tratare a evenimentelor
Page.Load:
protejat void Page_Load(Obiect expeditor, EventArgs e)
{
Trace.IsEnabled = adevărat;
}
Această tehnică este utilă deoarece vă permite să activați sau să dezactivați urmărirea pentru o pagină în
anumite circumstanțe pe care le testați în codul dvs.
Rețineți că, în mod prestabilit, după ce activați urmărirea, aceasta se va aplica numai solicitărilor locale. (Cu
alte cuvinte, dacă lucrați cu o aplicație web implementată, trebuie să faceți solicitările din browserul web de
pe computerul serverului web.) Această limitare împiedică utilizatorii finali să vadă informațiile de urmărire.
Dacă trebuie să urmăriți o pagină web dintr-o locație externă, va trebui să activați urmărirea la distanță
modificând unele setări din fișierul web.config. (Puteți găsi informații despre modificarea acestor setări în
secțiunea "Application-Level Tracing" din continuarea acestui capitol.) După ce activați urmărirea la distanță,
puteți utiliza codul pentru a activa selectiv urmărirea, de exemplu, pentru anumiți utilizatori.
Informații de urmărire
ASP.NET urmărire furnizează automat un set lung de informații standard, formatate. Figura 7-12 arată
cum arată aceste informații. Pentru a construi acest exemplu, puteți începe cu orice pagină de ASP.NET
de bază. Aici este prezentată o pagină rudimentară ASP.NET cu doar o etichetă și un buton.
240
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Pe cont propriu, această pagină face foarte puțin, afișând o singură linie de text. Cu toate acestea, dacă faceți
clic pe buton, urmărirea este activată setând proprietatea Trace.IsEnabled la true (așa cum se arată în
fragmentul de cod anterior). Când pagina este redată, aceasta va include o cantitate semnificativă de
informații de diagnosticare, așa cum se arată în Figura 7-13.
241
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Informațiile de urmărire sunt furnizate în mai multe categorii diferite, care sunt descrise în secțiunile
următoare. În funcție de pagina dvs., este posibil să nu vedeți toate informațiile de urmărire. De exemplu,
dacă solicitarea de pagină nu furnizează niciun parametru șir de interogare, nu veți vedea colecția
QueryString. În mod similar, dacă nu există date păstrate în starea aplicației sau a sesiunii, nu veți vedea nici
acele secțiuni.
Sfat Dacă utilizați foi de stiluri, regulile pot afecta formatarea și aspectul informațiilor de urmărire, ceea ce le poate face dificil de citit. Dacă aceasta devine o problemă, puteți utiliza urmărirea la nivel de aplicație, așa cum este descris mai jos în acest capitol (consultați secțiunea "Urmărire la nivel de aplicație").
242
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Solicitați detalii
Această secțiune include câteva informații de bază, cum ar fi ID-ul sesiunii curente, ora la care a fost efectuată
solicitarea web și tipul de solicitare web și codificare (a se vedea Figura 7-14). Cele mai multe dintre aceste detalii
sunt destul de neinteresante și nu veți petrece mult timp uitându-vă la ele. Excepția este ID-ul sesiunii. Urmărind
când se modifică ID-ul sesiunii, veți ști când este creată o nouă sesiune. (Sesiunile sunt utilizate pentru a stoca
informații pentru un anumit utilizator între solicitările de pagină. Veți afla despre ele în capitolul 8.)
Arborele de control
Arborele de control vă arată toate controalele de pe pagină, indentate pentru a afișa ierarhia lor (ce controale sunt
conținute în alte controale), așa cum se arată în Figura 7-16. În acest exemplu simplu de pagină, arborele de control
include butoane numite cmdWrite, cmdWrite_Category, cmdError și cmdSession, toate acestea fiind definite în mod
explicit în marcajul paginii web. ASP.NET adaugă, de asemenea, automat controale literale pentru a reprezenta spațierea
și orice alte elemente statice care nu sunt controale de server (cum ar fi text sau etichete HTML obișnuite). Aceste
controale apar între butoanele din acest exemplu și au generat automat nume precum ctl00, ctl01, ctl02 și așa mai
departe.
O caracteristică utilă a acestei secțiuni este coloana Stare vizualizare, care vă spune câți octeți de spațiu sunt necesari
243
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
pentru a persista informațiile curente în control. Acest lucru vă poate ajuta să evaluați dacă activarea stării de control
diminuează performanța, în special atunci când lucrați cu controale legate de date, cum ar fi GridView.
244
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Există o ciudățenie cu lista de cookie-uri din informațiile de urmărire. Dacă nu ați creat cel puțin un cookie
personalizat propriu, nu veți vedea niciun cookie, inclusiv cele pe care ASP.NET le creează automat (cum ar
fi cookie-ul de sesiune). ASP.NET presupune că, dacă nu utilizați cookie-uri, nu sunteți interesat să vedeți
aceste detalii.
Colecția de anteturi
Această secțiune listează toate anteturile HTTP (a se vedea figura 7-19). Din punct de vedere tehnic, anteturile
sunt biți de informații care sunt trimise serverului ca parte a unei solicitări. Acestea includ informații despre
browserul care face solicitarea, tipurile de conținut pe care le acceptă și limba pe care o utilizează. În plus, colecția
de anteturi de răspuns listează anteturile care sunt trimise clientului ca parte a unui răspuns (chiar înainte de codul
HTML real afișat în browser). Setul de anteturi de răspuns este mai mic și include detalii precum versiunea
ASP.NET și tipul de conținut trimis (text/html pentru paginile web). În general, nu este necesar să utilizați direct
informațiile antetului. În schimb, ASP.NET ia în considerare automat aceste informații.
245
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Colecția de formulare
Această secțiune listează informațiile din formularul postat. Informațiile din formular includ toate valorile remise de
controalele web, cum ar fi textul dintr-o casetă text și selecția curentă dintr-o casetă listă. Controalele web ASP.NET
extrag automat informațiile de care au nevoie din colecția de formulare, astfel încât rareori trebuie să vă faceți griji.
Figura 7-20 prezintă valorile formularului pentru pagina simplă prezentată în figura 7-12. Acesta include
câmpul de stare a vizualizării ascunse, un alt câmp ascuns care este utilizat pentru validarea evenimentelor
(o caracteristică de ASP.NET de nivel scăzut care împiedică utilizatorii să vă manipuleze paginile web înainte
de a le posta înapoi) și un câmp pentru butonul cmdTrace, care este singurul control web de pe pagină.
Figura 7-21 prezintă informațiile pentru o pagină care a fost solicitată cu două valori șir de interogare, una
numită căutare și cealaltă stil denumit. Puteți încerca acest lucru cu pagina SimpleTrace.aspx tastând
?search=cat&style=full la sfârșitul adresei URL din caseta de adrese a browserului web.
Variabile server
Această secțiune listează toate variabilele serverului și conținutul acestora. În general, nu este necesar să
examinați aceste informații. Rețineți, de asemenea, că, dacă doriți să examinați programatic o variabilă de
server, puteți face acest lucru după nume cu colecția încorporată Request.ServerVariables sau utilizând una
dintre cele mai utile proprietăți de nivel superior din obiectul Solicitare.
246
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
diferite proceduri (și sunt utilizate în ordinea pe care o așteptați). Încă o dată, acestea sunt sarcini pe care le puteți realiza
și utilizând depanarea Visual Studio, dar urmărirea este o tehnică neprețuită atunci când lucrați cu o aplicație web care a
fost implementată pe un server web. Pentru a scrie un mesaj de urmărire particularizat, utilizați metoda Write() sau
metoda Warn() a obiectului de urmărire încorporat. Aceste metode sunt echivalente. Singura diferență este că Warn()
afișează mesajul cu litere roșii, ceea ce face mai ușor să se distingă de alte mesaje din listă. Iată un fragment de cod care
scrie un mesaj de urmărire atunci când utilizatorul face clic pe un buton:
Aceste mesaje apar în secțiunea de informații de urmărire a paginii, împreună cu mesajele implicite pe care
ASP.NET le generează automat (vezi Figura 7-22).
De asemenea, puteți utiliza o metodă supraîncărcată de Scriere() sau Avertizare() care vă permite să specificați categoria.
A utilizare obișnuită a acestui câmp este de a indica metoda curentă, așa cum se arată în figura 7-23.
247
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Descărcați de la Wow! eBook <www.wowebook.com>
Alternativ, puteți furniza informații despre categorii și mesaje cu un obiect de excepție care va fi descris
automat în jurnalul de urmărire, așa cum se arată în Figura 7-24.
248
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
protejat void cmdError_Click(Object sender, EventArgs e) { try { DivideNumbers(5, 0); } captură (Excepție err) {
Trace.Warn("cmdError_Click", "Eroare prinsă", err);
}}
În mod implicit, mesajele de urmărire sunt listate în ordinea în care au fost scrise de codul dvs. Alternativ,
puteți specifica ca mesajele să fie sortate după categorie utilizând atributul TraceMode din directiva Pagini:
249
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Trace.TraceMode = TraceMode.SortByCategory;
...
</system.web> </configuration>
250
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
localNumai adevărat, fals Determină dacă informațiile de urmărire vor fi afișate numai clienților
locali (clienți care utilizează același computer) sau pot fi afișate și
clienților la distanță. În mod implicit, acest lucru este adevărat și
clienții la distanță nu pot vedea informațiile de urmărire.
mostRecente adevărat, fals Păstrează numai cele mai recente mesaje de urmărire, dacă sunt adevărate.
Când se atinge requestLimit maximum, informațiile pentru cea mai veche
solicitare sunt abandonate de fiecare dată când se primește o nouă
solicitare. Dacă este false (valoarea implicită), ASP.NET oprește colectarea
de noi mesaje de urmărire atunci când se atinge limita.
Pentru a vizualiza informațiile de urmărire, solicitați fișierul trace.axd în directorul rădăcină al aplicației web. Acest
fișier nu există de fapt; În schimb, ASP.NET interceptează automat cererea și o interpretează ca
o solicitare de informații de urmărire. Apoi va lista cele mai recente solicitări colectate, cu condiția să faceți
solicitarea de la echipamentul local sau să fi activat urmărirea la distanță (a se vedea figura 7-25).
251
CAPITOLUL GESTIONAREA, ÎNREGISTRAREA ÎN JURNAL ȘI URMĂRIREA ERORILOR
7
Notă Uneori, când solicitați trace.axd de la serverul web de testare Visual Studio, este posibil să nu vedeți cele mai recente solicitări urmărite. În această situație, faceți clic pe butonul Reîmprospătare al browserului pentru a obține o listă actualizată.
Puteți vedea informațiile detaliate pentru orice solicitare făcând clic pe linkul Vizualizare detalii. Aceasta oferă:
o modalitate utilă de stocare a informațiilor de urmărire pentru o perioadă scurtă de timp și vă permite să
le revizuiți fără a fi nevoie să vedeți paginile reale (a se vedea figura 7-26).
Ultimul cuvânt
Una dintre cele mai semnificative diferențe dintre un site web obișnuit și o aplicație web profesională este
adesea în modul în care se ocupă de erori. În acest capitol, ați învățat diferitele linii de apărare pe care le
puteți utiliza în .NET, inclusiv gestionarea structurată a erorilor, înregistrarea în jurnal și urmărirea.
252
CAPITOLUL8
•■■
Managementul statului
Cea mai importantă diferență între programarea pentru Web și programarea pentru desktop este gestionarea stării -
modul în care stocați informațiile pe durata de viață a aplicației. Aceste informații pot fi la fel de simple ca numele unui
utilizator sau la fel de complexe ca un coș de cumpărături umplut pentru un magazin de comerț electronic.
Într-o aplicație tradițională Windows, nu este nevoie să vă gândiți la gestionarea stării. Memoria este
abundentă și întotdeauna disponibilă și trebuie să vă faceți griji doar pentru un singur utilizator. Într-o aplicație
web, este o poveste diferită. Mii de utilizatori pot rula simultan aceeași aplicație pe același computer (serverul
web), fiecare comunicând printr-o conexiune HTTP apatridă. Aceste condiții fac imposibilă proiectarea unei
aplicații web ca un program tradițional Windows. Înțelegerea acestor limitări de stare este cheia pentru
crearea de aplicații web eficiente. În acest capitol, veți vedea cum puteți utiliza caracteristicile de gestionare a
stării ASP.NET pentru a stoca informații cu atenție și în mod consecvent. Veți explora diferite opțiuni de
stocare, inclusiv starea vizualizării, starea sesiunii și cookie-urile personalizate. De asemenea, veți lua în
considerare modul de transfer al informațiilor de la o pagină la alta utilizând postarea pe mai multe pagini și
șirul de interogare.
Problema statului
Într-un program tradițional Windows, utilizatorii interacționează cu o aplicație care rulează continuu. O parte
din memoria de pe computerul desktop este alocată pentru a stoca setul curent de informații de lucru. Într-o
aplicație web, povestea este destul de diferită. Un site profesional ASP.NET ar putea arăta ca o aplicație care
rulează continuu, dar aceasta este într-adevăr doar o iluzie inteligentă. Într-o solicitare web tipică, clientul se
conectează la serverul web și solicită o pagină. Când pagina este livrată, conexiunea este întreruptă și
serverul web elimină toate obiectele paginii din memorie. În momentul în care utilizatorul primește o pagină,
codul paginii web a încetat deja să ruleze și nu mai există informații rămase în memoria serverului web.
Acest design apatrid are un avantaj semnificativ. Deoarece clienții trebuie să fie conectați doar pentru câteva
secunde cel mult, un server web poate gestiona un număr imens de solicitări aproape simultane fără o lovitură de
performanță. Cu toate acestea, dacă doriți să păstrați informațiile pentru o perioadă mai lungă de timp, astfel încât
acestea să poată fi utilizate pe mai multe postback-uri sau pe mai multe pagini, trebuie să luați măsuri
suplimentare.
Vizualizare stare
Una dintre cele mai comune modalități de stocare a informațiilor este starea de vizualizare. Starea
Vizualizare utilizează un câmp ascuns pe care ASP.NET inserează automat în codul HTML final, redat al
unei pagini Web. Este un loc perfect pentru a stoca informații care sunt utilizate pentru mai multe
postback-uri într-o singură pagină web.
253
CAPITOLUL MANAGEMENTUL DE STAT
8
În capitolele anterioare, ați aflat cum controalele web utilizează starea vizualizării pentru a urmări anumite detalii. De
exemplu, dacă modificați textul unei etichete, controlul Etichetă stochează automat noul text în starea de vizualizare. În
acest fel, textul rămâne la locul său data viitoare când pagina este postată înapoi. Controalele Web stochează
majoritatea valorilor proprietăților lor în starea vizualizare, cu condiția să nu fi dezactivat ViewState (de exemplu, setând
proprietatea EnableViewState a controlului sau pagina la false).
Starea vizualizării nu se limitează la controalele web. Codul paginii dvs. web poate adăuga biți de informații
direct la starea de vizualizare a paginii care conține și le poate prelua mai târziu după ce pagina este
postată înapoi. Tipul de informații pe care le puteți stoca include tipuri de date simple și propriile obiecte
particularizate.
Colecția ViewState
Proprietatea ViewState a paginii furnizează informațiile despre starea curentă a vizualizării. Această proprietate oferă o
instanță a clasei de colectare StateBag. StateBag este o colecție de dicționare, ceea ce înseamnă că fiecare articol este
stocat într-un "slot" separat, folosind un nume unic de șir.
De exemplu, luați în considerare acest cod:
Acest cuvânt cheie se referă la obiectul curent Pagină. Este opțional. acest.
ViewState["Contor"] = 1;
Aceasta plasează valoarea 1 (sau, mai degrabă, un număr întreg care conține valoarea 1) în colecția ViewState și îi dă
numele descriptiv Counter. Dacă în prezent niciun articol nu are numele Contor, un element nou va fi adăugat automat.
Dacă un articol este deja stocat sub numele de Contor, acesta va fi înlocuit. Când regăsiți o valoare, utilizați numele
cheii. De asemenea, trebuie să aruncați valoarea preluată la tipul de date corespunzător utilizând sintaxa de turnare pe
care ați văzut-o în capitolele 2 și 3. Acest pas suplimentar este necesar deoarece colecția ViewState stochează toate
elementele ca obiecte de bază, ceea ce îi permite să gestioneze multe tipuri de date diferite.
Iată codul care preia contorul din starea de vizualizare și îl convertește într-un întreg:
Notă ASP.NET oferă multe colecții care utilizează aceeași sintaxă de dicționar. Aceasta include colecțiile pe care le veți utiliza pentru starea sesiunii și a aplicației, precum și cele utilizate pentru memorarea în cache și cookie-uri. Veți vedea câteva dintre aceste colecții în acest capitol.
254
CAPITOLUL MANAGEMENTUL DE STAT
8
value="dDw3NDg2NTI5MDg7Oz4="
Pe măsură ce adăugați mai multe informații la starea de vizualizare, această valoare poate deveni mult mai lungă. Deoarece
această valoare nu este formatată ca text clar, mulți programatori ASP.NET presupun că datele lor de stare de vizualizare sunt
criptate. Nu este. În schimb, informațiile despre starea vizualizării sunt pur și simplu patch-uri împreună în memorie și convertite
într-un șir Base64 (care este un tip special de șir care este întotdeauna acceptabil într-un document HTML, deoarece nu include
255
CAPITOLUL MANAGEMENTUL DE STAT
8
caractere extinse). Un hacker inteligent ar putea inversa acest șir și ar putea examina datele de stare a vizualizării în
câteva secunde.
Când pagina este postată înapoi, ASP.NET examinează datele stării vizualizării și recalculează codul hash
utilizând același proces. Apoi verifică dacă suma de control pe care a calculat-o se potrivește cu codul hash
stocat în starea de vizualizare pentru pagină. Dacă un utilizator rău intenționat modifică o parte din datele
stării vizualizării, ASP.NET va ajunge la un nou cod hash care nu se potrivește. În acest moment, va respinge
complet postback-ul. (S-ar putea să credeți că un utilizator cu adevărat inteligent ar putea ocoli acest lucru
generând informații false despre starea vizualizării și un cod hash corespunzător. Cu toate acestea, utilizatorii
rău intenționați nu pot genera codul hash corect, deoarece nu au aceeași cheie criptografică ca ASP.NET.
Aceasta înseamnă că codurile hash pe care le creează nu se vor potrivi.) Codurile hash sunt de fapt activate
în mod implicit, deci dacă doriți această funcționalitate, nu trebuie să faceți pași suplimentari.
Starea de vizualizare privată
Chiar și atunci când utilizați coduri hash, datele privind starea vizualizării vor putea fi citite în continuare de utilizator. În
multe cazuri, acest lucru este complet acceptabil - la urma urmei, starea vizualizării urmărește informațiile care sunt
adesea furnizate direct prin alte controale. Cu toate acestea, dacă starea vizualizării conține unele informații pe care doriți
să le păstrați secrete, puteți activa criptarea stării de vizualizare.
Puteți activa criptarea pentru o pagină individuală utilizând proprietatea ViewStateEncryptionMode din
directiva Pagină:
<%@Page ViewStateEncryptionMode="Always" %>
Sau puteți seta același atribut într-un fișier de configurare pentru a configura criptarea stării vizualizării pentru
toate paginile din site-ul dvs.
...
</system.web>
</configuration>
În orice caz, acest lucru impune criptarea. Aveți trei opțiuni pentru setarea de criptare a stării de vizualizare:
criptați întotdeauna (întotdeauna), nu criptați niciodată (niciodată) sau criptați numai dacă un control solicită în
mod specific acest lucru (automat). Valoarea implicită este Auto, ceea ce înseamnă că pagina nu își va cripta
starea de vizualizare decât dacă un control din pagina respectivă solicită în mod specific acest lucru. (Din
punct de vedere tehnic, un control face această solicitare apelând metoda
Page.RegisterRequiresViewStateEncryption().) Dacă niciun control apelează această metodă pentru a indica
faptul că are informații sensibile, starea vizualizării nu este criptată, salvând astfel criptarea deasupra capului.
Pe de altă parte, un control nu are putere absolută - dacă apelează
Page.RegisterRequiresViewStateEncryption() și modul de criptare este Niciodată, starea vizualizării nu va fi
criptată.
256
CAPITOLUL MANAGEMENTUL DE STAT
8
Sfat: Nu criptați datele de stare ale vizualizării dacă nu este necesar să faceți acest lucru. Criptarea va impune o penalizare de performanță, deoarece serverul web trebuie să efectueze criptarea și decriptarea cu fiecare postback.
257
CAPITOLUL MANAGEMENTUL DE STAT
8
Restaurați variabilele.
} contents = (șir)ViewState["contents"];
}
Variabile persistente.
} ViewState["contents"] = conținut;
Descărcați de la Wow! eBook <www.wowebook.com>
protejat void cmdSave_Click(Expeditor obiect, EventArgs e) { // Transferați conținutul casetei de text la variabila membru.
contents = txtValue.Text; } txtValue.Text = "";
Logica din rutinele de tratare a evenimentelor Load și PreRender permite restului codului să funcționeze mai
mult sau mai puțin ca într-o aplicație desktop. Cu toate acestea, trebuie să aveți grijă să nu stocați cantități
inutile de informații atunci când utilizați această tehnică. Dacă stocați informații inutile în starea de vizualizare,
aceasta va mări dimensiunea ieșirii finale a paginii și poate încetini astfel timpii de transmitere a paginii. Un alt
dezavantaj al acestei abordări este că ascunde realitatea de nivel scăzut că fiecare informație trebuie salvată
și restaurată în mod explicit. Când ascunzi această realitate, este mult mai probabil să uiți să o respecți și să
proiectezi pentru ea. Dacă decideți să utilizați această abordare pentru a salva variabilele membru în starea
vizualizare, utilizați-o exclusiv. Cu alte cuvinte, abțineți-vă de la salvarea unor variabile de stare de vizualizare
în etapa PreRender și a altora în gestionarii de evenimente de control, deoarece acest lucru vă va confunda
cu siguranță pe dvs. și pe orice alt programator care se uită la codul dvs.
258
CAPITOLUL MANAGEMENTUL DE STAT
8
Sfat
Exemplul de cod anterior reacționează la evenimentul Page.PreRender, care apare imediat după finalizarea procesării paginii și chiar înainte ca pagina să fie redată în HTML. Acesta este un loc ideal pentru a stoca orice informații rămase necesare. Nu puteți stoca informații de stare de vizualizare într-o rutină de tratare a evenimentelor pentru evenimentul Page.Unload. Deși codul nu va cauza o eroare, informațiile nu vor fi stocate în starea de vizualizare, deoarece ieșirea finală a paginii HTML este deja
redată.
Deoarece clasa Client este marcată ca serializabilă, aceasta poate fi stocată în starea de vizualizare:
Rețineți că, atunci când utilizați obiecte personalizate, va trebui să proiectați datele atunci când le
regăsiți din starea de vizualizare.
259
CAPITOLUL 8 MANAGEMENTUL STATULUI
Odată ce înțelegeți acest principiu, veți putea, de asemenea, să determinați ce obiecte .NET pot fi plasate
în starea de vizualizare. Trebuie doar să găsiți informațiile despre clasă în Ajutorul Visual Studio. Cea mai
ușoară abordare este să căutați clasa în index. De exemplu, pentru a afla despre clasa FileInfo (despre
care veți afla în capitolul 17), căutați intrarea index "Clasa FileInfo". În documentația clasei, veți vedea
declarația pentru clasa respectivă, care arată cam așa:
[Serializabil] [ComVisible(true)] clasă publică sigilată
FileInfo : FileSystemInfo
Dacă declarația de clasă este precedată de atributul serializabil (așa cum este aici), instanțele acestei clase
pot fi plasate în starea de vizualizare. Dacă atributul Serializable nu este prezent, clasa nu este serializabilă
și nu veți putea plasa instanțe ale acesteia în starea de vizualizare.
Infrastructura care acceptă postback-uri între pagini este o proprietate numită PostBackUrl, care este definită de
interfața IButtonControl și apare în controale de buton, cum ar fi ImageButton, LinkButton și Button. Pentru a
utiliza postarea încrucișată, pur și simplu setați PostBackUrl la numele unui alt formular web. Când utilizatorul
face clic pe buton, pagina va fi postată la acea nouă adresă URL cu valorile din toate controalele de introducere
de pe pagina curentă. (Aceste informații postate înapoi includ câmpul de stare a vizualizării ascunse. După cum
veți vedea în curând, ASP.NET permite să creați o instanță actualizată a paginii sursă în memorie.)
Iată un exemplu - o pagină numită CrossPage1.aspx care definește un formular cu două casete text și un
buton. Când se face clic pe buton, acesta este postat pe o pagină numită CrossPage2.aspx.
260
CAPITOLUL MANAGEMENTUL DE STAT
8
Pagina CrossPage1 nu include niciun cod. Figura 8-3 arată cum apare în browser.
Acum, dacă încărcați această pagină și faceți clic pe buton, pagina va fi postată înapoi la CrossPage2.aspx. În acest
moment, pagina CrossPage2.aspx poate interacționa cu CrossPage1.aspx utilizând proprietatea Page.PreviousPage.
Iată o rutină de tratare a evenimentelor care preia titlul de pe pagina anterioară și îl afișează:
261
CAPITOLUL MANAGEMENTUL DE STAT
8
}
Rețineți că această pagină verifică dacă există o referință nulă înainte de a încerca să accesați obiectul Pagina
anterioară. Dacă este o referință nulă, nu a avut loc nicio postare pe mai multe pagini. Aceasta înseamnă că
CrossPage2.aspx fost solicitat direct sau CrossPage2.aspx postat înapoi. Oricum ar fi, nu este disponibil niciun
obiect PreviousPage. Figura 8-4 arată ce veți vedea atunci când CrossPage1.aspx postați pe CrossPage2.aspx.
vid protejat Page_Load(expeditor obiect, EventArgs e) { CrossPage1 prevPage = PreviousPage as CrossPage1; if (prevPage !=
null) { // (Citiți câteva informații din pagina anterioară.) } }
262
CAPITOLUL MANAGEMENTUL DE STAT
8
Notă site Web fără proiect, Visual Studio poate semnaliza acest lucru ca o eroare, indicând
• Într-un
faptul că nu are informațiile de tip pentru clasa de pagini sursă (în acest exemplu, adică
CrossPage1). Cu toate acestea, odată ce compilați site-ul web, eroarea va dispărea.
De asemenea, puteți rezolva această problemă într-un alt mod. În loc să proiectați manual referința, puteți
adăuga directiva PreviousPageType la pagina .aspx care primește postback-ul pe mai multe pagini (în acest
exemplu, CrossPage2.aspx), imediat după directiva Pagină. Directiva PreviousPageType indică tipul estimat
de pagină care inițiază postback-ul între pagini. Iată un exemplu:
<%@ PreviousPageType VirtualPath="~/CrossPage1.aspx" %>
Acum, proprietatea PreviousPage va utiliza automat tipul CrossPage1. Acest lucru vă permite să săriți codul
de proiectare și să mergeți direct la lucru folosind obiectul paginii anterioare, astfel:
{
(Citiți câteva informații de pe pagina anterioară.)
}
}
Cu toate acestea, această abordare este mai fragilă, deoarece vă limitează la o singură clasă de pagini. Nu aveți
flexibilitatea de a face față situațiilor în care mai multe pagini ar putea declanșa o postback pe mai multe pagini. Din
acest motiv, este de obicei mai flexibil să folosiți abordarea turnării.
După ce ați proiectat pagina anterioară la tipul de pagină corespunzător, tot nu veți putea accesa direct obiectele de
control pe care le conține. Acest lucru se datorează faptului că controalele de pe pagina web nu sunt accesibile public
altor clase. Puteți rezolva acest lucru utilizând proprietăți.
De exemplu, dacă doriți să expuneți valorile din două casete text din pagina sursă, puteți adăuga proprietăți
care încadrează variabilele de control. Iată două proprietăți pe care le puteți adăuga la clasa CrossPage1
pentru a-i expune controalele TextBox:
public TextBox FirstNameTextBox {
get { return txtFirstName; } } public
TextBox LastNameTextBox { get {
return txtLastName; } }
Cu toate acestea, aceasta nu este de obicei cea mai bună abordare. Problema este că expune prea multe detalii, oferind
paginii țintă libertatea de a citi totul, de la textul din caseta de text până la fonturile și culorile sale. Dacă trebuie să
modificați pagina mai târziu pentru a utiliza diferite controale de intrare, va fi dificil să mențineți aceste proprietăți. În
schimb, probabil că veți fi forțat să rescrieți codul în ambele pagini.
O alegere mai bună este să definiți metode sau proprietăți specifice, limitate, care extrag doar informațiile de
care aveți nevoie. De exemplu, puteți decide să adăugați o proprietate Nume complet care regăsește doar
textul din cele două casete text. Iată codul paginii complete pentru CrossPage1.aspx cu această proprietate:
263
CAPITOLUL MANAGEMENTUL DE STAT
8
public clasa parțială CrossPage1 : System.Web.UI.Page { public string FullName { get { return txtFirstName.Text + " " +
txtLastName.Text; }
}}
În acest fel, relația dintre cele două pagini este clară, simplă și ușor de întreținut. Probabil că puteți modifica
controalele din pagina sursă (CrossPage1) fără a fi nevoie să modificați alte părți ale aplicației. De exemplu,
dacă decideți să utilizați controale diferite pentru introducerea numelui în CrossPage1.aspx, veți fi obligat să
revizuiți codul pentru proprietatea NumeComplet. Cu toate acestea, modificările dvs. ar fi limitate la
CrossPage1.aspx și nu ar trebui să CrossPage2.aspx modificați deloc.
Iată cum puteți rescrie codul în CrossPage2.aspx pentru a afișa informațiile din
CrossPage1.aspx:
}
}
Observați că pagina țintă (CrossPage2.aspx) poate accesa proprietatea Title a paginii anterioare (CrossPage1.aspx) fără
a efectua nicio turnare. Acest lucru se datorează faptului că proprietatea Title este definită ca parte a clasei
System.Web.UI.Page de bază și, prin urmare, fiecare pagină web o include. Cu toate acestea, pentru a obține acces la
proprietatea FullName mai specializată, trebuie să aruncați pagina anterioară la clasa de pagini din dreapta (CrossPage1)
sau să utilizați directiva PreviousPageType discutată mai devreme.
Figura 8-5 prezintă noul rezultat.
264
CAPITOLUL 8
MANAGEMENTUL STATULUI
Notă: Postback-urile pe mai multe pagini sunt cu adevărat utile, dar pot deschide calea către pagini mai complicate.
•
Dacă permiteți mai multor pagini sursă să posteze pe aceeași pagină de destinație, depinde de dvs. să codificați logica
care determină de la ce pagină a venit utilizatorul și apoi să acționați în consecință. Pentru a evita aceste dureri de cap,
este mai ușor să efectuați postări pe mai multe pagini numai între două pagini specifice.
ASP.NET folosește o sleight interesantă pentru a face să funcționeze postback-urile pe mai multe pagini. Prima dată
când a doua pagină accesează Page.PreviousPage, ASP.NET trebuie să creeze obiectul paginii anterioare. Pentru a
face acest lucru, începe de fapt procesarea paginii, dar o întrerupe chiar înainte de etapa PreRender și nu permite
paginii să redea nicio ieșire HTML.
Cu toate acestea, acest lucru are încă unele efecte secundare interesante. De exemplu, toate evenimentele
de pagină din pagina anterioară sunt declanșate, inclusiv Page.Load și Page.Init, iar evenimentul
Button.Click se declanșează și pentru butonul care a declanșat postback-ul pe mai multe pagini. ASP.NET
declanșează aceste evenimente, deoarece ar putea fi necesare pentru a readuce pagina sursă la starea în
care a fost ultima dată, chiar înainte de a declanșa postarea pe mai multe pagini.
Șirul de interogare
O altă abordare comună este de a transmite informații utilizând un șir de interogare în adresa URL. Această
abordare este frecvent întâlnită în motoarele de căutare. De exemplu, dacă efectuați o căutare pe site-ul Google,
veți fi redirecționat(ă) la o nouă adresă URL care încorporează parametrii de căutare. Iată un exemplu:
http://www.google.ca/search?q=organic+gardening
Șirul de interogare este porțiunea URL-ului după semnul întrebării. În acest caz, definește o singură variabilă
numită q, care conține șirul organic + grădinărit.
Avantajul șirului de interogare este că este ușor și nu exercită niciun fel de sarcină asupra serverului. Cu
toate acestea, are și câteva limitări:
CAPITOLUL MANAGEMENTUL DE STAT
8
• Informațiile sunt limitate la șiruri simple, care trebuie să conțină caractere juridice URL.
• Informațiile sunt vizibile în mod clar pentru utilizator și pentru oricine
altcineva care dorește să asculte pe Internet.
• Utilizatorul întreprinzător poate decide să modifice șirul de interogare și să furnizeze
noi valori, la care programul nu se va aștepta și împotriva cărora nu se poate proteja.
• Multe browsere impun o limită a lungimii unei adrese URL (de obicei de la 1KB la
2KB). Din acest motiv, nu puteți plasa o cantitate mare de informații în șirul de
interogare și totuși să fiți sigur de compatibilitatea cu majoritatea browserelor.
Adăugarea informațiilor la șirul de interogare este încă o tehnică utilă. Este deosebit de potrivit în aplicațiile de baze
de date, unde prezentați utilizatorului o listă de elemente care corespund înregistrărilor dintr-o bază de date, cum ar
fi produsele. Utilizatorul poate apoi să selecteze un element și să fie redirecționat către o altă pagină cu informații
detaliate despre elementul selectat. O modalitate ușoară de a implementa acest design este ca prima pagină să
trimită ID-ul elementului la a doua pagină. A doua pagină caută apoi acel element în baza de date și afișează
informațiile detaliate. Veți observa această tehnică pe site-urile de comerț electronic, cum ar fi Amazon. Pentru a
stoca informații în șirul de interogare, trebuie să le plasați acolo. Din păcate, nu aveți nicio modalitate bazată pe
colectare de a face acest lucru. În schimb, va trebui să îl inserați singur în adresa URL. Iată un exemplu care
utilizează această abordare cu metoda Response.Redirect():
Accesați newpage.aspx. Remiteți un singur argument șir de interogare //
numit recordID și setați la 10.
Response.Redirect("newpage.aspx?recordID=10");
Puteți trimite mai mulți parametri atâta timp cât sunt separați cu un ampersand (&):
Pagina de primire lucrează mai ușor cu șirul de interogare. Poate primi valorile din colecția de dicționare
QueryString expuse de obiectul Solicitare încorporat:
string ID = Request.QueryString["recordID"];
Rețineți că informațiile sunt întotdeauna preluate ca un șir, care poate fi apoi convertit într-un alt tip de date
simplu. Valorile din colecția QueryString sunt indexate după numele variabilei. Dacă încercați să regăsiți o
valoare care nu este prezentă în șirul de interogare, veți obține o referință nulă.
Notă Spre deosebire de starea de vizualizare, informațiile transmise prin șirul de interogare sunt clar vizibile și necriptate. Nu utilizați șirul de interogare pentru informații care trebuie ascunse sau făcute inviolabile.
266
CAPITOLUL MANAGEMENTUL DE STAT
8
}}
267
CAPITOLUL MANAGEMENTUL DE STAT
8
șir url = "QueryStringRecipient.aspx?"; url += "Item=" + lstItems.SelectedItem.Text + "&"; url += "Mode =" +
chkDetails.Checked.ToString();
} Response.Redirect(url);
}
}
clasa publică parțială QueryStringRecipient : System.Web.UI.Page { protected void Page_Load(Object sender, EventArgs e) {
lblInfo.Text = "Item: " + Request.QueryString["Item"]; lblInfo.Text += "<br />Arată înregistrarea completă: "; } lblInfo.Text +=
Request.QueryString["Mode"]; }
Descărcați de la Wow! eBook <www.wowebook.com>
Un aspect interesant al acestui exemplu este că plasează informații în șirul de interogare care nu sunt valide,
și anume, spațiul care apare în numele elementului. Când rulați aplicația, veți observa că ASP.NET codifică
șirul pentru dvs. automat, convertind spațiile la secvența de evacuare echivalentă %20 validă. Pagina
destinatar citește valorile originale din colecția QueryString fără probleme. Această codificare automată nu
este întotdeauna suficientă. Pentru a face față caracterelor speciale, ar trebui să utilizați tehnica de codificare
URL descrisă în secțiunea următoare.
268
CAPITOLUL MANAGEMENTUL DE STAT
8
Codificare URL
O problemă potențială cu șirul de interogare este că unele caractere nu sunt permise într-o adresă URL. De fapt,
lista de caractere permise într-o adresă URL este mult mai scurtă decât lista de caractere permise într-un
document HTML. Toate caracterele trebuie să fie alfanumerice sau dintr-un set mic de caractere speciale (inclusiv
$-_.+!*'(),). Unele browsere tolerează anumite caractere speciale suplimentare (Internet Explorer este notoriu lax),
dar multe nu. În plus, unele personaje au o semnificație specială. De exemplu, semnul ampersand (&) este utilizat
pentru a separa mai mulți parametri de șir de interogare, semnul plus (+) este un mod alternativ de a reprezenta un
spațiu, iar semnul numeric (#) este utilizat pentru a indica un anumit marcaj în document dintr-o pagină web. Dacă
încercați să trimiteți valori șir de interogare care includ oricare dintre aceste caractere, veți pierde unele date. Puteți
testa acest lucru cu exemplul anterior adăugând elemente cu caractere speciale în caseta listă.
Pentru a evita problemele potențiale, este o idee bună să efectuați codificarea URL pentru valorile text înainte de a le
plasa în șirul de interogare. Cu codificarea URL, caracterele speciale sunt înlocuite cu secvențe de caractere scăpate,
începând cu semnul procentual (%), urmat de o reprezentare hexazecimală din două cifre. De exemplu, caracterul &
devine %26. Singura excepție este caracterul spațiu, care poate fi reprezentat ca secvența de caractere %20 sau semnul
+.
Pentru a efectua codificarea URL, utilizați metodele UrlEncode() și UrlDecode() din clasa HttpServerUtility.
După cum ați învățat în capitolul 5, un obiect HttpServerUtility este pus la dispoziția codului dvs. în fiecare
formular web prin proprietatea Page.Server. Următorul cod utilizează metoda UrlEncode() pentru a rescrie
exemplul anterior, deci funcționează cu nume de produse care conțin caractere speciale:
șir url = "QueryStringRecipient.aspx?"; url += "Articol =" +
Server.UrlEncode(lstItems.SelectedItem.Text) + "&"; url += "Mode =" +
chkDetails.Checked.ToString(); Response.Redirect(url);
Observați că este important să nu codificați totul. În acest exemplu, nu puteți codifica caracterul & care
unește cele două valori ale șirului de interogare, deoarece este cu adevărat un caracter special.
Puteți utiliza metoda UrlDecode() pentru a readuce un șir codificat URL la valoarea inițială. Cu toate acestea,
nu trebuie să faceți acest pas cu șirul de interogare. Acest lucru se datorează faptului că ASP.NET
decodează automat valorile atunci când le accesați prin colecția Request.QueryString. (Mulți oameni încă
mai fac greșeala de a decoda valorile șirului de interogare a doua oară. De obicei, decodarea datelor deja
decodate nu va cauza o problemă. Singura excepție este dacă aveți o valoare care include semnul +. În
acest caz, utilizarea UrlDecode() va converti semnul + într-un spațiu, ceea ce nu doriți.)
Modulele cookie
Cookie-urile oferă un alt mod în care puteți stoca informații pentru utilizare ulterioară. Cookie-urile sunt fișiere mici care
sunt create în memoria browserului web (dacă sunt temporare) sau pe hard disk-ul clientului (dacă sunt permanente). Un
avantaj al cookie-urilor este că funcționează transparent, fără ca utilizatorul să fie conștient de faptul că informațiile trebuie
stocate. De asemenea, pot fi utilizate cu ușurință de orice pagină din aplicația dvs. și chiar pot fi păstrate între vizite, ceea
ce permite stocarea cu adevărat pe termen lung. Acestea suferă de unele dintre aceleași dezavantaje care afectează
șirurile de interogare - și anume, sunt limitate la informații simple despre șiruri și sunt ușor accesibile și lizibile dacă
utilizatorul găsește și deschide fișierul corespunzător. Acești factori le fac o alegere proastă pentru informații complexe sau
private sau cantități mari de date.
Unii utilizatori dezactivează cookie-urile în browserele lor, ceea ce va cauza probleme aplicațiilor web care le solicită. De
asemenea, utilizatorii pot șterge manual fișierele cookie stocate pe hard disk-urile lor. Dar, în cea mai mare parte,
cookie-urile sunt adoptate pe scară largă și utilizate pe scară largă pe multe site-uri web.
Înainte de a putea utiliza modulele cookie, ar trebui să importați spațiul de nume System.Net, astfel încât
să puteți lucra cu ușurință cu tipurile corespunzătoare:
269
CAPITOLUL MANAGEMENTUL DE STAT
8
folosind System.Net;
Cookie-urile sunt destul de ușor de utilizat. Atât obiectele Solicitare, cât și Răspuns (care sunt furnizate prin proprietățile
Paginii) oferă o colecție de cookie-uri. Trucul important de reținut este că preluați cookie-urile din obiectul Solicitare și
setați cookie-uri folosind obiectul Răspuns.
Pentru a seta un cookie, trebuie doar să creați un nou obiect HttpCookie. Apoi îl puteți completa cu
informații despre șir (utilizând modelul familiar de dicționar) și îl puteți atașa la răspunsul web curent:
Un cookie adăugat în acest mod va persista până când utilizatorul închide browserul și va fi trimis cu
fiecare solicitare. Pentru a crea un cookie cu durată mai lungă de viață, puteți seta o dată de expirare:
{
language = cookie["LanguagePref"];
}
Singura modalitate de a elimina un cookie este înlocuirea acestuia cu un cookie care are o dată de expirare
care a trecut deja. Acest cod demonstrează tehnica:
270
CAPITOLUL MANAGEMENTUL DE STAT
8
Un exemplu de cookie
Următorul exemplu arată o utilizare tipică a cookie-urilor pentru a stoca un nume de client (Figura 8-8).
Pentru a încerca acest exemplu, începeți prin a rula pagina, a introduce un nume și a face clic pe butonul
Creare modul cookie. Apoi, închideți browserul și solicitați din nou pagina. A doua oară, pagina va găsi
cookie-ul, va citi numele și va afișa un mesaj de întâmpinare.
}}
271
CAPITOLUL MANAGEMENTUL DE STAT
8
Notă: veți descoperi că alte funcții ASP.NET utilizează cookie-uri. Două exemple sunt starea sesiunii (care vă permite să stocați temporar informații specifice utilizatorului în memoria serverului) și securitatea formularelor (care vă permite să restricționați porțiuni ale unui site web și să forțați utilizatorii să îl acceseze printr-o pagină de conectare). Capitolul 19 discută despre securitatea formularelor, iar următoarea secțiune a acestui capitol discută despre starea
sesiunii.
Starea sesiunii
Vine un moment în viața majorității aplicațiilor când încep să aibă cerințe de stocare mai sofisticate. Este posibil ca o
aplicație să trebuiască să stocheze și să acceseze informații complexe, cum ar fi obiecte de date personalizate,
care nu pot fi ușor păstrate într-un modul cookie sau trimise printr-un șir de interogare. Sau aplicația ar putea avea
cerințe stricte de securitate care o împiedică să stocheze informații despre un client în starea de vizualizare sau
într-un cookie personalizat. În aceste situații, puteți utiliza facilitatea de stare de sesiune încorporată ASP.NET.
Gestionarea stării sesiunii este una dintre caracteristicile principale ale ASP.NET. Vă permite să stocați orice tip de
date în memoria de pe server. Informațiile sunt protejate, deoarece nu sunt transmise niciodată clientului și sunt
legate în mod unic de o anumită sesiune. Fiecare client care accesează aplicația are o sesiune diferită și o colecție
distinctă de informații. Starea sesiunii este ideală pentru stocarea informațiilor, cum ar fi articolele din coșul de
cumpărături al utilizatorului curent atunci când utilizatorul navighează de la o pagină la alta.
Urmărirea sesiunii
ASP.NET urmărește fiecare sesiune utilizând un identificator unic pe 120 de biți. ASP.NET folosește un algoritm
proprietar pentru a genera această valoare, garantând astfel (statistic vorbind) că numărul este unic și este suficient de
aleatoriu încât un utilizator rău intenționat să nu poată face inginerie inversă sau să "ghicească" ce ID de sesiune va
folosi un anumit client. Acest ID este singura informație legată de sesiune care este transmisă între serverul web și
client.
Când clientul prezintă ID-ul sesiunii, ASP.NET caută sesiunea corespunzătoare, recuperează obiectele pe
care le-ați stocat anterior și le plasează într-o colecție specială, astfel încât să poată fi accesate în codul dvs.
Acest proces are loc automat.
272
CAPITOLUL MANAGEMENTUL DE STAT
8
Pentru ca acest sistem să funcționeze, clientul trebuie să prezinte ID-ul de sesiune corespunzător cu
fiecare solicitare. Puteți realiza acest lucru în două moduri:
Utilizarea cookie-urilor: În acest caz, ID-ul sesiunii este transmis într-un cookie special (numit
ASP.NET_SessionId), pe care ASP.NET îl creează automat atunci când se utilizează colecția de sesiuni.
Aceasta este valoarea implicită.
Utilizarea adreselor URL modificate: În acest caz, ID-ul sesiunii este transmis într-o adresă URL special
modificată (sau modificată). Acest lucru vă permite să creați aplicații care utilizează starea sesiunii cu
clienți care nu acceptă cookie-uri.
Starea sesiunii nu vine gratuit. Deși rezolvă multe dintre problemele asociate cu alte forme de gestionare a stării,
forțează serverul să stocheze informații suplimentare în memorie. Această cerință suplimentară de memorie, chiar dacă
este mică, poate crește rapid la niveluri care distrug performanța, pe măsură ce sute sau mii de clienți accesează site-ul.
Cu alte cuvinte, trebuie să vă gândiți la orice utilizare a stării sesiunii. O utilizare neglijentă a stării sesiunii
este unul dintre cele mai frecvente motive pentru care o aplicație web nu poate scala pentru a servi un număr
mare de clienți. Uneori, o abordare mai bună este utilizarea memorării în cache, așa cum este descris în
capitolul 23.
Starea sesiunii este globală pentru întreaga aplicație pentru utilizatorul curent. Cu toate acestea, starea
sesiunii poate fi pierdută în mai multe moduri:
• Dacă utilizatorul închide și repornește browserul.
• Dacă utilizatorul accesează aceeași pagină printr-o fereastră de browser diferită, deși
sesiunea va exista în continuare dacă o pagină web este accesată prin fereastra browserului
original. Browserele diferă în ceea ce privește modul în care gestionează această situație.
• Dacă sesiunea expiră din cauza inactivității. Mai multe informații despre expirarea
sesiunii pot fi găsite în secțiunea de configurare.
273
CAPITOLUL MANAGEMENTUL DE STAT
8
• Dacă codul paginii dvs. web încheie sesiunea apelând metoda Session.Abandon().
În primele două cazuri, sesiunea rămâne de fapt în memoria serverului web, deoarece ASP.NET nu are idee că clientul
a închis browserul sau a schimbat ferestrele. Sesiunea va rămâne în memorie, rămânând inaccesibilă, până când va
expira în cele din urmă.
Tabelul 8-1 descrie metodele și proprietățile cheie ale clasei HttpSessionState.
Membru Descriere
IsCookieless Identifică dacă sesiunea este urmărită cu un modul cookie sau cu adrese URL modificate.
IsNewSession Identifică dacă sesiunea a fost creată numai pentru solicitarea curentă. Dacă nicio
informație nu este în starea sesiunii, nu ASP.NET deranja să urmăriți sesiunea sau să
creați un cookie de sesiune. În schimb, sesiunea va fi recreată cu fiecare solicitare.
Chei Obține o colecție a tuturor cheilor de sesiune care sunt utilizate în prezent pentru a stoca
elemente în colecția de stări a sesiunii.
Mod Furnizează o valoare enumerată care explică modul în care ASP.NET stochează
informațiile despre starea sesiunii. Acest mod de stocare este determinat pe baza
setărilor web.config discutate în secțiunea "Configurare stare sesiune" din acest capitol.
ID-ul sesiunii Furnizează un șir cu identificatorul unic de sesiune pentru clientul curent.
Timeout Determină numărul de minute care vor trece înainte ca sesiunea curentă să fie
abandonată, cu condiția să nu se mai primească solicitări de la client. Această valoare
poate fi modificată programatic, permițându-vă să faceți colecția de sesiuni mai lungă
atunci când este necesar.
Abandon() Anulează imediat sesiunea curentă și eliberează toată memoria pe care a ocupat-o.
Aceasta este o tehnică utilă într-o pagină de deconectare pentru a vă asigura că
memoria serverului este recuperată cât mai repede posibil.
Clar() Elimină toate elementele sesiunii, dar nu modifică identificatorul curent al sesiunii.
274
CAPITOLUL MANAGEMENTUL DE STAT
8
}
Trei obiecte de mobilier sunt create prima dată când pagina este încărcată și sunt stocate în starea
sesiune. Utilizatorul poate alege apoi dintr-o listă de nume de piese de mobilier. Când se face o selecție,
obiectul corespunzător va fi recuperat și informațiile sale vor fi afișate, așa cum se arată în figura 8-9.
275
CAPITOLUL MANAGEMENTUL DE STAT
8
Afișați câteva informații de bază despre sesiune. Acest lucru este util
pentru testarea setărilor de configurare. lblSession.Text = "ID
sesiune: " + Session.SessionID; lblSession.Text += "<br />Număr de
obiecte: "; lblSession.Text += Session.Count.ToString();
lblSession.Text += "<br />Mode: " + Session.Mode.ToString();
lblSession.Text += "<br />este fără cookie: "; lblSession.Text +=
Session.IsCookieless.ToString(); lblSession.Text += "<br />este nou:
"; lblSession.Text += Session.IsNewSession.ToString();
lblSession.Text += "<br />Timeout (minute): "; lblSession.Text +=
Session.Timeout.ToString();
276
CAPITOLUL MANAGEMENTUL DE STAT
8
Este, de asemenea, o practică bună să adăugați câteva funcții prietenoase pentru sesiune în aplicația dvs.
De exemplu, puteți adăuga un buton de deconectare la pagină care anulează automat o sesiune utilizând
metoda Session.Abandon(). În acest fel, utilizatorul va fi încurajat să încheie sesiunea, mai degrabă decât să
închidă fereastra browserului, iar memoria serverului va fi recuperată mai repede.
Atunci când dezvoltatorii web trebuie să stocheze o cantitate mare de informații despre stat, se confruntă cu o problemă
confuză. Acestea pot utiliza starea sesiunii și pot asigura performanțe excelente pentru un set mic de utilizatori, dar riscă
o scalabilitate slabă pentru numere mari. Alternativ, aceștia pot utiliza o bază de date pentru a stoca informații temporare
despre sesiune. Acest lucru le permite să stocheze o cantitate mare de informații despre sesiune pentru o perioadă lungă
de timp (potențial săptămâni sau luni în loc de doar câteva minute). Cu toate acestea, încetinește și performanța,
deoarece baza de date trebuie interogată pentru aproape fiecare solicitare de pagină.
Compromisul implică memorarea în cache. Abordarea de bază este de a crea o înregistrare temporară a bazei de date cu
informații despre sesiune și de a stoca ID-ul său unic în starea sesiunii. Acest lucru asigură faptul că informațiile sesiunii
din memorie sunt întotdeauna minime, dar codul paginii web poate găsi cu ușurință înregistrarea corespunzătoare a
sesiunii. Pentru a reduce numărul de interogări ale bazei de date, veți adăuga, de asemenea, informațiile despre sesiune
în memoria cache (indexate sub identificatorul sesiunii). La solicitările ulterioare, codul poate verifica mai întâi informațiile
sesiunii în memoria cache. Dacă informațiile nu mai sunt în memoria cache, codul le poate prelua din baza de date ca
ultimă soluție. Acest proces devine și mai transparent dacă creați o componentă particularizată care furnizează informațiile
despre sesiune și efectuează căutarea necesară în memoria cache pentru dvs.
Pentru mai multe informații, citiți despre componentele particularizate în capitolul 22 și memorarea în cache în
capitolul 23.
277
CAPITOLUL MANAGEMENTUL DE STAT
8
</system.web> </configuration>
Următoarele secțiuni descriu cele mai importante setări ale stării sesiunii.
Fără cookie-uri
Puteți seta setarea fără module cookie la una dintre valorile definite de enumerarea HttpCookieMode, așa
cum este descris în tabelul 8-2.
Valoare Descriere
Descărcați de la Wow! eBook <www.wowebook.com>
UtilizareCookie-uri Cookie-urile sunt utilizate întotdeauna, chiar dacă browserul sau dispozitivul nu acceptă cookie-uri sau
sunt dezactivate. Aceasta este valoarea implicită. Dacă dispozitivul nu acceptă cookie-uri,
Informațiile despre sesiune se vor pierde din cauza solicitărilor ulterioare, deoarece fiecare solicitare
va primi un nou act de identitate.
UseUri Cookie-urile nu sunt utilizate niciodată, indiferent de capacitățile browserului sau dispozitivului.
În schimb, ID-ul sesiunii este stocat în adresa URL.
Detectare automată ASP.NET încearcă să determine dacă browserul acceptă cookie-uri prin:
încercarea de a seta și recupera un cookie (o tehnică utilizată în mod obișnuit pe Web).
Această tehnică poate determina corect dacă un browser acceptă cookie-uri, dar
le dezactivează, caz în care se utilizează modul fără cookie-uri.
Iată un exemplu care forțează modul fără cookie-uri (care este util pentru testare):
278
CAPITOLUL MANAGEMENTUL DE STAT
8
Deoarece ID-ul sesiunii este inserat în adresa URL curentă, linkurile relative obțin automat și ID-ul sesiunii.
Cu alte cuvinte, dacă utilizatorul este staționat în prezent pe Page1.aspx și dă clic pe un link relativ către
Page2.aspx, linkul relativ include ID-ul sesiunii curente ca parte a adresei URL. Același lucru este valabil
și dacă apelați Response.Redirect() cu o adresă URL relativă, așa cum se arată aici:
Răspuns.Redirecționare("Page2.aspx");
Figura 8-11 prezintă un exemplu de site web (inclus cu mostrele online din directorul CookielessSessions)
care testează sesiunile fără cookie-uri. Acesta conține două pagini și utilizează modul fără cookie-uri. Prima
pagină (Cookieless1.aspx) conține un control HyperLink și două butoane, toate ducându-vă la o a doua
pagină (Cookieless2.aspx). Trucul este că aceste controale au moduri diferite de a-și efectua navigarea. Doar
doi dintre ei lucrează cu sesiune fără cookie-uri - al treilea pierde sesiunea curentă.
Controlul HyperLink navighează la pagina specificată în proprietatea sa NavigateUrl, care este setată la calea
relativă Cookieless2.aspx. Dacă faceți clic pe acest link, ID-ul sesiunii este păstrat în adresa URL și noul
279
CAPITOLUL 8 MANAGEMENTUL STATULUI
Pagina poate prelua informațiile sesiunii. Acest lucru demonstrează că sesiunile fără cookie-uri funcționează cu
linkuri relative.
Cele două butoane de pe această pagină utilizează redirecționarea programatică apelând metoda
Response.Redirect(). Primul buton utilizează calea relativă Cookieless2.aspx, la fel ca controlul
HyperLink. Această abordare funcționează cu starea sesiunii fără cookie-uri și păstrează adresa URL
modificată, fără a fi necesari pași suplimentari.
protejat void cmdLink_Click(Object sender, EventArgs e) {
Response.Redirect("Cookieless2.aspx"); }
Singura limitare reală a stării fără cookie-uri este că nu puteți utiliza link-uri absolute (link-uri care includ
URL-ul complet, începând cu http://). Al doilea buton folosește o legătură absolută pentru a demonstra
această problemă. Deoarece ASP.NET nu se poate insera ID-ul sesiunii în URL, sesiunea se pierde.
vid protejat cmdLinkAbsolute_Click(Object sender, EventArgs e) {
Response.Redirect("http://localhost:56371/CookielessSessions/Cookieless2.aspx"); }
Acum, pagina țintă (Figura 8-12) verifică informațiile despre sesiune, dar nu le găsește.
Scrierea codului pentru a demonstra această problemă într-un mediu de testare este un pic dificilă. Problema este că
serverul web integrat al Visual Studio alege un port diferit pentru site-ul dvs. web de fiecare dată când îl porniți. Prin
urmare, va trebui să editați codul de fiecare dată când deschideți Visual Studio, astfel încât URL-ul să utilizeze numărul
de port corect (cum ar fi 56371 în exemplul anterior).
Există o altă soluție. Puteți utiliza un cod viclean care obține adresa URL curentă din pagină și modifică
doar ultima parte a acesteia (schimbând numele paginii din Cookieless1.aspx în Cookieless2.aspx). Iată
cum:
280
CAPITOLUL MANAGEMENTUL DE STAT
8
Creați o adresă URL nouă pe baza adresei URL actuale (dar care se
termină cu // pagina Cookieless2.aspx în loc de Cookieless1.aspx. șir
url = "http://" + Request.Url.Authority + Request.Url.Segments[0] +
Request.Url.Segments[1] + "Cookieless2.aspx";
Response.Redirect(url);
Desigur, dacă implementați site-ul dvs. web într-un director virtual real găzduit de IIS, nu veți mai utiliza un
număr de port ales aleatoriu și nu veți experimenta această ciudățenie. Capitolul 26 conține mai multe
despre directoarele virtuale și implementarea site-urilor web.
În mod implicit, ASP.NET vă permite să reutilizați un identificator de sesiune. De exemplu, dacă efectuați o
solicitare și șirul de interogare conține o sesiune expirată, ASP.NET creează o sesiune nouă și utilizează acel ID de
sesiune. Problema este că un ID de sesiune poate apărea din greșeală într-un loc public, cum ar fi într-o pagină cu
rezultate dintr-un motor de căutare. Acest lucru ar putea duce la mai mulți utilizatori care accesează serverul cu
același identificator de sesiune și apoi se alătură aceleiași sesiuni cu aceleași date partajate.
Pentru a evita acest risc potențial de securitate, ar trebui să includeți atributul opțional
regenerateExpiredSessionId și să îl setați la true ori de câte ori utilizați sesiuni fără cookie-uri. În acest
fel, un nou ID de sesiune va fi emis dacă un utilizator se conectează cu un ID de sesiune expirat.
Singurul dezavantaj este că acest proces forțează, de asemenea, pagina curentă să piardă toate
datele de stare și formular de vizualizare, deoarece ASP.NET efectuează o redirecționare pentru a vă
asigura că browserul are un nou identificator de sesiune.
Timeout
O altă setare importantă a stării sesiunii în fișierul web.config este expirarea. Aceasta specifică numărul de minute
pe care ASP.NET le va aștepta, fără a primi o solicitare, înainte de a abandona sesiunea. Această setare reprezintă
unul dintre cele mai importante compromisuri ale stării sesiunii. O diferență de minute poate avea un efect dramatic
asupra încărcării serverului și a performanței aplicației. În mod ideal, veți alege un interval de timp suficient de scurt
pentru a permite serverului să recupereze memoria valoroasă după ce un client nu mai utilizează aplicația, dar
suficient de lung pentru a permite unui client să întrerupă și să continue o sesiune fără a o pierde.
De asemenea, puteți modifica programatic expirarea sesiunii în cod. De exemplu, dacă știți că o sesiune
conține o cantitate neobișnuit de mare de informații, poate fi necesar să limitați perioada de timp în care
sesiunea poate fi stocată. Apoi avertizați utilizatorul și modificați proprietatea Expirare. Iată un exemplu de
linie de cod care modifică durata de expirare la 10 minute:
Session.Timeout = 10;
Mod
Setările de stare a sesiunii rămase vă permit să configurați ASP.NET să utilizați diferite servicii de stare a
sesiunii, în funcție de modul pe care îl alegeți. Următoarele câteva secțiuni descriu modurile din care
puteți alege.
281
CAPITOLUL MANAGEMENTUL DE STAT
8
• Notă Schimbarea modului este o activitate de configurare complexă. Pentru a face acest lucru
cu succes, trebuie să înțelegeți mediul în care va fi implementată aplicația dvs. web. De exemplu,
dacă implementați aplicația la o gazdă web terță parte, trebuie să știți dacă gazda acceptă alte
moduri înainte de a încerca să le utilizați. Dacă implementați aplicația pe un server de rețea din
propria organizație, trebuie să faceți echipă cu administratorul de rețea prietenos din vecinătate.
InProc
InProc este modul implicit și are cel mai mult sens pentru site-urile mici. Acesta instruiește ca informațiile să fie stocate în
același proces ca și firele de lucru ASP.NET, ceea ce oferă cea mai bună performanță, dar cea mai mică durabilitate.
Dacă reporniți serverul, informațiile despre stare se vor pierde. (În ASP.NET, domeniile de aplicații pot fi repornite din mai
multe motive, inclusiv modificări de configurație și pagini actualizate, precum și atunci când sunt îndeplinite anumite
praguri. Dacă descoperiți că pierdeți sesiuni înainte de limita de expirare, vă recomandăm să experimentați cu un mod
mai durabil.)
Modul InProc nu va funcționa dacă utilizați o fermă web, care este un aranjament de echilibrare a încărcării
care utilizează mai multe servere web pentru a vă rula site-ul web. În această situație, diferite servere web
pot gestiona solicitări consecutive de la același utilizator. Dacă serverele web utilizează modul InProc, fiecare
va avea propria colecție privată de date de sesiune. Rezultatul final este că utilizatorii își vor pierde în mod
neașteptat sesiunile atunci când călătoresc pe o pagină nouă sau o postează înapoi pe cea curentă.
Notă utilizați modurile StateServer și SQLServer, obiectele pe care le stocați în starea sesiune
• Când
trebuie să fie serializabile. În caz contrar, ASP.NET nu va putea transmite obiectul serviciului de
stat sau nu îl va putea stoca în baza de date. Mai devreme în acest capitol, ați învățat cum să
creați o clasă de clienți serializabilă pentru stocarea în starea de vizualizare.
Off
Această setare dezactivează gestionarea stării sesiunii pentru fiecare pagină din aplicație. Acest lucru
poate oferi o ușoară îmbunătățire a performanței pentru site-urile web care nu utilizează starea sesiunii.
Server de stare
Cu această setare, ASP.NET va utiliza un serviciu Windows separat pentru gestionarea stării. Acest serviciu rulează pe
același server web, dar este în afara procesului principal de ASP.NET, ceea ce îi conferă un nivel de bază de protecție
dacă procesul de ASP.NET trebuie repornit. Costul este întârzierea crescută impusă atunci când informațiile de stat
sunt transferate între două procese. Dacă accesați și modificați frecvent informațiile de stare, acest lucru poate duce la
o încetinire destul de nedorită.
Când utilizați setarea StateServer, trebuie să specificați o valoare pentru setarea stateConnectionString.
Acest șir identifică adresa TCP/IP a computerului care execută serviciul StateServer și numărul său de port
(care este definit de ASP.NET și de obicei nu trebuie modificat). Acest lucru vă permite să găzduiți
StateServer pe un alt computer. Dacă nu modificați această setare, se va utiliza serverul local (setat ca
adresă 127.0.0.1).
282
CAPITOLUL MANAGEMENTUL DE STAT
8
Desigur, înainte ca aplicația dvs. să poată utiliza serviciul, trebuie să îl porniți. Cel mai simplu mod de a face
acest lucru este să utilizați Microsoft Management Console (MMC). Iată cum:
1. Selectați Start Control Panel.
2. Deschideți grupul Instrumente administrative, apoi alegeți Computer
Management.
3. În instrumentul Computer Management, accesați Servicii și aplicații
Nod de servicii. →
4. Găsiți serviciul numit Serviciul ASP.NET Stat în listă, așa cum se arată în
figura 8-13.
5. După ce găsiți serviciul în listă, îl puteți porni și opri manual făcând clic dreapta
pe el. În general, veți dori să configurați Windows pentru a porni automat
serviciul. Faceți clic dreapta pe el, selectați Proprietăți și modificați Tipul de
pornire, setându-l la Automat, așa cum se arată în Figura 8-14.
283
CAPITOLUL MANAGEMENTUL DE STAT
8
Notă
Când utilizați modul StateServer, puteți seta, de asemenea, un atribut opțional stateNetworkTimeout care specifică numărul maxim de secunde pentru a aștepta ca serviciul să răspundă înainte de a anula solicitarea. Valoarea implicită este 10 (secunde).
284
CAPITOLUL 8
MANAGEMENTUL STATULUI
SQLServer
Această setare instruiește ASP.NET să utilizați o bază de date SQL Server pentru a stoca informații despre sesiune,
așa cum sunt identificate prin atributul sqlConnectionString. Acesta este cel mai rezistent magazin de stat, dar și cel
mai lent de departe. Pentru a utiliza această metodă de gestionare a stării, va trebui să aveți un server cu SQL Server
instalat.
Când setați atributul sqlConnectionString, urmați același tip de model pe care îl utilizați cu ADO.NET acces la
date. În general, va trebui să specificați o sursă de date (adresa serverului) și un ID de utilizator și o parolă, cu
excepția cazului în care utilizați securitatea integrată SQL.
În plus, trebuie să instalați procedurile speciale stocate și bazele de date temporare de sesiune. Aceste proceduri stocate se
ocupă de stocarea și recuperarea informațiilor despre sesiune. ASP.NET include un instrument de linie de comandă care
face treaba automat pentru dvs., numit aspnet_regsql.exe. Se găsește în directorul
c:\Windows\Microsoft.NET\Framework\[Version] (unde [Version] este versiunea curentă de .NET, cum ar fi v4.0.30319). Cel
mai simplu mod de a rula aspnet_regsql.exe este să începeți prin lansarea promptului de comandă Visual Studio (deschideți
meniul Start și alegeți Programe → Visual Visual Studio 2010
→
Instrumente de studio Visual Studio linie de comandă). Apoi puteți introduce o comandă aspnet_regsql.exe,
→
indiferent în ce director vă aflați.
Puteți utiliza instrumentul aspnet_regsql.exe pentru a efectua mai multe activități legate de baza de date. Pe măsură
ce parcurgeți această carte, veți vedea cum să utilizați aspnet_regsql.exe cu funcții ASP.NET, cum ar fi calitatea de
membru (capitolul 20), profilurile (capitolul 21) și memorarea în cache (capitolul 23). Pentru a utiliza
aspnet_regsql.exe pentru a crea o bază de date de stocare a sesiunilor, furnizați parametrul –ssadd. În plus, utilizați
parametrul –S pentru a indica numele serverului bazei de date și parametrul –E pentru a vă conecta la baza de
date utilizând contul de utilizator Windows conectat în prezent.
Iată o comandă care creează baza de date de stocare a sesiunilor pe computerul curent, utilizând
numele implicit al bazei de date ASPState:
aspnet_regsql.exe -S localhost -E –ssadd
Această comandă utilizează aliasul localhost, care aspnet_regsql.exe spune să se conecteze la serverul
bazei de date de pe computerul curent.
Notă
Comanda aspnet_regsql.exe acceptă opțiuni suplimentare care vă permit să stocați informații despre sesiune într-o bază de date cu un nume diferit. Puteți afla despre aceste opțiuni consultând ajutorul Visual Studio (căutați aspnet_regsql în index) sau navigând la http://msdn2.microsoft.com/library/ms178586.aspx. Aceste informații descriu, de asemenea, pașii suplimentari pe care trebuie să îi efectuați pentru a utiliza stocarea sesiunii susținute de baza de date cu SQL Server Express.
După ce ați creat baza de date cu starea sesiunii, trebuie să ASP.NET spuneți să o utilizați modificând
secțiunea <sessionState> a fișierului web.config. Dacă utilizați o bază de date numită ASPState pentru a
stoca informațiile despre sesiune (care este implicit), nu este necesar să furnizați numele bazei de date. În
schimb, trebuie pur și simplu să indicați locația serverului și tipul de autentificare pe care ASP.NET trebui
să îl utilizați pentru a vă conecta la acesta, așa cum se arată aici:
<sessionState mode="SQLServer" sqlConnectionString="data
source=127.0.0.1; Securitate integrată = SSPI" ... />
CAPITOLUL MANAGEMENTUL DE STAT
8
Când utilizați modul SQLServer, puteți seta, de asemenea, un atribut opțional sqlCommandTimeout care
specifică numărul maxim de secunde pentru a aștepta ca baza de date să răspundă înainte de a anula
solicitarea. Valoarea implicită este de 30 de secunde.
Obicei
Când utilizați modul personalizat, trebuie să indicați ce furnizor de magazin de stare de sesiune să utilizați,
furnizând atributul customProvider. Atributul customProvider indică numele clasei. Clasa poate face parte din
aplicația dvs. web (caz în care codul sursă este plasat în subfolderul App_Code) sau poate fi într-un ansamblu pe
care îl utilizează aplicația dvs. web (caz în care ansamblul compilat este plasat în subfolderul Coș).
Crearea unui furnizor de stare particularizată este o activitate de nivel scăzut care trebuie gestionată cu atenție pentru a
asigura securitatea, stabilitatea și scalabilitatea. Furnizorii de stat vamal sunt, de asemenea, dincolo de domeniul de aplicare
al acestei cărți. Cu toate acestea, alți furnizori pot lansa furnizori de stare particularizați pe care doriți să îi utilizați. De exemplu,
Oracle ar putea furniza un furnizor de stare particularizat care vă permite să stocați informații despre stare într-o bază de date
Oracle.
Comprimare
Când setați enableCompression la true, datele sesiunii sunt comprimate înainte de a fi eliminate din proces. Setarea
enableCompression are un efect numai atunci când utilizați stocarea stării sesiunii în afara procesului, deoarece numai
în această situație datele sunt serializate.
Pentru a comprima și decomprima datele sesiunii, serverul web trebuie să efectueze lucrări suplimentare. Cu
toate acestea, aceasta nu este de obicei o problemă, deoarece compresia este utilizată în scenarii în care
serverele web au mult timp la CPU, dar sunt limitate de alți factori. Există două scenarii cheie în care
compresia stării sesiunii are sens:
Când stocați cantități uriașe de date despre starea sesiunii în memorie: Memoria serverului web este o resursă
prețioasă. În mod ideal, starea sesiunii este utilizată pentru bucăți relativ mici de informații, în timp ce o bază de date
se ocupă de stocarea pe termen lung a unor cantități mai mari de date. Dar dacă nu este cazul și dacă serverul de
stare în afara procesului consumă cantități uriașe de memorie, compresia este o soluție potențială.
Când stocați date despre starea sesiunii pe un alt computer: În unele aplicații web la scară largă, starea
sesiunii este stocată în afara procesului (de obicei în SQL Server) și pe un computer separat. Drept
urmare, ASP.NET trebuie să transmită informațiile sesiunii înainte și înapoi printr-o conexiune de rețea.
În mod clar, acest design reduce performanța față de vitezele pe care le veți vedea atunci când starea
sesiunii este stocată pe computerul serverului web. Cu toate acestea, este încă cel mai bun compromis
pentru unele aplicații web puternic traficate, cu nevoi uriașe de stocare a stării sesiunii.
Cantitatea reală de compresie variază foarte mult în funcție de tipul de date, dar în testarea Microsoft
clienții au obținut reduceri de dimensiune de 30% până la 60%, ceea ce este suficient pentru a
îmbunătăți performanța în aceste scenarii specializate.
Starea cererii
Starea aplicației vă permite să stocați obiecte globale care pot fi accesate de orice client. Starea aplicației se bazează
pe clasa System.Web.HttpApplicationState, care este furnizată în toate paginile web prin obiectul aplicației încorporat.
Starea aplicației este similară cu starea sesiunii. Suportă același tip de obiecte, păstrează informații pe server și
286
CAPITOLUL MANAGEMENTUL DE STAT
8
utilizează aceeași sintaxă bazată pe dicționar. Un exemplu comun cu starea aplicației este un contor
global care urmărește de câte ori a fost efectuată o operațiune de către toți clienții aplicației web.
De exemplu, puteți crea o rutină de tratare a evenimentelor global.asax care urmărește câte sesiuni au fost
create sau câte solicitări au fost primite în aplicație. Sau puteți utiliza o logică similară în rutina de tratare a
evenimentelor Page.Load pentru a urmări de câte ori o anumită pagină a fost solicitată de diverși clienți. Iată
un exemplu al acestuia din urmă:
vid protejat Page_Load(Object sender, EventArgs e) { // Regăsiți contravaloarea curentă.
Incrementați contorul.
număr++;
Încă o dată, elementele de stare a aplicației sunt stocate ca obiecte, deci trebuie să le aruncați atunci când le recuperați
din colecție. Elementele în starea aplicației nu expiră niciodată. Acestea durează până când aplicația sau serverul este
repornit sau domeniul aplicației se reîmprospătează singur (din cauza setărilor automate de reciclare a proceselor sau a
unei actualizări a uneia dintre paginile sau componentele din aplicație). Starea aplicației nu este adesea utilizată,
deoarece este în general ineficientă. În exemplul anterior, contorul nu ar ține probabil o numărătoare exactă, în special în
perioadele de trafic intens. De exemplu, dacă doi clienți au solicitat pagina în același timp, ați putea avea o secvență de
evenimente ca aceasta:
1. Utilizatorul A recuperează numărul curent (432).
2. Utilizatorul B recuperează numărul curent (432).
3. Utilizatorul A setează numărul curent la 433.
4. Utilizatorul B setează numărul curent la 433.
Cu alte cuvinte, o cerere nu este contorizată, deoarece doi clienți accesează contorul în același timp.
Pentru a preveni această problemă, trebuie să utilizați metodele Lock() și Unlock(), care permit în mod
explicit unui singur client să acceseze colecția de stări a aplicației la un moment dat.
protejat void Page_Load(Object sender, EventArgs e) {
287
CAPITOLUL MANAGEMENTUL DE STAT
8
Din păcate, toți ceilalți clienți care solicită pagina vor fi blocați până la lansarea colecției de aplicații. Acest
lucru poate reduce drastic performanța. În general, valorile modificate frecvent sunt candidați slabi pentru
starea aplicației. De fapt, starea aplicației este rar utilizată în lumea .NET, deoarece cele două utilizări cele
mai frecvente au fost înlocuite cu metode mai ușoare și mai eficiente:
• În trecut, starea aplicației era utilizată pentru a stoca constante la nivel de aplicație, cum
ar fi un șir de conexiune la baza de date. După cum ați văzut în capitolul 5, acest tip de
constantă poate fi stocat în fișierul web.config, care este în general mai flexibil, deoarece îl
puteți schimba cu ușurință fără a fi nevoie să căutați prin codul paginii web sau să vă
recompilați aplicația.
• Starea aplicației poate fi, de asemenea, utilizată pentru a stoca informații utilizate
Descărcați de la Wow! eBook <www.wowebook.com>
frecvent, a căror creare necesită mult timp, cum ar fi un catalog complet de produse
care necesită o căutare în baza de date. Cu toate acestea, utilizarea stării aplicației
pentru a stoca acest tip de informații ridică tot felul de probleme cu privire la modul de
verificare a validității datelor și la modul de înlocuire a acestora atunci când este
necesar. De asemenea, poate împiedica performanța dacă catalogul de produse este
prea mare. Capitolul 23 introduce o abordare similară, dar mult mai sensibilă –
stocarea informațiilor utilizate frecvent în memoria cache a ASP.NET. Multe utilizări ale
stării aplicației pot fi înlocuite mai eficient cu memorarea în cache.
Sfat
Dacă decideți să utilizați starea aplicației, puteți inițializa conținutul acesteia la prima pornire a aplicației. Doar adăugați codul de inițializare la fișierul global.asax într-o metodă numită Application_OnStart(), așa cum este descris în capitolul 5.
288
CAPITOLUL MANAGEMENTUL DE STAT
8
Tipuri de date Toate tipurile de date O cantitate limitată de date Date șir.
permise .NET serializabile. șir.
Generație Păstrat permanent pentru Pierdut când utilizatorul intră Set de programator.
postback-uri pe o singură o nouă adresă URL sau Poate fi folosit în mai
pagină. închide browserul. Cu toate multe pagini și poate
acestea, acest lucru poate
persista între vizite.
fi stocat într-un marcaj.
289
CAPITOLUL MANAGEMENTUL DE STAT
8
Tipuri de date Toate tipurile de date .NET pentru modul Toate tipurile de date .NET.
permise implicit de stocare în proces. Toate tipurile
de date .NET serializabile dacă utilizați un
mod de stocare în afara procesului.
Implicații Lent atunci când stocați o cantitate mare de Încetiniți atunci când stocați o cantitate
asupra informații, mai ales dacă există mai mulți mare de informații, deoarece aceste date
performanței utilizatori simultan, deoarece fiecare utilizator nu vor expira niciodată și nu vor fi
va avea propria copie a datelor sesiunii. eliminate.
Utilizare tipică Depozitarea articolelor într-un coș de cumpărături. Stocarea oricărui tip de date globale.
Rețineți ASP.NET are un alt tip mai specializat de management de stat numit profiluri. Profilurile vă permit să stocați și să preluați informații specifice utilizatorului dintr-o bază de date. Singura captură este că trebuie să autentificați utilizatorul pentru a obține informațiile corecte. Veți afla despre profiluri în capitolul 21.
Ultimul cuvânt
Managementul de stat este arta păstrării informațiilor între cereri. De obicei, aceste informații sunt specifice
utilizatorului (cum ar fi o listă de articole dintr-un coș de cumpărături, un nume de utilizator sau un nivel de
acces), dar uneori sunt globale pentru întreaga aplicație (cum ar fi statisticile de utilizare care urmăresc
activitatea site-ului). Deoarece ASP.NET utilizează o arhitectură deconectată, trebuie să stocați și să preluați
în mod explicit informații de stare cu fiecare solicitare. Abordarea pe care o alegeți pentru a stoca aceste date
poate afecta dramatic performanța, scalabilitatea și securitatea aplicației dvs. Nu uitați să consultați tabelul
8-3 și tabelul 8-4 pentru a vă ajuta să evaluați diferite tipuri de management de stat și să determinați ce este
mai bine pentru nevoile dvs.
290
PART3
• ■■
• ■■
Validare
Acest capitol analizează unele dintre cele mai utile controale care sunt incluse în ASP.NET: controalele de validare.
Aceste controale preiau o sarcină complicată și consumatoare de timp, care necesita mult timp – verificarea erorilor
introduse și de raportare de către utilizatori – și o automatizează cu o colecție elegantă și ușor de utilizat de validatori.
Fiecare validator are propria logică încorporată. Unii verifică datele lipsă, alții verifică dacă numerele se încadrează
într-un interval predefinit și așa mai departe. În multe cazuri, controalele de validare vă permit să verificați datele
introduse de utilizator fără a scrie o linie de cod.
În acest capitol, veți învăța cum să utilizați controalele de validare într-o pagină web ASP.NET și cum să
profitați la maximum de ele cu expresii regulate sofisticate, funcții de validare personalizate și multe altele. Și,
ca de obicei, veți privi sub capotă pentru a vedea cum ASP.NET implementează aceste caracteristici.
Înțelegerea validării
În calitate de dezvoltator experimentat, probabil că vă dați seama că utilizatorii vor face greșeli. Ceea ce este
deosebit de descurajant este gama de posibile greșeli pe care utilizatorii le pot face. Iată câteva exemple comune:
• Utilizatorii pot ignora un câmp important și îl pot lăsa necompletat.
• Utilizatorii ar putea încerca să tasteze un șir scurt de prostii pentru a eluda o verificare
de teren necesară, creând astfel dureri de cap nesfârșite la sfârșitul dvs. De exemplu,
este posibil să rămâneți blocat cu o adresă de poștă electronică nevalidă care cauzează
probleme programului automat de poștă electronică.
• Utilizatorii ar putea face o greșeală onestă, cum ar fi introducerea unei erori de tastare,
introducerea unui caracter nenumeric într-un câmp numeric sau trimiterea unui tip greșit
de informații. Acestea ar putea chiar să introducă mai multe informații care sunt corecte
individual, dar atunci când sunt luate împreună sunt inconsecvente (de exemplu,
introducerea unui număr MasterCard după alegerea Visa ca tip de plată).
• Utilizatorii rău intenționați ar putea încerca să exploateze o slăbiciune a codului dvs.
introducând valori greșite atent structurate. De exemplu, ar putea încerca să provoace o
eroare specifică care va dezvălui informații sensibile. Un exemplu mai dramatic al acestei
tehnici este atacul de injecție SQL, în care valorile furnizate de utilizator modifică
funcționarea unei comenzi de bază de date construite dinamic. (Desigur, validarea nu este
o apărare pentru codificarea slabă. Când luați în considerare programarea bazelor de date
în capitolul 14, veți învăța cum să utilizați comenzi parametrizate, care evită cu totul
pericolul atacurilor de injecție SQL.)
O aplicație web este deosebit de susceptibilă la aceste probleme, deoarece se bazează pe controale de intrare HTML de
bază care nu au toate caracteristicile omologilor lor Windows. De exemplu, o tehnică obișnuită într-o aplicație Windows este
293
CAPITOLUL VALIDARE
9
de a gestiona evenimentul KeyPress al unei casete text, de a verifica dacă caracterul curent este valid și de a împiedica
apariția acestuia dacă nu este. Această tehnică facilitează crearea unei casete de text care acceptă numai intrare numerică.
Această strategie nu este la fel de ușoară într-o pagină web de pe server. Pentru a efectua validarea pe serverul web,
trebuie să postați pagina înapoi și pur și simplu nu este practic să postați pagina înapoi pe server de fiecare dată când
utilizatorul introduce o scrisoare. Pentru a evita acest tip de problemă, trebuie să efectuați toate validările simultan atunci
când este trimisă o pagină (care poate conține mai multe controale de intrare). Apoi, trebuie să creați interfața de
utilizator adecvată pentru a raporta greșelile. Unele site-uri web raportează doar primul câmp incorect, în timp ce altele
utilizează un tabel, o listă sau o fereastră pentru a le descrie pe toate. Până când vă perfecționați strategia de validare,
veți fi petrecut o cantitate considerabilă de efort scriind cod plictisitor.
ASP.NET își propune să vă scutească de această problemă și să vă ofere un cadru reutilizabil de controale
de validare care gestionează detaliile de validare verificând câmpurile și raportând automat erorile. Aceste
controale pot utiliza chiar JavaScript din partea clientului pentru a oferi o interfață mai dinamică și mai
receptivă, oferind în același timp validarea obișnuită pentru browserele mai vechi (adesea denumite
browsere de nivel inferior ).
Controalele de validare
ASP.NET oferă cinci controale validatoare, care sunt descrise în tabelul 9-1. Patru vizează anumite tipuri de
validare, în timp ce al cincilea vă permite să aplicați rutine de validare personalizate. De asemenea, veți
vedea un control ValidationSummary în Toolbox, care vă oferă o altă opțiune pentru afișarea unei liste de
mesaje de eroare de validare într-un singur loc. Veți afla despre ValidationSummary mai târziu în acest
capitol (consultați secțiunea "Alte opțiuni de afișare").
Tabelul 9-1. Controale validator
CompareValidator Validarea reușește dacă controlul de intrare conține o valoare care se potrivește
valoarea dintr-un alt control de intrare sau o valoare fixă specificată.
Fiecare control de validare poate fi legat la un singur control de intrare. În plus, puteți aplica mai multe controale de
validare aceluiași control de intrare pentru a furniza mai multe tipuri de validare.
Dacă utilizați RangeValidator, CompareValidator sau RegularExpressionValidator, validarea va reuși
automat dacă controlul de intrare este gol, deoarece nu există nicio valoare de validat. Dacă nu acesta este
comportamentul dorit, ar trebui să adăugați și un RequiredFieldValidator și să îl legați la același control de
intrare. Acest lucru asigură efectuarea a două tipuri de validare, restricționând în mod eficient valorile
necompletate.
294
CAPITOLUL VALIDARE
9
Notă Multe alte controale asemănătoare butoanelor care pot fi utilizate pentru a remite pagina furnizează, de asemenea, proprietatea CausesValidation. Exemplele includ LinkButton, ImageButton și BulletedList. (Din punct de vedere tehnic, proprietatea CausesValidation este definită de interfața IButtonControl, pe care o implementează toate controalele asemănătoare butoanelor.)
Controalele de validare
Controalele de validare se găsesc în spațiul de nume System.Web.UI.WebControls și moștenesc de la clasa
BaseValidator. Această clasă definește funcționalitatea de bază pentru un control de validare. Tabelul 9-2
descrie proprietățile sale cheie.
295
CAPITOLUL VALIDARE
9
Proprietate Descriere
ControlToValidate Identifică controlul pe care acest validator îl va verifica. Fiecare validator poate verifica
valoare într-un control de intrare. Cu toate acestea, este perfect rezonabil să "stivuiți"
validatori - cu alte cuvinte, atașați mai mulți validatori la un control de intrare la
Efectuați mai multe tipuri de verificare a erorilor.
ErrorMessage și Dacă validarea eșuează, controlul validatorului poate afișa un mesaj text (setat de butonul
ForeColor Proprietatea ErrorMessage). Prin schimbarea ForeColor, puteți face acest lucru
Mesajul iese în evidență cu litere roșii furioase. (În versiunile anterioare ale ASP.NET,
Controalele de validare utilizau în mod implicit litere roșii. Dar dacă creați un nou
Pentru ASP.NET 4, mesajele de validare vor folosi negru obișnuit
text, cu excepția cazului în care setați proprietatea ForeColor sau utilizați stiluri CSS în pagina dvs.)
IsValid După efectuarea validării, aceasta returnează true sau false, în funcție de faptul dacă
a reușit sau a eșuat. În general, veți verifica starea întregii pagini
uitându-se în schimb la proprietatea IsValid pentru a afla dacă toate controalele de validare
Reuşit.
Activat Când este setat la fals, validarea automată nu va fi efectuată pentru acest control
când pagina este trimisă.
EnableClientScript Dacă este setat la true, ASP.NET va adăuga cod JavaScript și DHTML pentru a permite partea clientului
validarea pe browserele care o acceptă.
Când utilizați un control de validare, singurele proprietăți pe care trebuie să le implementați sunt
ControlToValidate și ErrorMessage. În plus, poate fi necesar să implementați proprietățile utilizate pentru
validatorul dvs. Tabelul 9-3 prezintă aceste proprietăți.
296
CAPITOLUL VALIDARE
9
RegularExpressionValidator ValidationExpression
Mai târziu în acest capitol (în secțiunea "Un formular de client validat"), veți vedea un exemplu de
formular de client care demonstrează fiecare tip de validare.
297
CAPITOLUL VALIDARE
9
În plus, plasați un control Etichetă în partea de jos a formularului. Această etichetă va raporta când pagina a fost postată
înapoi și codul de gestionare a evenimentelor a fost executat. Dezactivați proprietatea EnableViewState pentru a vă
asigura că va fi ștearsă de fiecare dată când pagina este postată înapoi.
Marcajul pentru această pagină definește un control RangeValidator, setează mesajul de eroare, identifică
controlul care va fi validat și necesită un număr întreg de la 1 la 10. Aceste proprietăți sunt setate în fișierul
.aspx, dar pot fi configurate și în rutina de tratare a evenimentelor pentru evenimentul Page.Load. Butonul
are automat proprietatea CauseValidation setată la true, deoarece aceasta este valoarea implicită.
Un număr (de la 1 la 10): <asp:TextBox
id="txtValidated" runat="server" />
<asp:RangeValidator id="RangeValidator" runat="server" ErrorMessage="Acest număr nu este în interval"
ControlToValidate ="txtValidated" MaximumValue="10" MinimumValue="1" ForeColor="Red" font-bold="true" type="integer" />
<br /><br /> Nevalidat: <asp:TextBox id="txtNotValidated" runat="server" /><br /><br /> <asp:Button id="cmdOK" runat="server"
text="OK" OnClick="cmdOK_Click" /> <br /><br /> <asp: Label id="lblMessage" runat="server" EnableViewState="False" />
Descărcați de la Wow! eBook <www.wowebook.com>
Nu toate browserele vor accepta validarea pe partea clientului. Pentru a vedea ce se va întâmpla într-un browser de
nivel inferior, setați proprietatea RangeValidator.EnableClientScript la false și executați din nou pagina. Acum,
mesajele de eroare nu vor apărea dinamic pe măsură ce schimbați focalizarea. Cu toate acestea, când faceți clic pe
butonul OK, pagina va fi returnată de pe server cu mesajul de eroare corespunzător afișat lângă controlul nevalid.
Problema potențială în acest scenariu este că codul de tratare a evenimentelor de clic se va executa în
continuare, chiar dacă pagina este nevalidă. Pentru a corecta această problemă și pentru a te asigura că
pagina ta se comportă la fel în browserele moderne și mai vechi, trebuie să anulezi codul evenimentului
dacă validarea nu a fost efectuată cu succes.
298
CAPITOLUL VALIDARE
9
Acest cod rezolvă problema curentă, dar nu este de mare ajutor dacă pagina conține mai multe controale de
validare. Din fericire, fiecare formular web oferă propria proprietate IsValid. Această proprietate va fi falsă
dacă vreun control de validare nu a reușit. Va fi adevărat dacă toate controalele de validare s-au finalizat cu
succes. Dacă validarea nu a fost efectuată (de exemplu, dacă controalele de validare sunt dezactivate sau
dacă butonul are CausesValidation setat la false), veți primi o excepție Http atunci când încercați să citiți
proprietatea IsValid.
protected void cmdOK_Click(Object sender, EventArgs e) { // Anulați
evenimentul dacă orice control de pe pagină este nevalid. dacă (!
Page.IsValid) returnare;
Amintiți-vă, validarea pe partea clientului este doar o glazură frumoasă deasupra aplicației dvs.
Validarea pe partea de server va fi întotdeauna efectuată, asigurându-se că utilizatorii vicleni nu pot
"falsifica" paginile.
299
CAPITOLUL VALIDARE
9
Când ValidationSummary afișează lista de erori, regăsește automat valoarea proprietății ErrorMessage de la
fiecare validator. În unele cazuri, veți dori să afișați un mesaj complet în rezumat și un fel de indicator vizual
lângă controlul contravenient. De exemplu, multe site-uri web utilizează o pictogramă de eroare sau un
asterisc pentru a evidenția casetele de text cu intrare nevalidă. Puteți utiliza această tehnică cu ajutorul
proprietății Text a validatorilor. De obicei, textul este lăsat gol, iar validatorul nu afișează niciun conținut în
pagina web. Cu toate acestea, dacă setați atât Text cât și ErrorMessage, valoarea ErrorMessage va fi utilizată
pentru rezumat în timp ce valoarea Text este afișată în validator. (Desigur, va trebui să vă asigurați că nu
setați și proprietatea Afișare a validatorului la Fără, care ascunde complet validatorul - și conținutul acestuia.)
Iată un exemplu de validator care include un mesaj de eroare detaliat (care va apărea în
ValidationSummary) și un indicator asterisc (care va apărea în validator, lângă controlul care are
problema):
<asp:RangeValidator id="RangeValidator" runat="server"
text="*" errormessage="primul număr nu este în interval" ControlToValidate="txtValidated"
MaximumValue="10" minimumValue="1" type="integer" />
Dacă aveți mult text, este posibil să preferați să îl imbricați în interiorul elementului
<asp:RangeValidator>. De exemplu, puteți rescrie marcajul afișat mai devreme cu aceasta:
300
CAPITOLUL VALIDARE
9
Aici, ASP.NET extrage automat codul HTML din interiorul elementului <asp:RangeValidator> și îl utilizează pentru
a seta proprietatea RangeValidator.Text.
Puteți obține chiar și un pic mai fantezist înlocuind asteriscul simplu cu un fragment de HTML mai
interesant. Iată un exemplu care utilizează eticheta <img> pentru a adăuga o mică imagine pictogramă
de eroare atunci când validarea nu reușește:
<asp:RangeValidator id="RangeValidator" runat="server"> <img
src="ErrorIcon.gif" alt="Error"> </asp:RangeValidator>
Controlul ValidationSummary oferă câteva proprietăți utile pe care le puteți utiliza pentru a regla fin afișarea erorilor.
Puteți seta proprietatea HeaderText să afișeze un titlu special în partea de sus a listei (cum ar fi Pagina dvs. conține
următoarele erori:). De asemenea, puteți schimba ForeColor și puteți alege un DisplayMode. Modurile posibile sunt
BulletList (implicit), List și SingleParagraf.
În cele din urmă, puteți alege ca rezumatul validării să fie afișat într-o casetă de dialog pop-up în loc de pagină (a
se vedea Figura 9-3). Această abordare are avantajul de a lăsa interfața cu utilizatorul a paginii neatinsă, dar obligă
utilizatorul să respingă mesajele de eroare închizând fereastra înainte de a putea modifica controalele de intrare.
Dacă utilizatorii vor trebui să se refere la aceste mesaje în timp ce repară pagina, afișarea în linie este mai bună.
Pentru a afișa rezumatul într-o casetă de dialog, setați proprietatea ShowMessageBox a ValidationSummary
la true. Rețineți că, dacă nu setați proprietatea ShowSummary la false, veți vedea atât caseta de mesaj, cât
și rezumatul din pagină (ca în Figura 9-4).
301
CAPITOLUL VALIDARE
9
Validare manuală
Opțiunea finală este să dezactivați validarea și să efectuați lucrările pe cont propriu, cu ajutorul controalelor de validare.
Acest lucru vă permite să luați în considerare alte informații sau să creați un mesaj de eroare specializat care implică
alte controale (cum ar fi imagini sau butoane).
Puteți crea validarea manuală într-unul din următoarele trei moduri:
• Utilizați propriul cod pentru a verifica valorile. În acest caz, nu veți utiliza niciunul
dintre controalele de validare ASP.NET.
• Dezactivați proprietatea EnableClientScript pentru fiecare control de validare. Acest
lucru permite trimiterea unei pagini nevalide, după care puteți decide ce să faceți cu ea
în funcție de problemele care pot exista.
• Adăugați un buton cu CausesValidation setat la false. Când faceți clic pe acest
buton, validați manual pagina apelând metoda Page.Validate(). Apoi examinați
proprietatea IsValid și decideți ce să faceți.
Următorul exemplu folosește a doua abordare. Odată ce pagina este trimisă, examinează toate controalele
de validare de pe pagină prin buclă prin colecția Page.Validators. De fiecare dată când găsește un control
care nu a fost validat cu succes, preia valoarea nevalidă din controlul de intrare și o adaugă la un șir. La
sfârșitul acestei rutine, afișează un mesaj care descrie ce valori au fost incorecte, așa cum se arată în Figura
9-5.
302
CAPITOLUL VALIDARE
9
Această tehnică adaugă o caracteristică care nu ar fi disponibilă cu validarea automată, care utilizează
proprietatea ErrorMessage. În acest caz, nu este posibil să includeți valorile incorecte reale în mesaj.
Pentru a încerca acest exemplu, setați proprietatea EnableCientScript a fiecărui validator la false. Apoi,
puteți utiliza codul din această rutină de tratare a evenimentelor pentru a verifica dacă există valori nevalide.
303
CAPITOLUL VALIDARE
9
Acest exemplu utilizează o tehnică avansată: metoda Page.FindControl(). Este necesar deoarece proprietatea
ControlToValidate a fiecărui validator furnizează pur și simplu un șir cu numele unui control, nu o referință la
obiectul de control real. Pentru a găsi controlul care se potrivește cu acest nume (și a-i regăsi proprietatea
Text), trebuie să utilizați metoda FindControl(). Odată ce codul a recuperat caseta de text potrivită, acesta
poate efectua alte sarcini, cum ar fi ștergerea valorii curente, modificarea unei proprietăți sau chiar
schimbarea culorii casetei de text. Rețineți că metoda FindControl() returnează o referință generică Control,
deoarece este posibil să căutați în orice tip de control. Pentru a accesa toate proprietățile controlului dvs.,
trebuie să îl proiectați la tipul corespunzător (cum ar fi TextBox în acest exemplu).
Sfat În acest exemplu, codul găsește fiecare validator și citește proprietatea ErrorMessage. Cu toate acestea, puteți seta, de asemenea, proprietatea ErrorMessage în acest moment, care vă permite să creați mesaje de eroare particularizate care încorporează informații despre valorile nevalide în textul lor.
Literale și metacaractere
Toate expresiile regulate constau din două tipuri de caractere: literale și metacaractere. Literalele nu sunt
diferite de literalele șir pe care le tastați în cod. Ele reprezintă un caracter specific definit. De exemplu,
dacă căutați șirul literal "l", veți găsi caracterul l și nimic altceva. Metacaracterele oferă adevăratul secret
pentru deblocarea întregii puteri a expresiilor regulate. Probabil că sunteți deja familiarizați cu două
metapersonaje din lumea DOS (? și *). Luați în considerare expresia de linie de comandă afișată aici:
Del*.*
Expresia *.* conține un literal (punctul) și două metacaractere (asteriscurile). Acest lucru se traduce prin
"ștergeți fiecare fișier care începe cu orice număr de caractere și se termină cu o extensie de orice număr
de caractere (sau nu are nicio extensie)". Deoarece toate fișierele din DOS au implicit extensii, acest lucru
are efectul bine documentat de a șterge totul din directorul curent. Un alt metacaracter DOS este semnul
întrebării, ceea ce înseamnă "orice caracter unic". De exemplu, următoarea declarație șterge orice fișier
numit salut care are o extensie de exact un caracter.
304
CAPITOLUL VALIDARE
9
Bună ziua.?
Limbajul de expresie regulat oferă multe metacaractere flexibile - mult mai multe decât linia de comandă
DOS. De exemplu, \s reprezintă orice caracter spațiu alb (cum ar fi un spațiu sau o filă). \d reprezintă orice
cifră. Astfel, următoarea expresie s-ar potrivi cu orice șir care a început cu numerele 333, urmat de un
singur caracter spațiu alb și oricare trei numere. Meciurile valide ar include 333, 333 și 333 945, dar nu
334, 333 sau 3334 945.
333\s\d\d\d
Un aspect care poate face expresiile regulate mai puțin lizibile este că folosesc metacaractere speciale care au mai mult
de un caracter. În exemplul anterior, \s reprezintă un singur caracter, la fel ca \d, chiar dacă ambele ocupă două
caractere în expresie.
Puteți utiliza semnul plus (+) pentru a reprezenta un caracter repetat. De exemplu, 5+7 înseamnă "una sau mai
multe apariții ale caracterului 5, urmate de un singur 7". Numărul 57 s-ar potrivi, la fel și 555557. De asemenea,
puteți utiliza paranteze pentru a grupa o subexpresie. De exemplu, (52)+7 s-ar potrivi cu orice șir care începe cu o
secvență de 52. Meciurile ar include 527, 52527, 5252527 și așa mai departe. De asemenea, puteți delimita un
interval de caractere utilizând paranteze pătrate. [a-f] s-ar potrivi cu orice caracter de la A la F (numai minuscule).
Următoarea expresie s-ar potrivi cu orice cuvânt care începe cu o literă de la a la f, conține unul sau mai multe
caractere "cuvânt" (litere) și se termină cu ing - potrivirile posibile includ actoria și dezvoltarea.
[a-f]\w+ing
Următoarea este o expresie regulată mai utilă care se poate potrivi cu orice adresă de e-mail, verificând dacă
conține simbolul @. Punctul este un metacaracter folosit pentru a indica orice caracter, cu excepția liniei noi.
Totuși, unele adrese de poștă electronică nevalide vor fi permise în continuare, inclusiv cele care conțin spații și
cele care nu includ un punct (.). Veți vedea un exemplu mai bun puțin mai târziu în exemplul formularului de client.
.+@.+
305
CAPITOLUL VALIDARE
9
Codul este destul de simplu. Butonul Setare expresie atribuie o nouă expresie regulată controlului
RegularExpressionValidator (utilizând orice text pe care l-ați tastat). Butonul Validare declanșează pur și
simplu o postback, ceea ce face ca ASP.NET să efectueze automat validarea. Dacă apare un mesaj de
eroare, validarea nu a reușit. În caz contrar, are succes.
public parțial clasa RegularExpressionTest : System.Web.UI.Page
{
protejat void cmdSetExpression_Click(Object sender, EventArgs e) { TestValidator.ValidationExpression =
txtExpression.Text; lblExpression.Text = "Expresia curentă: "; } lblExpression.Text += txtExpression.Text;
Tabelul 9-4 prezintă câteva dintre blocurile fundamentale de expresie regulată. Dacă trebuie să potriviți un
caracter literal cu același nume ca un caracter special, îl precedați în general cu un caracter \. De exemplu,
\*hello\* se potrivește cu *hello* într-un șir, deoarece caracterul asterisc special (*) este precedat de o bară
oblică (\).
306
CAPITOLUL VALIDARE
9
Caracter Descriere
* Zero sau mai multe apariții ale caracterului sau subexpresiei anterioare. De exemplu, 7*8
se potrivește cu 7778 sau doar 8.
+ Una sau mai multe apariții ale caracterului sau subexpresiei anterioare. De exemplu, 7+8
se potrivește cu 7778, dar nu cu 8.
{m,n} Caracterul anterior (sau subexpresia) poate apărea de la m la n ori. De exemplu, A{1,3}
se potrivește cu A, AA sau AAA.
[] Potrivește un caracter dintr-un interval de caractere valide. De exemplu, [A-C] se potrivește cu A, B sau
C.
. Orice caracter, cu excepția liniei noi. De exemplu, .here se potrivește unde și acolo.
\W Orice caracter care nu este un caracter "cuvânt" (literă, număr sau caracter de subliniere).
307
CAPITOLUL 9 VALIDAREA
Adresa de e-mail* \S+@\S+\.\S+ Verificați dacă există un semn at (@) și un punct (.)
și permiteți numai caractere care nu sunt spații
albe.
Parolă \w+ Orice secvență de unul sau mai multe caractere de
cuvinte (literă, spațiu sau subliniere).
Parolă cu \w{4,10} O parolă care trebuie să aibă cel puțin patru caractere, dar
lungime specifică nu mai mult de zece caractere.
O altă parolă [a-zA-Z]\w*\d+\w* Această parolă începe cu un caracter de literă, urmat de zero
avansată sau mai multe caractere de cuvinte, una sau mai multe cifre,
apoi zero sau mai multe caractere de cuvinte. Pe scurt,
forțează o parolă să conțină unul sau mai multe numere
undeva în interiorul acesteia. Puteți utiliza un model similar
pentru a solicita două numere sau orice alt caracter special.
Numărul de \d{3}-\d{2}-\d{4} O secvență de trei, două, apoi patru cifre, fiecare grup fiind
securitate socială separat printr-o liniuță. Puteți utiliza un model similar atunci
din SUA când solicitați un număr de telefon.
* Aveți multe modalități diferite de a valida adresele de e-mail cu expresii regulate de complexitate variabilă. Vezi
http://www.4guysfromrolla.com/webtech/validateemail.shtml pentru o discuție despre subiect și numeroase exemple.
Unele logici sunt mult mai dificil de modelat într-o expresie regulată. Un exemplu este algoritmul Luhn, care
verifică numerele cardurilor de credit dublând mai întâi fiecare a doua cifră, apoi adăugând aceste cifre
dublate împreună și, în final, împărțind suma la zece. Numărul este valid (deși nu este neapărat conectat la
un cont real) dacă nu există rest după împărțirea sumei. Pentru a utiliza algoritmul Luhn, aveți nevoie de un
control CustomValidator care rulează această logică pe valoarea furnizată. (Puteți găsi o descriere detaliată
a algoritmului Luhn la http://en.wikipedia.org/wiki/Luhn_formula.)
308
CAPITOLUL VALIDARE
9
309
CAPITOLUL VALIDARE
9
Formularul oferă două butoane de validare - unul care necesită validare și unul care permite utilizatorului să
anuleze activitatea cu grație:
{
lblMessage.Text = "Acesta este un formular valid.";
}}
Singurul cod la nivel de formular necesar pentru validare este codul de validare particularizat. Validarea are
loc în rutina de tratare a evenimentelor pentru evenimentul CustomValidator.ServerValidate. Această metodă
primește valoarea de care are nevoie pentru validare (e.Value) și setează rezultatul validării la true sau false
(e.IsValid).
310
CAPITOLUL VALIDARE
9
e.IsValid = adevărat; }
altceva {
e.IsValid = fals;
}}
e. = fals;
Acest exemplu introduce, de asemenea, un detaliu nou: tratarea erorilor. Acest cod de tratare a erorilor
asigură că problemele potențiale sunt detectate și tratate în mod corespunzător. Fără gestionarea erorilor,
codul dvs. poate eșua, lăsând utilizatorul cu nimic mai mult decât o pagină de eroare criptică. Motivul pentru
care acest exemplu necesită cod de gestionare a erorilor se datorează faptului că efectuează doi pași care
nu sunt garantați să reușească. Mai întâi, metoda Int32.Parse() încearcă să convertească datele din caseta
text într-un întreg. În timpul acestui pas va apărea o eroare dacă informațiile din caseta de text nu sunt
numerice (de exemplu, dacă utilizatorul a introdus caracterele 4G). În mod similar, metoda String.Substring(),
care extrage primele trei caractere, va eșua dacă apar mai puțin de trei caractere în caseta text. Pentru a vă
proteja împotriva acestor probleme, aveți posibilitatea să verificați în mod specific aceste detalii înainte de a
încerca să utilizați metodele Parse() și Substring() sau puteți utiliza tratarea erorilor pentru a răspunde la
probleme după ce apar. (O altă opțiune este să utilizați metoda TryParse(), care returnează o valoare
booleană care vă spune dacă conversia a reușit. Ați văzut TryParse () la lucru în capitolul 5.)
Sfat
În unele cazuri, este posibil să puteți înlocui validarea personalizată cu o utilizare deosebit de ingenioasă a unei expresii regulate. Cu toate acestea, puteți utiliza validarea particularizată pentru a vă asigura că codul de validare este executat numai la server. Acest lucru împiedică utilizatorii să vadă șablonul dvs. de expresie obișnuită (în codul JavaScript redat) și să îl folosească pentru a determina modul în care vă pot depăși rutina de validare. De exemplu, este posibil ca un utilizator să nu aibă un număr valid de card de credit, dar dacă cunoaște
algoritmul pe care îl utilizați pentru a testa numerele cărților de credit, poate crea unul fals mai ușor.
CustomValidator are o altă ciudățenie. Veți observa că validarea personalizată pe partea de server nu este efectuată
până când pagina nu este postată înapoi. Aceasta înseamnă că, dacă activați codul scriptului client (implicit), vor apărea
mesaje dinamice care informează utilizatorul atunci când celelalte valori sunt incorecte, dar nu vor indica nicio problemă
311
CAPITOLUL VALIDARE
9
cu codul de recomandare până când pagina nu este postată înapoi pe server. Aceasta nu este într-adevăr o problemă,
dar dacă vă deranjează, puteți utiliza proprietatea CustomValidator.ClientValidationFunction. Adăugați o funcție
JavaScript pe partea client la porțiunea .aspx a paginii web. Amintiți-vă, nu puteți utiliza codul ASP.NET pe partea
clientului, deoarece C# și VB nu sunt recunoscute de browserul client.
Funcția JavaScript va accepta doi parametri (în stil adevărat .NET), care identifică sursa evenimentului și parametrii
suplimentari de validare. De fapt, evenimentul de partea client este modelat pe evenimentul .NET ServerValidate. La fel
cum ați făcut în rutina de tratare a evenimentelor ServerValidate, în funcția de validare client, regăsiți valoarea de validat
din proprietatea Value a obiectului argument eveniment. Apoi setați proprietatea IsValid pentru a indica dacă validarea
reușește sau nu reușește.
Următorul este echivalentul pe partea client pentru codul din rutina de tratare a evenimentelor
ServerValide. Codul JavaScript seamănă superficial cu C#.
<script type="text/javascript">
<!--
funcția MyCustomValidation(objSource, objArgs)
{
Obțineți valoare.
numărul var = objArgs.Value;
}
--> </scenariu>
După ce ați adăugat funcția script de validare, trebuie să setați proprietatea ClientValidationFunction a
controlului CustomValidator la numele funcției. Aveți posibilitatea să editați manual eticheta CustomValidator
sau să utilizați fereastra Proprietăți din Visual Studio.
<asp:CustomValidator id="vldCode" runat="server"
ErrorMessage="Încercați un șir care începe cu 014."
ControlToValidate="txtCode"
OnServerValidate="vldCode_ServerValidate"
ClientValidationFunction="MyCustomValidation" />
ASP.NET va apela acum această funcție în numele dvs. atunci când este necesar.
Sfat: Chiar și atunci când utilizați validarea pe partea client, trebuie să includeți în continuare rutina de tratare a evenimentelor ServerValide, atât pentru a oferi validare pe partea de server pentru clienții care nu acceptă caracteristicile JavaScript și DHTML necesare, cât și pentru a împiedica clienții să vă eludeze validarea modificând pagina HTML pe care o primesc.
312
CAPITOLUL VALIDARE
9
În mod implicit, validarea personalizată nu se efectuează pentru valori goale. Cu toate acestea, aveți
posibilitatea să modificați acest comportament setând proprietatea CustomValidator.ValidateEmptyText la
true. Aceasta este o abordare utilă dacă creați o funcție JavaScript mai detaliată (de exemplu, una care se
actualizează cu informații suplimentare) și doriți ca aceasta să ruleze atunci când textul este șters.
Grupuri de validare
În paginile mai complexe, este posibil să aveți mai multe grupuri distincte de controale, posibil în panouri separate. În
aceste situații, poate doriți să efectuați validarea separat. De exemplu, puteți crea un formular care include o casetă cu
controale de conectare și o casetă dedesubt cu comenzile pentru înregistrarea unui utilizator nou. Fiecare casetă include
propriul buton de trimitere și, în funcție de butonul pe care faceți clic, doriți să efectuați validarea doar pentru acea
secțiune a paginii.
Acest scenariu este posibil datorită unei caracteristici numite grupuri de validare. Pentru a crea un grup de validare,
trebuie să puneți controalele de intrare, validatorii și controalele butonului CausesValidation în același grup logic. Faceți
acest lucru setând proprietatea ValidationGroup a fiecărui control cu același șir descriptiv (cum ar fi "LoginGroup" sau
"NewUserGroup"). Fiecare control care furnizează o proprietate CausesValidation include și proprietatea
ValidationGroup.
De exemplu, pagina următoare definește două grupuri de validare, denumite Grup1 și Grup2. Controalele
pentru fiecare grup sunt plasate în controale separate ale panoului.
Dacă faceți clic pe butonul din panoul cel mai de sus, numai prima casetă de text este validată. Dacă
faceți clic pe butonul din al doilea panou, numai a doua casetă de text este validată (așa cum se arată
în Figura 9-8).
313
CAPITOLUL VALIDARE
9
Ce se întâmplă dacă adăugați un buton nou care nu specifică niciun grup de validare? În acest caz, butonul
validează fiecare control care nu este atribuit în mod explicit unui grup de validare numit. În exemplul curent,
niciun control nu corespunde cerinței, astfel încât pagina este postată înapoi cu succes și considerată validă.
Dacă doriți să vă asigurați că un control este întotdeauna validat, indiferent de grupul de validare al butonului
pe care se face clic, va trebui să creați mai mulți validatori pentru control, câte unul pentru fiecare grup (și
unul fără grup de validare).
Ultimul cuvânt
În acest capitol, ați învățat cum să utilizați una dintre cele mai practice caracteristici ale ASP.NET: validarea.
Ați văzut cum ASP.NET combină validarea pe partea serverului și pe partea clientului pentru a asigura
securitatea antiglonț fără a sacrifica gradul de utilizare a paginilor dvs. web. De asemenea, ați analizat tipurile
de validare furnizate de diferitele controale de validare și chiar ați perfecționat sintaxa puternică de potrivire a
modelelor utilizată pentru expresiile regulate. În cele din urmă, v-ați gândit cum să personalizați și să extindeți
procesul de validare pentru a gestiona câteva scenarii diferite.
314
C A P I T O L U L 10
•■■
Controale bogate
Controalele îmbogățite sunt controale web care modelează elemente complexe de interfață cu utilizatorul. Deși nu există
o definiție strictă pentru ceea ce este și ceea ce nu este un control bogat, termenul descrie în mod obișnuit un control
web care are un model de obiect distinct separat de HTML-ul pe care îl generează. Un control bogat tipic poate fi
programat ca un singur obiect (și adăugat la o pagină web cu o singură etichetă de control), dar se redă folosind o
secvență complexă de elemente HTML. Controalele îmbogățite pot, de asemenea, să reacționeze la acțiunile
utilizatorului (cum ar fi un clic de mouse pe o anumită regiune a controlului) și să genereze evenimente mai
semnificative la care codul dvs. poate răspunde pe serverul web. Cu alte cuvinte, controalele bogate vă oferă o
modalitate de a crea interfețe de utilizator avansate în paginile dvs. web fără a scrie linii de HTML complicat.
În acest capitol, veți arunca o privire asupra mai multor controale web care nu au echivalent direct în lumea
HTML obișnuit. Veți începe cu Calendarul, care oferă funcționalitate elegantă de selectare a datei. Apoi, veți
lua în considerare AdRotator, care vă oferă o modalitate ușoară de a insera o imagine selectată aleatoriu
într-o pagină web. În cele din urmă, veți învăța cum să creați pagini sofisticate cu mai multe vizualizări
utilizând două controale avansate ale containerului: MultiView și Wizard. Aceste controale vă permit să
împachetați o aplicație miniaturală într-o singură pagină. Folosindu-le, puteți gestiona o sarcină în mai mulți
pași fără a redirecționa utilizatorul de la o pagină la alta.
Notă
ASP.NET include numeroase controale bogate care sunt discutate în altă parte în această carte, inclusiv controale de listă bazate pe date, controale de securitate și controale adaptate pentru portalurile web. În acest capitol, vă veți concentra pe câteva controale web utile care nu se încadrează perfect în niciuna dintre aceste categorii. Toate aceste controale apar în fila Standard din Visual Studio Toolbox.
Calendarul
Controlul Calendar prezintă un calendar miniatural pe care îl puteți plasa în orice pagină web. La fel ca
majoritatea controalelor bogate, calendarul poate fi programat ca un singur obiect (și definit într-o singură
etichetă simplă), dar se redă cu zeci de linii de ieșire HTML.
<asp:Calendar id="MyCalendar" runat="server" />
Controlul Calendar prezintă o vizualizare pentru o singură lună, așa cum se arată în Figura 10-1. Utilizatorul poate naviga
de la o lună la alta folosind săgețile de navigare, moment în care pagina este postată înapoi și ASP.NET furnizează
315
CAPITOLUL CONTROALE BOGATE
10
automat o pagină nouă cu valorile corecte ale lunii. Nu trebuie să scrieți niciun cod suplimentar de gestionare a
evenimentelor pentru a gestiona acest proces. Când utilizatorul face clic pe o dată, data devine evidențiată într-o
casetă gri (implicit). Puteți regăsi ziua selectată în cod ca obiect DateTime din proprietatea Calendar.SelectedDate.
Acest set de caracteristici de bază vă poate oferi tot ce aveți nevoie în aplicația dvs. Alternativ, puteți configura diferite
moduri de selecție pentru a permite utilizatorilor să selecteze săptămâni sau luni întregi sau să redea controlul ca un
calendar static care nu permite selecția. Singurul fapt pe care trebuie să-l amintiți este că, dacă permiteți selectarea lunii,
utilizatorul poate selecta și o singură săptămână sau o zi. În mod similar, dacă permiteți selectarea săptămânii,
utilizatorul poate selecta și o singură zi.
Setați tipul de selecție prin proprietatea Calendar.SelectionMode. De asemenea, poate fi necesar să setați
proprietatea Calendar.FirstDayOfWeek pentru a configura modul în care este selectată o săptămână. (De exemplu,
setați FirstDayOfWeek la valoarea enumerată duminică, iar săptămânile vor fi selectate de duminică până sâmbătă.)
Când permiteți selectarea mai multor date, trebuie să examinați proprietatea SelectedDates, care oferă o
colecție a tuturor datelor selectate. Puteți parcurge în buclă această colecție folosind sintaxa foreach.
Următorul cod demonstrează această tehnică:
lblDates.Text = "Ați selectat aceste date:<br />";
316
CAPITOLUL CONTROALE BOGATE
10
Formatarea calendarului
Controlul Calendar furnizează o serie întreagă de proprietăți legate de formatare. Puteți seta diverse părți ale
calendarului, cum ar fi antetul, selectorul și diverse tipuri de zile, utilizând una dintre proprietățile stilului (de
exemplu, WeekendDayStyle). Fiecare dintre aceste proprietăți de stil face referire la un obiect TableItemStyle
cu caracteristici complete, care furnizează proprietăți pentru colorare, stil bordură, font și aliniere. Luate
împreună, acestea vă permit să modificați aproape orice parte a aspectului calendarului. Tabelul 10-1
listează proprietățile de stil furnizate de controlul Calendar.
Tabelul 10-1. Proprietăți pentru stilurile de calendar
Membru Descriere
DayHeaderStyle Stilul pentru secțiunea din Calendar care afișează zilele săptămânii (ca
anteturi de coloană).
Stil de zi Stilul implicit pentru datele din luna curentă.
NextPrevStyle Stilul pentru controalele de navigare din secțiunea titlu care se mută de la o
lună la alta.
317
CAPITOLUL CONTROALE BOGATE
10
Membru Descriere
OtherMonthDayStyle Stilul pentru datele care nu se află în luna afișată curent. Acești
Datele sunt folosite pentru a "completa" grila calendarului. De exemplu, primele câteva celule din
Rândul cel mai de sus poate afișa ultimele zile din luna anterioară.
Puteți ajusta fiecare stil utilizând fereastra Proprietăți. Pentru o comandă rapidă rapidă, puteți seta o întreagă schemă de
Descărcați de la Wow! eBook <www.wowebook.com>
culori asociată utilizând funcția Format automat a calendarului. Pentru a face acest lucru, începeți prin selectarea
Calendarului pe suprafața de proiectare a unui formular web. Apoi, faceți clic pe pictograma săgeată care apare lângă
colțul din dreapta sus pentru a afișa eticheta inteligentă a calendarului și faceți clic pe linkul Formatare automată. Vi se
va prezenta o listă de formate predefinite care setează proprietățile stilului, așa cum se arată în Figura 10-3.
318
CAPITOLUL CONTROALE BOGATE
10
De asemenea, puteți utiliza proprietăți suplimentare pentru a ascunde unele elemente sau pentru a configura
textul afișat de acestea. De exemplu, proprietățile care încep cu "Afișare" (cum ar fi ShowDayHeader,
ShowTitle și ShowGridLines) pot fi utilizate pentru a ascunde sau a afișa un anumit element vizual.
Proprietățile care se termină în "Text" (cum ar fi PrevMonthText, NextMonthText și SelectWeekText) vă
permit să setați textul afișat într-o parte a calendarului.
Restricționarea datelor
În majoritatea situațiilor în care trebuie să utilizați un calendar pentru selecție, nu doriți să permiteți utilizatorului să
selecteze nicio dată din calendar. De exemplu, utilizatorul poate rezerva o rezervare sau poate alege o dată de livrare -
două servicii care sunt furnizate în general numai în zile stabilite. Controlul Calendar face surprinzător de ușoară
implementarea acestei logici. De fapt, dacă ați lucrat cu controalele de dată și oră de pe platforma Windows, veți
recunoaște rapid că versiunile ASP.NET sunt mult superioare. Abordarea de bază pentru restricționarea datelor este de a
scrie un handler de evenimente pentru evenimentul Calendar.DayRender. Acest eveniment apare atunci când controlul
Calendar este pe cale să creeze o lună pentru a se afișa utilizatorului. Acest eveniment vă oferă șansa de a examina
data care este adăugată la luna curentă (prin proprietatea e.Day) și de a decide dacă ar trebui să fie selectabilă sau
restricționată.
Următorul cod face imposibilă selectarea zilelor de weekend sau a zilelor din anii mai mari decât 2012:
Obiectul e.Day este o instanță a clasei CalendarDay, care oferă diverse proprietăți. Tabelul 10-2 descrie
unele dintre cele mai utile.
Proprietate Descriere
IsWeekend Adevărat dacă această dată cade într-o sâmbătă sau duminică.
IsOtherMonth True dacă această dată nu aparține lunii curente, dar este afișată pentru a completa
primul sau ultimul rând. De exemplu, aceasta poate fi ultima zi a lunii anterioare sau
următoarea zi a lunii următoare.
319
CAPITOLUL CONTROALE BOGATE
10
Evenimentul DayRender este extrem de puternic. Pe lângă faptul că vă permite să personalizați ce date sunt selectabile,
vă permite, de asemenea, să configurați celula în care se află data prin proprietatea e.Cell. (Calendarul este afișat
utilizând un tabel HTML.) De exemplu, puteți evidenția o dată importantă sau chiar adăuga informații. Iată un exemplu
care evidențiază o singură zi – a cincea mai – adăugând
a nou control Etichetă în celula de tabel pentru ziua respectivă:
e.Cell.Controls.Add(lbl);
}
}
320
CAPITOLUL CONTROALE BOGATE
10
Următorul cod demonstrează această abordare, utilizând un set diferit de valori de timp dacă este selectată
o zi de luni în calendar decât pentru alte zile:
}
Pentru a încerca aceste caracteristici ale controlului Calendar, rulați pagina Appointment.aspx din eșantioanele
online. Această pagină oferă un control Calendar formatat care restricționează unele date, formatează altele în
mod special și actualizează un control de listă corespunzător atunci când se modifică selecția.
Tabelul 10-3 vă oferă o privire dintr-o privire asupra aproape tuturor membrilor clasei de control Calendar.
Membru Descriere
Subtitrare și Vă oferă o modalitate ușoară de a adăuga un titlu la calendar. În mod prestabilit, legenda
legendăAliniere apare în partea de sus a zonei de titlu, chiar deasupra titlului lunii. Cu toate acestea,
puteți controla acest lucru într-o oarecare măsură cu proprietatea CaptionAlign. Utilizați
Stânga sau Dreapta pentru a păstra legenda în partea de sus, dar mutați-o într-o parte
sau alta și utilizați Partea de jos pentru a plasa legenda sub calendar.
Căptușeală celulară ASP.NET creează o dată într-o celulă separată a unui tabel invizibil. CellPadding
este spațiul, în pixeli, dintre marginea fiecărei celule și conținutul acesteia.
DayNameFormat Stabilește modul de afișare a zilelor în antetul calendarului. Valorile valide sunt
Full (ca în Sunday), FirstLetter (S), FirstTwoLetters (Su) și Short (Sun), care este
implicit.
321
CAPITOLUL CONTROALE BOGATE
10
Membru Descriere
Prima zia săptămânii Stabilește ce zi este afișată în prima coloană a calendarului. Valorile sunt orice
nume de zi din enumerarea FirstDayOfWeek (cum ar fi Sunday). În mod
implicit, aceasta este duminică.
NextMonthText și Setează textul pe care utilizatorul face clic pentru a trece la luna următoare sau
PrevMonthText anterioară. Aceste linkuri de navigare apar în partea de sus a calendarului și sunt
semnele mai mari decât (>) și mai mici (<) în mod implicit. Această setare se
aplică numai dacă NextPrevFormat este setat la CustomText.
NextPrevFormat Setează textul pe care utilizatorul face clic pentru a trece la luna următoare sau
anterioară. Aceasta poate fi FullMonth (de exemplu, decembrie), ShortMonth
(decembrie) sau CustomText, caz în care sunt utilizate proprietățile
NextMonthText și PrevMonthText. CustomText este implicit.
SelectedDate și Setează sau obține data selectată curent ca obiect DateTime. Puteți specifica
SelectedDates acest lucru în eticheta de control într-un format ca acesta: "12:00:00 AM,
12/31/2010" (în funcție de setările regionale ale computerului). Dacă permiteți
selectarea mai multor date, proprietatea SelectedDates va returna o colecție de
obiecte DateTime, câte unul pentru fiecare dată selectată. Puteți utiliza metode
de colectare, cum ar fi Adăugare, Eliminare și Golire pentru a modifica selecția.
Modul de selecție Stabilește câte date pot fi selectate simultan. Valoarea implicită este Zi, care
permite selectarea unei date. Alte opțiuni includ DayWeek (o singură dată sau o
săptămână întreagă) sau DayWeekMonth (o singură dată, o săptămână întreagă
sau o lună întreagă). Nu aveți nicio modalitate de a permite utilizatorului să
selecteze mai multe date necontigue. De asemenea, nu aveți nicio modalitate
de a permite selecții mai mari fără a include și selecții mai mici. (De exemplu,
dacă permiteți selectarea lunilor întregi, trebuie să permiteți, de asemenea,
selectarea săptămânii și selectarea individuală a zilei.)
SelectMonthText și Textul afișat pentru linkul care permite utilizatorului să selecteze o lună sau o
SelectWeekText săptămână întreagă. Aceste proprietăți nu se aplică dacă SelectionMode este Day.
ShowDayHeader, Aceste proprietăți booleene vă permit să configurați dacă sunt afișate diferite
ShowGridLines, părți ale calendarului, inclusiv titlurile zilelor, liniile de grilă dintre fiecare zi,
ShowNextPrevMonth linkurile de navigare anterioare/luna următoare și secțiunea titlu. Rețineți că
și ShowTitle ascunderea secțiunii titlu ascunde, de asemenea, comenzile de navigare din
luna următoare și din luna anterioară.
TitleFormat Configurează modul în care este afișată luna în zona de titlu. Valorile valide
includ Month și MonthYear (valoarea implicită).
VisibleDate Obține sau setează data care specifică luna care va fi afișată în calendar. Acest
lucru vă permite să modificați afișarea calendarului fără a modifica selecția
curentă a datei.
322
CAPITOLUL 10
CONTROALE COMPLEXE
Membru Descriere
Evenimentul DayRender Apare o dată pentru fiecare zi creată și adăugată la luna vizibilă în prezent
înainte de redarea paginii. Acest eveniment vă oferă posibilitatea de a aplica
formatare specială, de a adăuga conținut sau de a restricționa selecția pentru o
celulă de dată individuală. Reține că zilele pot apărea în calendar chiar și atunci
când nu cad în luna curentă, cu condiția să cadă aproape de sfârșitul lunii
anterioare sau aproape de începutul lunii următoare.
SelecțieEveniment Apare atunci când utilizatorul selectează o zi, o săptămână sau o lună întreagă
modificat făcând clic pe controalele selectorului de dată.
Eveniment Apare atunci când utilizatorul face clic pe controalele de navigare din luna
VisibleMonthChanged următoare sau din luna anterioară pentru a trece la altă lună.
AdRotatorul
Scopul de bază al AdRotator este de a oferi un grafic pe o pagină care este aleasă aleatoriu dintr-un grup
de imagini posibile. Cu alte cuvinte, de fiecare dată când pagina este solicitată, o imagine este selectată la
întâmplare și afișată, care este "rotația" indicată de numele AdRotator. O utilizare a AdRotator este de a
afișa reclame în stil banner pe o pagină, dar îl puteți utiliza oricând doriți să variați o imagine aleatoriu.
Folosind ASP.NET, nu ar fi prea dificil să implementați un tip de design AdRotator pe cont propriu. Puteți
reacționa la evenimentul Page.Load, puteți genera un număr aleatoriu și apoi puteți utiliza acel număr
pentru a alege dintr-o listă de fișiere imagine predeterminate. Puteți chiar să stocați lista în fișierul
web.config, astfel încât să poată fi ușor modificată separat ca parte a configurației aplicației. Desigur, dacă
doriți să activați mai multe pagini cu o imagine aleatorie, va trebui fie să repetați codul, fie să creați propriul
control personalizat. AdRotator oferă aceste funcții gratuit.
Fișierul publicitar
AdRotator stochează lista sa de fișiere imagine într-un fișier XML. Acest fișier utilizează formatul afișat aici:
1 <Cuvânt-cheie>Computer</Cuvânt-cheie>
</Anunț> </Reclame>
CAPITOLUL CONTROALE BOGATE
10
Sfat: După cum veți vedea în capitolul 18, un fișier XML este doar un fișier text cu etichete specifice (așa cum se arată anterior). Puteți crea un fișier XML utilizând nimic mai mult decât un editor de text, cum ar fi Notepad, dar puteți utiliza și editorul de text Visual Studio. Doar selectați site-ul web
•
→ Adăugare element nou din meniu și selectați Fișier XML. Depinde de dvs. să completați
etichetele și conținutul potrivit. Puteți plasa fișierul de anunțuri oriunde doriți, fie în folderul
principal al site-ului web, fie într-un subfolder pe care l-ați creat.
Acest exemplu arată o singură reclamă posibilă, pe care controlul AdRotator o alege la întâmplare din lista de
reclame. Pentru a adăuga mai multe reclame, trebuie să creați mai multe elemente <Ad> și să le plasați pe
toate în interiorul elementului rădăcină <Reclame>:
<Reclame> <Anunț> <!--
Primul anunț aici. --> </Ad>
Fiecare element <Ad> are o serie de alte proprietăți importante care configurează legătura, imaginea și
frecvența, așa cum este descris în tabelul 10-4.
Element Descriere
ImageUrl Imaginea care va fi afișată. Acesta poate fi un link relativ (un fișier din directorul
curent) sau o adresă URL de internet complet calificată.
NavigateUrl Linkul care va fi urmat dacă utilizatorul face clic pe banner. Aceasta poate fi o adresă
URL relativă sau complet calificată.
Text alternativ Textul care va fi afișat în locul imaginii, dacă nu poate fi afișat. Acest text va fi, de
asemenea, utilizat ca sfat ecran în unele browsere mai noi.
Impresii Un număr care stabilește cât de des va apărea o reclamă. Acest număr este relativ la
numerele specificate pentru alte anunțuri. De exemplu, un banner cu valoarea 10 va fi
afișat de două ori mai des (în medie) decât bannerul cu valoarea 5.
Cuvânt cheie Un cuvânt cheie care identifică un grup de anunțuri. Puteți utiliza acest lucru pentru
filtrare. De exemplu, puteți crea zece anunțuri și puteți da jumătate dintre ele cuvântul
cheie Retail și cealaltă jumătate cuvântul cheie Computer. Pagina web poate alege
apoi să filtreze anunțurile posibile pentru a include doar unul dintre aceste grupuri.
324
CAPITOLUL CONTROALE BOGATE
10
Clasa AdRotator
Clasa AdRotator actuală oferă un set limitat de proprietăți. Specificați atât fișierul de publicitate
corespunzător în proprietatea AdvertisementFile, cât și tipul de fereastră pe care linkul ar trebui să o
urmeze (fereastra țintă). Ținta poate denumi un anumit cadru sau poate utiliza una dintre valorile
definite în tabelul 10-5.
Tabelul 10-5. Obiective cadru special
Scop Descriere
_culme Legătura se deschide în cadrul cel mai de sus al ferestrei curente (astfel încât legătura apare în
fereastră completă).
Opțional, puteți seta proprietatea KeywordFilter astfel încât bannerul să fie ales dintr-un anumit grup
de cuvinte cheie. Aceasta este o etichetă AdRotator complet configurată:
Notă
Atributul target nu este permis în XHTML strict. Dacă decideți să-l utilizați, asigurați-vă că utilizați XHTML 1.0 doctype de tranziție, așa cum este descris în capitolul 4. (Acesta este doctype implicit pentru paginile web noi pe care le creați în Visual Studio.)
În plus, puteți reacționa la evenimentul AdRotator.AdCreated. Acest lucru se întâmplă atunci când pagina
este creată și o imagine este aleasă aleatoriu din fișierul de anunțuri. Acest eveniment vă oferă informații
despre imaginea pe care o puteți utiliza pentru a personaliza restul paginii. De exemplu, puteți afișa un
conținut similar sau un link, așa cum se arată în Figura 10-5.
325
CAPITOLUL CONTROALE BOGATE
10
Codul de gestionare a evenimentelor pentru acest exemplu configurează pur și simplu un control
HyperLink numit lnkBanner pe baza reclamei selectate aleatoriu:
După cum puteți vedea, controalele bogate, cum ar fi Calendar și AdRotator, nu adaugă doar o ieșire
HTML sofisticată; Acestea includ, de asemenea, un cadru de evenimente care vă permite să vă ocupați
de comportamentul controlului și să îl integrați în aplicația dvs.
326
CAPITOLUL CONTROALE BOGATE
10
utilizatorului să comute de la o vizualizare la alta fără a părăsi pagina. Sau, poate doriți să gestionați o mică activitate în
mai mulți pași într-un singur loc (cum ar fi furnizarea de informații despre utilizator pentru un proces de înregistrare a
contului). În aceste exemple, aveți nevoie de o modalitate de a crea pagini dinamice care oferă mai multe vizualizări
posibile. În esență, pagina ascunde și afișează diferite controale în funcție de vizualizarea pe care doriți să o prezentați.
Cel mai simplu mod de a înțelege această tehnică este de a crea o pagină cu mai multe controale ale panoului. Fiecare
panou poate conține un grup de controale ASP.NET. De exemplu, imaginați-vă că creați un expert simplu în trei pași. Veți
începe prin a adăuga trei panouri la pagina dvs., câte unul pentru fiecare pas - să zicem, panouPasul 1, panouPasul 2 și
panouPasul 3. Puteți plasa panourile unul după altul, deoarece veți afișa doar unul câte unul. După ce ați adăugat
panourile, puteți plasa controalele corespunzătoare în interiorul fiecărui panou. Pentru a începe, proprietatea Vizibil a
fiecărui panou ar trebui să fie falsă, cu excepția panouluiPasul 1, care apare prima dată când utilizatorul solicită pagina.
Notă
Când setați proprietatea Vizibil a unui control la false, controlul nu va apărea în pagină la momentul rulării. Orice controale din interiorul unui panou invizibil sunt, de asemenea, ascunse vederii și nu vor fi prezente în codul HTML redat pentru pagină. Cu toate acestea, aceste controale vor apărea în continuare în suprafața de proiectare Visual Studio, astfel încât să le puteți selecta și configura în continuare.
În cele din urmă, veți adăuga unul sau mai multe butoane de navigare în afara panourilor. De exemplu,
următorul cod gestionează clicul unui buton Următorul, care este plasat imediat după panouPasul 3 (deci
apare întotdeauna în partea de jos a paginii). Codul verifică pasul în care se află utilizatorul, ascunde panoul
curent și afișează următorul panou. În acest fel, utilizatorul este mutat la pasul următor.
vid protejat cmdNext_Click(expeditor obiect, EventArgs e)
{
dacă (panelStep1.Visible)
{ // Treceți la pasul 2.
327
CAPITOLUL CONTROALE BOGATE
10
panelStep3.Visible = false;
Controlul MultiView
Descărcați de la Wow! eBook <www.wowebook.com>
MultiView este cel mai simplu dintre cele două controale cu vizualizare multiplă. În esență, MultiView vă oferă o
modalitate de a declara mai multe vizualizări și de a afișa doar una la un moment dat. Nu are o interfață de utilizator
implicită - obțineți doar orice HTML și controale adăugați. MultiView este echivalent cu abordarea personalizată a
panoului explicată anterior.
Crearea unui MultiView este destul de simplă. Adăugați eticheta <asp:MultiView> la fișierul de pagină
.aspx și apoi adăugați o etichetă <asp:View> în interiorul acesteia pentru fiecare vizualizare separată:
328
CAPITOLUL CONTROALE BOGATE
10
Crearea vizualizărilor
Iată marcajul complet pentru o vizualizare multiplă care împarte controalele felicitării în trei vizualizări
denumite Vizualizare1, Vizualizare2 și Vizualizare3:
</asp:MultiView>
Visual Studio afișează toate vizualizările la momentul proiectării, una după alta (consultați Figura 10-6).
Puteți edita aceste regiuni în același mod în care proiectați orice altă parte a paginii.
329
CAPITOLUL CONTROALE BOGATE
10
Acest exemplu arată prima vizualizare (Vizualizare1) și ascunde orice vizualizare afișată în prezent, dacă
există.
330
CAPITOLUL CONTROALE BOGATE
10
Sfat Pentru a face codul mai lizibil, puteți crea o enumerare care definește un nume pentru fiecare vizualizare. În acest fel, aveți posibilitatea să setați ActiveViewIndex utilizând numele descriptiv din enumerare, nu un număr obișnuit. Consultați capitolul 3 pentru o recapitulare a enumerărilor.
De asemenea, puteți utiliza metoda SetActiveView(), care acceptă oricare dintre obiectele de vizualizare pe care
le-ați creat. Acest lucru poate avea ca rezultat un cod mai lizibil (dacă ați ales coduri descriptive pentru comenzile de
vizualizare) și asigură detectarea erorilor mai devreme (la momentul compilării în loc de timpul de execuție).
MultiView1.SetActiveView(Vizualizare1);
Acest lucru vă oferă suficientă funcționalitate încât să puteți crea butoanele de navigare anterioare și următoare. Cu
toate acestea, depinde în continuare de dvs. să scrieți codul care verifică ce vizualizare este vizibilă și schimbă
vizualizarea. Acest cod este puțin mai simplu, deoarece nu mai trebuie să vă faceți griji cu privire la ascunderea
vizualizărilor, dar este încă mai puțin decât ideal.
Din fericire, MultiView include câteva inteligente încorporate care vă pot salva multe probleme. Iată cum funcționează:
MultiView recunoaște comenzile butoanelor cu nume de comenzi specifice. (Din punct de vedere tehnic, un control cu
buton este orice control care implementează interfața IButtonControl, inclusiv Button, ImageButton și LinkButton.) Dacă
adăugați un control buton la vizualizarea care utilizează unul dintre aceste nume de comenzi recunoscute, butonul
primește unele funcționalități automate. Folosind această tehnică, puteți crea butoane de navigare fără a scrie niciun cod.
Tabelul 10-6 listează toate numele de comenzi recunoscute. Fiecare nume de comandă are, de asemenea,
un câmp static corespunzător în clasa MultiView, astfel încât să puteți obține cu ușurință numele corect al
comenzii dacă alegeți să îl setați programatic.
Tabelul 10-6. Nume de comenzi recunoscute pentru MultiView
331
CAPITOLUL CONTROALE BOGATE
10
Când faceți clic, acest buton setează MultiView pentru a afișa vizualizarea specificată de CommandArgument
(View2).
În loc să creați butoane care duc utilizatorul la o anumită vizualizare, este posibil să doriți un buton care să se
deplaseze înainte sau înapoi cu o vizualizare. Pentru aceasta, utilizați numele de comandă PrevView și
NextView. Iată un exemplu care definește butoanele anterior și următor din a doua vizualizare:
<asp:Button ID="Button1" runat="server" text="< prev" CommandName="PrevView" />
<asp:Button ID="Button2" runat="server" text="Next >" CommandName="NextView" />
După ce adăugați aceste butoane la vizualizarea dvs., puteți trece cu ușurință de la vizualizare la
vizualizare. Figura 10-7 prezintă exemplul anterior, a doua vizualizare fiind vizibilă în prezent.
332
CAPITOLUL CONTROALE BOGATE
10
Sfat: Aveți grijă câte vizualizări înghesuiți într-o singură pagină. Atunci când utilizați controlul MultiView, întregul model de control - inclusiv controalele din fiecare vizualizare - este creat în fiecare postback și persistă în starea de vizualizare. În cele mai multe situații, acest lucru nu va fi un factor semnificativ. Cu toate acestea, crește dimensiunea generală a paginii, mai ales dacă modificați controalele programatic (ceea ce crește cantitatea de informații pe care trebuie să le stocheze în starea de
vizualizare).
Controlul expertului
Controlul Expert este o versiune mai plină de farmec a controlului MultiView. De asemenea, acceptă afișarea uneia dintre
mai multe vizualizări simultan, dar include un comportament destul de încorporat, dar personalizabil, inclusiv butoane de
navigare, o bară laterală cu linkuri de pași, stiluri și șabloane.
De obicei, vrăjitorii reprezintă o singură sarcină, iar utilizatorul se mișcă liniar prin ele, trecând de la pasul curent la cel
imediat următor (sau cel imediat precedent în cazul unei corecții). Controlul ASP.NET Wizard acceptă, de asemenea,
navigarea neliniară, ceea ce înseamnă că vă permite să decideți să ignorați un pas pe baza informațiilor furnizate de
utilizator.
În mod implicit, controlul Expert furnizează butoane de navigare și o bară laterală cu linkuri pentru fiecare
pas din stânga. Puteți ascunde bara laterală setând proprietatea Wizard.DisplaySideBar la false. De obicei,
veți face acest pas dacă doriți să impuneți o navigare strictă pas cu pas și să împiedicați utilizatorul să sară
din secvență. Furnizați conținutul pentru fiecare pas utilizând orice controale HTML sau ASP.NET. Figura
10-8 arată regiunea în care puteți adăuga conținut la o instanță predefinită a expertului.
Pași de vrăjitor
Pentru a crea un expert în ASP.NET, pur și simplu definiți pașii și conținutul acestora utilizând etichetele
<asp:WizardStep>. Iată structura de bază pe care o veți utiliza:
333
CAPITOLUL CONTROALE BOGATE
10
</asp:WizardStep>
</asp:WizardStep>
...
<WizardSteps> </asp:Wizard>
Puteți adăuga oricâte controale WizardStep doriți în interiorul expertului. Conceptual, WizardStep joacă același rol ca
vizualizarea într-o vizualizare multiplă (sau panoul de bază din primul exemplu pe care l-ați luat în considerare). Plasați
conținutul pentru fiecare pas în interiorul controlului WizardStep.
Înainte de a începe să adăugați conținutul la expert, merită să consultați tabelul 10-7, care prezintă câteva
informații de bază pe care le puteți defini pentru fiecare pas.
Proprietate Descriere
Titlu Numele descriptiv al pasului. Acest nume este utilizat pentru textul linkurilor din
Bara laterală.
AllowReturn Indică dacă utilizatorul poate reveni la acest pas. Dacă este fals, odată ce utilizatorul a trecut
Acest pas, utilizatorul nu va putea reveni. Linkul barei laterale pentru acest pas va avea
fără efect, iar butonul Anterior al pasului următor fie va sări peste acest pas, fie va fi
ascuns complet (în funcție de valoarea AllowReturn a pașilor precedenți).
Pentru a vedea cum funcționează acest lucru, luați în considerare un expert care utilizează din nou
exemplul GreetingCardMaker. Acesta ghidează utilizatorul prin patru pași. Primii trei pași permit
utilizatorului să configureze felicitarea, iar ultimul pas arată felicitarea generată.
<asp:Wizard ID="Wizard1" runat="server" ActiveStepIndex="0" BackColor="LemonChiffon"
BorderStyle="Groove" BorderWidth="2px" CellPadding="10">
334
CAPITOLUL CONTROALE BOGATE
10
</asp:Expert>
Dacă vă uitați cu atenție, veți găsi câteva diferențe față de pagina originală și exemplul bazat pe MultiView. În
primul rând, comenzile nu sunt setate să posteze automat înapoi. Acest lucru se datorează faptului că
felicitarea nu este redată până la pasul final, la încheierea vrăjitorului. (Veți afla mai multe despre cum să
gestionați acest eveniment în secțiunea următoare.) O altă modificare este că nu există butoane de navigare.
Acest lucru se datorează faptului că expertul adaugă automat aceste detalii pe baza tipului de pas. De
exemplu, veți primi un buton Următorul pentru primii doi pași, un buton Anteriorul pentru pașii 2 și 3 și un
buton Terminare pentru pasul 3. Pasul final, care afișează fișa completă, nu furnizează linkuri de navigare,
deoarece StepType este setat la Finalizare. Figura 10-9 prezintă pașii expertului.
335
CAPITOLUL CONTROALE BOGATE
10
Spre deosebire de controlul MultiView, puteți vedea doar câte un pas la un moment dat în Visual Studio.
Pentru a alege pasul pe care îl proiectați în prezent, selectați-l din eticheta inteligentă, așa cum se arată în
Figura 10-10. Dar fiți avertizat - de fiecare dată când faceți acest lucru, Visual Studio modifică proprietatea
Wizard.ActiveStepIndex la pasul pe care îl alegeți. Asigurați-vă că setați acest lucru înapoi la 0 înainte de a
rula aplicația, astfel încât să înceapă la primul pas.
336
CAPITOLUL CONTROALE BOGATE
10
Notă Rețineți că, atunci când adăugați controale la pași separați pe un expert, controalele sunt toate instanțiate și persistate în starea de vizualizare, indiferent de pasul care este afișat în prezent. Dacă trebuie să reduceți un expert complex, va trebui să îl împărțiți în pagini separate, să utilizați metoda Server.Transfer () pentru a trece de la o pagină la alta și să tolerați un model de programare mai puțin elegant.
Evenimente Wizard
Puteți scrie codul care stă la baza expertului răspunzând la mai multe evenimente (așa cum sunt
enumerate în tabelul 10-8).
Eveniment Descriere
ActiveStepChanged Apare atunci când controlul comută la un pas nou (fie pentru că utilizatorul a
făcut clic pe un buton de navigare, fie pentru că codul a modificat proprietatea
ActiveStepIndex).
AnulareButonFaceți Apare când se face clic pe butonul Anulare. Butonul Anulare nu este afișat în
clic pe mod implicit, dar îl puteți adăuga la fiecare pas setând proprietatea
Wizard.DisplayCancelButton. De obicei, un buton Anulare iese din expert. Dacă
nu aveți niciun cod de curățare de efectuat, trebuie doar să setați proprietatea
CancelDestinationPageUrl, iar expertul se va ocupa automat de redirecționare.
337
CAPITOLUL CONTROALE BOGATE
10
Eveniment Descriere
NextButtonFaceți clic și Apare atunci când se face clic pe butonul Următor sau Anterior în orice pas. Însă
AnteriorButonFaceți clic pe Deoarece există mai multe moduri de a trece de la un pas la altul, este
adesea mai ușor de gestionat evenimentul ActiveStepChanged.
Bară lateralăButonFaceți clic pe Apare atunci când se face clic pe un buton din zona barei laterale.
Committ-as-you-go: Acest lucru are sens dacă fiecare pas al vrăjitorului încheie o operație atomică care nu poate fi
inversată. De exemplu, dacă procesați o comandă care implică o autorizare a cardului de credit urmată de o
achiziție finală, nu puteți permite utilizatorului să facă un pas înapoi și să editeze numărul cardului de credit. Pentru
a accepta acest model, setați proprietatea AllowReturn la fals pe unii sau toți pașii. De asemenea, se recomandă
să răspundeți la evenimentul ActiveStepChanged pentru a efectua modificări pentru fiecare pas.
Descărcați de la Wow! eBook <www.wowebook.com>
Committ-at-the-end: Acest lucru are sens dacă fiecare pas al expertului colectează informații pentru o
operațiune care se efectuează numai la sfârșit. De exemplu, dacă colectați informații despre utilizator și
intenționați să generați un cont nou după ce aveți toate informațiile, probabil că veți permite unui
utilizator să facă modificări la jumătatea procesului. Executați codul pentru generarea noului cont atunci
când expertul se termină reacționând la evenimentul FinishButtonClick.
Pentru a implementa commit-at-the-end cu exemplul curent, trebuie doar să răspundeți la evenimentul
FinishButtonClick. De exemplu, pentru a implementa expertul pentru felicitări, trebuie doar să răspundeți la
acest eveniment și să apelați UpdateCard(), metoda privată care reîmprospătează felicitarea:
protejat void Wizard1_FinishButtonClick(expeditor obiect,
WizardNavigationEventArgs e)
{
UpdateCard();
}
Pentru codul complet pentru metoda UpdateCard(), care generează felicitarea, consultați capitolul 6 (sau
consultați exemplul de cod descărcabil).
Dacă decideți să utilizați modelul commit-as-you go, răspundeți la evenimentul ActiveStepChanged și
apelați UpdateCard() în acel moment pentru a reîmprospăta cardul de fiecare dată când utilizatorul trece de
la un pas la altul. Acest lucru presupune că felicitarea este întotdeauna vizibilă. (Cu alte cuvinte, nu este
conținut în pasul final al vrăjitorului.) Modelul commit-as-you-go este similar cu exemplul anterior care a
utilizat MultiView.
Formatarea expertului
Fără îndoială, cel mai mare punct forte al controlului vrăjitorului este modul în care vă permite să-i personalizați
aspectul. Aceasta înseamnă că dacă doriți modelul de bază (un proces în mai mulți pași cu butoane de navigare și
diverse evenimente), nu sunteți blocat în interfața de utilizator implicită.
În funcție de cât de radical doriți să schimbați expertul, aveți mai multe opțiuni. Pentru modificări mai puțin dramatice,
puteți seta diferite proprietăți de nivel superior ale controlului expertului. De exemplu, puteți controla culorile, fonturile,
338
CAPITOLUL CONTROALE BOGATE
10
spațierea și stilul bordurii, așa cum puteți face cu orice control ASP.NET. De asemenea, puteți modifica aspectul fiecărui
buton. De exemplu, pentru a modifica butonul Următorul, puteți utiliza următoarele proprietăți: StepNextButtonType
(utilizați un buton, un link sau o imagine pe care se poate face clic), StepNextButtonText (particularizați textul pentru un
buton sau un link), StepNextButtonImageUrl (setați imaginea pentru un buton imagine) și StepNextButtonStyle (utilizați un
stil dintr-o foaie de stiluri). De asemenea, puteți adăuga un antet utilizând proprietatea HeaderText.
Mai mult control este disponibil prin stiluri. Puteți utiliza stiluri pentru a aplica opțiuni de formatare la diverse porțiuni ale
controlului expert, la fel cum puteți utiliza stiluri pentru a formata părți ale controalelor de date îmbogățite, cum ar fi
GridView. Tabelul 10-9 listează toate stilurile pe care le puteți utiliza. Ca și în cazul altor controale bazate pe stil, setările
de stil mai specifice (cum ar fi SideBarStyle) suprascriu setările de stil mai generale (cum ar fi ControlStyle) atunci când
intră în conflict. În mod similar, StartNextButtonStyle suprascrie NavigationButtonStyle la primul pas.
Stil Descriere
Stil antet Se aplică secțiunii antet a expertului, care este vizibilă numai dacă setați
un text în proprietatea HeaderText.
BorderStyle Se aplică bordurii din jurul controlului expert. Îl puteți utiliza împreună
cu proprietățile BorderColor și BorderWidth.
Stil de navigare Se aplică în zona de jos a comenzii unde sunt afișate butoanele de
navigare.
StartNextButtonStyle Se aplică butonului de navigare Next la primul pas (când StepType este
Start).
339
CAPITOLUL CONTROALE BOGATE
10
• Notă Controlul Expert acceptă, de asemenea, șabloane, care vă oferă o abordare mai radicală a
formatării. Dacă nu puteți obține nivelul de particularizare dorit prin proprietăți și stiluri, puteți utiliza
șabloane pentru a defini complet aspectul fiecărei secțiuni a controlului expert, inclusiv anteturile și
linkurile de navigare. Modelele necesită expresii de legare a datelor și sunt discutate în capitolele
15 și 16.
Validarea cu expertul
Evenimentele FinishButtonClick, NextButtonClick, PreviousButtonClic și SideBarButtonClick pot fi
anulate. Aceasta înseamnă că puteți utiliza un astfel de cod pentru a împiedica desfășurarea acțiunii de
navigare solicitate:
protejat void Wizard1_NextButtonClick(expeditorul obiectului,
WizardNavigationEventArgs e) { // Efectuați un fel de
verificare.
dacă (e.NextStepIndex == 1 &&; txtName.Text == "")
{
Anulați navigarea și afișați un mesaj în altă parte a paginii. e.Cancel = true;
lblInfo.Text = "Nu puteți trece la pasul următor până când nu furnizați
numele dvs.";
}
}
Aici codul verifică dacă utilizatorul încearcă să treacă la pasul 1 utilizând proprietatea NextStepIndex.
(Alternativ, puteți examina pasul curent utilizând proprietatea CurrentStepIndex.) Dacă da, codul verifică apoi
o casetă de text și anulează navigarea dacă nu conține niciun text, menținând utilizatorul la pasul curent.
Scrierea acestui tip de logică devine puțin dificilă, deoarece trebuie să rețineți că navigarea pas cu pas poate
fi efectuată în mai multe moduri. Pentru a vă simplifica viața, puteți scrie o rutină de tratare a evenimentelor
care se ocupă de evenimentele NextButtonClick, PreviousButtonClick și SideBarButtonClick și efectuează
aceeași verificare. Ați văzut această tehnică în capitolul 6 cu GreetingCardMaker.
• Notă De asemenea, aveți posibilitatea să utilizați fără nicio problemă controalele de validare
ASP.NET dintr-un expert. În cazul în care controalele de validare detectează date nevalide,
acestea vor împiedica utilizatorul să facă clic pe oricare dintre linkurile din bara laterală (pentru a
trece la un alt pas) și vor împiedica utilizatorul să continue făcând clic pe butonul Următorul. Cu
toate acestea, în mod implicit, butonul Anterior are proprietatea CausesValidation setată la false,
ceea ce înseamnă că utilizatorului i se va permite să revină la pasul anterior.
340
CAPITOLUL 10
CONTROALE COMPLEXE
Ultimul cuvânt
Acest capitol v-a arătat cum controalele îmbogățite Calendar, AdRotator, MultiView și Wizard pot depăși cu
mult limitările elementelor HTML obișnuite. Când lucrați cu aceste controale, nu trebuie să vă gândiți deloc
la HTML. În schimb, vă puteți concentra asupra modelului de obiect definit de control.
De-a lungul acestei cărți, veți lua în considerare mai multe exemple de controale bogate și veți învăța cum
să le utilizați pentru a crea aplicații web bogate care sunt o lume diferită de elementele de bază HTML.
Unele dintre cele mai interesante controale bogate care sunt încă în față includ controalele de navigație
(capitolul 13), controalele de date (capitolul 16) și controalele de securitate (capitolul 20).
Sfat
Ați putea fi, de asemenea, interesat să adăugați controale terță parte pe site-urile dvs. Internetul conține multe hub-uri pentru partajarea controlului. O astfel de locație este propriul http://www.asp.net al Microsoft, care oferă o galerie de control unde dezvoltatorii își pot trimite propriile controale web ASP.NET. Unele dintre aceste controale sunt gratuite (cel puțin într-o versiune limitată), iar altele necesită o achiziție.
•
C A P I T O L U L 11
•■■
În acest capitol, veți lua în considerare două modalități de a vă extinde paginile web cu o altă crestătură.
În primul rând, veți aborda controalele utilizatorului, care vă oferă o modalitate eficientă de a reutiliza un bloc de marcaj al
interfeței cu utilizatorul - și codul care îl însoțește. Controalele utilizatorilor sunt un instrument cheie pentru construirea de
aplicații web modulare. De asemenea, vă pot ajuta să creați modele consecvente de site-uri web și să vă reutilizați munca
grea. Apoi, veți explora desenul personalizat cu GDI +. Veți vedea cum puteți picta exact imaginea de care aveți nevoie la
cerere. Veți învăța, de asemenea, cel mai bun mod de a încorpora aceste imagini în paginile dvs.
Controale utilizator
O aplicație web bine construită își împarte activitatea în blocuri discrete, independente. Cu cât aplicația web este mai
modulară, cu atât este mai ușor să vă mențineți codul, să depanați problemele și să reutilizați biții cheie de
funcționalitate.
Deși este destul de ușor să reutilizați codul (trebuie pur și simplu să îl scoateți din paginile dvs. și să îl puneți în clase
separate), nu este la fel de simplu să reutilizați marcarea paginilor web. Puteți tăia și lipi blocuri de HTML și ASP.NET
etichete de control, dar acest lucru provoacă dureri de cap nesfârșite dacă doriți să vă schimbați marcajul mai târziu. În
schimb, aveți nevoie de o modalitate de a înfășura marcarea paginii web într-un pachet reutilizabil, la fel cum puteți
înfășura codul obișnuit C #. Trucul este de a crea un control al utilizatorului.
Controalele utilizatorului arată aproape la fel ca ASP.NET formularele web. La fel ca formularele web, acestea sunt
compuse dintr-o porțiune de marcare cu etichete HTML și de control (fișierul .ascx) și pot utiliza opțional un fișier de cod în
spatele cu logică de gestionare a evenimentelor. De asemenea, pot include aceeași gamă de conținut HTML și controale
ASP.NET și se confruntă cu aceleași evenimente ca obiectul Pagină (cum ar fi Încărcare și Prerandare). Singurele
diferențe dintre controalele utilizatorului și paginile web sunt următoarele:
• Controalele utilizatorului utilizează extensia de fișier .ascx în loc de .aspx, iar fișierele lor din
spatele codului moștenesc de la clasa System.Web.UI.UserControl. De fapt, clasa UserControl
și clasa Page moștenesc ambele de la aceleași clase de bază, motiv pentru care împărtășesc
atât de multe dintre aceleași metode și evenimente, așa cum se arată în diagrama moștenirii din
Figura 11-1.
• Fișierul .ascx pentru un control utilizator începe cu o directivă <%@ Control %> în loc de
o directivă <%@ Page %>.
• Comenzile utilizatorului nu pot fi solicitate direct de un browser web. În schimb, acestea
trebuie să fie încorporate în alte pagini web.
343
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
344
CAPITOLUL 11 CONTROALE
UTILIZATOR ȘI GRAFICĂ
Pentru a testa acest control al utilizatorului, trebuie să îl inserați într-o pagină web. Acesta este un proces în
două etape. În primul rând, trebuie să adăugați o directivă Înregistrare la pagina care va conține controlul
utilizatorului. Plasați directiva Înregistrare imediat după directiva Pagină. Directiva Registru identifică
controlul pe care doriți să îl utilizați și îl asociază cu un prefix unic de control, după cum se arată aici:
<%@ Register TagPrefix="apress" TagName="Footer" src="Footer.ascx" %>
Directiva privind registrul specifică un prefix și un nume de etichetă. Prefixele etichetelor grupează seturi de controale asociate
(de exemplu, toate controalele web ASP.NET utilizează prefixul etichetei asp). Prefixele etichetelor sunt de obicei minuscule -
din punct de vedere tehnic, nu sunt sensibile la litere mari și mici - și ar trebui să fie unice pentru compania sau organizația
dvs. Directiva Src identifică locația fișierului șablon de control al utilizatorului, nu fișierul din spatele codului.
În al doilea rând, acum puteți adăuga controlul utilizatorului oricând doriți (și de câte ori doriți) în pagină,
introducând eticheta de control. Luați în considerare acest exemplu de pagină:
Acest exemplu (prezentat în Figura 11-2) demonstrează o modalitate simplă prin care puteți crea un antet
sau un subsol și îl puteți reutiliza în toate paginile de pe site-ul dvs. web doar adăugând un control de
utilizator. În cazul subsolului simplu, nu veți salva mult cod. Cu toate acestea, această abordare va deveni
mult mai utilă pentru un control complex cu formatare extinsă sau mai multe controale conținute.
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Desigur, acest lucru zgârie doar suprafața a ceea ce puteți face cu un control al utilizatorului. În secțiunile
următoare, veți învăța cum să îmbunătățiți un control cu proprietăți, metode și evenimente -
transformându-l dintr-un simplu "includeți fișierul" într-un obiect cu drepturi depline.
Notă Clasa Page furnizează o metodă LoadControl() care vă permite să creați un control de utilizator dinamic la momentul rulării dintr-un fișier .ascx. Controlul utilizatorului vă este returnat ca obiect de control, pe care îl puteți adăuga apoi la colecția Controale a unui control container de pe pagina web (cum ar fi Substituent sau Panou) pentru a-l afișa pe pagină. Această tehnică nu este un substitut bun pentru utilizarea declarativă a unui control al utilizatorului, deoarece este mai complexă. Cu toate acestea, are
În Visual Studio, aveți o comandă rapidă utilă pentru adăugarea unui control de utilizator la o pagină fără a tasta manual
directiva Înregistrare. Începeți prin a deschide pagina web pe care doriți să o utilizați. Apoi, găsiți fișierul .ascx pentru
controlul utilizatorului în Exploratorul de soluții. Glisați-l din Exploratorul de soluții și fixați-l în zona de design vizual a
formularului web (nu în zona de vizualizare sursă). Visual Studio va adăuga automat directiva Înregistrare pentru controlul
utilizatorului, precum și o instanță a etichetei de control utilizator.
O altă opțiune este să configurați controlul utilizatorului în fișierul web.config pentru aplicația dvs. Iată un
exemplu care înregistrează controlul subsol în acest fel:
346
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Puteți adăuga mai multe elemente <adăugați> la secțiunea <controale> pentru a înregistra câte controale de
utilizator doriți.
Când faceți acest pas, controlul utilizatorului este disponibil în fiecare pagină, fără a fi necesare directive de
înregistrare. Visual Studio va respecta, de asemenea, configurația dvs., astfel încât, dacă plasați un control
de utilizator pe o pagină, acesta va utiliza prefixul etichetei definite și nu va adăuga o directivă Înregistrare.
Notă Puteți utiliza controalele de navigare mai bogate în funcții pentru a furniza navigarea pe site-ul web. Crearea propriilor controale personalizate vă oferă o abordare mai flexibilă (și mai obositoare) pentru furnizarea navigației. Este foarte probabil să utilizați controale personalizate, mai degrabă decât o hartă întreagă a site-ului, pentru o navigare simplă între câteva pagini.
Următorul exemplu definește un control simplu care prezintă o listă de linkuri formatată atractiv. Rețineți că
atributul stil al etichetei <div> (care definește fonturile și formatarea) a fost omis pentru claritate.
347
CAPITOLUL 11 CONTROALE UTILIZATOR ȘI GRAFICĂ
Linkurile nu declanșează de fapt niciun cod pe partea de server - în schimb, se redau ca etichete ancoră HTML
obișnuite cu o adresă URL codificată hard.
Pentru a testa acest meniu, puteți utiliza următoarea pagină web MenuHost.aspx. Acesta include două
controale: controlul Meniu și un control Etichetă care afișează parametrul șir de interogare produs. Ambele
sunt poziționate folosind o masă.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="MenuHost.aspx.cs"
mostenit="MenuHost"%> <%@ Register TagPrefix="apress" TagName="LinkMenu"
src="LinkMenu.ascx" %>
<! DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML
1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
Figura 11-3 prezintă rezultatul final. Ori de câte ori faceți clic pe un buton, pagina este postată înapoi și
textul este actualizat.
348
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Puteți utiliza controlul LinkMenu pentru a repeta același meniu pe mai multe pagini. Acest lucru este deosebit
de util într-o situație în care nu puteți utiliza paginile coordonatoare pentru a standardiza aspectul (posibil
pentru că paginile sunt prea diferite).
Următorul pas este să adăugați o proprietate la clasa Subsol care permite paginii web să regăsească sau
să seteze formatul curent aplicat subsolului. Formatul real este stocat într-o variabilă privată numită format,
care este setată implicit la formatul de dată lungă atunci când controlul este creat pentru prima dată. (Dacă
sunteți neclar cu privire la modul în care funcționează procedurile de proprietate, nu ezitați să consultați
explicația din capitolul 3.)
349
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
În cele din urmă, rutina de tratare a evenimentelor UserControl.Load trebuie să țină cont de starea curentă
a subsolului și să formateze ieșirea în consecință. Următorul este codul complet al clasei Footer:
}
}
Pentru a testa acest subsol, trebuie să creați o pagină care modifică proprietatea Format a controlului
utilizator Subsol. Figura 11-4 prezintă un exemplu de pagină, care setează automat proprietatea Format
pentru controlul utilizatorului pentru a se potrivi cu o selecție a butonului radio ori de câte ori pagina este
postată înapoi.
350
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Rețineți că proprietatea de control utilizator este modificată în rutina de tratare a evenimentelor Page.Load, nu
în rutina de tratare a evenimentelor cmdRefresh.Click. Motivul este că evenimentul Încărcare are loc înainte ca
controlul utilizatorului să fie redat de fiecare dată când este creată pagina. Evenimentul Click are loc după ce
controlul utilizatorului a fost redat și, deși modificarea proprietății este vizibilă în codul dvs., aceasta nu
afectează ieșirea HTML a controlului utilizatorului, care a fost deja adăugată la pagină.
public clasa partiala FooterHost : System.Web.UI.Page { protejat void Page_Load(Object sender, EventArgs e)
{
dacă (optLong.Checked) { Footer1.Format =
Footer.FooterFormat.LongDate; } else if (optShort.Checked) {
Footer1.Format = Footer.FooterFormat.ShortTime; } else { // Se
va aplica valoarea implicită din clasa Footer. }
}}
351
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Primul pas pentru a crea acest control este definirea evenimentelor. Amintiți-vă, pentru a defini un eveniment, trebuie mai
întâi să alegeți o semnătură de eveniment. Standardul .NET pentru evenimente specifică faptul că fiecare eveniment
trebuie să utilizeze doi parametri. Primul oferă o referință la controlul care a trimis evenimentul, în timp ce al doilea
încorporează orice informații suplimentare. Aceste informații suplimentare sunt împachetate într-un obiect EventArgs
particularizat, care moștenește de la clasa System.EventArgs. (Dacă evenimentul dvs. nu necesită informații suplimentare,
puteți utiliza doar clasa EventArgs predefinită, care nu conține date suplimentare. Multe evenimente din ASP.NET, cum ar fi
Page.Load sau Button.Click, urmează acest model.) Puteți consulta capitolul 4 pentru o prezentare generală rapidă a
modului de utilizare a evenimentelor în .NET.
Controlul LinkMenu2 utilizează un singur eveniment, care indică când se face clic pe un link:
Acest cod definește un eveniment numit LinkClicked. Evenimentul LinkClicked are semnătura specificată de
delegatul System.EventHandler, care include doi parametri - expeditorul evenimentului și un obiect EventArgs
obișnuit. Aceasta înseamnă că orice rutină de tratare a evenimentelor pe care o creați pentru a gestiona
evenimentul LinkClicked trebuie să arate astfel:
vid protejat LinkMenu_LinkClicked(expeditor obiect, EventArgs e) { ... }
Acest lucru are grijă de definirea evenimentului, dar cum rămâne cu ridicarea acestuia? Această parte este ușoară. Pentru a
declanșa evenimentul, controlul LinkMenu2 pur și simplu apelează evenimentul după nume și trece în cei doi parametri,
astfel:
Ridicați evenimentul LinkClicked, trecând o referință la // obiectul curent
(expeditorul) și un obiect EventArgs gol. LinkClicked(acest,
EventArgs.Empty);
Controlul LinkMenu2 are nevoie de fapt de câteva modificări. Versiunea originală a folosit controlul HyperLink. Acest lucru nu va
funcționa, deoarece controlul HyperLink nu declanșează un eveniment atunci când se face clic pe link. În schimb, va trebui să
352
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
utilizați LinkButton. LinkButton declanșează evenimentul Clic, pe care controlul LinkMenu2 îl poate intercepta, apoi ridică
evenimentul LinkClicked la pagina web. Următorul este codul complet de control al utilizatorului:
protejat void lnk_Click(expeditor obiect, EventArgs e) { // S-a făcut clic pe unul dintre controalele LinkButton. // Ridicați un
eveniment pe pagină.
}}
}
Observați că înainte de a ridica evenimentul LinkClicked, controlul LinkMenu2 trebuie să testeze evenimentul
LickedClick pentru o referință nulă. Există o referință nulă dacă nu sunt atașate rutine de tratare a evenimentelor. În
acest caz, nu ar trebui să încercați să ridicați evenimentul, deoarece ar provoca doar o eroare. Puteți crea o pagină
care utilizează controlul LinkMenu2 și puteți adăuga o rutină de tratare a evenimentelor. Din păcate, nu veți putea
conecta aceste rutine de tratare a evenimentelor utilizând fereastra Visual Studio Properties, deoarece fereastra
Proprietăți nu va afișa evenimentele particularizate furnizate de controlul utilizatorului. În schimb, va trebui să
modificați direct eticheta LinkMenu2, după cum se arată aici:
<apress:LinkMenu2 id="Menu1" runat="server" OnLinkClicked="LinkClicked" />
Iată rutina de tratare a evenimentelor care răspunde în pagina web:
Notă
• Nu veți putea crea rutine de tratare a evenimentelor de control al utilizatorului prin fereastra
Proprietăți Visual Studio. În schimb, va trebui să introduceți manual rutina de tratare a
evenimentelor.
353
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Conceptual, această abordare ar trebui să ofere paginii dvs. web mai multă putere pentru a personaliza
modul în care funcționează controlul utilizatorului. Din păcate, nu este cazul în acest moment, deoarece
lipsește o informație cheie. Când are loc evenimentul LinkClicked, pagina web nu are nicio modalitate de a ști
pe ce link s-a făcut clic, ceea ce o împiedică să ia orice fel de acțiune rezonabilă. Singura modalitate de a
rezolva această problemă este de a crea un eveniment mai inteligent care poate transmite unele informații
prin argumente de eveniment. Veți vedea cum în secțiunea următoare.
354
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Pentru a utiliza această clasă particularizată EventArgs, trebuie să modificați definiția evenimentului
LinkClicked astfel încât să utilizeze obiectul LinkClickedEventArgs:
eveniment public EventHandler<LinkClickedEventArgs> LinkClicked;
Magia genericelor este cea care face ca acest lucru să funcționeze. În esență, configurați clasa generică
EventHandler pentru a utiliza clasa EventArgs dorită - în acest caz, LinkClickedEventArgs. Apoi, codul de control al
utilizatorului pentru ridicarea evenimentului trebuie să trimită informațiile necesare atunci când apelați evenimentul.
Dar cum determină controlul utilizatorului pe ce link s-a făcut clic? Trucul este să comutați de la evenimentul
LinkButton.Click la evenimentul LinkButton.Command. Evenimentul Comandă primește automat argumentul
CommandArgument definit în etichetă. Deci, dacă definiți comenzile LinkButton astfel:
<asp:LinkButton ID="lnkBooks" runat="server"
CommandArgument="Menu2Host.aspx?product=Books"
OnCommand="lnk_Command">Books </asp:LinkButton><br /> <asp:LinkButton
ID="lnkToys" runat="server" CommandArgument="Menu2Host.aspx?product=Toys"
OnCommand="lnk_Command">Toys </asp:LinkButton><br /> <asp:LinkButton
ID="lnkSports" runat="server" CommandArgument="Menu2Host.aspx?product=Sports"
OnCommand="lnk_Command">Sports </asp: LinkButton><br /> <asp:LinkButton
ID="lnkFurniture" runat="server" CommandArgument="Menu2Host.aspx?product=Furniture"
OnCommand="lnk_Command"> Furniture</asp:LinkButton>
Iată codul complet de control al utilizatorului. Implementează încă o caracteristică. După ce evenimentul a
fost ridicat și gestionat de pagina web, LinkMenu2 verifică proprietatea Anulare. Dacă este fals, merge
mai departe și efectuează redirecționarea folosind Reponse.Redirect().
clasa publică parțială LinkMenu2 : System.Web.UI.UserControl
{
eveniment public LinkClickedEventHandler LinkClicked;
355
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
În cele din urmă, trebuie să actualizați codul din pagina web (unde este plasat controlul utilizatorului), astfel
încât rutina de tratare a evenimentelor să utilizeze noua semnătură. În următorul cod, rutina de tratare a
evenimentelor LinkClicked verifică adresa URL și o permite în toate cazurile, cu excepția unuia:
vid protejat LinkClicked(expeditor obiect, LinkClickedEventArgs e) { if (e.Url == "Menu2Host.aspx?product=Furniture") {
lblClick.Text = "Acest link nu este permis."; e.Cancel = true; } else { // Permiteți redirecționarea și nu modificați adresa URL. } }
Dacă faceți clic pe linkul Mobilier, veți vedea mesajul afișat în Figura 11-6.
356
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Grafică dinamică
Una dintre caracteristicile .NET Framework este GDI +, un set de clase concepute pentru desenarea imaginilor. Puteți
utiliza GDI + într-o aplicație Windows sau ASP.NET pentru a crea grafică dinamică. Într-o aplicație Windows, grafica pe
care o desenați ar fi copiată într-o fereastră pentru afișare. În ASP.NET, codul dvs. poate reda grafica dorită și le poate
trimite direct în browserul clientului.
În general, utilizarea codului GDI + pentru a desena un grafic este mai lentă decât utilizarea unui fișier
imagine gata făcut. Cu toate acestea, GDI + vă oferă mult mai multă libertate. De exemplu, vă puteți
adapta imaginea pentru a se potrivi unui anumit scop, încorporând informații precum data sau numele
de utilizator curent. De asemenea, puteți amesteca text, forme și alte hărți de biți pentru a crea o
imagine completă.
Desen de bază
Trebuie să urmați patru pași de bază atunci când utilizați GDI +. În primul rând, trebuie să creați un bitmap în
memorie. Acesta este spațiul de desen în care vă veți crea capodopera. Pentru a crea bitmap-ul, declarați o
nouă instanță a clasei System.Drawing.Bitmap. Trebuie să specificați înălțimea și lățimea imaginii în pixeli. Aveți
grijă - nu faceți bitmap-ul mai mare decât este necesar, altfel veți pierde inutil memoria.
Notă
Metoda Graphics.FromImage() funcționează cu orice obiect Image. Clase precum Bitmap derivă din Image, deci funcționează bine.
•
Acum vine partea interesantă. Folosind metodele clasei Grafică, puteți desena text, forme și imagini pe bitmap. Tabelul 11-1 enumeră unele dintre cele mai
fundamentale metode ale clasei Grafică. Metodele care încep cu cuvântul Desenează contururi, în timp ce metodele care încep cu cuvântul desenează regiuni solide.
Singurele excepții sunt metoda DrawString(), care desenează text completat folosind un font specificat de dvs. și metodele de copiere a imaginilor bitmap, cum ar fi
DrawIcon() și DrawImage().
Umple
357
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Metodă Descriere
DrawBezier() și Desenează infama și atractiva curbă Bezier, care este definită de patru
DrawBeziers() puncte de control.
DrawLine()și Desenează una sau mai multe linii. Fiecare linie conectează cele două
DrawLines() puncte specificate de o pereche de coordonate.
DrawRectangle() și Desenează unul sau mai multe dreptunghiuri obișnuite. Fiecare dreptunghi
DrawRectangles() este definit de o pereche de coordonate de pornire, o lățime și o înălțime.
358
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Când apelați metodele clasei Grafică, trebuie să specificați mai mulți parametri pentru a indica coordonatele
pixelilor pentru ceea ce doriți să desenați. De exemplu, atunci când desenați un dreptunghi, trebuie să
specificați locația colțului din stânga sus și lățimea și înălțimea acestuia. Iată un exemplu despre cum ați putea
desena un dreptunghi solid cu galben:
Desenați un dreptunghi începând de la locație (0, 0) //
care are 300 pixeli lățime și 50 pixeli înălțime.
g.FillRectangle(Pensule.Galben, 0, 0, 300, 50);
Când măsurați pixeli, punctul (0, 0) este colțul din stânga sus al imaginii în coordonate (x, y). Coordonata x
crește pe măsură ce mergeți mai departe spre dreapta, iar coordonata y crește pe măsură ce mergeți mai
departe. În exemplul curent, imaginea are 300 de pixeli lățime și 50 de pixeli înălțime, ceea ce înseamnă că
punctul (299, 49) este colțul din dreapta jos.
Notă cod desenează pe obiectul Bitmap din memorie creat anterior. Până când această
• Acest
imagine nu este redată (o abilitate pe care o veți prelua în curând), nu veți vedea nimic pe
pagina web.
Veți observa, de asemenea, că trebuie să specificați fie un obiect Pensulă, fie un obiect Peniță atunci când desenați majoritatea
conținutului. (Ambele clase sunt definite în spațiul de nume System.Drawing, alături de clasa Grafică.) Metodele care desenează
contururi de forme necesită un creion, în timp ce metodele care desenează forme umplute necesită o pensulă. Puteți crea
propriile obiecte personalizate pentru Pen și Pensulă, dar .NET oferă o soluție mai ușoară cu clasele Pensule și Stilouri. Aceste
clase expun proprietăți statice care oferă diferite pensule și stilouri pentru diferite culori. De exemplu, Pensule.Galben
returnează un obiect Pensulă care umple forme utilizând o culoare galbenă continuă, iar Stilouri.Galben returnează un obiect
Peniță care desenează contururi de formă utilizând aceeași culoare galbenă solidă.
Odată ce imaginea este completă, o puteți trimite browserului folosind metoda Image.Save (). Conceptual,
"salvați" imaginea în fluxul de răspuns al browserului. Apoi este trimis clientului și afișat în browser.
Sfat salva o imagine în orice flux valid, inclusiv în clasa FileStream descrisă în Capitolul 17.
• Puteți
Această tehnică vă permite să salvați imaginile generate dinamic pe disc, astfel încât să le puteți
utiliza ulterior în alte pagini web.
În cele din urmă, ar trebui să eliberați în mod explicit contextul imaginii și graficii când ați terminat, deoarece
ambele păstrează unele resurse negestionate care ar putea să nu fie lansate imediat dacă:
Utilizarea GDI + este o tehnică specializată, iar caracteristicile sale mai avansate depășesc scopul acestei
cărți. Cu toate acestea, puteți învăța multe luând în considerare câteva exemple simple.
359
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Acest cod este ușor de înțeles. Urmează modelul de bază stabilit mai devreme - creează Bitmap-ul în
memorie, obține obiectul grafic corespunzător, efectuează pictura și apoi salvează imaginea în fluxul de
răspuns. Acest exemplu utilizează metodele FillRectangle(), DrawRectangle(), DrawString() și
DrawImageUnscaled() pentru a crea desenul complet prezentat în Figura 11-7.
Sfat: Deoarece această imagine este generată pe serverul web, aveți posibilitatea să utilizați orice font instalat pe server. Clientul nu trebuie să aibă același font, deoarece clientul primește textul ca imagine redată.
360
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Din fericire, aceasta are o soluție simplă: vă puteți conecta la o imagine generată dinamic utilizând eticheta HTML <img>
sau controlul web Imagine. Dar, în loc să legați imaginea la un fișier imagine fix, legați-o la fișierul .aspx care generează
imaginea.
De exemplu, puteți crea un fișier numit GraphicalText.aspx care scrie o imagine generată dinamic în fluxul de
răspunsuri. Într-o altă pagină, puteți afișa imaginea dinamică adăugând un control web Imagine și setând proprietatea
ImageUrl la GraphicalText.aspx. De fapt, veți vedea chiar și imaginea apărând în mediul de proiectare al Visual Studio
înainte de a rula pagina web!
Când utilizați această tehnică pentru a încorpora grafică dinamică în paginile web, trebuie să vă gândiți și la modul
în care pagina web poate trimite informații graficului dinamic. De exemplu, ce se întâmplă dacă nu doriți să afișați
un fragment fix de text, ci doriți să generați o etichetă dinamică care să includă numele utilizatorului curent? (De
fapt, dacă doriți să afișați o bucată fixă de text, este probabil mai bine să creați graficul din timp și să îl stocați
într-un fișier, decât să îl generați folosind codul GDI + de fiecare dată când utilizatorul solicită pagina.) O soluție
este să transmiteți informațiile utilizând șirul de interogare, așa cum este descris în capitolul 8. Pagina care redă
elementul grafic poate verifica apoi informațiile despre șirul de interogare de care are nevoie.
Iată cum ați rescrie generatorul grafic dinamic având în vedere acest lucru:
361
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Conceptual, acest cod nu este mult diferit de exemplele pe care le-ați văzut înainte. Singura modificare este
că o informație - șirul utilizat cu metoda DrawString() - este regăsită din șirul de interogare.
Figura 11-8 prezintă o pagină care utilizează această pagină grafică dinamică, împreună cu două
controale Etichetă. Pagina transmite argumentul șir de interogare Joe Brown la pagină. Image.ImageUrl
complet devine astfel GraphicalText.aspx? Name=Joe%20Brown, așa cum se arată aici:
<asp:Label id="Label1" runat="server">Iată un conținut.</asp:Label> <br /><br />
362
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Este posibil să fie necesar să trimiteți mai multe informații sau informații mai complexe la pagina care
desenează imaginea. De exemplu, poate doriți să transmiteți un obiect de date unei pagini care desenează
o diagramă radială. În acest caz, șirul de interogare nu este suficient de bun și va trebui să utilizați un alt tip
de gestionare a stării. O opțiune este starea sesiunii, așa cum este descris în capitolul 8.
Cu toate acestea, cea mai bună alegere a formatului este PNG. PNG este un format universal care oferă întotdeauna
o calitate înaltă prin combinarea compresiei fără pierderi a GIF-urilor cu suportul bogat de culoare al JPEG-urilor.
(Singurul sughiț este că versiunile de Internet Explorer anterioare versiunii 7 nu tratează corect conținutul PNG
returnat de pe o pagină web. Dacă utilizați una dintre aceste versiuni vechi de IE, nu veți vedea conținutul imaginii, în
schimb, veți primi un mesaj care vă solicită să descărcați imaginea și să o deschideți în alt program. Pentru a evita
această problemă, trebuie să utilizați abordarea etichetei <img> prezentată în exemplul anterior.)
De asemenea, trebuie să fiți conștienți de încă o ciudățenie atunci când utilizați PNG - nu puteți utiliza metoda
Bitmap.Save() prezentată în exemplele anterioare. Dacă faceți acest lucru, va apărea o eroare. Din punct de vedere
tehnic, problema este că metoda Save() necesită un flux care poate fi căutat- un flux în care poziția poate fi schimbată
după bunul plac. Acest lucru se datorează faptului că .NET trebuie să poată trece înainte și înapoi prin conținutul imaginii
în timp ce este generat. Soluția este ușor de implementat, dacă este puțin ciudată. În loc să salvați direct în
Response.OutputStream, puteți crea un obiect System.IO.MemoryStream, care reprezintă un tampon de date în
memorie. MemoryStream este întotdeauna căutabil, astfel încât să puteți salva imaginea pe acest obiect. După ce ați
efectuat acest pas, puteți copia cu ușurință datele din MemoryStream în Response.OutputStream. Singurul dezavantaj
este că această tehnică necesită mai multă memorie, deoarece conținutul complet redat al graficului trebuie păstrat
363
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
simultan în memorie. Cu toate acestea, grafica pe care o utilizați în paginile web, în general, nu este atât de mare, deci
probabil că nu veți observa nicio reducere a performanței.
Pentru a implementa această soluție, începeți prin a importa spațiul de nume System.IO:
folosind System.IO;
Acum puteți înlocui exemplul anterior cu acest cod modificat care salvează imaginea în format PNG.
Liniile modificate sunt evidențiate.
Nu afișați nimic.
} else { string name = Request.QueryString["Name"];
Response.ContentType = "imagine/png";
g. imagine.
dispune(); }
• Notă Veți afla mai multe despre fluxuri atunci când abordați accesul
la fișiere în capitolul 17.
Calitatea nu este determinată doar de formatul imaginii. De asemenea, depinde de modul în care desenați conținutul imaginii
pe bitmap-ul din memorie. GDI + vă permite să alegeți între optimizarea codului de desen pentru aspect sau viteză. Când
364
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
alegeți să optimizați pentru cel mai bun aspect, .NET utilizează tehnici suplimentare de redare, cum ar fi antialiasing,
pentru a îmbunătăți desenul.
Antialiasul netezește marginile zimțate din forme și text. Funcționează prin adăugarea de umbrire la marginea
unei muchii. De exemplu, umbrirea gri poate fi adăugată la marginea unei curbe negre pentru a face un colț
să pară mai neted. Din punct de vedere tehnic, antialiasing amestecă o curbă cu fundalul său. Figura 11-9
prezintă un prim-plan al unei elipse antialias.
Pentru a utiliza netezirea în aplicațiile dvs., setați proprietatea SmoothingMode a obiectului Grafică. Puteți
alege între None, HighSpeed (implicit), AntiAlias și HighQuality (care este similar cu Antialias, dar utilizează
alte optimizări mai lente care îmbunătățesc afișarea pe ecranele LCD). Proprietatea Graphics.SmoothingMode
este unul dintre puținii membri ai clasei de grafică. Aceasta înseamnă că îl setați înainte de a începe să
desenați și se aplică oricărui text sau forme pe care le desenați în restul sesiunii de pictare (până când
obiectul Grafică este eliberat).
g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias;
Sfat
Antialiasing face cea mai mare diferență atunci când afișați curbe. Asta înseamnă că va îmbunătăți dramatic aspectul elipselor, cercurilor și arcelor, dar nu va face nicio diferență cu liniile drepte, pătratele și dreptunghiurile.
De asemenea, puteți utiliza antialiasing cu fonturi pentru a înmuia marginile zimțate ale textului. Puteți seta
proprietatea Graphics.TextRenderingHint pentru a asigura un text optimizat. Puteți alege între
SingleBitPerPixelGridFit (cea mai rapidă performanță și cea mai slabă calitate), AntiAliasGridFit (calitate mai
bună, dar performanță mai lentă) și ClearTypeGridFit (cea mai bună calitate pe un ecran LCD). Sau puteți
utiliza valoarea SystemDefault pentru a aplica orice setări de netezire a fonturilor configurate de utilizator.
SystemDefault este setarea implicită, iar setările implicite de sistem pentru majoritatea computerelor
activează antialiasing text. Chiar dacă nu setați acest lucru, textul redat dinamic va fi probabil desenat de
înaltă calitate. Cu toate acestea, deoarece nu puteți controla neapărat setările de sistem ale serverului web,
este o practică bună să specificați această setare în mod explicit dacă trebuie să desenați text într-o imagine.
365
CAPITOLUL CONTROALE UTILIZATOR ȘI GRAFICĂ
11
Ultimul cuvânt
În acest capitol, puneți încă două instrumente în setul de instrumente ASP.NET. În primul rând, ați văzut cum
controalele utilizatorului vă permit să reutilizați un bloc de interfață cu utilizatorul în mai multe pagini web. Apoi, ați luat
în considerare modul în care desenul personalizat vă permite să creați grafică pe măsură.
În capitolul următor, veți afla despre teme și pagini coordonatoare - două caracteristici care completează
controalele utilizatorului și vă oferă și mai multe modalități de a standardiza aspectul paginilor dvs. Temele
sunt mai detaliate decât controalele utilizatorului - acestea grupează presetările de formatare pe care le
puteți aplica controalelor individuale pentru a asigura un stil elegant și consecvent în întreaga aplicație.
Paginile coordonatoare sunt mai largi decât controalele utilizatorului - acestea vă permit să definiți un
șablon de pagină standardizat pe care îl puteți aplica pentru a bloca aspectul și aspectul mai multor pagini,
oferindu-vă o consecvență completă. Învățarea modului de amestecare a tuturor acestor ingrediente face
parte din arta plastică a programării ASP.NET.
366