bancuri, glume, imagini, video, fun, bancuri online, bancuri tari, imagini haioase, videoclipuri haioase, distractie online Pe HaiSaRadem.ro vei gasi bancuri, glume, imagini, video, fun, bancuri online, bancuri tari, imagini haioase, videoclipuri haioase, distractie online. Nu ne crede pe cuvant, intra pe HaiSaRadem.ro ca sa te convingi.

Aplicatii Web cu C# si ASP.NET - Lectia 5

Cookies

Folosirea de cookies la nivel de client este un mod prin care pot sa stochez informatie relevanta in cadrul aplicatiei. Spre deosebire de sesiune (Session), lucru prezentat in lectia 2, in care informatiile se retin la nivel de server, aici totul este retinut la nivel de client. Exista doua tipuri de cookies: legate de sesiune (care se sterg odata cu inchiderea browserului) si persistente, care trebuie neaparat sa aiba asociata o perioada de viata, adica cat timp va exista la nivel de client.

In lectia 4 am dat un exemplu de creare de Ticket pentru autentificarea bazata pe Forms, in care foloseam un cookie. De fapt, acesta este un mod de a retine informatie utila pe o perioada determinata. In exemplul acela eu nu foloseam in mod explicit informatia din cookie-ul, ci doar stocam in el Ticket-ul.

Iata insa un exemplu de cod in care se poate folosi un cookie in care pastrez informatie utila pe care o folosesc mai tarziu. In Page_Load se verifica daca exista un cookie si daca nu, se creaza unul. In acelasi Form, in metoda GetStyle, se foloseste informatia din cookie.

// Form1.aspx
protected void Page_Load(Object sender, EventArgs e) {
    if (Request.Cookies["preferences1"] == null) 
    {
        HttpCookie cookie = new HttpCookie("preferences1");
        cookie.Values.Add("ForeColor", "black");
        ...
        Response.AppendCookie(cookie);
    }
}
 
// Form1.aspx
protected String GetStyle(String key) {
  HttpCookie cookie = Request.Cookies["preferences1"];
  if (cookie != null) 
  {
    switch (key)
    {
      case "ForeColor" : return cookie.Values["ForeColor"]; break;
      ...
    }
  }
  return "";
}

Limitari :

Trimiterea de email-uri

In foarte multe scenarii este util sau chiar obligatoriu ca aplicatia noastra web sa poata sa trimita in mod automat email. Acest lucru se realizeaza foarte usor programatic folosind clasele din System.Web.Mail.

Pentru asta trebuie sa specificati la un moment dat un IP, la care sa se gaseasca un server de email. Daca nu dispuneti de o retea care sa aiba un Windows Server 2003 cu Exchange 2003 pe el J, atunci puteti sa incercati sa trimiteti email din aplicatia voastra folosind IIS. Da, IIS poate sa trimita email-uri !!!

Ca sa setati IIS sa trimita email-uri, trebui sa urmati urmatorii pasi: deschideti Internet Information Services, click dreapta pe Default SMTP Virtual Server, Properties, tab-ul Access. Aici trebuie sa vedeti un buton Relay. Click pe el si trebuie sa adaugati o lista de IP-uri de la care el trimite email-uri. Deci faceti Add si la Single Computer introduceti IP-ul de localhost (127.0.0.1). Acum ar trebui ca IIS sa poata sa trimita email-uri.

Iata si un exemplu de cod care citeste din web.config IP-ul la care se gaseste un server de SMTP si trimite email-uri la o lista care se gaseste intr-un sir de obiecte la nivel de aplicatie.

public string SendMailToSignIns(string strSubject, string strMessage)
{
    string sSMTPServer;
    bool ok = true;
    //citeste IP server din web.config
    System.Configuration.AppSettingsReader apsr = new System.Configuration.AppSettingsReader();
    sSMTPServer = (string)apsr.GetValue("SMTPServer",typeof(string));
    System.Web.Mail.SmtpMail.SmtpServer = sSMTPServer;
    
    /* SignIns este un sir de obiecte care contine studentii inscrisi Cu proprietatile lor */
    for (int i = 0; i < SignIns.Length; i++)
    {
        System.Web.Mail.MailMessage mMessage = new System.Web.Mail.MailMessage();
        //proprietatea Email contine un string de forma gigi@k.ro
        mMessage.To = SignIns[i].Email;
        mMessage.Subject = strSubject;
        mMessage.From = eu@personal.ro;
        mMessage.BodyFormat = System.Web.Mail.MailFormat.Text;
        mMessage.Body = strMessage;
        
        try
        {
              System.Web.Mail.SmtpMail.Send(mMessage);
        }
        catch(Exception ex)
        {
              ok = false;
        }
    }
    
    if (ok)
    {
        return "Email sent ok to all Signins.";
    }
    else
    {
        return "At least one email could not be sent.";
    }
}

