Sei sulla pagina 1di 61

Active Server Page - ASP.

NET
Concepte de baz Dinamicitatea paginilor web paginile statice se mai numesc i pagini HTML, cci nu conin alt tip de cod dect cel scris n HTML; coninutul unei pagini nu variaz n timp sau de la un utilizator la altul ; toi vd la fel, fr informaii specifice contextului rulrii; coninutul este fixat i cunoscut nainte de lansarea cererii ctre pagina respectiv. - securitate redus, cci codul este vizibil din browser, cu View / Source. Pentru a reflecta chestiuni legate de un context ( de exemplu afiarea orei exacte, sau pentru adaptarea coninutului paginii la profilul utilizatorului care solicit pagina html ) pagina ar trebui compus abia dup ce s-a naintat cererea din partea unui client. paginile dinamice sunt cele configurate abia la momentul execuiei, n funcie de context i de resursele disponibile pe calculatorul de pe care se lanseaz cererea; de obicei aceste pagini au i un nivel nalt de interactivitate. Pentru a realiza dinamicitatea, trebuie scris cod surs care se ruleaz la momentul lansrii unei cereri i care prin rulare stabilete coninutul ce va fi afiat n pagin; trebuie avut ns n vedere n ce limbaj este scris acest cod, cine nelege i poate prelucra acest cod.

Dinamicitate client-side: codul surs HTML este mixat cu instruciuni de compunere a paginii (ntr-un limbaj script, uzual JavaScript sau VBScript); pagina e creat dinamic de ctre browser, la momentul solicitrii ei; gradul de dinamicitate depinde de capacitile browser-ului (Internet Explorer, Netscape Navigator, Opera); script-ul este vizibil n browser (View / Source) ceea ce nu e tocmai bine. Se poate folosi acest tip de dinamicitate eventual n Intranet, unde tim ce se afl instalat pe maini i cunoatem gradul de securitate ce trebuie asigurat. Dinamicitate server-side: codul surs HTML este mixat cu instruciuni de compunere a paginii, scrise n diverse limbaje de programare i interpretate de un soft din sever-ul unde se afl pagina solicitat. Pagina este compus tot dinamic, dar n server, la momentul solicitrii ei de la distan, de ctre un client. Pagina circul tot ca stream HTML; mai precis, n modul de prelucrare server, ctre client n reea circul doar rezultatul prelucrrii paginii, nu i instruciunile de prelucrare. De asemenea, o parte din codul de prelucrare a paginii poate fi precompilat, iar la momentul solicitrii paginii el este doar rulat, ceea ce poate mri considerabil performana accesului. Tipologia dinamicitii, Client sau Server, se deduce n funcie de cine proceseaz cererea: un modul specializat din browser sau un software din server.

Web server este un software care: gestioneaz spaiul pentru site-uri i paginile Web ale acestora; intercepteaz cererile i asigur regsirea i disponibilitatea paginilor de pe un site. Tehnologia CGI Common Gateway Interface Avantaje: acces la resursele sistemului de operare; vitez bun de execuie, dac aplicaia CGI este deja compilat Dezavantaje: depanare dificil; se execut n proces separat, consumnd multe resurse.

22.10.2012

Tehnologia ASP.NET Modelul disponibilizat sub .NET de ctre Microsoft pentru aplicaiile accesibile din Internet este denumit pe scurt ASP.NET (Active Server Page) i are urmtoarele caracteristici principale: - se bazeaz pe formulare Web ( Web Forms) i separ logica prezentrii de logica de business; - furnizeaz controale de server ce recunosc evenimente la nivel de server, dar sunt redate ca HTML, pentru a fi recunoscute i tratate de orice browser; - asigur accesul la date prin mecanismul ADO.NET; - permite caching pentru date i pentru salvarea strii unui client, pe server, pe calculatorul client sau pe servere SQL specializate. Avantaje ASP este o tehnologie orientat obiect pentru dezvoltare rapid de aplicaii; elementele HTTP sunt tratate tot obiectual; lucreaz cu pagini compilate, nu interpretate pas cu pas; recompilarea se face doar cnd este nevoie; permite accesul la toate clasele din .NET, clase care pot ndeplini sarcini complexe; asigur securitatea prin mecanisme forms-based i Passport authentication; trateaz fiiere XML, inclusiv pentru reconfigurri, fr a necesita restartarea server-ului; ofer extensibilitate prin crearea i integrarea de noi componente sau nlocuirea unora existente.

Directorul fizic c:\inetpub\wwwroot; Director virtual Virtual Directory, este o legtur ctre un alt director aflat fizic n afara arborelui site-ului Web. - Start / Programs / Administrative Tools / Internet Service Manager ( sau Start / Settings / Control Panel / Administrative Tools / Internet Information Services ) ne introduce n fereastra IIS coninnd lista site-urilor din evidena serverului Web ( Default Web Site, plus altele ). Trebuie ca IIS s fie ns instalat. - Dac nu e startat IIS l putem starta de aici: mouse right pe Default Web Site / Play sau Restart IIS; nu necesit restartarea calculatorului. - O alt modalitate de a ajunge n fereastra de startare IIS: Start / Run inetmgr permite i stabilirea unor drepturi i interdicii pe diverse servicii ale IIS. - Adugare director virtual: Default Web Site / buton dreapta mouse / New / Virtual Directory; aplicaiile create cu Visual Studio 2008 beneficiaz de propriul director virtual, creat odat cu aplicaia; cele create cu Visual Studio 2005 / 2008 pot rula i n afara IIS, sub un server web de dezvoltare; ele vor fi aduse la finalizare (deployment) ntr-un director virtual, fiind nregistrate n metabaza IIS, pentru ca site-ul s fie vizibil din afara aplicaiei.

Control Panel / Administrative Tools / Computer Management / Services & Apps / IIS / Web Sites / Default Web Site cu click mouse dreapta / Properties se poate schimba portul prin care se comunic cu serverul: TCP Port = 80 sau 81.

22.10.2012

Dac pe calculator se dispune de mai multe plci de reea pot exista mai multe Local Area Connection (Start / Control Panel / Network and DialUp Connection); ele pot avea setri diferite. Se pot pune mai multe adrese IP chiar pe aceeai conexiune. O adres IP poate avea i pseudonim: - n registru DNS, pe serverul de reea; - local, n c:\winnt\system32\drivers\etc\hosts ca text:
38.25.63.10 www.ceva.ro

Creare site Web n fereastra IIS cu buton dreapta mouse pe calculatorul dorit, se alege New / Web site i se indic adresa de IP nregistrat mai sus, plus drepturile de acces.

La ncercarea de conectare de la distan: fie se afieaz directoarele din site (opiunea Directory Browsing activ); fie se pred controlul unui document implicit (Enable Default Document activat). Cele dou opiuni se controleaz din fereastra IIS, click mouse dreapta pe site-ul dorit / Properties. Trebuie creat ns una din paginile: default.htm, default.asp, default.aspx. Mixarea informaiilor ntr-o pagin web O pagin Web poate conine: cod html, recunoscut de orice browser; cod ntr-un limbaj de programare recunoscut de ctre serverul care ine pagina Web; cod script ntr-un limbaj de tip script, recunoscut de majoritatea browserelor ( JavaScript, VB Script fiind cele mai rspndite limbaje de tip script). Modul n care se mixeaz aceste trei tipuri de cod complic oarecum nelegerea lucrurilor, dar este foarte important pentru c el d ordinea n care se afieaz diferitele informaii n pagin. Din punctul nostru de vedere, reinem dou dintre tag-urile care introduc cod scris ntr-un alt limbaj dect html: seciunea de cod
<script language="C#" runat="server"> cod C# </script>

seciunea de folosire a codului


<% // apel cod C# %>

De obicei punem codul propriu-zis n prima parte a paginii, iar apelul codului (partea de prezentare ) n interior, acolo unde dorim s apar efectul rulrii, n pagin. Uzual, se practic i gruparea ntregului cod n fiier separat, tehnic denumit "code behind"; la nceputul paginii se indic numele fiierului coninnd codul, iar n interiorul paginii se trece apelul codului, ce va genera ca rezultat prezentarea paginii.
<%@ Page Language="c#" Src="fis.cs"%> <% // apel cod C# %>

22.10.2012

Cteva exemple complete vor clarifica cele discutate mai sus. Exemplu DataOra.aspx Dinamicitate server-side
c:\inetpub\wwwroot

Cu un editor de text se introduce secvena de mai jos, ntr-un fiier DataOra.aspx plasat n ( tipul aspx este obligatoriu pentru a identifica programul care l trateaz):

<html> <script runat="server" language="c#"> </script> <% Response.Output.Write( System.DateTime.Now.ToString()); %> </html>

i se apeleaz din Internet Explorer sub forma http://localhost/DataOra.aspx; ea va afia data i ora exact. Observm c avem doar cod de redare, nu i cod propriu-zis; blocul script este gol n acest caz i se pune doar pentru a preciza limbajul n care este scris codul de redare, lucru care sar fi putut da i n directiva de pagin. Pagina web de mai sus exemplific i tipologia de dinamicitate server side, deoarece programul arat alt coninut n funcie de momentul solicitrii paginii; serverul este responsabil n acest caz, cu extragerea i afiarea orei exacte. Dac nu dispunem de serverul de web IIS instalat, putem starta serverul de web de sub VS 2010 rulnd o aplicaie oarecare; ct timp serverul de dezvoltare e activ, modificm n linia de adres din browser doar numele fiierului ce conine pagina (spre ex. default.aspx, cu DataOra.aspx, cu condiia ca fiierul s fi fost plasat n acelai director cu aplicaia care a startat serverul , cci serverul vede directorul ca pe unul virtual ). Observaie. Save Target as... din browser salveaz pagina aa cum arat ea prelucrat (tradus n html); astfel, fiierul salvat cu Save Target as... la rularea paginii, cu extensia html, n wwwroot, va afia la un nou apel n browser, mereu aceeai or ! Pentru fiierul iniial, ce conine codul de prelucrare, extensia fiierului trebuie s fie aspx, pentru a anuna serverul cui s-o paseze pentru prelucrare, deoarece fiierul conine nu forma prelucrat a paginii, ci instruciunile de prelucrare ! Exemplu DataOraJS.html Dinamicitate client-side Cu un editor de text se introduce secvena de mai jos, ntr-un fiier DataOraJSP.html plasat n c:\inetpub\wwwroot ( tipul html ne indic faptul c pagina poate fi prelucrat direct de ctre browser):
<html> <script language="javaScript"> document.write( " <b> Dinamicitate client side: </b>" ); azi = new Date(); document.write( azi.getDate(),"/ ",azi.getMonth()+1, "/ ", azi.getYear(), " ",azi.getHours(),":", azi.getMinutes(),":", azi.getSeconds() ); </script> </html>

Aceast pagin realizeaz aproximativ acelai lucru ca n exemplul anterior, dar responsabil cu aceast sarcin este de data aceasta browser-ul cu care un client navigheaz pe aceast pagin; aadar browser-ul clientului interpreteaz script-ul Java i l execut, apoi afieaz rezultatul. Ora afiat va fi cea de pe calculatorul clientului, nu cea din server; presupunnd c ambele ceasuri arat bine ora exact, cele dou exemple de mai sus vor afia ore diferite, dac server-ul se afl pe un alt fus orar dect clientul! Exemplu functia.aspx

22.10.2012

n acest exemplu vom avea ambele categorii de cod: n prima parte se prezint codul unei funcii, iar n interiorul paginii se pune codul de vizualizare, care apeleaz aceast funcie i afieaz ptratele rezultate prin rularea funciei.
<script runat="server"> double Patrate(double nr) { return (nr)*(nr); } </script> <html> <h2> Patratele primelor 10 numere naturale </h2> <table border="2"> <tr> <th> Numarul </th><th> Patratul </th> </tr> <% for (double i = 1.0; i<=10.0; i++) { Response.Output.Write( "<tr><td>{0}</td><td>" + "{1:f}</td><tr>", i, Patrate(i)); } %> </table> </html> Pagina se apeleaz n browser sub forma http://localhost/functia.aspx

Reiese c funcia ( n general, codul din blocul script ) nu este activat dect n momentul cnd este solicitat de un eveniment sau de ctre un alt cod executabil, pus n partea de redare <% %>. n exemplul nostru, apelul Patrate(i) invoc partea de cod din blocul script. Reamintim c la client ajunge pagina deja prelucrat, astfel nct dac n browser cerem din meniu View / Source, vedem ptratele deja calculate, browser-ul doar afindu-le. Nepreciznd runat="server" se presupune c se execut implicit n browser. ntr-o pagin se poate pune cod scris doar ntr-un singur limbaj, n cazul nostru C#. Sensul codului de redare de mai sus este urmtorul: obiectul pagin are proprietatea care este o referin la un obiect HTML de tip Response, ce conine rspunsul dat de server la solicitarea unei pagini de ctre un client. Obiectul Response recunoate metodele Response.Write() i Response.Output.Write() cu care putem aduga linii n rspunsul returnat clientului; Response.Output.Write() permite chiar i scrierea de text formatat, pe care un browser tie s-l interpreteze. O alt variant ar fi s punem funcia ntr-un fier separat, pe care s-l citm n clauza Src="fis.cs", lsnd n pagin doar partea de apel i de redare pagin. n ambele variante codul surs se compileaz la momentul cererii paginii; vom vedea n continuare c o alternativ mai eficient este s precompilm codul, mrind astfel viteza de rspuns la o cerere.
Response

ASP.NET ofer alternativa obiectual pentru crearea i accesul la paginile Web. Documentul html este mpachetat ntr-un obiect de clas WebForm1 sau _Default, derivat din clasa Page. Ceea ce este cuprins ntre <script runat="server" language="c#"> i </script> se include n aceast clas, iar ceea ce se specific ntre <% i %> poate fi imaginat ca o parte dintr-o funcie Render() a clasei derivat din clasa Page. Reiese c ntre <script> i </script> putem include funcii, pe cnd ntre <% i %> nu dm dect elemente specifice redrii paginii Web, neputnd defini alte funcii n interiorul unei funcii ( adic n funcia Render() ). Un exemplu n care codul mixat ntr-o pagin web nu este apelat explicit din zona de redare, ci implicit, pe baz de eveniment semnalat la nivel de pagin ( evenimentul Page_Load ) ar fi urmtorul:

22.10.2012

Exemplu bdPage.aspx
<%@ import Namespace="System.Data" %> <%@ import Namespace="System.Data.OleDb" %> <script language="c#" runat="server"> private void Page_Load(object sender, System.EventArgs e) { string strSql = "SELECT codp, denum, pret FROM produse"; OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data" + " Source=C:\prod.mdb"); try {con.Open(); } catch(Exception ex) {mesaje.Text ="Eroare open conexiune"+ex.Message;} OleDbCommand myCmd = new OleDbCommand(strSql,con);

OleDbDataReader dr = myCmd.ExecuteReader(); while (dr.Read()) { mesaje.Text+="\r\n"+dr["codp"]+ " " + dr["denum"]+ " " + dr["pret"]; mesaje.Text+="\r\n"; } dr.Close(); con.Close(); } </script> <html> <body> <form id="Form1" method="post" runat="server"> <h4> Interogare BD folosind un obiect DataReader </h4> <asp:TextBox id="mesaje" runat="server" TextMode="MultiLine"> </asp:TextBox> <h4> End Interogare BD </h4> </form> </body> </html> Se ruleaz dnd n linia de adres a browser-ului http://localhost/bdPage.aspx; trebuie doar s ne asigurm c exist fiierul C:\prod.mdb coninnd o baz de date Access, cu tabela produse i cmpurile: codp, denum i pret.

Pregtirea paginii se face tot pe server; o problem care apare aici este cum va cltori informaia extras de pe server ( spre exemplu, dintr-o baz de date) pn la client, pentru vizualizare n browser. Putem defini o variabil la nivelul paginii, string strRezultat; ea este recunoscut i de funcia Render(), dar i pierde coninutul ntre dou cereri succesive. Putem apela la un control de tip TextBox, care va transporta informaia n proprietatea sa numit Text, folosit drept container; acesta este mecanismul pentru care s-a optat n exemplul de mai sus, rolul de container avndu-l TextBox-ul mesaje. La ncrcarea paginii n server, se lanseaz evenimentul Page_Load, care apeleaz implicit funcia de tratare cu acelai nume, moment n care se acceseaz baza de date i se adaug informaia, linie cu linie, n textBox; n rest, dup cum se poate observa, lucru cu obiecte .NET este cel uzual, chiar cnd e vorba de obiecte pentru acces la baze de date. Web Forms controls desemneaz server controls

22.10.2012

Crearea unei aplicaii Web folosind Visual Studio Sub .NET, File / New / Web Sites / ASP.NET Web Site i se alege un nume de aplicaie i ca localizare se alege File System; pentru a se putea lucra rapid, cel puin pentru faza de realizare i depanare a aplicaiei este preferabil aceast localizare. Localizarea site-ului pe care se lucreaz se poate face alegnd una din opiunile: File System dac se experimenteaz pe un site creat provizoriu ntr- un director local sau de pe un alt calculator din reea expus ca partajabil (shared). Se poate crea i un director nou, folosind icon-ul Create New Folder sau pur i simplu adugnd numele noului director, n finalul unei ci de acces deja selectat. Rularea se face ntr-un server de web de testare, numit ASP.NET Development Server i folosete un port, ales adhoc, nu pe cel folosit de IIS; avem avantajul c putem muta directorul, cci el nu e luat n evidena IIS (metabaza IIS) ca director virtual i nu e accesibil din Internet. Local IIS dac dorim ca site-ul s se afle ntr-un director virtual recunoscut de server-ul de web local (IIS). Cu icon-ul din colul dreapta-sus Create New Web Application se poate crea chiar acum un nou director virtual. FTP Site - cnd lucrm pe un site la distan ( sub alt IIS, dect cel local ) i -l accesm prin FTP, furniznd informaiile de conectare (FTP site, port, director, user, password). Remote Web Server - cnd lucrm pe un site la distan i-l accesm prin protocolul HTTP, furniznd URL (uniform resource locator); n acest caz este nevoie s avem instalate extensiile FrontPage; la conectare vom furniza user i password.

