ASP.NET Managing State Roberto Brunetti [email protected] Blog: blogs.devleap.com/rob.rss http://www.DevLeap.it Chi siamo • www.DevLeap.it • Un gruppo di 5 persone con tanta voglia di • • • • • Studiare a fondo le tecnologie Capire il “behind the scenes” Implementare soluzioni reali Confrontarsi con le problematiche reali Sperimentare nuove idee http://www.DevLeap.it Cosa Facciamo • • • • • • • • • Sviluppo Corsi Conferenze Seminari Mentoring Analisi e disegno di progetto Auditing su realizzazioni proprie o di terze parti Valutazione skill risorse umane Non facciamo sviluppo direttamente • (Supporto telefonico/via email a contorno di altri servizi: mentoring) • Definizione di percorsi di crescita per team di sviluppo http://www.DevLeap.it Html e Http La dura verità http://www.DevLeap.it Request/Response Http Server Client IIS/Apache Richiesta HTTP default.htm Risposta HTTP http://www.DevLeap.it ASP: flusso dell’applicazione Server Client IIS http://www.dcc.com/equipment/catalog_type.asp? ProductType=rock+shoes Richiesta HTTP Active Server Pages engine Risposta HTTP Esecuzione JScript VB / C# ADO.NET Recupero risultati http://www.DevLeap.it default.aspx Stateless • Ogni richiesta è a se stante • Non esistono informazioni di stato in Http • Per ogni richiesta dobbiamo preoccuparci di inviare il contenuto • Ad esempio riempire i campi di un form con le informazioni digitate dall’utente http://www.DevLeap.it Stateless • Ripresentare le informazioni digitate <INPUT TYPE=“TEXT” NAME=“txtNome” VALUE=<%=Request.QueryString(“txtNome”) %> > http://www.DevLeap.it ASP.NET Web Form <FORM action=“NomeRisorsa” METHOD=“POST”> <INPUT TYPE=“Text” ID=“txtNome” runat=“server”> <INPUT TYPE=“Text” ID=“txtCognome” runst=“server”> <INPUT TYPE=“Submit”> </FORM> • I controlli mantengono lo stato http://www.DevLeap.it Mantengono lo stato ? • I controlli server mantengono le proprietà impostate fra round-trip • Tramite un campo hidden • __VIEWSTATE • Pro • Meno plumbing • Meno roundtrip verso i dati • Contro • __VIEWSTATE occupa banda • E’ disabilitabile http://www.DevLeap.it Demo 10 • ViewState • View Source • Modifica attributo al click • Azzera: Cambia colore pulsante • Disable su Controllo • Non tiene il bgcolor • Disable su Pagina • Non tiene il bgcolor http://www.DevLeap.it Gestione dello stato Burocrazia ? Intro/Real http://www.DevLeap.it Manage State ? • Il Web è stateless • Mantenere lo stato delle informazioni • Valori • Variabili • Proprietà • Server-Side per riutilizzarli fra richieste diverse • Sulla stessa pagina • Sull’intera applicazione http://www.DevLeap.it Manage State • Server Side • • • • Web.Config Application Session (se cookie andrebbe dopo) Caching • Client/Server Side • • • • Cookie Hidden Field QueryString ViewState http://www.DevLeap.it Web.Config • Può contenere valori Custom • Connection String • Informazioni statiche che prima si mettevano in Application o su file esterni • <appSettings> • <add key=“cString” value=“.....” /> • </appSettings> • Nel codice • Using/Imports System.Configuration • strConn = Configuration.AppSettings(“DSN”) http://www.DevLeap.it Occhio al Publish • Differenziare Test / Produzione • • • • • Connessioni al DB Email routing Log Security Etc • Exclude / Include da VS.NET http://www.DevLeap.it Web.Config • Quando viene letto • Alla partenza dell’applicazione • Quando è necessario ricompilare • Dove viene mantenuto • HashTable nell’HttpContext • Come si accorge dei cambiamenti • Viene calcolato l’hash di • CreationTime + LastWriteTime + Lenght • E memorizzato in un file esterno nella directory di compilazione • Ad ogni richiesta viene fatta la verifica del valore dell’hash • Se non quadra viene riletto http://www.DevLeap.it Application • Classe HttpApplicationState • Oggetto Application • Esposto come proprietà di • HttpContext e Page • Memoria condivisa per tutta l’applicazione • Indipendente dall’utente • Accesso tramite Nome/Valore • Non usarla per dati temporanei • Difficile impostare una scadenza • Da non confondere con la classe HttpApplication esposta come ApplicationInstance che rappresenta l’intera applicazione ASP.NET e non un’area di memoria http://www.DevLeap.it Session Session... • In ASP 1/2/3 le session • Necessitano del supporto dei cookie sul client • Sono single-machine e non adatte a configurazione di load-balancing • Consumano molta RAM • In ASP.NET le session • • • • Possono lavorare come prima oppure Non necessitare dei cookie Essere multi-machine Appoggiarsi su DB o su uno State Server http://www.DevLeap.it Session • Classe HttpSessionState • Oggetto Session • Esposto come proprietà di • HttpContext e Page • Memoria condivisa per tutta l’applicazione • Dipendente dall’utente • Accesso tramite Nome/Valore • Non usarla per dati temporanei • Difficile impostare una scadenza • Implementata dal modulo System.Web.SessionState.SessionStateModule http://www.DevLeap.it Cos’è Browser Browser Server Cookie URL Sess Session Cookie Session URL Sess ASP.NET worker thread 1 HttpRuntime Class Modulo X Session HTTP Handler Pagina1.aspx ASP.NET worker thread 2 HttpRuntime Class Modulo X Session ASPNET_WP.EXE http://www.DevLeap.it HTTP Handler Pagina2.aspx Come si usa • Session(“nome”) = Valore • Response.Write(Session(“nome”)) • Non occorre definire le varibili • Come nella vecchia versione • Ma occhio a controllarne l’esistenza prima di utilizzarne un valore • Oppure valorizzare tutte la var nel Session_OnStart http://www.DevLeap.it Configurazioni possibili <sessionState mode="Off|Inproc|StateServer|SQLServer" cookieless="true|false" timeout="number of minutes" stateConnectionString="tcpip=server:port" sqlConnectionString="sql connection string" /> • Off se non si usa http://www.DevLeap.it Session senza Cookie <sessionState cookieless=“true" /> • Non necessita di cookie abilitati sul client • Il cookie viene copiato nei vari Url linkati dalla pagina • Http://xxx.com/3463287462764/pagina.aspx • Utilizzabile in tutte le modalità • Session.Mode • Gestiti dal filtro ISAPI ASPNET_FILTER.DLL http://www.DevLeap.it In-process Session ASPNET_WP Browser Browser Cookie URL Sess Session Cookie Session URL Sess <sessionState mode=“InProc” cookieless="true|false" /> • Più veloce • Singolo Server – No Load Balancing • Se ASPNET_WP crasha – Addio Session http://www.DevLeap.it Browser Browser Cookie URL Sess Cookie URL Sess ASPNET_WP ASPNET_STATE SERVER 3 SERVER 1 Session Session Browser Cookie URL Sess ASPNET_WP SERVER 2 Session <sessionState mode=“StateServer” cookieless="true|false" stateConnectionString="tcpip=server3:42424" /> • ASPNET_STATE Può girare anche sullo stesso server • Se ASPNET_WP crasha – Le Session sopravvivono • Più lento di InProcess – Più veloce di SQL Server Session • Load Balancing • Se crasha ASPNET_STATE – Addio Sessioni di tutti i server http://www.DevLeap.it Browser Browser Browser Cookie URL Sess Cookie URL Sess Cookie URL Sess ASPNET_WP Sql Server o Sql Cluster SERVER 1 Session ASPNET_WP SERVER 2 Session Session <sessionState mode=“SQLServer” cookieless="true|false" sqlConnectionString=“ConnString” /> • SQL può girare anche sullo stesso server • Se ASPNET_WP crasha – Le Session sopravvivono • Metodo più lento ma più sicuro (se in cluster) • Load Balancing http://www.DevLeap.it SQL Server Session • %WinDir%\Microsoft.NET\Framework\vxxxx\I nstallSQLState.sql • Per creare Database e Stored Procedure • DataBase: ASPState • SP: Insert, Get, Update • I dati vengono appoggiati al TEMPDB • Al Restart di SQL Server le Session vengono perse • Possiamo modificare InstallSQLState per creare e appoggiare i dati su un altro DB • Nella 1.1 InstallPersistSQLState.sql http://www.DevLeap.it Per avere un idea 1400 Requests/Sec (2P Server) 1200 1000 800 600 400 200 0 ASP.NET InProc ASP.NET State Store ASP.NET SQL Store http://www.DevLeap.it HttpHandler e HttpModule ASP.NET worker thread 1 HttpRuntime Class Modulo 1 Modulo 2 PageHandler Pagina1.aspx ASP.NET worker thread 2 HttpRuntime Class Modulo 1 Modulo 2 ASPNET_WP.EXE http://www.DevLeap.it PageHandler Pagina2.aspx HttpHandler e HttpModule ASP.NET worker thread 1 HttpRuntime Class Authent Session PageHandler Pagina1.aspx ASP.NET worker thread 2 HttpRuntime Class Authent ASPNET_WP.EXE http://www.DevLeap.it PageHandler Pagina2.aspx SessionStateModule • Dopo aver letto la configurazione relativa alle sessioni • Si abbona all’evento AcquireRequestState, ReleaseRequestState e EndRequest. • Durante la gestione dell’ AcquireRequestState recupera il SessionID ed i valori da inserire nell’oggetto Session http://www.DevLeap.it Session Conclusione • Non abbiamo più i problemi di ASP 3.0 • Nessun problema di COM Affinity • Load Balancing consentito • Detto questo, non usatele se non ne avete bisogno • Togliere l’HttpModule da Machine.Config • Oppure <page enableSessionState=“false” /> • Togliere il modulo dal Web.Config • <httpModules> • <remove name=“Session” /> • </httpModules> • Oppure <page enableSessionState=“false” /> • Disabilitare le session sulle pagine che non le utilizzano • @Page EnableSessionState=“false” • Se una pagina legge solamente i valori senza scriverli • @Page EnableSessionState=“readonly” http://www.DevLeap.it Cookie • Namespace System.Web • Semplice • x = new HttpCookie(name,value) • Response.AppendCookie(x) • If Request.Cookies(name) = Null / null • Stringa = Request.Cookies(name) • Da non confondere con • System.Net.Cookie http://www.DevLeap.it Cookie multivalue • x = new HttpCookie(name) • x.Values.Add(“nome”, “valore”) • Response.AppendCookie(x) • If Request.Cookies(name) = Null / null • Stringa = Request.Cookies(name).Values(“nome”) • Usare il meno possibile gli oggetti -> http://www.DevLeap.it Passare da variabile locale • x = new HttpCookie(name) • x.Values.Add(“nome”, “valore”) • Response.AppendCookie(x) • HttpCookie x = Request.Cookies(name) • If x = Null / null • Stringa =x.Values(“nome”) http://www.DevLeap.it Cookie Member • Domain • Expires • Dominio da associare al cookie • DateTime per la scadenza. • HasKeys • True se ha subkeys • Item • Shortcut per HttpCookie.Values[ key ] • Per compatibilità con ASP 3.0 • Name • Legge/Imposta il nome del cookie • Path • Path da associare al cookie • Secure • Legge/Imposta l’invio sicuro (su Https) • Value • Valore del cookie single-value • Values • Collection nome/valore contenuto nel cookie http://www.DevLeap.it Cookie Warnings • Usare Https per • Criptare il traffico di username e password • Criptare i cookie persistenti su disco • RedirectFromLoginPage(..., True) • Su tutto il sito per evitare che il cookie di login passi in chiaro • Occhio ai tag IMG e HREF • Negare l’accesso Http a tutte le parti protette per essere sicuri • Se il sito ha una parte protetta Https si deve stare attenti • Path=qualcosa per inviarlo solo a tali directory • Altrimenti viene inviato anche per le richieste http verso le altre sezioni del sito http://www.DevLeap.it Manage State • Per Roundtrip su stessa pagina • Campi Hidden • Li conosciamo • ViewState http://www.DevLeap.it VIEWSTATE • • • • Proprietà della classe Control Contiene le informazioni di stato dei controlli Dictionary della classe State Si trasforma in un campo hidden • Dopo Base64 Encoding • __VIEWSTATE • Per default è null o empty • I valori possono essere letti e scritti anche da codice • ViewState[“xxx”] = “ABC” http://www.DevLeap.it ViewState nella sequenza eventi Page/ Control Init PreRender VIEWSTATE Save VIEWSTATE Load Events: _Change _Click Page_Load Render http://www.DevLeap.it Update input field Validation Dispose ViewState • • • • • LoadViewState SaveViewState Metodi implementati dalla classe base Sono Overridable Filtri per i valori più comuni • String, Int, Boolean, Array, ArrayList, HashTable • Possiamo scriverci filtri per nostri tipi • Che devono essere serializzati http://www.DevLeap.it ViewState VS ... • Hidden • E’ un campo hidden • Cookie • Non necessita di cookie abilitati • Il viewstate serve per singola pagina • Session • Le session sono pesanti, soprattutto su DB • Il viewstate serve per singola pagina • Application • Non è specifica per utenti • Il viewstate serve per singola pagina • Cache • Il viewstate serve per singola pagina • La Cache è temporanea • La vediamo fra un attimo http://www.DevLeap.it ViewState Property/Method • EnableViewState • Per pagina o controllo • IsTrackingViewState • True mentre il controllo scrive nella StateBag • ViewStateIgnoreCase • • • • • True = StateBag Case insensitive HasChildViewState ClearChildViewState Load/Save TrackViewState • Monitorizza le modifiche al viewstate per salvarle nella StateBag http://www.DevLeap.it ViewState Sicuro • Default • Base64 Encoding: Come se fosse in chiaro • <pages enableViewStateMac="true“ • Disabilitabile anche da Machine / Web.Config • Non da codice • Controllo integrità • Machine.Config machineKey per algoritmo di hash • SHA1 • MD5 • Cripting • Machine.Config machineKey • 3DES http://www.DevLeap.it Cripting Response Request SaveViewState Client “VIEWSTATE” “ETATSWEIV” decriptionKey decriptionKey “ETATSWEIV” Client “VIEWSTATE” LoadViewState http://www.DevLeap.it Controllo Integrità Response VIEW Request validationKey Hash VIEW Client Hash VIEW Hash VIEW validationKey Hash Hash http://www.DevLeap.it = Hash Hash e Cript • Machine.Config • validationKey • Per controllo signature • decriptionKey • Per chiave di criptaggio • Se single-server • autogenerate va benissimo • Se Load-Balancing • Devono essere uguali in tutti i machine.config dei server in questione http://www.DevLeap.it ViewState Performance • Server • Disabilitabile per pagina o controllo • @Page EnableViewState = “false” ... • <asp:TextBox EnableViewState = “false” ... • Disabilitabile da Web.Config • <pages enableViewState="true“ • Disabilitabile da Machine.Config • <pages enableViewState="true“ • Da Codice • Page.EnableViewState = false • Control.EnableViewState = false http://www.DevLeap.it ViewState Performance • Ancora Server • Usare solo i 6 filtri di default • Oggetti custom serializzabili • Molto alto il costo di serializzazione • Non consuma risorse server (RAM, DISCO) • Non criptarlo per maggiori performance • Client • E’ un campo hidden • Se troppo grande lentezza nel passaggio dei dati • Tracing per controllare il peso dei singoli controlli http://www.DevLeap.it Caching Occhio alla pronuncia Intro http://www.DevLeap.it Caching • Il miglior modo di ottimizzare il codice è • Non eseguirlo !!! • Se i dati non cambiano in un arco di tempo perchè rieseguire le query ? • Il codice statico è molto più veloce del codice dinamico • Torniamo a FrontPage • Mai ! magari a DreamWeaver http://www.DevLeap.it Caching di Pagine e Controlli • Implementato da System.Web.Caching.OutputCacheModule Cache ASP.NET worker thread 1 HttpRuntime Class OutputCache Session HTTP Handler Pagina1.aspx ASP.NET worker thread 2 HttpRuntime Class OutputCache ASPNET_WP.EXE http://www.DevLeap.it HTTP Handler Pagina2.aspx Page Output Caching • La pagina viene eseguita la prima volta • Viene cachata • E recuperata dalla cache per le richieste successive • Direttiva di cache per la pagina • <%@ OutputCache Duration=“10” VaryByParams=“none” %> • Oppure da codice • Response.Cache.SetExpires(DateTime.Now.Ad dSeconds(10)) http://www.DevLeap.it Cache Location • <%@OutputCache Location= “ “ %> • • • • • Server Client Downstream Public None • Da codice • Response.Cache.SetCacheability • HttpCacheability.Server • HttpCacheability.Client • .... http://www.DevLeap.it Direttiva OutputCache • La pagina potrebbe essere diversa in base al QueryString o alla POST • VaryByParam • Cacha n copie della pagina in base ai parametri HTTP GET / POST • Indicare i parametri da considerare separati da “;” • Supporta * (per tutti i parametri) • Esempio VaryByParam=“TipoCorso; SedeCorso” • Parametro obbligatorio • Impostarlo a ‘none’ http://www.DevLeap.it Oppure OutputCache • VaryByHeader • Cache le pagine in base agli header HTTP • Sempre stringa con “;” • Esempio LOGON_USER • VaryByCustom • Su tipo di browser – ‘Browser’ • Estensibile • Sempre stringa “;” http://www.DevLeap.it VaryByCustom Esempio • VaryByCustom=“Preferenze” • VB Public Overrides Function GetVaryByCustomString(context as HttpContext, arg as String) as String Select Case arg Case “Preferenze” Return(“Preferenze=“ & Request.Cookies(“Pref”) Case ... End Select End Function • C# public override string GetVaryByCustomString(HttpContext context, string arg ) { switch (arg) { case “Preferenze” Return(“Preferenze=“ & Request.Cookies(“Pref”); case ... } } http://www.DevLeap.it Partial Caching • Non è detto che si voglia sempre cachare tutta la pagina • Sensato cachare solo le parti comuni • Partial Page Caching • • • • • Consente di cachare User Control Ognuno con criteri diversi La sintassi è identica Attributo VaryByControl Estensibile con Proprietà http://www.DevLeap.it Caching API Occhio alla pronuncia Intro http://www.DevLeap.it Cache API • Classe Cache • Namespace System.Web.Caching • Oggetto Cache • Esposto da Page.Response • Memoria condivisa per tutta l’applicazione • • • • Indipendente dall’utente Accesso tramite Nome/Valore Usarla per dati temporanei Gli item usati “poco” vengono rimossi • Supporta la notifica di rimozione tramite il Delegate CacheItemRemovedCallBack http://www.DevLeap.it Un esempio • Cache.Add o Cache.Insert ( Nome Valore Dependency Time TimeSpan Priority PriorityDecay CallBack ) http://www.DevLeap.it Cache Dependency • Dependency da file • New CacheDependency • Da File/Directory (Array di File o Directory) • Iniziare ad un DateTime specifico • Da un altro elemento in cache • Da un array di elementi in cache • Da un’altra dependency • Mshelp://MS.NETFrameworkSDK/cpref/html/f rlrfSystemWebCachingCacheDependencyCl assctorTopic.htm http://www.DevLeap.it Cache RemovedCallBack private static CacheItemRemovedCallback onRimoz =null; onRimoz = new CacheItemRemovedCallBack(this.RemovedCallBack); Cache.Insert(“xx”,”xx”, null, d, t, null, null, onRimoz); public void RemovedCallback(String strX, Object O, CacheItemRemovedReason R) { // Codice per ricreare l’elemento Accesso al DB Cache.Insert(.....) } http://www.DevLeap.it Altre Informazioni • Dove posso ottenere maggiori informazioni • www.DevLeap.it • www.asp.net • Developer resources • Microsoft Visual Studio.NET • Microsoft .NET Framework SDK • Microsoft Developer Network http://www.DevLeap.it ASP.NET Managing State I vostri feedback sono importanti • Scrivetemi Grazie della partecipazione – A presto – [email protected] http://www.DevLeap.it