Upload si download

De asemenea, de multe ori este necesar sa dam utilizatorilor aplicatiei noastre posibilitatea de a “upload-a” un fisier pe serverul nostru. Iata pe scurt cum se poate realiza un scenariu de Upload, respectiv Download de fisiere prin intermediul unei aplicatii ASP.NET.

Pentru lucrul cu fisierele este nevoie de clasele din namespace-ul System.IO.

Upload

Pentru asta este nevoie de folosirea controlului File Field, aflat in categoria de controale HTML. Iata cum arata codul executat in urma apasarii unui buton “btnUpload”:

private void btnUpload_Click(object sender, System.EventArgs e)
{
    /* verific daca userul a postat ceva in controlul File Field cu numele fileRead */
    if (fileRead.PostedFile.ContentLength != 0)
    {
        /* separ numele fisierului postat in mai multe string-uri, fiecare fiind o bucata din numele intreg separate de fiecare gasire de . De fapt urmaresc sa separ extensia fisierului postat */
        char[] cSepP = {'.'};
        string[] rgSep = fileRead.PostedFile.FileName.Split(cSepP,10);
        string strExt = rgSep[rgSep.Length -1];
        if (strExt == "zip")
        {
            /* retin continutul fisierului citit */
            HttpPostedFile file = fileRead.PostedFile;
            int iFileSize = file.ContentLength;
            byte[] rgbFileData = new byte[iFileSize];
            file.InputStream.Read(rgbFileData,0,iFileSize);
            string strRootPath = Server.MapPath(DBConnection.GetPath());
            /* functia PostFile() salveaza fisierul citit pe disc */
            lblMessage.Text = PostFile(strRootPath,rgbFileData);
        }
        else
        {
          lblMessage.Text = "Please give a zip file!!!";
        }
    }
    else
    {
        lblMessage.Text = "Please select a file from your hard disk!!!";
    }
}

Iata si continutul metodei PostFile():

private string PostFile(string strRoot, byte[] FileData)
{
    string strDest = strRoot + "\\Courses\\course_" + CourseID.ToString();
    strDest += "\\" + Name + "_lesson" + (CurrentLesson+1).ToString() 
                    + ".zip";
    try
    {
        FileStream fsWrite = new FileStream(strDest, FileMode.CreateNew);
        fsWrite.Write(FileData,0,FileData.Length);
        fsWrite.Close();
    }
    catch(Exception ex)
    {
        return "Could not save the file!!!";
    }
    return "Homework posted.";
}

Download

Odata fisierele postate undeva pe server, intr-o cale relativa la directorul radacina al aplicatiei ASP.NET, eu pot sa descarc acele fisiere.

Pentru asta am nevoie de un Form “gol”, adica fara nici un fel de control, dar care are in Page_Load codul urmator:

/* download.aspx */
private void Page_Load(object sender, System.EventArgs e)
{
    Response.Clear();
    Response.ContentType = "application/octet-stream";
    Response.AddHeader("Content-Disposition","attachment; filename=" + '"' + (string)Session["Filename"]+ '"');
    Response.Flush();
    Response.WriteFile((string)Session["Path"]);
}

Evident ca valorile din sesiune (“Filename” si “Path”) au fost setate inainte, de exemplu la apasarea unui buton “btnGetHomework”:

/* trainer_course.aspx */
private void btnGetHomework_Click(object sender, System.EventArgs e)
{
    objTrainer = (Trainer)Session["Trainer"];
    string strPath = Server.MapPath(DBConnection.GetPath());
    strPath += "\\Courses\\course_" + objTrainer.CourseID.ToString() + "\\" + ddlSignIns.SelectedValue + "_lesson" + ddlLessonNo.SelectedValue + ".zip";
    Session["Path"] = strPath;
    Session["FileName"] = Path.GetFileName(strPath);
    Response.Redirect("download.aspx");
}

Performanta

Aplicatiile ASP.NET sunt aplicatii web, deci accesibile probabil unui numar mare de utilizatori. De multe ori, este foarte important ca aplicatia sa faca fata cu succes unei incarcari mari: multi utilizatori simultani, multe tranzactii cu baza de date etc.