Spre deosebire de Windows Forms, aplicaiile Web au fereastra de vizualizare grafic (Designer) cu mai multe formate de vizualizare, accesibile prin comutatorii din josul paginii: - Design View vizualizarea grafic a controalelor din pagin, care permite lucru n regim grafic; controlele din ToolBox vor fi selectate din tab-ul Web Forms, nu din Windows Forms.

Source View vizualizare n format HTML a codului ce integreaz formularul Web. Se observ aici descrierea html aferent controalelor adugate vizual pe form.

22.10.2012

Rularea paginii de sub Visual Studio declanseaz activarea unui ASP Development Server, folosind cte un port specific pentru comunicare; lansarea paginii din afara mediului Visual Studio se poate face direct din Internet Explorer sau alt browser, indicnd adresa paginii ( ex. http://localhost:1966/WebSite3/myPage.aspx) pe care o folosea i mediul cnd rulam sub mediul integrat (extras din bara de adres) i va funciona dac serverul de dezvoltare este nc activ la acel moment. Specificarea altor detalii de trasare pagin se poate face folosind foi de stiluri. Consultnd directorul n care a fost creat aplicaia (C:\Inetpub\wwwroot\prima) observm mai multe fiiere: xxx.aspx conine codul de vizualizare a paginii Web (implicit se numete default.aspx); xxx.aspx.cs conine codul surs C# pentru declaraiile controalelor i funciilor de tratare a evenimentelor de la nivelul paginii. Un utilizator nu vede acest cod, chiar dac n browser alege View/Source, cci codul vizibil n View/Source este cel deja prelucrat de server. global.asax (dac se adaug la proiect / mouse dreapta pe Solution Explorer); conine informaiile i codul de tratare a evenimentelor de la nivel de aplicaie. web.config conine detaliile de configurare a site-ului web i care sunt preluate cu eventuale modificri la nivel de aplicaie.

ASP.NET ncepnd cu versiunea 2.0 folosete pentru dezvoltarea aplicaiei un server web integrat; acesta lucreaz pe un port distinct de portul pe care lucreaz IIS, prevenind astfel eventualele conflicte ce pot apare. Server-ul web ncorporat ruleaz o pagin web n numele utilizatorului logat n Windows, deci cu eventuale privilegii extinse, fa de IIS care ruleaz cu privilegii stricte, din considerente de securitate sporit. n scopul prevenirii conflictelor de apartene a unei clase la mai multe namespace-uri, va trebui dat calificarea complet a clasei; cum aceast ar putea fi prea lung, se poate folosi using pentru a introduce un alias mai scurt:
using scurt = NumeDeSpatiuLung; scurt.Cls ex;

Ierarhiile din namespace-uri nu reflect neaprat derivri; la derivare clasele pot aparine unor namespace-uri diferite. Namespace-ul nu se confund cu library; o bibliotec dll are un corespondent fizic ( fiier dll ce conine codul executabil aferent unor clase i funcii ), pe cnd namespace-urile sunt mai degrab grupri logice ale unor clase i funcii.

Fazele de lucru cu o pagin Web 1. Iniializarea paginii este rezultatul unei cereri de la un browser; instaniaz controalele din pagin i le iniializeaz cu valori indicate prin Properties; dac suntem pe postback (adic pagina nu e la prima solicitare) valorile curente ale controalelor sunt extrase din ViewState i folosite la iniializare. n aceast faz se declaneaz i evenimentul PageInit, dar e puin folosit, cci se declaneaz nainte de instanierea i ncrcarea controalelor cu valori utile. 2. Iniializarea pe baza codului indicat de utilizator declaneaz evenimentul PageLoad i deci va executa codul scris de programator n funcia de tratare PageLoad. Denumirea de PageLoad este aleas pentru a sugera c uzual, pe server se ncarc i pagini care au mai fost vizualizate n browser i se ntorc n server cu completri. In funcia de tratare PageLoad, pe

22.10.2012

ramura !Page.IsPostBack se pot pune valori de iniializare ale controalelor; pe cealalt ramur valorile nu trebuie puse cci se preiau automat (vezi faza anterioar) din ViewState. Dac iniializm controlul prin cod, atunci trebuie pus EnableViewState pe false, altfel nu se justific munca pierdut prin suprascriere. 3. Validarea prin controale de validare este o faz asociat cu controalele de validare introduse de ASP.NET; ea se derulez naintea oricror evenimente de utilizator. 4. Tratarea evenimentelor de utilizator este o faz derulat dup ce pagina e complet ncrcat n server, iniializat i validat. n principiu, evenimentele de utilizator ar putea fi mprite n dou categorii: evenimente cu rspuns imediat (notificate imediat serverului, pentru a fi tratate); intr n aceast categorie evenimentul de Click pe diverse controale care-l recunosc; evenimente de modificare ( de exemplu, TextChanged, IndexChanged ntr-un control de selecie etc.; ele vor fi tratate nu imediat, ci la urmtoarea ncrcare a paginii n server; dac dorim tratare imediat, proprietatea AutoPostBack a controlului respectiv se pune pe true, ceea ce foreaz notificarea imediat a severului despre producerea evenimentului.

5. Legarea datelor este o faz care se deruleaz n dou trepte: insert, delete i update se execut imediat dup producerea evenimentelor pe controale, dar nainte de Page.PreRender(); select se execut dup Page.PreRender(), alimentnd cu date controalele legate la surse de date; aceast succesiune are dezavantajul c funciile de tratare evenimente nu beneficiaz de cele mai recente date, aduse n controale. Legarea datelor se face automat la fiecare postback; dac se dorete scrierea de cod ce folosete datele dintr-un control cu data-binding, acest cod poate fi pus numai ntr-o suprancrcare a metodei Page.OnPreRenderComplete(), care se execut dup legare i nainte de redarea paginii ca HTML. 6. Eliberarea resurselor se face dup ce au avut loc toate transformrile paginii n server i pagina este redat ca HTML i pornete spre client. n acest moment se declaneaz evenimentul Page.Unload i nicio modificare asupra paginii nu mai este posibil. Garbage collector-ul elibereaz toate instanele de obiecte ce nu mai sunt referite i se declaneaz evenimentul Page.Disposed, care ncheie ciclul de via al paginii n server. Pentru aezarea mai flexibil n pagin se poate folosi un control de tip Table, care permite plasarea diverselor controale n celule, cu posibilitatea de merge, resize, insert etc. Se recomand controlul Table simplu, din seciunea HTML, nu cel din seciunea Standard, care ar necesita resurse ASP.NET, la runtime. Punctul de vedere n baza cruia s-au denumit evenimentele este cel al server-ului: desemneaz ncrcare pagina pe server, pentru prelucrri; Page.PreRender pe server, nainte de a o face HTML, Page.Unload plecare din server ctre client i eliberare resurse pe server.
Page.Load

i pentru Request i Response; spre exemplu, Response.Redirect("newpage.aspx"); precizeaz c n rspuns, serverul cere browser-ului s fac o cerere ctre o alt pagin newpage.aspx. Spre deosebire de aceasta, Server.Transfer("newpage.aspx"); nu presupune un du-te - vino de pagin, ci serverul n loc s prelucreze pagina cerut de browser, prelucreaz o alta, dar de pe acelai server; n browser adresa paginii nu se schimb.

Similar

stau

lucrurile

22.10.2012

worker process =

aspnet_wp.exe

Web server = Internet Information Services [ IIS ] = inetinfo.exe Internet Server Application Programming Interface (ISAPI) conine funcii DLL ce se ncarc dinamic, n acelai proces cu serverul. Avantaj: sunt rapide, partajabile. Pot fi mprite n dou categorii: filtre ncrcate la iniializare server i folosite la tratarea evenimentelor la nivel de server; extensii - ncrcate la prima solicitare i apoi partajate ntre aplicaii. Dezavantaj: la euare, afecteaz tot serverul, fcnd parte din acelai proces. 1. IIS primete cererea i dup extensia de fiier vede ce DLL din ISAPI deservete cererea. Dac extensia este .aspx, adic ASP.NET, atunci invoc funcia adecvat din aspnet_isapi.dll pentru tratarea cererii ( vezi Control Panel / Administrative Tools / IIS / Default Web site / Properties cu mouse dreapta alegem pagina Home Directory i apsm butonul Configuration pentru a vedea asocierile dintre extensiile de fiiere i executabilele ce le deservesc ). 2. Procesul aspnet_isapi.dll transmite cererea ASP.NET ctre worker process (aspnet_wp.exe), care o trateaz; 3. worker process compileaz fiierul .aspx obinnd un assembly, creaz un application domain i instruiete CLR s execute assembly-ul n contextul application domain creat 4. assembly folosete clase din BCL pentru a rezolva cererea i genereaz un rspuns; 5. worker process preia rspunsul generat, l mpacheteaz i-l transmite procesului aspnet_isapi.dll, care l transmite la rndul lui serverului IIS pentru a fi naintat clientului, la distan. Uzual, structura unei pagini include trei seciuni distincte:

seciunea de directive, prin care se stabilesc condiiile de mediu n care pagina se va executa, instruind HTTP runtime cum s proceseze pagina, eventuale namespace-uri folosite n zona de codificare, controale noi de utilizator etc. seciunea de cod, introdus prin tag-ul <script> i care precizeaz codul executabil folosit la execuia unor comenzi din pagin (uzual precompilat, nu neaprat script, cum s-ar putea nelege din delimitator); seciunea de machetare, Page layout, reprezentnd scheletul paginii i preciznd cum se mixeaz elementele de cod cu elementele vizuale din pagin ( controale, texte etc.)

Sintaxa directivelor este unic pentru toate directivele, iar n cazul atributelor multiple acestea sunt separate cu un spaiu; nu trebuie separat cu spaiu semnul egal (=), de asignare a valorilor unui atribut:
<%@ Directive_Name attribute="value" [attribute="value"...] %>

n cadrul unui formular web, adic ntre <form id="Form1" method="post" > putem pune cod C#, declarat ca script:

</form>

Eventualele erori de compilare sunt raportate doar cnd se ruleaz pe aceeai main ( localhost ), dar se poate cere raportarea erorilor i cnd se ruleaz pe un server aflat la distan ; n acest scop n fiierul de configurare web.config, se pune n rubrica adecvat codul urmtor:
<compilation defaultLanguage=c# debug=true

22.10.2012

10

/>

Rezultatul compilrii este un DLL i este pus n directorul c\winnt\Microsoft.Net\ Framework\ ...\Temporary ASP.NET Files. ( precum i n directorul aplicaiei c:\inetpub\wwwroot\... \.bin ). Dac nu s-au fcut modificri n surs, la urmtoarea rulare nu se mai compileaz. Se pot cere mesaje detaliate ( click pe Show Detailed Compiler). Concret, n fiierul Default.aspx.cs se definete dinamic o clas _Default , derivat din clasa System.Web.UI.Page. dintr-unul din exemplele de mai sus, este o metod a acestei clase, dar clasa fiind generat dinamic dispune i de alte metode; spre exemplu. codul repetitiv din sursa de mai sus plasat ntre <%...%> este pasat unei metode numit __Render__control1() pentru redare.
double Patrate(double nr)

Utilizarea unor controale Web simple 1. Se poate rula o pagina ce face adunarea a dou numere, la apsarea pe un buton:
private void btnAduna_Click(object sender, System.EventArgs e) { double s = double.Parse(a.Text)+double.Parse(b.Text); r.Text=s.ToString(); }

unde a,b i r sunt trei textBox-uri. S se modifice programul astfel nct n funcie de selecia dintr-un control DropDownList, la apsarea pe buton s se efectueze Adunare, Scdere sau nimic (None). S se modifice programul astfel nct s se renune la buton, operaia declanndu-se automat la schimbarea seleciei din DropDownList. 2. Aplicatie cu o macheta de introducere date, care la Save face mutarea datelor ntr-un textBox multiline (sau in ListBox ). 3. Pentru familiarizarea cu mediul .NET se va elabora o aplicaie simpl, exemplificnd lucrul cu controale de tipul: Button, TextBox, RadioButton, DropDownList, AddRotator, Calendar. TextBox; RadioButton;Button Mai nti se vor aduce din Toolbox controale de tip TextBox, Label, RadioButton i se vor completa corespunztor proprietile dorite, ca n figura de mai jos. Se adaug apoi trei textBox-uri cu identificatorii a, b i r i un buton inscriptionat cu +, care la apsare (evenimentul Click) declaneaz adunarea a dou numere i afiarea rezultatului. Funcia pus ca tratare a mesajului emis la de buton ar putea arta astfel:
private void btnAduna_Click(object sender, System.EventArgs e) { double s = double.Parse(a.Text)+double.Parse(b.Text); r.Text=s.ToString(); }

22.10.2012

11

DropDownList Se aduce prin dragare din ToolBox un control DropDownList i se populeaz adugnd cteva linii n colecia (proprietatea) Items; i se fixeaz proprietatea AutoPostBack pe true, pentru a anuna serverul de orice schimbare de selectie; se trateaz evenimentul SelectedIndexChanged prin funcia:
private void cbModel_SelectedIndexChanged(object sender, System.EventArgs e) { tbTip.Text = cbModel.SelectedValue; }

funcia preia valoarea selectat i o pune ntr-un TextBox numit tbTip.

AddRotator Fiierul reclama.xml se adaug la proiect cu meniu Project (WebSite) / Add Existing Item...
<?xml version="1.0" encoding="utf-8" ?> <Advertisements> <Ad> <ImageUrl>p29.jpg</ImageUrl> <NavigateUrl>http://localhost/WebApplication10/</NavigateUrl> <AlternateText>Doctorat</AlternateText> <Impressions>40</Impressions> <Keyword>Curs</Keyword> <Specialization>Acces INTERNET </Specialization> </Ad> <Ad> <ImageUrl>p30.jpg</ImageUrl> <NavigateUrl>http://localhost/WebApplication10/ </NavigateUrl> <AlternateText> Biblioteca Academiei </AlternateText> <Impressions>30</Impressions> <Keyword>Books</Keyword> <Specialization>Books for Professionals </Specialization> </Ad> <Ad> <ImageUrl>p31.jpg</ImageUrl>

22.10.2012

12

<NavigateUrl>http://localhost/WebApplication10/</NavigateUrl> <AlternateText> Libraria ASE </AlternateText> <Impressions>30</Impressions> <Keyword>Books</Keyword> <Specialization>Academic Books</Specialization> </Ad> </Advertisements>

Se adaug un control AddRotator care este capabil s afieze aleator, la fiecare schimbare de pagin, cte o imagine cu text asociat ; i se pune proprietatea AdvertisementFile pe valoarea reclama.xml; ne preocupm s existe fiierele imagine citate n reclama.xml.

Calendar Se dragheaz un control Calendar i i se fixeaz proprietatea SelectionMode pe valoarea DayWeekMonth; i se trateaz evenimentul SelectionChange cu funcia:

private void Calendar1_d(object sender, System.EventArgs e) { string sbMesaj=""; for( int k=0; k < Calendar1.SelectedDates.Count; k++) sbMesaj += Calendar1.SelectedDates[k].ToShortDateString() + "<br>"; lblMesaj.Text = sbMesaj; }

Funcia preia datele selectate din calendar i le pune ntr-un control Label lblMesaj.

Un alt exerciiu care s ne apropie mai mult i de partea de gestiune a datelor, ar putea fi o aplicaie cu o machet de introducere date, care la Save face mutarea ntr-un textBox multiline sau ntr-un ListView. Clasa Page Ierarhia derivrii:
System.Object System.Web.UI.Control System.Web.UI.TemplateControl System.Web.UI.Page

22.10.2012

13

deci clasa Page este i un control avnd o mulime de proprieti i evenimente pe care le recunoate. Este i container de controlale, colecia Controls furniznd acces la controalele de pe pagin. Aa cum aminteam, etapele crerii paginii sunt semnalate prin evenimente ce pot fi interceptate i folosite pentru a plasa cod de utilizator pentru executat legat de acel moment: - Init generat la crearea unei instane de tip Page; se poate folosi i pentru a ataa dinamic handlere altor evenimente recunoscute de pagin i declanate ulterior. la terminarea iniializrii i ncrcarea obiectului Page n memorie; se poate folosi i pentru a ataa cod de iniializare controalelor de pe pagin. PreRender declanat nainte de redarea vizual a paginii pe ecran; e folosit pentru eventuale retuuri nainte de a trimite pagina n browser pentru trasare. Unload la descrcarea paginii din server ( page cleanup).
Load

Tratarea evenimentelor permite aplicaiilor s se adapteze dinamic la schimbrile contextuale din mediul de rulare
<%...%>

e un bloc de redare a interfeei i se pune n interiorul unei metode; deci nu poate conine definirea unei alte metode !

Tratarea unui eveniment se poate face ntr-una din modalitile: 1. adugnd un handler la delegatul disponibil pentru acel eveniment; 2. sau suprancrcnd metoda (OnXxxx() ) motenit din clasa de baz. Varianta cu handler este avantajoas deoarece: - nu cere ca tratarea s se fac ntr-o clas derivat din clasa de baz (suprancrcarea metodei (OnXxxx() se poate face doar n clasele derivate dintr-o clas de baz ); - permite ataarea / detaarea dinamic a mai multor metode de tratare a aceluiai eveniment; - aceeai funcie de tratare se poate aplica i altor evenimente fr a o rescrie n diverse clase. n .NET exist clasa care descrie un delegat generic, numit EventHandler; instanierea clasei produce un obiect delegat i presupune furnizarea prototipului funciilor de tratare ce le va conine. Declaraia prototipului acestui delegat este deja facut n mediul de programare:
public delegate void EventHandler(object sender, EventArgs e);

i arat c acest tip de delegat poate ine referina oricrei funcii ce primete un obiect generic i un bloc de parametri cu argumentele specifice unui eveniment generic i returneaz void. Cnd adugm unui eveniment o funcie de tratare, se instaniaz un nou delegat, care prin constructor primete i referina pe care o va transporta:
this.Load += new EventHandler(tratareLoad);

Se observ aici evenimentul ( Load ), delegatul generic (EventHandler) i numele funciei de tratare ( tratareLoad ). Mecanismul AutoEventWireup="true" n aplicaiile Web mai exist un mecanism de ataare a unor funcii de tratarea evenimentelor unei pagini Web numit mecanism AutoEventWireup. Este cel de-al treilea mecanism de ataare cod executabil unor evenimente, alturi de suprancrcarea funciilor motenite din clasa de baz, respectiv mecanismul delegrii.

22.10.2012

14

El se activez numai dac pagina are atributul AutoEventWireup = "true" i se bazeaz pe definirea de ctre programator a unor funcii de tratare cu nume impus, de forma Page_EventName(). Presupunem c se creeaz o aplicaie Web numit AprindereAutomat. n fereastra de vizualizare se alege formatul HTML i se modific codul surs pentru a arta astfel:
<%@ Page Language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="true" Inherits="AprindereAutomata.WebForm1"%> <!--Exemplificare mecanism AutoEventWireup --> <HTML> <body> <script runat="server"> protected void Page_Load(Object o, EventArgs e) {Response.Write("Mesaj din functia de tratare eveniment Load .<br>");} protected void Page_Init(Object o, EventArgs e) {Response.Write("Acum se produce eveniment Page_Init .<br>");} protected void Page_PreRender(Object o, EventArgs e) {Response.Write("Mesaj pentru eveniment PreRender .<br>");} </script> <hr> </body> </HTML>

Atenie cnd textul surs se preia cu Copy / Paste, ghilimelele trebuie s fie cele drepte, nu "smart" !

Clauza AutoEventWireup="true", altfel Visual Studio o pune implicit pe false. Exemplul funcioneaz de sine stttor, fr a necesita construire de delegai de evenimente i ataare de funcii de tratare. Preul pltit este c funciile de tatare au nume impus, corelat cu evenimentul la care se refer: Page_Load, Page_Init, respectiv Page_PreRender. recomand folosirea simultan a mecanismelor delegate i AutoEventWireup="true" deoarece unele din funciile de tratare pot fi apelate de dou ori; explicaia const n faptul c n cadrul mecanismului AutoEventWireup ASP.NET leag automat la delegaii corespunztori, metodele cu numele impus, iar cnd programatorul ataeaz metodele cu += le leag a doua oar! Exemplul de mai sus se putea da i ca fiier text, ataabil la un proiect vid, nemaifiind necesar trimiterea la fiierul cu cod surs Codebehind="WebForm1.aspx.cs", care oricum nu aducea n plus ceva major. Mecanismul code-behind separ codul necesar descrierii interfeei utilizator (user interface) de codul ce detaliaz algoritmii de prelucrare (business logic). Prima categorie se pune n fiierul de tip .aspx, cea de-a doua n fiierul .cs; astfel este posibil i lucru n echip, designerii ocupndu.se de proiectarea vizual a paginii, iar programatorii de prelucrri. Cele dou fiiere sunt legate prin atributul Codebehind din directiva Page; acesta precizeaz fiierul cu cod surs . Linkeditarea apare astfel ca fiind iniiat din pagina de utilizator. Directiva Page precizeaz atribute necesare compilrii i vizualizrii paginii Web. Src- citeaz numele fiierului surs ce conine clasa code-behind care este compilat dinamic la solicitarea unei pagini Web. Cnd folosimVisual Studio .NET nu este nevoie de acest atribut doarece clasa code-behind este precompilat. Nu se

22.10.2012

15

Inherits furnizeaz numele clasei code-behind ce conine codul paginii ASPX i din care clasa generat dinamic va moteni prin derivare. Desi Src furnizeaz aceeai informaie ca atributul Codebehind; ntre ele exist o deosebire major: Src e necesar cnd compilarea se face la momentul vizualizrii paginii. Visual Studio a optat pentru precompilarea codului ce nsoete pagina Web. Pentru c mediul Visual Studio separ i el codul de vizualizare de cel de prelucrare, are totui nevoie la momentul proiectrii aplicaiei de numele fiierului ce ine codul surs C#, pentru a-l compila din vreme; acesta e indicat prin Codebehind. Aadar, Codebehind este un atribut neles i folosit numai de VS (nu i de ASP.NET la execuia paginii) pentru localizarea fiierului surs ce conine definirea claselor folosite n pagin. Asocierea Src i Inherits sugereaz o pagin fr compilare prealabil. Asocierea Codebehind i Inherits sugereaz o pagin cu precompilare Precompilarea are urmtoarele avantaje: - ne asigur c am rezovat toate erorile de compilare; - nu mai trebuie dat beneficiarului codul surs, ci doar dll-urile; - chiar cnd pe calculatorul beneficarului exist alt versiune de .NET, clasa folosete versiunea cu care a fost ea creat. Meniu Project / Show All Files permite vizualizarea n Solution Explorer a tuturor fiierelor folosite n cadrul unui proiect, altfel implicit sunt vizibile doar o parte dintre ele. Fiierul de configurare Web.config conine toate clauzele de configurare a proiectului, inclusiv debug = true, necesar cnd aplicaia nu poate fi rulat n mod depanare, cci ea a fost compilat fr opiuni de depanare. Punnd-o pe true, ne asigurm c recompilarea se face cu adugarea tuturor facilitilor de depanare. Ildasm.exe (Intermediate Language Disassembler) poate vizualiza EXE i DLL ntr-un format accesibil utilizatorului. Tipologia controalelor dintr-o aplicaie ASP.NET HTML Controls preluate din HTML clasic; accesul la informaii este greoi (trebuie analizat pagina de rspuns). HTML Server Controls identice cu cele de mai sus, dar prin runat = server devin accesibile prin program i ruleaz pe server; asigur acces uor la informaii prin intermediul proprietilor i evenimentelor. Web Server Controls specifice ASP.NET; acoper toate controalele de mai sus i ceva n plus; ofer alt model, mai consistent, de programare. Validation Controls User Controls, Composite Controls i CustomControls extensii sau adaptri, create de utilizator

Web Server Controls - orientate obiect; built-in i recunoscute automat de browser-ele de nivel nalt; - unele produc postback imediat la click sau la schimbare de valori; - unele las mesajele primite s ajung i mai sus, la containerul controaleleor. Au numele prefixat cu asp: , ca mai jos: <asp:Label runat=server/>

22.10.2012

16

Label - <span> TextBox - <input type=text>, <input type=password>, <textarea> Proprietatea AutoPostBack a unui textBox precizeaz cnd pagina va fi transmis server-ului automat la orice modificare a textului sau cnd evenimentul TextChanged va fi tratat de client. Este efectiv doar dac browser-ul suport client-side scripting. ASP.NET ataeaz controlului un mic script ce face ca evenimentul s fie transmis serverului cu ocazia altui eveniment, uzual Click de buton. Image <img>
ImageUrl

indic locaia URL n care rezid imaginea de afiat

CheckBox i RadioButton - <input type=checkbox> i <input type=radio> Proprietatea AutoPostBack precizeaz cnd pagina va fi transmis server-ului la schimbarea strii butoanelor. Button - <input type=submit> LinkButton - hyperlink , <a> tratat doar de browsere ce suport client-side scripting ImageButton - <input type=image> ImageClickEventsArgs ncapsuleaz informatii despre coordonatele punctului din imagine unde s-a dat click. Repeater, DataList, DataGrid suport bubbling de evenimente, adic posibilitatea ridicrii automate a evenimentelor ctre controlul printe. Dup modul n care sunt sesizabile la nivelul serverului, evenimentele din pagina web se mpart n dou categorii: Postback, care sunt anunate imediat serverului; Non-postback, care nu sunt anunate imediat serverului, pentru a nu mri excesiv traficul n reea. Evenimentele non-postback sunt evenimente mrunte, cu rol mai ales local, la nivelul paginii ( spre exemplu, completarea unor rubrici ntr-un formular - TextChanged), urmnd ca dup mai multe astfel de evenimente s se genereze un eveniment de tip postback ( Click pe un buton Submit) care s permit transferul spre server al tuturor modificrilor produse n pagin. Controalele care genereaz evenimente dein o proprietate boolean AutoPostBack, cu valori implicite, prin care se specific dac evenimentele generate de acestea sunt postback sau nonpostback. Dup valoarea implicit a acestei proprieti putem distinge: controale postback : Button, Calendar, DataGrid, DataList, ImageButton, LinkButton, Repeater. controale non-postback: CheckBox, CheckBoxList, DropDownList, ListBox, RadioButtonList, RadioButton, TextBox.

Modificnd valoarea proprietii AutoPostBack putem schimba dinamic "vizibilitatea" acestor evenimente la nivelul serverului. Putem observa ns, c la un moment dat, toate evenimentele generate de un control sunt fie postback, fie non-postback. Categorii de controale tag HTML
<input>

Categoria Input

Nume HTML HtmlInputButton HtmlInputCheckBox HtmlInputFile

Descriere <input type=button | submit | reset> <input type=checkbox> <input type=file>

22.10.2012

17

Categorii de controale tag HTML Categoria Nume HTML HtmlInputHidden HtmlInputImage HtmlInputRadioButton HtmlInputText
<img> <textarea> <a> <button> <form> <table> <td> <th> <tr> <select>

Descriere <input type=hidden> <input type=image> <input type=radio> <input type=text | password> Image Text multilinie Ancor Customizable output format, usable with IE 4.0 and above browsers Maximum of one HtmlForm control per page; default method is POST Tabel, format din linii, ce conin celule Celul de tabel sau celul antet de tabel Linie de tabel Meniu pull-down Control HTML generic

Input Input Container Container Container Container Container Container Container Container

HtmlImage HtmlTextArea HtmlAnchor HtmlButton HtmlForm HtmlTable HtmlTableCell HtmlTableRow HtmlSelect HtmlGenericControl

22.10.2012

18

Gestiunea datelor
folosind clasele File, FileStream, StreamReader, StreamWriter, BinaryReader i BinaryWriter; n baze de date, folosind clasele ADO.NET specifice fiecrui SGBD; n fiiere XML, care pot ine att date, ct i descrierea lor, clasele folosite fiind XmlNode, XmlDocument, XmlTextReader i XmlTextWriter. n fiiere,

Controlul GridView sub Visual Studio pentru aplicaiile Web, se aseamn cu cel din Windows Forms, dar are cteva particulariti ce in de o mai bun gestiune a resurselor, avnd n vedere c BD se afl pe server, iar transferul de volume mari de date ctre client presupune band larg de transfer i necesit timp considerabil. n aplicaiile Web, gridul: 1. permite paginarea, adic posibilitatea prelurii datelor din DataSet sau din sursa de date, pe msura defilrii n sus i n jos, n grid; 2. lucreaz deconectat de la baza de date, ca i n Windows Forms, dar disponibilizeaz datele ca text, implicit read-only; anumite proprieti ale gridului permit ns introducerea n regim de editare, cnd pentru linia editat se disponibilizeaz o linie de TextBox-uri ce mediaz aceast editare.

Caching
n lucru cu baze de date, avem de ales ntre: a avea date care beneficiaz de cele mai recente actualizri, cu preul extragerii lor direct din baza de date; a ine datele n memorie cache, mai rapid accesibil dect baza de date, dar reflectnd situaia de la momentul citirii lor din baza de date; modificrile survenite ntre timp ar putea fi semnificative, mai ales n cazul accesului simultan al mai multor utilizatori pe acceai baz. Memoria cache se rezerv uzual pe server, n cadrul procesului ce execut cererile n contul aplicaiei client. Se poate rezerva i n memoria global, cnd deservete mai muli clienti (sau chiar pe disc, depinznd de configurarea serverului, de ctre administrator ). Cache este un obiect n care punem date (aici ntreg dataSet-ul) identificate prin nume. Funciile Page_Load i LeagaGrid arat n aceast situaie astfel:
private void Page_Load(object sender, System.EventArgs e) { if(!IsPostBack) {// daca pagina e ncrcat prima data, incarca datele in cache oleDbDataAdapter1.Fill(dataSet1); Cache["ProdCache"]=dataSet1; LeagaGrid(); } } private void LeagaGrid() { dataSet1=(DataSet)Cache["ProdCache"]; dg.DataSource= dataSet1; dg.DataBind(); }

Lucrul cu un control GridView i baz de date SqlServer sub Visual Studio

22.10.2012

19

Configurare ASP.NET 3.5 pentru a lucra cu Microsoft SQL Server 2005 sau SQL Server Express 2008 1. Trebuie s existe instalat serverul de web IIS sau se descarc de pe site-ul Microsoft. Testare local se poate face i cu serverul de dezvoltare furnizat de Visual .NET. 2. Se instaleaz VS 2008 i implicit .NET Framework 3.5 3. Se instaleaz SQL Server Express 2008, iar la instalare se las opiunea implicit de autentificare: Windows Authentication, nu optm pentru varianta SQL Authentication, unde ar fi trebuit s introducem username i password pentru un utilizator nregistrat n prealabil n BD. Pentru generalitate, din punctul de vedere al bazei de date, n cele ce urmeaz se vor aborda exemple de lucru pe trei direcii: SQL Server Express 2008, pe calculatorul local SQL Server 2005, la distan Microsoft Access, pe calculatorul local Inregistrarea utilizatorului ASPNET la o baz de date sub SQL Server Express 2008 4. Se deschide SQL Server Management Studio Express (daca nu il aveti instalat, se poate face download de la adresa http://msdn.microsoft.com/vstudio/express/sql/download/ 5. La deschidere apare fereastra Connect to server, n care se cer informaiile de conectare la server (Server name: numele calculatorului dvs.\SQLExpress; Authentication:Windows Authentication). 6. In fereastra din stnga (Object Explorer), se deschide Security->Logins. Se face right click pe Logins i alegei din meniul contextual New Login... In fereastra Login New, la Login name: numele calculatorului dvs.\ASPNET i apsai OK. 7. Tot n fereastra din stnga, Databases->prod->Security->Users->right click->New User...(In noua fereastra deschisa-> User Name:ASPNET; Login name: numele calculatorului dvs.\ASPNET; n fereastra de jos "Database role membership:" selectai db_datareader i db_datawriter i apsai OK). Detalii interesante putei gsi la adresa: http://www.spaanjaars.com/QuickDocId.aspx?quickdoc=395 Popularea unei baze de date sub SQL Server 2008 pe local, prin import din Access Start / All programs / MS SqlServer 2008 / Import and Export Data (32 bits); se declaneaz un wizard n care se alege Data Source MS Access, cu Browse fiierul ce contine BD surs, apoi se dau coordonatele BD destinaie. Pregtirea unei baze de date sub SQL Server la distan Pentru lucru pe un server (n cazul nostru Orion ) plasat n alt parte dect pe calculatorul local se poate proceda astfel: 4. se deschide un terminal Remote Desktop ( Run mstsc sau Remote Desktop din Programs / Accesories sau un Remote Desktop Web Connection , de exemplu, aris.ase.ro/tsweb ) 5. se indic serverul Orion sau IP 10.2.64.73 i se cere conectarea la acesta; 6. n fereastra de conectare se indic user admin i password meca2007/1 7. conectat la calculatorul respectiv, se activeaz din Programs, Sql Server Management Studio 8. urmeaz conectarea la baza de date de pe serverul ORION folosind Autentificare Windows

22.10.2012

20

9. la conectare vedem i baza de date doctorat, cu trei tabele deja construite i populate cu date de test.

Dac nu avem aceste elemente deja create, sub Sql Server Management Studio se pot face operaii de genul crerii unei noi baze de date, adugrii de tabele sau actualizarea datelor dintr-o tabel. n aceast manier a fost creat baza de date doctorat, cu tabelele produse, materiale i consumuri. Crearea i popularea unei BD SqlServer folosind Server Explorer sub Visual Studio In Server Explorer pe Data Connections, mouse dreapta, Create New Sql Server DB; in fereastra care apare: Server name: 10.2.64.73 Use SQL Server Authentication user : sa password : as se d un nume bazei de date Selectnd conexiunea creat cu aceast ocazie, cu mouse dreapta pe Tables se cere Add new table i apoi se descriu cmpurile i se salveaz tabela sub un nume dorit. Este bine ca unul din cmpuri s fie declarat drept cheie (cu icon sau mouse dreapta / Set Primary key) pentru a beneficia ulterior de generare automat a comenzilor INSERT, UPDATE, DELETE. Selectnd tabela creat, cu mouse dreapta se alege Show Table Data, iar n gridul care apare se introduc pe rnd tuplurile dorite.

22.10.2012

21

Smart tag este un artificiu semnalat printr-o mic sgeat plasat n coltul dreapta-sus al unor controale complexe (GridView, TreeView, Calendar etc.) prin care se accede la un meniu de configurare rapid a controlului.

Etape de lucru cu un control grid 1. n Designer, se trage un control GridView din Tools i se denumete dg; 2. cu butonul mouse dreapta pe grid se poate cere AutoFormat, avnd posibilitatea de a alege dintre mai multe formate de grid i scheme de colorare; n Properties, i se pot fixa apoi diverse alte proprieti de vizualizare (headerStyle, backColor, border style etc.); n general vorbind, proprietile din grupul Appearance afecteaz caracteristicile estetice la nivelul ntregului grid; proprietile din grupul Styles afecteaz caracteristicile la nivel de linie din grid; proprietile la nivel de coloan din grid pot fi stabilite doar prin intermediul smart tag ului (colul dreapta sus, al gridului), de unde se va selecta Edit Columns. 3. dac nu exist, se creaz o baz de date doctorat sub SqlServer. Ne asigurm c ea conine i tabela produse, n care exist cmpurile: codp, denum, pret. 4. Se dragheaz din Tools un control SqlDataSource ( dac nu exist n Tools, poate fi adus cu buton dreapta mouse Choose Items... din galeria de controale ), denumit implicit SqlDataSource1, pe care l vom redenumi n Properties SqlDataSourceOrion; 5. se configureaz obiectul SqlDataSourceOrion cu buton dreapta mouse Configure Data Source, care declaneaz un wizard prin care: n Server Explorer se alege o nou conexiune, avnd grij s selectm corect provider-ul Sql Server, dar ar putea fi i Oracle, MS Access etc. se indic baza de date ( sau fiierul coninnd baza de date, dac BD e orientat pe fiiere ca n Access, Fox etc). se compune fraza SELECT folosit la ncrcarea datelor din baza de date; pe butonul Advanced pot fi configurate i comenzile UPDATE, INSERT i DELETE, dac se dorete i acest lucru. Este posibil generarea automat a acestor comenzi doar dac unul din cmpuri (n cazul nostru codp ) este cmp cheie; altfel trebuie mai nti sub SQL Server Management Studio declarat cmpul cheie. Observaie: pentru o surs de date Access se poate folosi un obiect mai simplu, de tip AccessDataSource.

22.10.2012

22

Se poate alege opiunea ca irul de conexiune s poat fi pstrat n fiierul web.config, fiind accesibil astfel din orice pagin a aplicaiei web; n acest caz, se vor memora automat n web.config numele dat conexiunii i valoarea propriu-zis, printr-o secven de genul:
<connectionStrings> <add name="doctoratConnectionString" connectionString="Data Source=orion;Initial Catalog=doctorat;User ID=sa;Password=as" providerName="System.Data.SqlClient"/> </connectionStrings>

Acest lucru, ne permite ulterior s folosim numele doctoratConnectionString pentru a localiza legtura la baza de date doctorat. 6. Controlul GridView poate deja folosi acum sursa de date creat, fixndu-i-se acestuia proprietatea Data Source pe SqlDataSourceOrion; la rulare gridul va afia datele din tabela aleas. La legarea sursei de date la un grid, partea declarativ a gridului (vezi codul surs n Designer, tab-ul Source ) se dezvolt rapid, prin preluarea informaiilor despre coloanele sursei de date. Dup legare, denumirile generice ale coloanelor din grid pot fi actualizate rapid prin click pe Refresh Schema din "smart tag". pe true, dac vrem s apar toate coloanele i n ordinea din sursa de date. pe false i adugm n Properties, Columns ( sau din smart tag, Edit Columns ) doar ce coloane dorim i n ce ordine dorim; procedm aa i cnd adugm coloane cu butoane de editare a datelor din grid.
dg.AutoGenerateColumns dg.AutoGenerateColumns

Coloanele au coninutul de un anumit tip; cele mai folosite tipuri de coloane sunt: BoundField cnd coloana este legat, adic afiez coninutul unui cmp din sursa de date; ButtonField cnd coloana afiez cte un buton pentru fiecare item din list. CheckBoxField cnd coloana afiez un checkBox pentru fiecare item din list, semnificnd true/false, pentru cmpurile cu valori logice, stocate la nivel de bit, n SQL Server; CommandField cnd coloana afiez butoane pentru selecie, editare, tergere etc. Se observ c pentru a nu crea confuzie de terminologie ntre coloan tabel i coloan grid, coloanele din grid au fost denumite cmpuri ( field ).

22.10.2012

23

Se pot combina ambele variante, caz n care coloanele autogenerate sunt puse primele. O tehnic mai subtil ar fi urmtoarea: se las dg.AutoGenerateColumns pe false aa cum e pus implicit la dragarea obiectului; la legarea sursei nu se observ nimic n grid, dar apsnd Refresh Schema aferent controlului data source, AutoGenerateColumns comut automat pe true i mediul adaug cte o coloan de tip BoundField pentru fiecare cmp din data source; putem acum s schimbm ordinea coloanelor, sau n BoundField Properties denumirile din cap de coloan, s tergem coloanele care nu ne intereseaz, sau s le pstrm fcndu -le invizibile (doar programatic): dg.Columns[2].Visible = false;

La rulare, gridul este legat automat la surs i va afia datele din tabela indicat n fraza Select.

Paginarea gridului pentru a afia doar o parte din date cu smart tag (Enable Paging bifat) sau n Properties (Allow Paging true), se declar opiunea ca gridul s poat afia pe mai multe pagini informaia; n Properties, la PagerSettings / Mode se stabilete modul de navigare ntre pagini (Numeric, salt direct la pagina dorit) i numrul de indeci de pagin afiai simultan (PageButtonCount, 10); n Properties, la Page Style se precizeaz cte nregistrri sunt vizibile pe o pagin (Page Size, 4); CurrentPageIndex va conine indexul paginii curent selectat; la schimbarea paginii se genereaz automat (i poate fi tratat) evenimentul PageIndexChanged. Aceast paginare automat se realizeaz uor datorit motenirilor prin derivare din clasa
ICollection i este posibil pentru un GridView bazat pe o surs de date cu proprietatea DataSourceMode pus pe DataSet, deoarece doar acesta se afl pe filiera de motenire amintit. 22.10.2012

24

Sortarea datelor din grid dup una sau mai multe coloane Sortarea datelor din grid se poate face: a. chiar din fraza select, prin care se ncarc dateSet-ul; aceast comand poate conine i clauza ORDER BY. Are dezavantajul c va sorta datele ori de cte ori le rencarc din BD, dar are avantajul unei sortri rapide; b. folosind obiectul DataView asociat dataSet-ului; orice dataSet are o vizualizare implicit sau explicit; un obiectul DataView e specializat pe vizualizri sub diverse forme de prezentare, inclusiv sortri complexe; concret, proprietatea DataSource a gridului poate cita obiectul DataView, care asigur vizualizarea datelor din dataSet. c. folosind faciliti ale gridului (AllowSorting pe true); cu smart tag se alege Edit Columns; pe coloanele dorite, se stabilete proprietatea SortExpression, care permite citarea unei expresii de sortare, format din nume de cmpuri nsoite de cuvintele cheie ASC i DESC; eventual se cere i Refresh Schema pentru a reactualiza schema de legare a cmpurilor.

La execuie, dnd click pe antetul unei coloane se face sortarea dup expresia de sortare corespunztoare cmpului respectiv. Editarea datelor din grid Ideea de baz a actualizrii n grid const n a aduga o coloan cu butoane de comand, cte unul pentru fiecare linie din grid; se trateaz evenimentul Click buton pentru a executa operaia corespunztoare butonului liniei respective i se rencarc gridul. n cazul editrii, apsarea butonului Edit declaneaz transformarea celulelor legate de cmpuri non-cheie, n textBox-uri. Butonul Edit se substituie pe durata editrii cu alte dou butoane, Update (apsat cnd dorim ca modificrile s fie reinute) i Cancel (cnd se renun la modificrile operate n textBox-uri). Paii de lucru: cu gridul selectat, n smart tag / Edit Columns se adaug cu Add o nou coloan de data acesta de tip Command Field, mai precis un cmp Edit, Update, Cancel; s-ar fi putut realiza acelai lucru i cu Properties / AutoGenerateEditButton pe true, dar aveam mai puine posibiliti de control asupra cmpului; cu sgeat sus-jos se alege poziia cmpului nou introdus, n raport cu celelalte existente n grid, iar din fereastra din dreapta se stabilesc alte proprieti ( spre exemplu ButtonType se alege Button, ca mod de apariie), ce s scrie pe butoanele respective etc.

22.10.2012

25

obiectul SqlDataSource are printre proprieti i UpdateQuery, ce conine o comand de UPDATE, care poate fi de tip text sau procedur catalogat; n cazul nostru, textul comenzii citeaz cmpurile i parametrii asociai (pui implicit, prin mecanismul de legare date i denumii dup numele cmpurilor, plus un prefix):
UPDATE produse SET denum =@denum, pret = @pret WHERE (codp = @codp)

Dei analiznd codul surs din fiierul aspx constatm c parametrii se numesc la fel i pentru comanda UPDATE i pentru INSERT sau DELETE, ei sunt inui n colecii diferite i deci nu pot fi confundai.
<DeleteParameters> <asp:Parameter </DeleteParameters> <UpdateParameters> <asp:Parameter <asp:Parameter <asp:Parameter </UpdateParameters> <InsertParameters> <asp:Parameter <asp:Parameter <asp:Parameter </InsertParameters> Name="codp" Type="String" /> Name="denum" Type="String" /> Name="pret" Type="Double" /> Name="codp" Type="String" /> Name="codp" Type="String" /> Name="denum" Type="String" /> Name="pret" Type="Double" />

Gridul fiind legat la o surs de date, DataBinding-ul funcioneaz n ambele sensuri, astfel nct parametrii aparinnd sursei de date vor fi ncrcai cu valorile modificate din grid. vor fi declanate acum, nainte de actualizarea propriu-zis, i evenimentele asociate aciunilor de modificare i tergere, astfel nct li se pot asocia funcii de tratare:
dg_RowUpdating, dg_RowCancelingEdit.

Uzual se pun aici diverse validri specifice; dac se preia n aceast funcie chiar sarcina actualizrii (spre exemplu, folosind obiecte SqlCommand i scriind n baz cu cmd.ExecuteNonQuery, se va inhiba actualizarea i cu comanda UPDATE-ul de pe sursa de date, punnd n dg_RowUpdating instruciunea e.Cancel = true. Se pot face diverse combinaii; de exemplu pentru funcia de inserare se pot ncrca unul cte unul parametrii cu valori (nu funcioneaz Binding automat cci nu avem linie nou n grid) i apoi se lanseaz metoda ExecuteNonQuery a obiectului de InsertCommand, aparinnd SqlDataSource; n felul acesta nu mai este nevoie s declarm alt obiect SqlCommand, s-l echipm cu parametri, conexiune etc.

22.10.2012

26

tergerea datelor din grid n grid, cu smart tag / Edit Columns se adaug cu Add o nou coloan de tip Command Field, mai precis un cmp Delete; cu sgeat sus-jos se poziioneaz cmpul nou introdus, ca ultim coloan din grid, iar din fereastra din dreapta se stabilesc alte proprieti ale acestuia; SqlDataSource are printre proprieti i DeleteQuery, ce conine o comand DELETE; o putem edita direct sau o putem construi cu QueryBuilder, nct s arate astfel:
DELETE FROM produse WHERE (codp = @codp)

la rulare, prin apsarea butonului Delete, este tears nregistrarea curent selectat n grid; pentru testarea tergerii, pot fi adugate noi nregistrri fictive, folosind Server Explorer, selectnd conexiunea ctre orion.doctorat.dbo, tabela produse i beneficiem de un gen de client SQL cu care putem opera direct modificri pe baza de date.

DataKeyNames precizeaz din ce cmpuri va prelua valoarea n dicionarul Keys n dicionarele NewValues i OldValues valorile se pun O pagin poate conine extrem de multe controale; ele pot genera o mulime de evenimente, care genereaz la rndul lor cereri multiple ctre server, mrind exagerat traficul client-server. n plus, odat cu argumentele evenimentului trebuie s circule i alte informaii din pagin (spre exemplu starea controalelor) pentru a se putea reconstitui pagina la momentul primirii rspunsului de la server. Pentru diminuarea frecvenei traficului i volumului de date transferate se recomand: evitarea populrii n exces a paginii, cu controale; setarea proprietii EnableViewState a controalelor pe false, cnd nu este nevoie de pstrarea strii lor ntre dou configurri ale paginii. Adugarea datelor n grid Proprietatea DataSourceMode a sursei de date precizeaz dac ea lucreaz cu DataSet sau DataReader, drept container de date. n principiu, dac sursa de date are proprietatea

22.10.2012

27

DataSourceMode pe valoarea DataSet, putem recompune dataSet-ul sau tabela de date cu care lucreaz SqlDataSource, dup modelul oferit de funcia de mai jos:
protected void btnPullDataSet_Click(object sender, EventArgs e) { string conexiunea= "Data Source=orion;Initial Catalog=doctorat;User ID=sa;Password=as"; string frazaSelect="select * from produse"; SqlDataSource SqlDataSource2= new SqlDataSource(conexiunea,frazaSelect); DataSourceSelectArguments args = new DataSourceSelectArguments(); DataView dataView1 = (DataView)SqlDataSource2.Select(args); DataTable dataTabl1 = dataView1.ToTable(); ds.Tables.Add(dataTabl1); // dg.DataSourceID = null; dg.DataSource = ds; dg.DataBind(); }

Funcia de inserare nu este implementat direct prin controlul GridView, astfel nct vom folosi SqlDataSource i vom aborda programatic problema, declarnd i instaniind obiecte de tip SqlConection, i SqlCommand. Vom aduga namespace-urile care definesc clasele aferente acestor controale
using System.Data.SqlClient; using System.Data.SqlTypes;

Adugm un buton, pe al crui eveniment de click legm funcia de adugare a unei noi nregistrri:
public void btnAdd_Click(object sender, System.EventArgs e) { DataSourceSelectArguments args = new DataSourceSelectArguments(); DataView dataView1 = (DataView)SqlDataSourceOrion.Select(args); DataTable dataTabl1 = dataView1.ToTable(); DataRow linNoua; linNoua = dataTabl1.NewRow(); int cateRecords = dataTabl1.Rows.Count, maxCod = 0, crtCod; for (int i = 0; i < cateRecords; i++) { crtCod = Convert.ToInt32(dataTabl1.Rows[i][0]); if (crtCod > maxCod) maxCod = crtCod; } maxCod++; linNoua["codp"] = "" + maxCod; // cod in secventa, dupa cel mai mare existent linNoua["denum"] = "pr_" + maxCod; linNoua["pret"] = maxCod * 100; // aducere la zi si in baza de date SqlConnection con = new SqlConnection(SqlDataSourceOrion.ConnectionString); con.Open(); SqlCommand cdaInsert = new SqlCommand( "INSERT INTO produse(codp, denum, pret) " + " VALUES (@codp, @denum, @pret)", con); cdaInsert.Parameters.Add(new System.Data.SqlClient.SqlParameter( "@codp", System.Data.SqlDbType.NVarChar, 50, "codp")); cdaInsert.Parameters.Add(new System.Data.SqlClient.SqlParameter( "@denum", System.Data.SqlDbType.NVarChar, 50, "denum")); cdaInsert.Parameters.Add(new System.Data.SqlClient.SqlParameter( "@pret", System.Data.SqlDbType.Float, 8, "pret")); // da.InsertCommand = cdaInsert; cdaInsert.Parameters["@codp"].Value = linNoua["codp"]; cdaInsert.Parameters["@denum"].Value = linNoua["denum"]; cdaInsert.Parameters["@pret"].Value = linNoua["pret"]; if (cdaInsert.ExecuteNonQuery() > 0) { mes.Text = ("Inserare cu succes "); dg.DataBind(); }

22.10.2012

28

else mes.Text = ("Esec la inserare "); } }

Se observ c am folosit doar principiu de extragere a dataSet-ului sursei de date, nu ntreaga funcie, oprindu-ne doar la nivel de tabel, pentru a-i aduga o linie nou. Dac se cere Refresh pe pagin, aceasta este retrimis n server; primim un avertisment n acest sens de la browser i ntr-adevr constatm c va insera cte o linie la fiecare Refresh !! Alte detalii i alte modaliti de lucru cu un GridView putei gsi consultnd exemplul de proiect complet sub VS 2008, ce va fi prezentat ntr-un capitol viitor.

22.10.2012

29

Vizualizarea grafic a datelor folosind un control de tip chart Pentru varietate se prezint dou controale diferite de tip chart: un control open source, disponibil pe Internet, ca surs i ca biblioteci DLL, ZedGraph (http://www.codeproject.com/KB/graphics/zedgraph.aspx) unul furnizat drept component Web de ctre Office 2003 ( Office Web Component 11.0, control similar chart-ului din Excel); trebuie s dispunem de controalele aduse de ctre MS Office 2003; dac nu, controalele pot fi descrcate de pe site-ul Microsoft. n cazul folosirii controlului ZedGraph n aplicaia care conine un GridView i o surs de date, paii de lucru ar putea fi urmtorii: In Solution Explorer cu buton dreapta mouse se cere Add Reference i se localizeaz cu Browse i se leag la proiect cele dou fiiere ZedGraph.dll i ZedGraph.Web.dll, descrcate de pe Internet i care conin clasele cu care lucreaz controlul web. Se construiete n directorul aplicaiei un subdirector de lucru numit ZedGraphImages, n care controlul i compune imaginile grafice. Se adaug o pagin nou pe care o vom numi WebFormZedGraph (Website / Add New Item i alegem WebForms) i pe ea (fiierul WebFormZedGraph.aspx.cs) se pune codul din funciile Page_Load (care leag funcia de tratare a evenimentului RenderGraph ) i OnRenderGraph (care face reprezentarea grafic propriu-zis). Dup cum se observ din cod, datele se preiau dintr-un DataSet adus din Cache, unde a fost pus de ctre pagina principal a aplicaiei.

protected void Page_Load(object sender, EventArgs e) { this.ZedGraphWeb1.RenderGraph += new ZedGraph.Web.ZedGraphWebControlEventHandler(this.OnRenderGraph); } private void OnRenderGraph(ZedGraph.Web.ZedGraphWeb z, System.Drawing.Graphics g, ZedGraph.MasterPane masterPane) { DataSet ds = (DataSet)Cache["ProdCache"]; GraphPane myPane = masterPane[0]; myPane.Title.Text = ""; myPane.XAxis.Title.Text = "Produs"; myPane.YAxis.Title.Text = "Pret"; Color[] colors = { Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Purple,Color.Pink,Color.Plum,Color.Silver, Color.Salmon }; if (Request.QueryString["tip"] != null) { List<string> listaX = new List<string>(); PointPairList list = new PointPairList(); int i = 0; foreach (DataRow r in ds.Tables[0].Rows) { listaX.Add(r[1].ToString()); // denumire produs list.Add(0, (double)r[2], i++); // pret } switch (Request.QueryString["tip"]) { case "Bare": { BarItem myCurve = myPane.AddBar(

22.10.2012

30

"Curve 2", list, Color.Blue); myCurve.Bar.Fill = new Fill(colors); myCurve.Bar.Fill.Type = FillType.GradientByZ; myCurve.Bar.Fill.RangeMin = 0; myCurve.Bar.Fill.RangeMax = list.Count; myPane.XAxis.Type = AxisType.Text; myPane.XAxis.Scale.TextLabels = listaX.ToArray(); break; } case "Bare3D": break; case "Pie3D": break; case "Linie": { LineItem curve = myPane.AddCurve( "Spline", list, Color.Red, SymbolType.Diamond); curve.Line.IsSmooth = true; curve.Line.SmoothTension = 0.5F; curve.Line.Width = 2; curve.Symbol.Fill = new Fill(Color.White); curve.Symbol.Size = 10; myPane.XAxis.Scale.TextLabels = listaX.ToArray(); myPane.XAxis.Type = AxisType.Text; break; } case "Pie": { i = 0; foreach (DataRow r in ds.Tables[0].Rows) { PieItem segment1 = myPane.AddPieSlice(( double)r[2], colors[(i++) % colors.Length], Color.White, 45f, (i % 2 == 0) ? 0.2 : 0, r[1].ToString()); } break; } } } }

Dup cum se observ, funcia OnRenderGraph este legat n Page_Load la delegatul evenimentului RenderGraph, aparinnd controlului.
this.ZedGraphWeb1.RenderGraph += new ZedGraph.Web.ZedGraphWebControlEventHandler(this.OnRenderGraph);

Cu mouse dreapta, Choose Items pe ToolBox, cu Browse, se aduce controlul ZedGraph i n trusa cu instrumente grafice i apoi prin dragare se include controlul n pagina WebFormZedGraph. se adaug la nceputul paginii WebFormZedGraph i using ZedGraph, respectiv using System.Collections.Generic dac nu exist, cci se lucreaz cu astfel de colecii. Pot fi stabilite diverse proprieti ale controlului folosind fereastra Properties; ca s pstrm ct mai multe valori implicite, se poate draga controlul direct n codul html i se adaug tot aici doar proprietile Height = "500" Width = "500" Se adaug un buton pentru revenirea n pagina principal a aplicaiei, dup vizionarea graficului; evenimentul click al butonului va avea drept funcie de tratare:

22.10.2012

31

protected void btnBack_Click(object sender, EventArgs e) { Response.Redirect("default.aspx"); }

Pentru variaie se pune pe prima pagin i un combobox (DropDownList) din care se alege tipul graficului; pentru aceasta colecia Items a comboBox-ului va fi populat cu denumiri de tipuri posibile de grafice: Bare, Bare3D, Pie, Pie3D, Linie etc. Controlul combo trebuie s aib proprietatea AutoPostBack = true, pentru a anuna serverul despre evenimentul de schimbare a tipului de grafic, obligndu-l astfel s retraseze graficul la fiecare rencrcare a paginii principale. Pe evenimentul de schimbare index selecie n DropDownList1, se extrage setul de date din sursa de date i se pune n Cache, dup care se transfer controlul ctre pagina webFormZed.aspx, mpreun cu tipul graficului ales:

protected void DropDownList1_SelectedIndexChanged (object sender, System.EventArgs e) { DataSourceSelectArguments args = new DataSourceSelectArguments(); DataView dataView1 = (DataView)SqlDataSourceLocal.Select(args); DataTable dataTabl1 = dataView1.ToTable(); DataSet ds = new DataSet(); ds.Tables.Add(dataTabl1); Cache["ProdCache"] = ds; Response.Redirect("webFormZed.aspx?tip=" + this.DropDownList1.SelectedItem.Text); }

* * * In cazul folosirii controlului chart din Office 2003, paii de parcurs sunt urmtorii:

In Solution Explorer cu buton dreapta mouse se cere Add Reference i se alege din pagina COM, Microsoft Office Web Component 11.0. Dac avem o aplicaie mai veche care adusese deja o copie a referinei, o putem selecta pe aceasta, cu Browse. Depinznd de versiune (vezi Properties cnd inem selectat noua referin ) adugm i usingul corespunztor bibliotecii adus ca referin: using Microsoft.Office.Owc11; sau using OWC11; sau altceva, n funcie de controlul de chart folosit. Se adaug o pagin nou (Website / Add New Item i alegem WebForms) i pe ea se pune codul din WebFormGrafic.aspx.cs al aplicaiei webChart. Datele se preiau dintr-un DataSet adus din Cache sau se pun ca string, cifrele fiind separate cu virgul.

using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using OWC11; public partial class webFormGrafic : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { DataSet ds = (DataSet)Cache["ProdCache"]; 22.10.2012

32

//Obiect ChartSpace container de chart-uri ChartSpace objCSpace = new ChartSpaceClass(); //Add un chart si-i stabileste tipul ChChart objChart = objCSpace.Charts.Add(0); if (Request.QueryString["tip"] != null) { switch (Request.QueryString["tip"]) { case "Bare": objChart.Type = ChartChartTypeEnum.chChartTypeBarStacked; break; case "Bare3D": objChart.Type = ChartChartTypeEnum.chChartTypeBar3D; break; case "Linie": objChart.Type = ChartChartTypeEnum.chChartTypeSmoothLine; break; case "Pie3D": objChart.Type = ChartChartTypeEnum.chChartTypePie3D; break; } } else objChart.Type = ChartChartTypeEnum.chChartTypePie3D; // Titlu si legenda objChart.HasTitle = true; objChart.Title.Caption = "Nivelul preturilor"; objChart.HasLegend = false; //objChart.Legend.Border.DashStyle = ChartLineDashStyleEnum.chLineDash; //objChart.Legend.Position = ChartLegendPositionEnum.chLegendPositionRight; //Populare chart cu date din dataSet string strCategory = ""; string strValue = ""; foreach (DataRow r in ds.Tables[0].Rows) { strCategory += r[1].ToString() + ","; // denumire produs strValue += r[2].ToString() + ","; // pret } if (strCategory != "") strCategory = strCategory.Remove(strCategory.Length - 1, 1); if (strValue != "") strValue = strValue.Remove(strValue.Length - 1, 1); //Adauga o serie de date la colectia de serii objChart.SeriesCollection.Add(0); //leaga denumirile de pe Ox si valorile de pe Oy objChart.SeriesCollection[0].SetData(ChartDimensionsEnum.chDimCategories, (int)ChartSpecialDataSourcesEnum.chDataLiteral, strCategory); objChart.SeriesCollection[0].SetData(ChartDimensionsEnum.chDimValues, (int)ChartSpecialDataSourcesEnum.chDataLiteral, strValue); // "prepara" pagina introducand gif-ul dat de chart Response.ContentType = "image/gif"; Response.BinaryWrite((byte[])objCSpace.GetPicture("gif", 500, 400)); Response.End(); } }

pagina principal va conine un obiect Image adus din ToolBox, care va afia chart-ul furnizat de WebFormGrafic, deoarece are proprietatea ImageURL = WebFormGrafic, pus prin cod, folosind o cale relativ la directorul aplicaiei.

22.10.2012

33

Graficul e furnizat deja "preparat", doar l extragem ca gif din spaiul chart-ului; putem avea mai multe chart-uri n acelai spaiu i le putem activa pe rnd, cte unul. Pentru variaie se pune pe prima pagin i un combobox (DropDownList) din care se alege tipul graficului; pentru aceasta colecia Items a comboBox-ului va fi populat cu denumiri de tipuri posibile de grafice: Bare, Bare3D, Pie, Pie3D, Linie etc. Controlul combo trebuie s aib proprietatea AutoPostBack = true, pentru a anuna serverul despre evenimentul de schimbare a tipului de grafic, obligndu-l astfel s retraseze graficul la rencrcarea paginii principale. Pe evenimentul de schimbare index selecie n DropDownList1, se precizeaz i prin cod surs c imaginea va prelua ca surs graficul din pagina WebFormGrafic.aspx indicnd n plus prin QueryString i tipul de grafic ales:
protected void DropDownList1_SelectedIndexChanged (object sender, System.EventArgs e) { DataSourceSelectArguments args = new DataSourceSelectArguments(); DataView dataView1 = (DataView)SqlDataSourceOrion.Select(args); DataTable dataTabl1 = dataView1.ToTable(); DataSet ds = new DataSet(); ds.Tables.Add(dataTabl1); Cache["ProdCache"] = ds; this.Image1.ImageUrl = "WebFormGrafic.aspx?tip=" + this.DropDownList1.SelectedItem.Text; }

La adugarea referinei n proiect, se poate bifa opiunea Copy to local, prin care controlul este copiat n directorul aplicaiei, astfel nct s pot fi testat aplicaia i pe o main care nu are controalele din Office 2003 instalate. * * *

22.10.2012

34

Proceduri stocate
Exploatarea bazei de date folosind obiecte de tip Command Lucru cu procedurile stocate Exploatarea bazei de date folosind obiecte de tip Command Am observat pn acum c obiecte precum DataAdapter, respectiv SqlDataSource au comenzi pe care le in ca proprieti ce sunt de fapt referine ctre obiecte de tip XxxCommand (SqlCommand, OleDbCommand, OdbcCommand etc.). Obiectele de tip XxxCommand ofer n fond unica modalitate de acces la date, numai c ele: pot echipa un DataAdapter (sau DataSource) pe care l ajut, dup caz, s umple un DataSet cu nregistrri (metoda Fill a adaptorului) sau s opereze modificrile, tergerile sau inserrile n baza de date (metoda Update a adaptorului); pot fi folosite independent, caz n care pot genera la execuie un DataReader, container de date, care furnizeaz nregistrare cu nregistrare, read only; Obiectele de tip Command sunt purttoare ale unor comenzi textuale de tip SELECT, INSERT, DELETE, UPDATE din limbajul SQL sau ale unor nume de proceduri, pe care le pot lansa n execuie. Comenzile de acces direct la baza de date sunt de trei tipuri : ExecuteReader, care ntoarce o colecie de tupluri de date, accesibile apoi linie cu linie; ExecuteScalar, care returneaz o singur valoare, de tip generic object ; ExecuteNonQuery, care execut actualizrile asupra bazei de date i returneaz un int, indicnd numrul de nregistrri afectate prin modificri, tergeri sau inserri n baza de date. Obiectele claselor de tip Reader ( SqlDataReader, OleDbDataReader ) pot fi generate de ctre obiectele de tip Command prin apelul ExecuteReader i furnizeaz un flux de date, read-only, disponibiliznd cte o nregistrare la fiecare apel al metodei Read(), spre deosebire de metoda Fill() a unui adaptor, care furnizeaz o colecie de nregistrri:
OleDbDataReader dr = myCmd.ExecuteReader(); DataReader-ul

pointeaz aprioric pe BOF i e nevoie de o citire prealabil pentru a dispune de prima nregistrare.

Parcurgerea nregistrrilor cu DataReader este simpl i se aseamn cu citirea cte unei nregistrri dintr-un fiier. Localizarea unui cmp n nregistrarea din DataReader se face fie prin indexare, fie cunoscnd numele coloanei din tabel.
textBox1.Text = dr["pret"];

sau

textBox1.Text = dr[2];

O aplicaie care utilizeaz DataReader presupune parcurgerea urmtorilor pai: - se creaz o aplicaie nou, n care prin suprascrierea fiierelor webForm1.aspx.cs, webForm1.aspx se aduce codul surs prezentat mai jos; - se ataeaz delegaii pentru cele trei butoane, cci prin copiere nu s-au adus i legturile; - se face o copie pentru fiierul prod.mdb, cci va fi alterat prin ExecuteNonQuery; - se ruleaz i comenteaz fiecare linie surs, constatnd efectele rulrii. - se poate completa aplicaia cu un GridView, pentru vizualizarea simultan a tuturor tuplurilor selectate; - pe un buton puneInGrid se adaug codul de la funcia btnExecuteReader, iar n loc de parcurgere cu while a dataReader -ului, se pune cod de legare a dataReader-ului ca surs de

22.10.2012

35

date pentru gridView ( gridul va trebui s aib ID-ul sursei pe nul, cci va folosi DataSource n loc de DataSourceID : GridView1.DataSourceID = null;)
//while (dr.Read()) //{ // textBox1.Text+="\r\n"+dr["codp"]+ " " + dr["denum"]+ " " + dr["pret"]; //} GridView1.DataSource = dr; GridView1.DataBind(); dr.Close(); con.Close();

Legarea dataReader-ului ca DataSource pentru un grid funcioneaz numai pentru controlul GridView din Web Forms, nu i pentru cel din Windows Forms. Comparaii ntre cele dou modaliti de folosire a obiectelor de tip xxxCommand: Echipnd un dataAdapter, obiectele de tip Command: 1. permit lucru vizual cu dataAdapter; 2. dataAdapter-ul nchide/deschide implicit conexiunea; 3. acces mai lent la baza de date; 4. disponibilizeaz tot setul de nregistrri. Folosite individual, obiectele de tip Command: 1. permit doar programare soft; 2. trebuie nchis /deschis conexiunea explicit; 3. acces mai rapid la baza de date; 4. disponibilizeaz nregistrare cu nregistrare, prin intermediul unui obiect dataReader.

Observaie. Se poate folosi metoda ExecuteReader() i n locul celorlalte metode ( ExecuteNonQuery, ExecuteScalar ), cci metoda se va adapta dup cerin. n esen, obiectul de tip XxxCommand primete din construcie cele dou informaii de care avea nevoie i adaptorul: stringul SQL de executat i conexiunea:
OleDbCommand myCmd = new OleDbCommand(strSql,con);

Ce se ntmpl ns dac pri din comand sunt variabile i nu se cunosc la momentul construirii obiectului xxxCommand, ci se schimb de la o execuie la alta ? Se poate rezolva aceast problem n dou moduri: - prin concatenare de string-uri, la momentul execuiei, nainte de crearea obiectului xxxCommand ( cci comanda n sine este static); - prin ncrcare de parametri i folosirea lor la momentul execuiei comenzii n baza de date. Obiectele de tip XxxCommand au o colecie de parametri, obiecte de tip Parameter, ce sunt caracterizate prin nume, tip, direcie i valoare; aceti parametri circul impreun cu comanda i conin valori n reprezentare intern; trebuie s coincid cu tipul celor din baza de date, cnd sunt folosii la stocare valori n BD, dar pot fi i de lat tip dac sunt folosii n alt scop ( spre exemplu, parametru @PretMin poate fi i de tip int, deoarece el este folosit doar n comparaii, chiar dac preul de referin este stocat n baza de date ca double.
private void pretPeste200_Click(object sender, System.EventArgs e) { string strSql = "SELECT codp, denum, pret FROM produse where pret > @PretMin"; OleDbConnection con = new OleDbConnection (@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\prod.mdb"); try { con.Open(); } catch(Exception ex) { mesaje.Text="Eroare open conexiune"+ex.Message;}

22.10.2012

36

OleDbCommand myCmd = new OleDbCommand(strSql,con); OleDbParameter param1; param1 = myCmd.Parameters.Add (new OleDbParameter("@PretMin", OleDbType.Integer) ); param1.Direction = ParameterDirection.Input; myCmd.Parameters["@PretMin"].Value=200; OleDbDataReader dr = myCmd.ExecuteReader(); dg.DataSource = dr; dg.DataBind(); dr.Close(); con.Close(); }

Observaie. Comanda poate face astfel referiri mai sofisticate la acel parametru, identificat dup nume; spre exemplu, putem s transferm ca parametru de intrare un BLOB Binary Large Object ce ar putea conine o imagine ! Se observ c nu se folosesc obiecte DataAdapter sau DataSet, ci doar obiecte XxxCommand i DataReader. Pentru exemplificarea unei comenzi ExecuteScalar()am presupus c dorim s afim numrul de produse distincte, aflate n tabela produse. n acest scop am pus pe un buton din macheta aplicaiei, urmtoarea funcie :
private void btnExecScalar_Click (object sender, System.EventArgs e) { OleDbConnection conn = null; OleDbCommand myCommand = null; try { conn = new OleDbConnection( @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\prod.mdb"); conn.Open(); myCommand = new OleDbCommand ( "SELECT COUNT(*) FROM produse", conn); int nrProd = (int)myCommand.ExecuteScalar(); textBox1.Text="Numar produse comercializate: "+ nrProd; } catch(Exception excpt) { mesaje.Text= "Esec pe ExecuteScalar: "+excpt.Message; } }

Un apel ExecuteNonQuery()a fost exemplificat presupunnd c se dorete modificarea denumirii produselor care ncep cu p , prin adugarea prefixului txt . Funcia care realizeaz acest lucru trateaz evenimentul Click al unui buton inscripionat sugestiv:
private void btnExecNonQuery_Click (object sender, System.EventArgs e) { OleDbConnection conn = null; OleDbCommand command = null; string ConnString = "Provider=Microsoft.Jet.OLEDB.4.0;"+ "Data Source=C:\\prod.mdb"; string cmd = "UPDATE produse SET denum = 'txt'&denum "+ "where denum like 'p%'"; try

22.10.2012

37

{ conn = new OleDbConnection(ConnString); conn.Open(); command = new OleDbCommand(cmd, conn); int nrRec = command.ExecuteNonQuery(); textBox1.Text="Numar inregistrari afectate: "+ nrRec; } catch(Exception excpt) { mesaje.Text= "Esec pe ExecuteNonQuery: "+ excpt.Message; } finally { if (conn.State == ConnectionState.Open) conn.Close(); } }

Pentru rulare sub Visual Studio 2008, cu baz de date sub SQL Server Express, codul surs este urmtorul :
using using using using using using using using using using using using System; System.Data; System.Configuration; System.Web; System.Web.Security; System.Web.UI; System.Web.UI.WebControls; System.Web.UI.WebControls.WebParts; System.Web.UI.HtmlControls; System.Data.Sql; System.Data.SqlTypes; System.Data.SqlClient;

public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void btnIncarca_Click(object sender, EventArgs e) { string strSql = "SELECT codp, denum, pret FROM produse"; SqlConnection con = new SqlConnection("Data Source=DOCTORAT2006\\SQLEXPRESS;Initial Catalog=masterat;Integrated Security=True"); textBox1.Text = "Lista produselor disponibile"; try { con.Open(); } catch (Exception ex) { mesaje.Text = "Eroare open conexiune" + ex.Message; } SqlCommand myCmd = new SqlCommand(strSql, con); SqlDataReader dr = myCmd.ExecuteReader(); //while (dr.Read()) //{ // textBox1.Text += "\r\n" + dr["codp"] + " " + // dr["denum"] + " " + dr["pret"]; //} GridView1.DataSource = dr; GridView1.DataBind(); dr.Close(); con.Close(); } protected void btnExecScalar_Click (object sender, System.EventArgs e)

22.10.2012

38

{ SqlConnection conn = null; SqlCommand myCommand = null; try { conn = new SqlConnection( @"Data Source=DOCTORAT2006\SQLEXPRESS;Initial `Catalog=masterat;Integrated Security=True"); conn.Open(); myCommand = new SqlCommand ("SELECT COUNT(*) FROM produse", conn); int nrProd = (int)myCommand.ExecuteScalar(); textBox1.Text = "Numar produse comercializate: " + nrProd; } catch (Exception excpt) { mesaje.Text="Esec pe ExecuteScalar: " + excpt.Message; } } protected void btnExecNonQuery_Click (object sender, System.EventArgs e) { SqlConnection conn = null; SqlCommand command = null; string ConnString = "Data Source=DOCTORAT2006\\SQLEXPRESS;Initial Catalog=masterat;Integrated Security=True"; string cmd = "UPDATE produse SET denum = 'txt'+denum " + "where denum like 'p%'"; try { conn = new SqlConnection(ConnString); conn.Open(); command = new SqlCommand(cmd, conn); int nrRec = command.ExecuteNonQuery(); textBox1.Text = "Numar inregistrari afectate: " + nrRec; } catch (Exception excpt) { mesaje.Text="Esec pe ExecuteNonQuery: " + excpt.Message; } finally { if (conn.State == ConnectionState.Open) conn.Close(); } } }

Pagina web cu rezultatele rulrii arat astfel :

22.10.2012

39

Lucru cu procedurile stocate


Procedurile stocate sunt cereri frecvent folosite asupra unei baze de date, grupate sub un nume de apel. Ele se concretizeaz sub forma unor poriuni de cod, compilabile separat, existente pe server. Avantajele folosirii procedurilor stocate: procedurile sunt deja compilate i deci nu mai conin erori de compilare, fiind direct lansabile n execuie; fiind cunoscute de sever beneficiaz i de utilizarea statisticilor interne pentru optimizarea accesului la datele unei tabele; aflndu-se pe server, procedurile stocate nu au nevoie s fie compuse i retransmise prin reea de fiecare dat cnd sunt invocate; astfel accesul este mai rapid deoarece se transmit doar parametrii de apel i numele procedurii; au un grad de securitate mai ridicat, deoarece nu este vizibil codul surs ( a se vedea SQL injection ca element de insecuritate); controlm mai bine accesul, dnd dreptul de a executa proceduri stocate, dar nu i instruciuni individuale. Observaii. - A se vedea ce a pus n baza de date (Queries / Design / View SQL code pentru Microsoft Access, respectiv Stored procedures pentru SQL Server). - Parametrii trebuie s aib acelai tip cu ce s-a declarat la crearea procedurilor, iar dac ei se asociaz unor cmpuri din baza de date trebuie s corespund ca tip cu acetia sau s fie convertii la momentul folosirii (vezi webBdProc1, cu pret float comparat cu param int ). - Concordana la tipurile asociate cu DateTime este delicat existnd multe formate de dat calendaristic, diferind ca lungime i ca moment de referin ales. Pentru nceput vom crea i folosi o procedur fr parametri; pentru simplitate presupunem c avem funcii distincte care creaz, respectiv apelez procedura, la apsarea cte unui buton inscripionat corespunztor. Funcia de creare ncearc mai nti s tearg o eventual versiune mai veche a aceleeai proceduri, pentru a ne permite mbuntirea progresiv a procedurii.
protected void btnCreareProc_Click(object sender, System.EventArgs e) { string strCreare = "CREATE PROCEDURE ProdScumpe AS " + "Select * From produse where pret > 615 Order By denum"; SqlConnection con = 22.10.2012

40

new SqlConnection( "Data Source=orion;Initial Catalog=doctorat;User ID=sa;Password=as;" ); con.Open(); SqlCommand myCmd = new SqlCommand(); myCmd.CommandType = CommandType.Text; myCmd.Connection = con; myCmd.CommandText = "DROP PROCEDURE ProdScumpe"; try { myCmd.ExecuteNonQuery(); } catch { TextBox1.Text = "Procedura de sters nu exista!!"; } myCmd.CommandText = strCreare; try { myCmd.ExecuteNonQuery(); TextBox1.Text = "Procedura creata cu succes!!"; } catch { TextBox1.Text = "Procedura nu a fost creata!!"; } con.Close(); }

Se pot folosi diverse modaliti de a apela o procedur stocat; cel mai simplu mod este ca ntr-un obiect de tip Command, s nlocuim fraza SELECT cu numele procedurii stocate:
protected void btnApelProc_Click(object sender, System.EventArgs e) { SqlConnection con = new SqlConnection( "Data Source=orion;Initial Catalog=doctorat;User ID=sa;Password=as;" ); con.Open(); SqlCommand myCmd = new SqlCommand("ProdScumpe", con); myCmd.CommandType = CommandType.StoredProcedure; SqlDataReader dr = myCmd.ExecuteReader(); TextBox1.Text = "Lista produselor scumpe"; while (dr.Read()) { TextBox1.Text += "\r\n" + dr["codp"] + " " + dr["denum"] + " " + dr["pret"]; } dr.Close(); con.Close(); }

Dac procedura ar lucra cu parametri de intrare, spre exemplu numai produsele cu preul peste o valoare, dat ca text ntr-un TextBox al formei, procedura s-ar schimba, deoarece comanda trebuie s declare acum i parametri de intrare / ieire; n acest caz este nevoie s lucrm i cu obiecte de tip Parameter. Aa cum spuneam, obiectele Command dispun de o colecie numit Parameters, n care prin metoda Add, adugm parametrii pregtii anterior sau furnizm metodei informaia necesar pentru a construi ea aceti parametri:
param1 = cmdMea.Parameters.Add(new SqlParameter("@PretMin", SqlDbType.Int)); param1.Direction = ParameterDirection.Input; cmdMea.Parameters["@PretMin"].Value = Convert.ToInt32(txtPret.Text);

Metoda Add a coleciei Parameters are mai multe versiuni suprancrcate, n funcie de numrul de argumente folosite la construirea unui obiect de tip parametru. Se observ c, n afara faptului c metoda a construit i a adugat un parametru de tip int la o comand, ea returneaz i referina parametrului, astfel nct acesta s poat fi ulterior echipat i cu alte proprieti, spre exemplu direcia:

22.10.2012

41

param1.Direction = ParameterDirection.Input; param2.Direction = ParameterDirection.Output;

Un parametru mai este accesibil i prin metoda de indexare a coleciei, care localizeaz un parametru dup poziie sau dup numele su; construcia de mai jos stocheaz drept valoare pentru parametru de intrare n procedur, preul rezultat prin conversia n int a textului introdus de utilizator la rulare, n cmpul txtPret: sau
cmdMea.Parameters["@PretMin"].Value = Convert.ToInt32(txtPret.Text); cmdMea.Parameters[0].Value = Convert.ToInt32(txtPret.Text);

Reamintim c n ADO.NET parametrii trebuie s se numeasc la fel cu cei definii n procedura stocat i s aib acelai tip i aceeai lungime. Direcia unui parametru poate fi: parametru de intrare n procedur; - parametru de ieire, returnat de procedur i care nu poate conine date de intrare pentru procedur; InputOutput - parametru folosit n acelai timp i pentru intrare i pentru ieire, n comunicarea cu procedura; ReturnValue - parametru de ieire, returnat de subprogramele de tip function.
Input Output

Pot exista mai muli parametri de tip Input, Output, InputOutput, dar doar un singur parametru de tip ReturnValue. Funciile de creare, respectiv folosire a unei proceduri stocate cu un parametru de intrare, arat acum astfel:
protected void btnCreareProc_Click(object sender, System.EventArgs e) { string strCreare = "CREATE PROCEDURE ProdPestePret(@pretMin INT) AS " + "SELECT * FROM produse WHERE pret > @pretMin "; SqlConnection con = new SqlConnection( "Data Source=orion;Initial Catalog=doctorat;User ID=sa;Password=as;" ); con.Open(); SqlCommand cmdMea = new SqlCommand(); cmdMea.CommandType = CommandType.Text; cmdMea.Connection = con; // daca exista, o sterge pentru a crea o noua versiune cmdMea.CommandText = "DROP PROCEDURE ProdPestePret"; try { cmdMea.ExecuteNonQuery(); } catch (Exception excpt) { TextBox1.Text = "Stergere esuata: " + excpt.Message; } // refolosire comanda pentru a crea noua procedura cmdMea.CommandText = strCreare; cmdMea.CommandType = CommandType.Text;

22.10.2012

42

try { cmdMea.ExecuteNonQuery(); TextBox1.Text = "Creare cu succes!!"; } catch (Exception excpt) { TextBox1.Text = "Creare esuata: " + excpt.Message; } con.Close(); } protected void btnTestareProc_Click(object sender, System.EventArgs e) { SqlConnection con = new SqlConnection( "Data Source=orion;Initial Catalog=doctorat;User ID=sa;Password=as;" ); con.Open(); SqlCommand cmdMea = new SqlCommand("ProdPestePret", con); cmdMea.CommandType = CommandType.StoredProcedure; SqlParameter param1; param1 = cmdMea.Parameters.Add( new SqlParameter("@PretMin", SqlDbType.Int)); param1.Direction = ParameterDirection.Input; cmdMea.Parameters["@PretMin"].Value = Convert.ToInt32(txtPret.Text); SqlDataReader dr = null; try { dr = cmdMea.ExecuteReader(); TextBox1.Text = "Lista produselor peste " + txtPret.Text + " EUR \r\n\r\n"; while (dr.Read()) { TextBox1.Text += "\r\n" + dr["codp"] + " " + dr["denum"] + " " + dr["pret"] + " EUR"; } dr.Close(); } catch (Exception excpt) { TextBox1.Text = excpt.Message; } con.Close(); }

De reinut c parametrii de ieire sunt accesibili doar dup nchiderea DataReader-ului. Exerciiu. Transformai procedura din aplicaia de mai sus, astfel nct s returneze i cte produse sunt n baza de date, cu preul cuprins ntre dou valori date. Rezolvare. Se declar un alt treilea parametru, de data aceasta de tip Output i se folosete ca n textul surs de mai jos.
protected void btnCreareProc_Click(object sender, System.EventArgs e) { SqlConnection myCon = 22.10.2012

43

new SqlConnection( "Data Source=orion;Initial Catalog=doctorat;User ID=sa;Password=as;" ); SqlCommand myCmd = new SqlCommand(); myCmd.CommandType = CommandType.Text; myCmd.Connection = myCon; // daca procedura exista, o sterge pentru a crea o noua versiune myCon.Open(); myCmd.CommandText = "DROP PROCEDURE ProdIntre2Preturi"; try { myCmd.ExecuteNonQuery(); tbMesaje.Text = "Creare procedura Ok"; } catch (Exception excpt) { tbMesaje.Text = "Esec la stergere procedura: " + excpt.Message; } finally { myCon.Close(); } // refolosire comanda pentru inregistrare procedura string strCreare = "CREATE PROCEDURE ProdIntre2Preturi(@pretMin FLOAT , @pretMax FLOAT, @CateProd INT OUTPUT ) AS " + "SELECT * FROM produse WHERE pret > @pretMin AND pret < @pretMax " + "SELECT @CateProd = COUNT (*)FROM produse WHERE pret > @pretMin AND pret < @pretMax "; myCmd.CommandText = strCreare; myCmd.CommandType = CommandType.Text; myCon.Open(); try { myCmd.ExecuteNonQuery(); tbMesaje.Text = "\r\nCreare procedura OK "; } catch (Exception excpt) { tbMesaje.Text = "Exceptie scriere procedura " + excpt.Message; } myCon.Close(); } protected void btnApelProc_Click(object sender, System.EventArgs e) { SqlConnection MyCon = new SqlConnection( "Data Source=orion;Initial Catalog=doctorat;User ID=sa;Password=as;" ); if (MyCon.State == ConnectionState.Closed) MyCon.Open(); SqlCommand myCmd = new SqlCommand("ProdIntre2Preturi", MyCon); myCmd.CommandType = CommandType.StoredProcedure; SqlParameter param1, param2, param3; param1 = myCmd.Parameters.Add( new SqlParameter("@PretMin", SqlDbType.Float)); param1.Direction = ParameterDirection.Input; myCmd.Parameters["@PretMin"].Value = double.Parse(tbMin.Text); param2 = myCmd.Parameters.Add( new SqlParameter("@PretMax", SqlDbType.Float)); param2.Direction = ParameterDirection.Input; myCmd.Parameters["@PretMax"].Value = double.Parse(tbMax.Text); ; param3 = new SqlParameter("@CateProd", SqlDbType.Int);

22.10.2012

44

param3.Direction = ParameterDirection.Output; myCmd.Parameters.Add(param3); SqlDataReader dr = null; try { dr = myCmd.ExecuteReader(); while (dr.Read()) { tbMesaje.Text += "\r\n" + dr["codp"] + " " + dr["denum"] + " costa " + dr["pret"]; } } catch (Exception excpt) { tbMesaje.Text = "Exceptie la executie procedura" + excpt.Message; } finally { if (dr != null) dr.Close(); MyCon.Close(); } tbCateProd.Text = myCmd.Parameters["@CateProd"].Value.ToString(); }

22.10.2012

45

Validarea datelor pe formularele Web Nu exist evenimentele Validating / Validated ca la aplicaiile Windows Forms. Apoi, nu toate evenimentele notific imediat serverul despre producerea lor, pentru a nu ncrca excesiv traficul client sever, spre exemplu, TextChanged, generat la orice modificare ntr-un textBox, nu anun serverul despre modificarea textului, n pagina clientului; dac dorim totui s executm imediat funcia de tratare a unui astfel de eveniment trebuie s setm proprietatea AutoPostBack a controlului ce-l genereaz, pe valoarea true. O alt particularitate a validrii pe formularele Web const n faptul c se poate face: pe server, adic la distan de locul care a generat evenimentul prin care se solicit validarea; avem ns avantajul folosirii oricrui limbaj pentru care a fost instalat un compilator pe server; n cazul.NET se poate folosi orice limbaj care a aderat la aceast platform; la client, n browser, cu dezavantajul folosirii doar a limbajelor recunoscute de majoritatea browser-elor (pentru c nu tim aprioric pe ce browser se va rula aplicaia noastr), adic Java Script sau Visual Basic Script. Dac e vorba de validare ncruciat e bine ca ea s se execute pe server; pentru validri simple este mult mai eficient ca ele s se execute n browser, la client. Probleme de securitate !! IE 4.0 i versiunile urmtoare suport DHTML i se pot genera scripturi Java ce se execut n browser i care pot efectua validri. Cele mai frecvente controale de validare disponibile pentru aplicaiile ASP.NET i dragabile din ToolBox pentru web forms sunt: RequiredFieldValidator - pentru a indica obligativitatea introducerii unui cmp ( text n textBox, selecie obligatorie n controale de selecie etc.). RangeValidator test de apartenen la un interval numeric, alfabetic, date calendaristice; poate fi specificat static la momentul realizrii aplicaiei, sau dinamic, la momentul execuiei ( spre exemplu ca valoare introdus ntr-un textBox). CompareValidator - test de egalitate cu o constant sau cu o valoare cunoscut abia la momentul execuiei. RegularExpressionValidator test de format standard ( de exemplu formatul internaional al unui numr de telefon, numr de card de credit cu checksum intern, adres de email, parole, cont bancar IBAN, etc.). CustomValidator test specificat printr-un algoritm furnizat de programator.

Exemplu (aplicaia webValidari) 1. Se trage un RequiredFieldValidator din ToolBox; i se pune proprietate Text pe valoarea "Trebuie introdus obligatoriu un nume"; pentru proprietatea ControlToValidate se alege din comboBoxul disponibil id-ul unui control textBox tbNumele, existent deja pe form; proprietatea Display (Static, Dinamic, None) precizeaz dac mesajul de eroare are un loc rezervat permanent n pagina Web, doar la producere, sau deloc. 2. Se trage din ToolBox un RangeValidator i i se stabilesc proprietile: Text: 1 < varsta < 100 MaxVal = 100, minVal = 1 ControlToValidate puncteaz controlul tbVarsta, selectat din lista afiat; EnableClientScript: true validarea se face la client; false - validarea se face pe server. Enabled cu true / false pentru a activa / inhiba uor validrile introduse prin acest control;
22.10.2012

46

textul explicit al mesajului afiat n ValidationSummary, n cazul unei erori de validare; Text - mesaj afiat de control n situaia invalidrii. Type tipul datei de validat; informaia e convertit la acest tip nainte de validare. Dac n cmp nu se introduce nimic, se consider situaie valid; dac se dorete altfel, se va aduga i un control RequiredFieldValidator,intind spre acelai cmp. Dac eueaz conversia la tipul indicat, se consider de asemenea situaie valid.
ErrorMessage

Ca s fixm momentul validrii am folosit un buton Save, care implicit anun serverul cnd este apsat cu mouse-ul i care n realitate afieaz ntr-un textBox numele preluat din tbNumele.
private void btnSave_Click(object sender, System.EventArgs e) { tbAfisaj.Text+="\r\n"+tbNumele.Text; }

Un control poate fi inta mai multor controale de validare, implementnd astfel criterii diferite de validare; practic i se asociaz cte un control de validare pentru fiecare tip de eroare controlat. ValidationSummary Permite afiarea centralizat a tuturor erorilor de validare ( textul precizat n proprietatea ErrorMessage a diferitelor controale de validare), n locul celor afiate de controalele de validare individuale. 1. Se trage un control ValidationSummary din ToolBox i i se stabilesc proprietile: Enabled = true ShowMessageBox = false (nu afieaz i un MessageBox cu mesaje, n afara mesajului din centralizator).
ShowSummary = true, dac se dorete ca mesajul de eroare s se afieze i n corpul documentului HTML. DisplayMode, forma de afiare a mesajelor, prin alegere din BulletList, List, SingleParagraph; Proprietatea Text pentru controalele individuale de validare se pune pe proprietatea ErrorMessage se trece textul de afiat n clar, astfel nct

enumerarea

2.

"*", iar n n dreapta controlului ce prezint eroarea se afieaz doar un asterisc, iar mesajul de eroare se afieaz n centralizator. Dac ShowMessageBox este false afiarea mesajelor de eroare se va face doar n ValidationSummary, nu i ntr-un MessageBox separat.

CustomValidator

22.10.2012

47

Pentru validri particulare, specifice fiecrui program, se poate folosi controlul CustomValidator; el deine: o proprietate, ClientValidationFunction, care precizeaz metoda de validare aplicat n browser-ul clientului; un eveniment, ServerValidate, care poate fi tratat printr-o funcie executat pe server. Deoarece validarea se execut la client s-au pe server depinznd i de capacitile browserului, se recomand furnizarea ambelor funcii de validare. Aa cum aminteam, n timp ce funcia de validare pe server este scris n orice limbaj acceptat sub .NET, funcia de validare la client este scris, pentru a fi acceptat de majoritatea browserelor, n JavaScript sau VBScript. Exemplu (aplicaia CustomValidator ) Vom exemplifica lucru cu acest control considernd c atam unui textBox tbNumar un CustomValidator care semnaleaz eroare la introducerea unui numr impar. 1. Se creaz o aplicaie WebForm coninnd, printre altele, un textbox tbNumar i un buton btnTrimite; 2. Se aduce un control CustomValidator din ToolBox i i se stabilesc proprietile:
ControlToValidate: tbNumar ErrorMessage: Eroare de paritate ClientValidationFunction: ValidarePeClient Cu CustomValidator1 selectat, n Properties / Events se stabilete ServerValidate: ValidarePeServer, avnd coninutul:

3.

funcia de tratare pentru

private void ValidarePeServer(object source, System.Web.UI.WebControls.ServerValidateEventArgs args) { tbMesaje.Text="\r\n Validare pe sever cu "+args.Value.ToString()+ " si "; try { int nrPar = Int32.Parse(args.Value); if (nrPar % 2 == 0) args.IsValid = true; else args.IsValid = false; } catch (Exception) { Response.Write("<br><br>Introduceti doar numere pare.<br>"); } } Funcia primete ca parametri un obiect ce deine proprietatea IsValid (pagina, n cazul nostru ) i un bloc de argumente specifice evenimentului ServerValidate; acest bloc conine printre altele i valoarea supus validrii args.Value. Funcia ncearc o conversie a intrrii din tbNumr n

numr, considernd ca intrri valide doar numerele ntregi pare. 4. La nivelul codului HTML al paginii se insereaz ( nainte de terminarea descrierii formei </form> ) i scriptul aferent funciei Java, de validare la nivel de browser:
<script language="javascript"> function ValidarePeClient(source, args) { // document.write( "<tr><td> ValidarePeClient </td><td>" ); // document.write(args.Value.toString()); if (args.Value % 2 == 0) args.IsValid=true;

22.10.2012

48

else args.IsValid = false; } </script>

5. Cu CustomValidator1 selectat, n Properties se stabilete c scriptul de mai sus conine funcia de tratare la nivel de browser, adic proprietatea ClientValidationFunction:
ValidarePeClient.

6. Pe un buton btnTrimite se foreaz prin trimiterea paginii, cererea de validare:

private void btnTrimite_Click(object sender, System.EventArgs e) { if (Page.IsValid) tbMesaje.Text+="\n"+tbNumar.Text + ": Input valid."; else tbMesaje.Text+="\r\n"+tbNumar.Text + ": Input invalid."; }

n plus, ntr-o caset de mesaje se afieaz pentru o confirmare suplimentar, prezena erorii de validare la nivel de pagin. 7. Punnd pe rnd pentru CustomValidator1 proprietatea EnableClientScript pe true, respectiv false, constatm efectul celor dou tipuri de validri. Funcia ValidarePeClient nu are return i se execut cu prioritate ( nainte de a se trimite pagina n server); dac detam handler-ul ValidarePeServer atunci se afieaz doar ce se stabilete n funcie de validarea din client (mesajul scurt, fr meniunea de validare pe server). Dac lsm nedetaat handler-ul ValidarePeServer atunci se execut ambele validri, astfel nct se va afia validitatea constatat de funcia din server. RegularExpressionValidator Funcioneaz dup modelul controalelor de validare de mai sus, avnd n plus proprietatea ValidationExpression prin care se indic expresia uzual ce st la baza validrii:
ValidationExpression = "[0-9]{8}|[0-9]{5}-[0-9]{3}" ValidationExpression = "^\d{5}$"

8 cifre sau 5 + 3 cifre separate cu liniu ; cu semnificaia:

nceput de ir
22.10.2012

49

\d

digit {5} exact cinci cifre $ sfrit de ir pentru a descrie formatul unei adrese de

[a-zA-Z] conine doar caractere alfabetice [a-zA-Z0-9\.\_]+@[ a-zA-Z.]+\.[ a-zA-Z]{3}

email. De un real folos n validarea datelor sunt aanumitele expresii regulate; ele sunt nite abloane abstracte folosite pentru a preciza structura pe care trebuie s o respecte un cmp pentru a fi considerat valid. Sub Visual Studio, namespace-ul System.Text.RegularExpressions conine clasa specializat al crei constructor de clas, Regex. Regex(pattern, options), primete un model de expresie regulat i opiuni (un singur caracter; "i" insensitive matching; ). Clasa mai conine: IsMatch metod static i nestatic, pentru cutarea unui pattern ntr-un ir, returnnd true sau false. Varianta nestatic cere doar irul n care caut, deoarece modelul de cutare s-a dat n constructor. Metoda Matches returneaz toate subirurile n care se gsete pattern-ul de cutare, sub forma unei colecii MatchCollection ce conine obiecte de tip Match, colecie care poate apoi fi apoi iterat cu foreach. Metoda nestatic Replace a clasei Regex primete doi parametri, irul n care caut pattern-ul i un ir cu care va substitui orice apariie a pattern-ului n sir. De remarcat generalitatea cutrii, n sensul c n constructorul expresiei regulate se pot da pattern-uri complexe, de genul "ceva\b" care semnaleaz i substituie "ceva" doar cnd apare ca margine de cuvnt (\b - boundary). Lucrurile stau similar i cu metoda Split a clasei Regex, care se aseamn cu metoda Split a clasei String, dar ofer n plus faciliti incomparabil mai puternice de calificare a subirului pe baza cruia se va face splitarea irului ntr-un vector de subiruri. Marcheaz caracterul urmtor drept secven de escape sau un caracter special, literal sau back-reference. De exemplu, '\n' indic newline; '\\' indic "\" ca proprie secven de escape. Inceput de string; pentru un obiect Multiline, ^ indic prima poziie dup '\n' sau '\r' (nceput de rnd). Sfrit de string; pentru un obiect Multiline, $ marcheaz poziia ce precede '\n' or '\r' ( sfrit de rnd). Poziie identic cu precedenta, sau subexpresie lips sau prezent de mai multe ori. Spre exemplu, zo* permite "z" sau "zoo". * este echivalent cu {0,}. Poziie identic cu precedenta sau o subexpresie ce se produce o dat sau de mai multe ori. Spre exemplu, 'zo+' permite "zo" i "zoo", nu i "z". + este echivalent cu {1,}. Poziie identic cu precedenta sau o subexpresie ce se produce de zero ori sau o dat. Spre exemplu, "do(es)?" indic "do" sau "does". ? este echivalent cu {0,1} n ntreg nenegativ, pentru o poziie ce se repet de exact n ori. Spre exemplu, 'o{2}' nu permite 'o' n "Bob,", dar poate desemna cei doi de 'o' din "food". n ntreg nenegativ, pentru o poziie ce se repet de cel puin n ori. Spre exemplu, 'o{2,}' nu permite "o" n "Bob", dar permite mai muli de 'o' ca n "foooood". 'o{1,}' este echivalent cu 'o+' , iar 'o{0,}' este echivalent cu 'o*'. m i n doi ntregi nenegativi, cu n <= m, desemneaz cel puin n i cel mult m apariii. Spre exemplu, "o{1,3}" permite descrierea doar a primilor trei de 'o' n "fooooood". 'o{0,1}' este echivalent cu 'o?'. De reinut c nu se pune spaiu ntre
22.10.2012

^ $ * +

? {n} {n,}

{n,m}

50

. (pattern)

(?:pattern)

(?=pattern)

(?!pattern)

x|y [xyz] [^xyz]

[a-z]

[^a-z]

\b \B \cx

\d \D \f \n \r

virgul i numere. Cnd urmez altor caractere cuantificatori, (*, +, ?, {n}, {n,}, {n,m}), pattern-ul devine non-greedy. Un pattern non-greedy indic cel mai puin posibil din irul cutat, n timp ce un pattern greedy permite cel mai mut posibil dintr-un ir cutat. Spre exemplu, n irul "oooo", 'o+?' indic un singur "o", n timp ce 'o+' i indic pe toi. Un singur caracter, oarecare, exceptnd "\n". Pentru a desemna un caracter oarecare, inclusiv "\n"se folosete pattern-ul '[\s\S]'. Desemneaz pattern i capteaz rezultatul. Rezultatul potrivirii poate fi regsit din colecia Matches, folosind SubMatches n VBScript sau $0$9 n JScript. Pentru descrierea parantezelor ( ), se folosesc secvenele de escape '\(' i '\)'. Ca mai sus, dar nu reine rezultatul potrivirii, pentru o folosire ulterioar. Este util pentru a combina pri dintr-un pattern cu operatori "or" ( | ). Spre exemplu, 'industr(?:y|ies) este o descriere prescurtat a expresiei 'industry|industries'. Anticiparea pozitiv indic o potrivire dac pattern-ul ncepe oriunde n irul cutat. Este un test fr reinerea rezultatului. Spre exemplu, 'Windows (?=95|98|NT|2000)' acoper "Windows" n "Windows 2000", dar nu i "Windows" din "Windows 3.1". Anticiparea pozitiv nu consum caractere; deci, cutarea pentru urmtoarea potrivire ncepe imediat dup ultimul caracter potrivit, nu dup toate caracterele cuprinse n anticipare. Anticiparea negativ indic o potrivire dac irul cutat ncepe oriunde apare ceva diferit de pattern. Este un test fr reinerea rezultatului. Spre exemplu, 'Windows (?!95|98|NT|2000)' acoper "Windows" din "Windows 3.1", dar nu accept "Windows" din "Windows 2000". Anticiparea nu consum caractere; deci, cutarea pentru urmtoarea potrivire ncepe imediat dup ultimul caracter potrivit, nu dup toate caracterele cuprinse n anticipare. x sau y. Spre exemplu, 'z|food' acoper "z" sau "food", n timp ce '(z|f)ood' descrie "zood" sau "food". Mulime de caractere, format din oricare din caracterele date ntre cele dou paranteze nchise. Spre exemplu, '[abc]' poate acoperi pe 'a' din "plain". Mulime complementar de caractere, format din oricare din caracterele care nu apar ntre cele dou paranteze nchise. Spre exemplu, '[abc]' poate acoperi pe 'p' din "plain". Interval de caractere. Spre exemplu, '[a-z]' desemneaz literele mici din alfabet, cuprinse ntre 'a' i 'z' , iar [37adAD] , cifre ntre 3-7 sau litere mici sau mari ntre a-d. Complementul unui interval de caractere, cuprinznd orice caracter ce nu face parte din intervalul specificat. Spre exemplu, '[^a-z]' precizeaz orice caracter necuprins ntre 'a' i 'z'. Margine de cuvnt, adic o poziie ntre cuvnt i spaiu. Spre exemplu, 'er\b' identific 'er' n "never", dar nu i 'er' n "verb". Ne-margine de cuvnt. 'er\B' identific pe 'er' n "verb", dar nu i pe 'er' n "pioner". Caracter de control asociat cu x. Spre exemplu, \cM indic Control-M sau carriage return. Valorile lui x trebuie s fie cuprinse n intervalul A-Z sau a-z; altminteri, construcia e tratat ca literal pentru caracterul 'c'. Digit, cifr din intervalul 0-9; echivalent cu [0-9]. Nondigit, caracter din afara intervalului 0-9; echivalent cu [^0-9]. Caracterul form-feed; echivalent cu \x0c sau \cL. Caracterul newline; echivalent cu \x0a sau \cJ. Caracterul carriage return; echivalent cu \x0d sau \cM.
22.10.2012

51

\s \S \t \v \w \W \xn

\num \n

\nm

\nml \un

Caracter spaiu (whitespace), incluznd space, tab, form-feed, tab vertical, new line, cariage return; echivalent cu [ \f\n\r\t\v]. Caracter non-whitespace; echivalent cu [^ \f\n\r\t\v]. Caracterul tab orizontal, adic \x09 sau \cI. Caracterul tab vertical, adic \x0b sau \cK. Caracter de tip "word", litere, cifre i underscore; echivalent cu [A-Za-z0-9_]. Caracter "nonword", adic echivalentul lui [^A-Za-z0-9_]. Hexa-digit; n este o valoare hexadecimal dat ca secven de escape, din dou cifre. Spre exemplu, '\x41' indic pe "A". '\x041' deoarece excede dou cifre va fi tratat ca '\x04' & "1". Permite folosirea codurilor ASCII n expresii regulate. Identific un numr num, ntreg pozitiv, pentru o referin napoi capturat anterior. Spre exemplu, '(.)\1' desemneaz dou caractere consecutive, identice. Identific o secven octal de escape sau o referin napoi. Dac \n este precedat de cel puin n subexpresii capturate, \n este tratat ca backreference. Altminteri, \n este tratat ca secven octal de escape, dac n aparine intervalului 0-7. Identific o secven octal de escape sau o referin napoi. Dac \nm este precedat de cel puin nm subexpresii capturate, \nm este tratat ca backreference. Dac \nm este precedat de cel puin n subexpresii capturate, \nm este tratat ca backreference urmat de un literal. Dac niciuna din condiiile de mai sus nu este ndeplinit, \nm este tratat ca secven octal de escape, cu condiia ca m i n s fie cifre octale (07). Secven de escape octal; n ia valori n 0-3, iar m i l iau valori n 0-7. Identific pe n, un caracter Unicode exprimat prin patru cifre hexazecimale. Spre exemplu, \u00A9 desemneaz simbolul pentru copyright ().

Numrul de prezene ale unui caracter sau clase de caractere se specific printr-un cuantificator; el se pune imediat dup caracter sau clasa de caractere din ablon i permite specificarea numrului de produceri ale caracterului sau ansamblului de caractere, acceptat ca valid. Cuantificator Interpretare * Nicio sau mai multe potriviri + Una sau mai multe potriviri ? Nicio sau o potrivire {N} N potriviri {N,} N sau mai multe potriviri {N,M} ntre N i M Cteva exemple lmuresc cel mai bine lucrurile. [aeiou]{2,4}\+[15]* precizeaz c se ateapt un ir care ncepe cu dou pn la patru vocale, urmate de semnul + i terminat cu nicio sau mai multe cifre cuprinse ntre 1 i 5. ^[\w-_\.]+\@([\w]+\.)+\w+$ este un pattern pentru validarea adresei de email

22.10.2012

52

Gestiunea strii n aplicaiile web


Conexiunile prin Internet sunt "stateless connections", adic dup conectarea unui client, serverul furnizeaz informaia cerut dup care "uit" totul despre acel utilizator. n situaia n care se completeaz nite valori ntr-un formular i se solicit serverului s le prelucreze i s ne dea un rspuns, pe care s-l vedem mpreun cu valorile introduse de noi, este nevoie de un mecanism prin care o parte din informaiile din pagin s fie restaurate n forma la care se aflau cnd pagina a plecat spre server. Problema restaurrii paginii apare deci, ori de cte ori se lucreaz mai mult timp cu aceeai pagin, care efectueaz un "du-te vino" spre server, de cte ori este nevoie. Starea se definete ca mulime a valorilor coninute n controalele i variabilele paginilor, a informaiilor corespunztoare utilizatorilor sau aplicaiei n ansamblu. "stateless connections" presupune ns c la fiecare rencrcare, pagina s se reconstruiasc de la zero, folosind valorile implicite ale controalelor i variabilelor, lucru care nu e de dorit dac vrem s vedem pagina cu ultimile valori introduse de noi. ASP.NET permite gestiunea acestei stri att de ctre mediu ASP, ct i de ctre programator, diviznd informaia n trei categorii distincte, n funcie de nivelul de referin pagin, utilizator, aplicaie - i de containerul n care se in:
View state

avnd drept container un obiect de clas StateBag, instaniat automat de

sistem;
Session state container fiind obiectul Session; Application state pentru care containerul este obiectul Application.

View state gestiunea strii la nivel de pagin View State reprezint starea paginii i controalelor sale; ea se ine automat de ctre ASP.NET Framework pentru paginile i controalele care au setat proprietatea EnableViewState pe true. La transmiterea paginii ctre server, informaia de stare este ncrcat n state bag, nite cmpuri ascunse n pagin, care codific aceast stare i circul odat cu pagina, aceast tehnic fiind recunoscut de orice browser. La rencrcarea paginii din server ( adic la postback), informaia de stare este rescris n controale, utilizatorul vznd pagina completat i cu valorile pe care le -a introdus anterior. creterea performanei aplicaiei, programatorul poate pune proprietatea EnableViewState pe false pentru ntreaga pagin sau pentru controalele din pagin a cror stare nu intereseaz. Spre exemplu, dac ne putem permite la fiecare ncrcare de pagin s citim din nou, direct din baza de date, datele prezentate ntr-un GridView (dg ), putem declara ( sau pune vizual n fereastra Properties ):
dg.EnableViewState = false;

Pentru

Dac informaia de stare a ntregii pagini nu necesit salvare i restaurare la fiecare transmitere ctre / dinspre server, putem solicita acest lucru chiar prin directiva de pagin:
<%@ Page Language="C#" EnableViewState="false" %>

Dac dorim inhibarea salvrii ViewState la nivelul ntregii aplicaii ( pentru toate paginile acesteia ), punem proprietatea EnableViewState pe false n seciunea <pages> din fiierele de configurare machine.config sau web.config. Cum informaia din ViewState circul de fiecare dat cu pagina ctre i dinspre server, nu orice informaie trebuie salvat la acest nivel. n general, nu se stocheaz la nivel de ViewState informaia de volum mare sau informaia care trebuie s aib un grad nalt de securitate.

22.10.2012

53

n plus, doar pentru informaia de tip string, int, boolean, Arrays, ArrayLists i a fost optimizat mecanismul de transfer; pentru celelalte tipuri acest transfer poate deveni foarte neperformant. Informaiile din variabile nu sunt puse automat n ViewState, programatorul trebuind s scrie cod pentru adugarea lor explicit n state bag; acest container este un obiect de clas StateBag i poate fi gndit ca un dicionar ce stochez asociaii de tip atribut - valoare. Atributul este un string ce permite regsirea valorii, iar valoarea este interpretat ca un obiect generic, putnd fi de toate tipurile. Un astfel de dicionar deine att funcii pentru inserare de perechi atribut - valoare, ct i funcii pentru extragere sau modificare.
HashTable

Exemplu stareView. La nivel de pagin, s se in evidena numrului de rencrcri ale paginii, pe ntreaga durat a sesiunii. n clasa principal a aplicaiei se declar variabila int contor; ea este iniializat n funcia de tratare OnInit():
override protected void OnInit(EventArgs e) { contor=0; ViewState.Add("kContor", contor); tbNrAcc1.Text="0"; base.OnInit(e); } ocazie cu care este i stocat n ViewState cu cheia de identificare kContor.

Pe un textBox tbNrAcc adugat vizual pe form i etichetat corepunztor, la fiecare ncrcare de pagin, extragem din ViewState valoarea contorului, o incrementm i afim noua valoare:
protected void Page_Load(object sender, EventArgs e) { if (IsPostBack) { contor = (int)ViewState["kContor"]; contor++; tbNrAcc.Text = contor.ToString(); int aux = Convert.ToInt32(tbNrAcc1.Text); aux++; tbNrAcc1.Text = aux.ToString(); } Response.Write("Valoarea lui y este: " + (string)Application["y"]); }

22.10.2012

54

De remarcat cast-ul spre int aplicat obiectului returnat de indexarea elementului din Ori de cte ori apsm butonul btnTrimite, noua valoare este restocat n StateBag, pentru a cltori mpreun cu pagina:
ViewState. private void btnTrimite_Click(object sender, System.EventArgs e) { ViewState["kContor"] = contor; }

De menionat c textBox-ul tbNrAcc are proprietatea EnableViewState pe false, dei numrul de accesri, fiind vorba de o informaie mic, ar fi putut fi lsat s circule implicit cu controlul tbNrAcc, nu neaprat pus explicit ca variabil, n ViewState. S realizm acest lucru, n paralel, folosind un alt control tbNrAcc1, cu proprietatea EnableViewState pe true, caz n care textul coninut de control circul, fiind pus implicit n StateView; nu ne rmne dect ca n funcia de iniializare s punem textul pe string-ul "0", iar la ncrcarea paginii ( adic n funcia Page_Load ) s l convertim la int, s incrementm contorul i s-l reconvertim la string, afindu-l:
int aux = Convert.ToInt32(tbNrAcc1.Text); aux++; tbNrAcc1.Text=aux.ToString();

O ntrebare pe care ne-o punem este de ce merg decalat cele dou afiri ? Rspunsul const n faptul c una numeroteaz o dat n plus ( i pe !isPostback ). Dac punem totul ntr-o secven ca mai jos i iniializm cele dou textBox -uri cu 0 observm c cele dou incrementri merg n tandem.
if(IsPostBack) { // instructiuni executate doar la prima incarcare pagina // adica nu la incarcare ca raspuns la cerere (repostare) }

n acest fel ambele numerotri se fac doar la rencrcarea unei pagini, nu i la prima ncrcare. Gestiunea strii la nivel de sesiune n afara obiectului state bag, instaniat i gestionat automat de sistem, mai exist nc dou obiecte care in informaia de stare: Session - care ine informaia specific fiecrui utilizator n parte, pe durata unei sesiuni de lucru, cnd navigheaz ntre dou pagini diferite. Application - care ine informaia comun mai multor utilizatori ai aceleeai aplicaii Web. Alturi de acestea, n programarea aplicaiilor web, ne vom ntlni frecvent cu nc dou obiecte:
Request - obiect pentru acces la cererea n curs; el circul ctre server; Response - obiect pentru expedierea unui rspuns ( HttpResponse ) napoi

la client.

O sesiune se definete printr-o secven de cereri lansate de la acelai browser client i derulate astfel nct intervalul de timp dintre dou cereri s nu depeasc intervalul de timeout definit n fiierul de configurare web.config (implicit 20 min); depirea acestui interval ncheie automat sesiunea curent de lucru. Managementul strii sesiunii rezolv problema pstrrii informaiei, cnd navignd ntr-o aplicaie web accesm pagini diferite. Sesiunea poate fi aadar comparat cu o vizit la un site, cu rsfoirea mai multor pagini. Exemple n care apare necesar pstrarea strii la nivel de sesiune: Coul de cumprturi o list a tuturor produselor reinute pe msura vizitrii unor pagini de prezentare a produselor, dintr-un magazin virtual.

Datele despre vizitatorul unui site , n scopul personalizrii unui acces viitor (customer profiling ), se in ntr-o baz de date. Pentru colectarea i actualizarea lor

22.10.2012

55

periodic, pe msura rsfoirii paginilor se acumuleaz informaii n Session (de unde a venit, ce pagini a vizitat, ct timp a stat ntr-o pagin, ce link-uri a ales la plecare etc.). Aplicaie stareSesiune2. Probabil cel mai simplu exemplu ar fi s construim o aplicaie web cu dou pagini; prima pagin citete ntr-un textBox numele unei persoane, pe care-l va memora apoi n obiectul de stare al sesiunii ( la ncrcarea paginii n server ), sub indexul "utilizator" :
private void Page_Load(object sender, System.EventArgs e) { Session["utilizator"] = tbNume.Text; }

Adugm nc o pagin web aplicaiei noastre: Website / Add New Item / WebForm, pe care o vom denumi pag2.aspx.Pe butonul Continua din prima pagin declanm trecerea n pagina a doua:
private void btnContinua_Click(object sender, System.EventArgs e) { Response.Redirect("pag2.aspx"); }

iar la ncrcarea paginii urmtoare vom recupera i afia informaia din obiectul Session (cnd se declaneaz Page_Load i din al cui punct de vedere, server sau client, este vzut ca ncrcare ?): Server!! Punctul de vedere este cel al serverului, iar succesiunea evenimentelor este: PageInit, PageLoad, RequiredFieldValidator, btnClick, TextChanged, insert, delete i update, select, Page.Unload
private void Page_Load(object sender, System.EventArgs e) { // in pagina a doua lblSalut.Text = (string)Session["utilizator"]+ ", bine ai venit in pagina 2 !" ; }

22.10.2012

56

Gestiunea strii la nivel de aplicaie O aplicaie Web se definete ca fiind mulimea paginilor Web, a fiierelor de date i cod, a altor tipuri de resurse disponibile n directorul virtual sau n subdirectoarele acestuia. Aadar, aplicaia Web se identific cu directorul virtual, mai precis cu fiierul global.asax din acest director; acesta conine de altfel codul partajabil ntre mai muli utilizatori simultani ai aplicaiei Web. Fiierul global.asax conine i codul surs pentru tratarea evenimentelor ce apar la nivelul aplicaiei. Exist un singur fiier global.asax ce utilizeaz un singur limbaj de programare pentru a preciza codul executabil de tratare a evenimentelor ce apar la nivelul aplicaiei Web. La instanierea unei pagini Web se instanieaz un obiect din clasa HttpApplication; el are metode, proprieti i evenimente specifice i dispune de obiectele ce-i permit s intercepteze cereri HTTP. Principalele referine de obiecte pe care HttpApplication le deine sunt ctre obiectele:
Application, ce memoreaz informaia privind starea aplicaiei; Request, ce conine cererea unui client ctre server; Response, ce conine HttpResponse dat ca rspuns clientului la o cerere; Session, ce memoreaz informaia privind starea sesiunii de lucru.

Uneori este nevoie de pstrarea unor informaii despre toate sesiunile de lucru pe un site, informaii accesibile n permanen tuturor utilizatorilor, din oricare pagin a site-ului. Ele sunt frecvent folosite de aplicaie i se in n memorie, pe server, ct timp aplicaia este accesat de vreun utilizator; reiese c orice nou informaie adugat n obiectul Application, consum un plus de memorie. O parte din aceste informaii se refer la sesiunile de lucru cu o aplicaie (durata lor) i sunt legate de evenimente precum nceperea sau terminarea unei sesiuni de lucru, lansarea unei cereri etc.. Pentru c mai muli utilizatori au acces simultan la acelai obiect Application, pentru prevenirea blocajelor n lan, se impune ca toate operaiile pe acest obiect s se fac dup blocarea lui de ctre cel care dorete s opereze pe el:
Application.Lock(); { // modificri pe obiectul Application } Application.UnLock();

Aplicaia JurnalApp Cu WebSite Add / New Item / Global Application Class (care ulterior nu mai apare ca optiune, dac site-ul are deja fiierul global.asax) se creaz automat fiierul coninnd toate funciile de tratare a evenimenteleor aprute la nivel de aplicaie i la nivel de sesiune de lucru.
22.10.2012

57

Din Solution Explorer / Global.asax vedem unele dintre evenimentele generale ale aplicaiei, deja tratate prin funcii vide. Le vom modifica pentru a semnala n pagina Web, prin mesaje, succesiunea declanrii principalelor evenimente la nivelul aplicaiei. Deoarece o parte dintre evenimentele aplicaiei au ca efect schimbarea paginii, ntreruperea unei sesiuni de lucru etc., pentru a le consemna nu putem totdeauna s le afim n pagin, astfel nct preferm nscrierea lor ntr-un jurnal, pe disc. Pentru aceasta construim o funcie de jurnalizare, care scrie textul mesajului primit, mpreun cu ora la care l-a primit:
void ScrieJurnal(string mesaj) { System.IO.StreamWriter fisout = // append daca exista new System.IO.StreamWriter("C:\\jurnal.txt",true); string rand = "\n"+DateTime.Now.ToString( ) + " " + mesaj; fisout.WriteLine(rand); fisout.Close( ) } Dac sistemul de operare nu permite accesul la fiierul "C:\\jurnal.txt" pentru a nu drepturi pe tot directorul C:\ se creaz mai bine cu notepad-ul fiierul "C:\\jurnal.txt" i

da se dau drepturi de acces utilizatorului ASP.NET, aa cum s-a precizat n capitolul despre accesul la baze de date. Aplicaia JurnalApp folosete aceast funcie pentru a marca prin mesaje, succesiunea diferitelor evenimente aprute la nivelul aplicaiei.
protected void Application_Start(Object sender, EventArgs e) { Application.Add("nrSes",0);Application.Add("nrCer",0); ScrieJurnal("Aplicatia a fost lansata."); } protected void Session_Start(Object sender, EventArgs e) { Application.Lock(); int nrSesiuni=(int)Application.Contents["nrSes"]+1; Application.Set("nrSes",nrSesiuni); Response.Write("Sesiunea "+ nrSesiuni+" a inceput la " +DateTime.Now.ToLongTimeString()+"<br>"); Response.Write("Aplicatia are "+ Application.AllKeys.Length+" variabile globale <br>"); Response.Write(" Aplicatia detine perechile: "); foreach( string cheie in Application.Contents.AllKeys) Response.Write(" <br> "+ cheie +" = " +Application.Contents[cheie].ToString()); ScrieJurnal("Sesiunea nr. "+Application["nrSes"]+" " + Session.SessionID+ " a fost deschisa"); Application.UnLock(); } protected void Application_BeginRequest(Object sender, EventArgs e) { Application.Lock(); Response.Write("Lansat ev. BeginRequest <br><br>"); int nrCereri=(int)Application.Contents["nrCer"]+1; Application.Set("nrCer",nrCereri); ScrieJurnal("A fost primita cererea cu nr. " +nrCereri); Application.UnLock(); } protected void Session_End(Object sender, EventArgs e) {

22.10.2012

58

ScrieJurnal("Sfarsitul sesiunii nr. " +Application["nrSes"]+" " +Session.SessionID); int nrSesiuni=(int)Application["nrSes"]-1; Application.Set("nrSes",nrSesiuni); } protected void Application_End(Object sender, EventArgs e) { ScrieJurnal("Aplicatia stop"); }

Se lanseaz n paralel o nou sesiune pe acelai server de dezvoltare, observnd atent portul prin care comunic cu site-ul i tastnd sub IE n bara de adres http://localhost:2521/ JurnalApp/). Se cere din cnd n cnd, View / Refresh din browser i observm nregistrarea cererii ctre server, adic evenimentul BeginRequest. Se poate lucra i cu serverul de web IIS; n acest sens directorul fizic n care a fost creat siteul este dus n Inetpub\wwwroot i este apoi fcut director virtual ( sub IIS, Default website / director fizic / Properties i se alege Create); se pot apoi deschide cte sesiuni dorim, direct din instane diferite ale Internet Explorer-ului. Consultnd apoi fiierul jurnal C:\\jurnal.txt, constatm c la primul apel de pagin web se genereaz un grup de obiecte, de mai multe tipuri. La crearea obiectului Application se declaneaz evenimentul Application_Start; la crearea cte unui obiect Session se declaneaz i evenimentul Session_Start. Pe timeout ( depirea numrului de minute de inactivitate) se genereaz automat evenimentul Session_End pentru fiecare obiect Session. Cnd ultimul obiect Session se distruge, se declaneaz pe lng Session_End i evenimentul Application_End.Trebuie s avem n web.config declarat:
<sessionState mode="InProc" timeout="1" /> Obiectul Response nu exist cnd Application_Start nu poate afia informaii n intermediul obiectului Response.

se lanseaz aplicaia, astfel nct functia pagina web, cci pagina primete informaiile prin

Observm c e uor de intuit momentul nceperii aplicaiei, respectiv sesiunii (cnd cerem vizualizarea paginii), dar dificil de ntrevzut momentul terminrii sesiunii, respectiv aplicaiei. Aceasta deoarece serverul nu tie dac un client deja conectat va mai reveni sau a ncheiat deja lucru cu aceast pagin. Putem specifica n fiierul de configuraie web.config parametrul timeout = 1, n loc de ct era pus automat, astfel nct dup un minut de inactivitate sesiunea de lucru s se considere ncheiat; putem s marcm astfel n timp scurt, trecerea prin toate evenimentele declanate la vizitarea site-ului.
timeout = 20,

n ce privete aplicaia, probabil cel mai bine este s form terminarea ei fcnd o modificare n fiierul global.asax, caz n care ASP.NET sesizeaz c s-a schimbat aplicaia, ncheie aplicaia curent i o restarteaz n noul format. global.asax i default.aspx lucreaz pe acelai namespace, astfel nct putem folosi n webform1.aspx variabile sau funcii definite n global.asax. Un alt mod de a menine valori pe toat durata aplicaiei i cu vizibilitate la nivelul ntregii aplicaii l reprezint variabilele de tip static. Ele se declar n Global.asax (cod script necompilat) sau Global.asax.cs (cod precompilat) i devin utilizabile n toate paginile aplicaiei. ntr-un script din Global.asax o declaraie ar putea arta astfel:

22.10.2012

59

<%@ Application Classname="myClass" %> <script language="c#" runat=server> public static int cntApplication = 0; public void Session_Start() { cntApplication++; }
</script>

adic se d un nume de clas obiectului ce va conine variabila, se declar i iniializeaz variabila, ulterior ea putnd fi folosit ntr-un eveniment, chiar la nivel de sesiune. Pentru lucru cu variabile globale definite n codul ce va fi compilat n prealabil, adic n fiierul Global.asax.cs procedeul este tot cel standard, impus de limbajul C#. Spre exemplu, n global.asax.cs, clasa definit de mediu este numit implicit Global i ca orice clas, poate conine definiii de variabile sau funcii:
public static int x;

n WebForms putem adresa aceste variabile sau funcii, folosind rezoluia de clas sau obiectul, sub forma:
Global.x = 3;

Revenind la fiierul global.asax, putem preciza c mai exist un alt mod de a declara variabile statice i anume direct n fiier, n afara blocului de script, caz n care cele dou mecanisme application state i static variables se confund. n acest scop, deschidem cu notepad fiierul global.asax i adaugm n afara blocului de script, secvena:
<object id="y" class="System.String" scope="Application" runat="server"/>

Astfel se adaug variabila y, de tip string, la nivel de Application ( putea fi i la nivel de Session). Variabila nu este recunoscut nainte de aceast declaraie i dureaz atta timp ct dureaz i aplicaia ( sau sesiunea, dac scopul este Session). Variabila poate fi calificat apoi ca fcnd parte din dicionarul aplicaiei i poate intra n evaluarea unor expresii.
<% Application["y"]="3333"; %>

pus n webform1.aspx face o iniializare, iar


Response.Write("Valoarea lui y este: "+ (string)Application["y"]);

pus n webform1.aspx.cs afieaz n pagin coninutul lui y. n blocul <script runat="server"> </script> se pot pune handlere, metode sau variabile statice. Aadar, ca orice cod, declaraiile de variabile pot fi puse n fiierul citat n code-behind sau n blocul script. Implicaiile gestiunii strii n lucru cu baze de date Aplicaia stareGrid Considerm o aplicaie simpl cu un grid, care la apsarea unui buton IncarcaGrid afieaz datele dintr-o tabel a bazei de date; pentru aceasta, construim un proiect Web Application, dragm un obiect dataAdapter i cu mouse dreapta i cerem Generate DataSet; aducem apoi un obiect dataGrid, iar pe un buton solicitm umplerea dataSet-ului i legarea gridului la dataSet pentru a vizualiza informaiile:
private void incarcaGrid_Click(object sender, System.EventArgs e) { try { oleDbDataAdapter1.Fill(dataSet1); DataGrid1.DataSource =this.dataSet1; DataGrid1.DataBind(); 22.10.2012

60

} catch(Exception exc) { mesaje.Text=exc.Message; }

Dac mai adugm un buton CerePostBack, care nu face nimic, dar la apsare forez un PostBack ( adic solicit vizitarea serverului pentru recompunerea paginii curente, cu eventuale modificri dinamice indicate prin prelucrrile din funcia de tratare a evenimentului click pe acest buton), observm c gridul va continua s afieze bine datele. Secretul const n faptul c dei nu s -a mai apsat pe butonul IncarcaGrid datele se vd cci ele circul cu controlul DataGrid, care are setat implicit proprietatea EnableViewState pe true. Dac setm aceast proprietate pe false observm c datele nu mai apar n grid dup apsarea butonului CerePostBack. O problem poate fi totui formulat n legtur cu acest lucru: se justific aceast cltorie a unui volum, uneori foarte mare, de date ctre server i napoi? Dac nu se justific, cum am putea totui vedea i beneficia de datele din grid ? Exist dou alternative: 1. punem instruciunile de ncrcare grid direct n Page_Load, astfel nct datele vor fi preluate din baza de date la fiecare ncrcare de pagin ( mcar nu mai circul i ctre server, ci doar napoi ctre client); 2. caching, caz n care datele rezid pe server, n memoria procesului ce execut cererea sau n cea global i nu mai trebuie citite din baza de date, lucru care ar consuma mai mult timp. Mecanismul de cache extinde ntructva facilitile introduse prin application state; acesta nu numai c ine informaia la nivelul ntregii aplicaii, ci d, spre exemplu, posibilitatea sesizrii momentului n care un obiect din cache a fost modificat i deci pagina necesit un refresh, pentru a beneficia de noua versiune (a se vedea metodele clasei Cache).

22.10.2012

61

Potrebbero piacerti anche