In general se urmareste ameliorarea urmatorilor parametri:

·         Incarcarea procesorului si a memoriei sistemului.

·         Numarul de cereri pe care aplicatia le poate servi pe unitate de timp.

·         Timpul de raspuns, latenta.

·         Utilizarea cache-ului. Se pot urmari cache hits si cache misses.

·         Erori. Numarul de erori si exceptiile generate.

Pentru a masura efectiv ceea ce am mentionat, avem nevoie de niste indicatori de performanta, oferiti de toate sistemele Microsoft (>= Windows 2000). Acestia se pot gasi la Control Panel -> Administrative Tools -> Performance.

Deoarece aplicatiile ASP.NET pot fi foarte diferite si mai ales pot sa functioneze in scenarii diferite, nu exista niste limite cantitative clare, adica niste cifre asociate fiecarui indicator, care odata atinse sa putem spune ca aplicatia nu mai este performanta. Acestea se stabilesc mai mult calitativ, iar cifre concrete se pot asocia doar atunci cand se vorbeste de aplicatii si scenarii concrete.

Iata care ar fi niste indicatori care merita urmariti:

Incarcarea procesorului

Processor(_Total) \ % Processor Time
Process(aspnet_wp) \ % Processor Time
Process(aspnet_wp) \ Private Bytes
Process(aspnet_wp) \ Virtual Bytes
Process(aspnet_wp) \ Handle Count

Memoria

Memory \ Available Mbytes

Numarul de cereri servite

ASP.NET Applications \ Requests/sec
ASP.NET \ Application Restarts
ASP.NET \ Requests Rejected

Latenta

ASP.NET \ Request Execution Time

Cache

ASP.NET Applications \ Cache Total Entries
ASP.NET Applications \ Cache Total Hit Ratio

Erori

.NET CLR Exceptions \ # Exceptions thrown / sec

Aici gasiti putin mai detaliat niste explicatii legate de indicatori de performanta, in aplicatii .NET: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt15.asp .

Totusi, la un mod mult mai concret, trebuie sa tinem cont in aplicatiile ASP.NET pe care le construim de urmatoarele sfaturi:

  1. Trebuie sa evitam sa accesam prea des baza de date, daca aplicatia noastra foloseste una. Se stie, ca reteaua este cel mai lent dispozitiv de intrare iesire dintre cele uzuale (memorie cache, memorie centrala, memorie externa). Trebuie ca toate manipularile de date sa fie realizate la nivel de aplicatie si accesarea bazei de date sa fie realizata numai cand avem nevoie de informatii si sa stocam date. Prin urmare, se impune sa retinem date la nivel de aplicatie.
  2. Trebuie sa alegem cu grija modul in care stocam date la nivel de aplicatie. Exista mai multe moduri: Session, Cookies (despre care am discutat pe scurt); dar si Cache (http://msdn.microsoft.com/msdnmag/issues/04/07/CuttingEdge/ ). Discutand despre primele doua, diferenta majora este ca prima presupune stocarea aproape nelimitata si la nivel de server, iar a doua stocarea la nivel de client, limitata in dimensiune si dependenta de browser.
  3. Sa avem grija sa facem cat mai putine Requests la server. Multe validari se pot face la nivel de client (folosind JavaScript). De exemplu verificarea ca intr-un TextBox s-a introdus un anumit tip de informatie se poate face folosind controalele predefinite (vezi lectia 2), dar asta insemna un drum dus-intors la server; acelasi lucru se poate realiza la nivel de client evitand drumuri aiurea la server.

Tot la acest capitol, se recomanda folosirea IsPostBack pentru a nu incarca niste date de fiecare data cand se executa Page_Load. Va reamintesc ca un Form ASP.NET se incarca la fiecare response primit de la server, generat in urma unui request (apasare de buton, etc.).

void Page_Load(Object sender, EventArgs e) 
{
    // ...set up a connection and command here...
    if (!Page.IsPostBack) 
    {
        String query = "select * from Authors where FirstName like '%JUSTIN%'";
        myCommand.Fill(ds, "Authors");
        myDataGrid.DataBind();
    }
}
 
void Button_Click(Object sender, EventArgs e) 
{
    String query = "select * from Authors where FirstName like '%BRAD%'";
    myCommand.Fill(ds, "Authors");
    myDataGrid.DataBind();
}
  1. Accesarea paginata a datelor. Controlul DataGrid expune o functionalitate foarte utila, si anume suport pentru paginare. Astfel, daca sursa de date pentru DataGrid contine foarte multe inregistrari, cand setam Paging putem sa afisam un numar fix de inregistrari la un moment dat.
  2. Connection Pooling. Este o functionalitate intrinseca a ADO.NET, prin care orice conexiune la baza de date creata la un moment dat, folosita si apoi inchisa este introdusa intr-un „bazin” iar atunci cand se incearca crearea unei conexiuni, se alege una existenta din acel „bazin”.

Mai concret, inseamna ca daca am o aplicatie ASP.NET care este accesata simultan de 100 de utiliatori, nu voi avea 100 de conexiuni la MS SQL Server, ci mult mai putine, deoarece este o singura aplicatie.

Nu acelasi lucru se poate spune daca aplicatia este Windows Forms si instalata la fiecare client - fiecare aplicatie de fapt acceseaza baza de date, deci voi avea 100 de conexiuni la MS SQL Server !!!

  1. Se recomanda folosirea de proceduri stocate SQL. Acestea rezida in serverul de baze de date sub forma de cod precompilat, spre deosebire de query-urile pe care le scriem la nivel de aplicatie .NET, care se compileaza de fiecare data.

Chiar daca din punct de vedere al performantei, procedurile stocate SQL sunt recomandate, trebuie sa luam in considerare si alte aspecte, cum ar fi mentenanta. Cat ma costa pe termen lung sa fac proceduri stocate ? Ganditi-va la: vreau sa schimb serverul de baze de date; expertul pe T-SQL (limbajul in care aceste proceduri sunt scrise) pleaca din firma !!!

  1. Atentie la ce clase folosim cand accesam date SQL. SqlDataReader parcurge datele intr-o singura directie (inainte), cate o inregistrare odata, si se recomanda pentru obtinerea de „calupuri” mici de date. SqlDataAdapter si DataSet sunt recomandate pentru obtinerea unui calup mare de date o singura data.
  1. Nu va bazati pe blocuri try ... catch. Acestea sunt foarte costisitoare si ar trebui sa fie folosite cat mai rar. Daca fluxul codului poate fi controlat altfel, reusind totusi sa construim o aplicatie robusta (care nu crapa din 5 in 5 minute J), se recomanda sa o facem. Iata un exemplu:
// Modificati asta:
try 
{
   result = 100 / num;
}
catch (Exception e) 
{
  result = 0;
}
 
// cu asta:
 
if (num != 0)
   result = 100 / num;
else
  result = 0;

In unele situatii pur si simplu try ... catch nu se poate evita. Un exemplu este atunci cand executam comenzi pe o conexiune la baza de date.

Output Caching

OutputCaching este o metoda foarte utila de a mari capacitatea de trecere (throughput) a aplicatiilor web, prin caching-ul continutului generat. Cu alte cuvinte, exista posibilitatea ca, odata ce a fost generata o pagina, continutul acesteia sa fie trimis tuturor clientilor care cer pagina, fara ca acestia sa astepte regenerarea continutului. Evident ca, dupa un timp (configurabil), versiunea cache-uita a paginii va expira si atunci la urmatoarea cerere, se va genera o noua pagina, care va fi automat servita clientilor o noua perioada de timp, pana expira. Aceasta tehnica este deosebit de utila in cazul in care avem portiuni de site care se modifica destul de rar. Datorita faptului ca output caching este configurabil la nivel de pagina, putem specifica ce pagini dorim sa fie cache-uite si care nu. De alfel, ca sa fiu exact, chiar si Web User Control-urile pot fi configurate sa fie cache-uite. In acest caz, trebuie sa fim atenti: daca pagina in care este continut un control este configurata pentru cache-uire, atunci degeaba va fi controlul setat sa nu fie cache-uit, pentru ca pagina intreaga va fi luata din cache oricum, controlul nemaiavand posibilitatea sa-si genereze continutul. Intotdeauna cand avem o astfel de situatie (cu controale web care au setata o politica de caching), pagina din care fac parte, trebuie sa nu fie cache-uita.

Pentru a face un raspuns al server-ului eligibil pentru caching, trebuie ori adaugata o clauza <@OutputCache> la inceputul paginii web. Aceasta clauza are mai multi parametrii (pentru detalii complete vezi: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconOutputCache.asp):

·         Duration: specifica durata de timp cat pagina va fi servita din cache (pana expira)

·         Location: limiteaza unde se va face caching-ul paginii – exista posibilitatea sa se faca pe server-ul sursa (care ruleaza aplicatia), la client (in browser-ul sau), Downstream, adica undeva pe „drumul” intre server si client (server proxy de ex.) si combinatii.

·         VaryByParam: exista posibilitatea sa se cache-uiasca mai multe versiuni ale paginii, in functie de parametrii dati paginii (in QueryString pentru cererile de tip GET, sau in parametrii trimisi in cazul metodei POST).

Exemplu de utilizare:

<%@ OutputCache Duration="60" VaryByParam="none"%>

Aici se seteaza ca perioada pana la expirarea paginii sa fie de 60 secunde si sa existe o singura versiune cache-uita (VaryByParam=”none”).

De asemenea, exista posibilitatea de a cache-ui si obiecte utilizator, nu doar pagini web. Pentru aceasta se poate folosi o instanta a clasei Cache (din System.Web.Caching). Implicit orice pagina web (Page) contine un obiect de tip Cache, accesibil prin intermediul proprietatii Cache. Pentru a adauga un obiect in cache se utilizeaza metodele Add, Insert. Extragerea unui obiect se face prin intermediul indexer-ului. Va las pe voi sa vedeti cum se foloseste obiectul din cod (vezi http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwebcachingcacheclasstopic.asp)

Tema 5

Datorita faptului ca avem mai multi studenti pe primele locuri cu acelasi punctaj (sau foarte apropiat), voi propune o tema speciala de aceasta data, care sa necesite cunostinte in plus fata de ce am prezentat in lectie (pentru a va putea departaja). Pentru documentare, vezi www.google.ro!!! Punctajul va fi tot de 5 puncte maxim, doar ca punctarea va fi facuta semi-subiectiv-semi-obiectiv, fara sa va spun de la inceput care sunt criteriile de punctare!!! Daca si dupa lectia 5 vor fi la egalitate, vom da un mic test online saptamana viitoare din ASP.NET.

Creati o aplicatie de Bursa electronica. Aceasta va contine o pagina de login-are in care utilizatorul va introduce un nume si o parola. Acest cont va fi verificat dintr-o lista de conturi specificate in web.config (<forms><credentials>). Daca autentificarea a fost realizata cu succes, utilizatorul va fi redirectat catre pagina default.aspx, care contine un Web User Control. Controlul afiseaza intr-un DataGrid informatii despre cotatiile bursiere (aceste informatii sunt generate random, vezi starter-ul). Se doreste ca acest control sa nu afiseze informatiile chiar realtime (deoarece exista foarte multe cereri pe secunda si server-ul ar fi prea „surmenat” daca ar trebui sa genereze informatii pentru fiecare client), ci se doreste cache-uirea informatiilor 30s. Pentru generarea propriu-zisa a DataSet-ului care contine informatiile bursiere, se foloseste o clasa StockGenerator. Aceasta are o metoda statica publica GetData, care returneaza un DataSet (generat in GenerateDataSet). GetData va trebui sa cache-uiasca (System.Web.Caching.Cache) obiectul generat de GenerateDataSet si, doar atunci cand acesta expira, va fi recreat din nou (prin apelarea metodei de generare).

Datagrid-ul din StockGrid mai contine (pe langa cele 3 coloane ID, Symbol si Price) si o coloana cu un TextBox (Template Column), in care utilizatorul poate introduce un numar, care specifica cate actiuni doreste sa cumpere user-ul de la firma selectata. Intial, cand se face DataBind la grid, se initializeaza automat pe 0. Dupa ce a terminat de selectat, va putea apasa un buton Buy (din afara grid-ului), in acest moment realizandu-se tranzactia; in cazul nostru, simulam cumpararea prin log-area unui mesaj continand informatii despre ce si cat a cumparat (nr. Actiuni x pret actiune + total), folosind obiectul System.Diagnostics.Trace. Se mentioneaza ca se doreste consultarea mai tarziu a acestor informatii despre tranzactii, asa ca acestea trebuie salvate intr-un fisier (~/transaction.txt, unde „~” este directorul aplicatiei web). Folositi neaparat obiectul Trace pentru aceasta (vezi documentatia http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdiagnosticstraceclasstopic.asp)!!!

Starter-ul se gaseste la adresa: bursa.zip.

Am pus mai jos o poza cu o posibila interfata pentru aceasta aplicatie. Succes!


 

preview --- Cursuri