ASP.NET: Politiche di Caching

Corso ASP.NET: tredicesima puntata

Esempio funzionante | Sorgente | Scarica il sorgente (zip)

La ripetitività e l’intensità nell’uso delle applicazioni Internet fa sì che sia teoricamente possibile prevedere dei meccanismi di salvataggio e recupero di pagine od oggetti dalla memoria, ai fini di aumentare le prestazioni.

Per questo motivo, a differenza di Asp, Asp .Net rende disponibili delle sofisticate tecniche di caching che, adottate correttamente, consentono allo sviluppatore di ridurre l’uso intensivo di alcune risorse, come la Cpu e le connessioni a database.

Con Asp.Net è possibile utilizzare due tipi di caching:

  • Output caching – utilizzato per memorizzare pagine o porzioni di pagine in memoria, così da ridurre l’esecuzione del codice che le compongono
  • Data caching – utilizzato per memorizzare qualunque tipo di oggetto, soprattutto Dataset o risultati di trasformazioni Xml

La cache viene normalmente riempita al primo caricamento della pagina o dell’oggetto da parte dell’utente. Le successive richieste vengono invece servite impiegando la copia compilata e precedentemente memorizzata nella cache, evitando la ri-esecuzione del codice.

Con Asp.Net è anche possibile definire dei discriminanti che possono invalidare la copia cache non valida e richiedere quindi la sua ricostruzione. Tipici eventi sono rappresentati dallo scadere di un intervallo di tempo o la modifica di file di dipendenza.

Output caching

L’output caching consente di ridurre il carico applicativo perché, dopo la prima richiesta della pagina, questa viene memorizzata nella cache.

Questa funzionalità si ottiene specificando in testa alla pagina qualcosa del tipo:

<%@ OutputCache Duration=”30″ VaryByParam=”None” %>

L’esempio sopra riportato mantiene la pagina nella cache per 30 minuti, allo scadere dei quali una nuova versione viene compilata e memorizzata.

I discriminanti con i quali è possibile confrontare la pagina sono:

  • Duration – la durata (in minuti) della pagina nella cache
  • VaryByParam – i parametri che provengono da una QueryString (get) o dal post di un form
  • VaryByHeader – l’header Http associato ad una pagina
  • VaryByCustom – un parametro configurabile, normalmente il tipo di browser utilizzato

Supponiamo ad esempio di avere una pagina che riceve come parametro l’anno di pubblicazione di un libro. E’ possibile inserire nella cache una versione di pagina per ogni anno di ricerca. La direttiva assume in questo caso una forma del tipo:

<%@ OutputCache Duration=”30″ VaryByParam=”AnnoPubblicazione” %>

Data caching

Il data caching consente un controllo più raffinato, perché opera a livello di oggetti invece che a livello di pagina.

Per inserire e rimuovere oggetti dalla cache è in questo caso possibile utilizzare la classe Cache, ospitata dal namespace System.Web.Caching.

Nel caso più semplice, per inserire un oggetto nella cache si usa una struttura del tipo:

Cache(“chiave”) = valore

Per rimuovere un elemento, si usa invece:

Cache.Remove(“chiave”)

Un elemento può essere inserito nella cache anche con il metodo Insert, tramite il quale è possibile specificare i discriminanti che portano alla “scadenza” dell’oggetto.

C’è ad esempio la possibilità di legare la cache ad un file presente sul server o ad un altro oggetto presente nella cache, e di invalidarla al modificarsi del documento. Per farlo si utilizza la classe CacheDependency.

Nell’esempio che segue viene realizzata una trasformazione tra un documento Xml e un documento Xsl. Il risultato viene memorizzato in cache e lì rimane fino a quando il file Xml non subisce un aggiornamento.

La prima volta che viene caricata la pagina, viene eseguita la trasformazione e l’oggetto è salvato in cache:

Tabella di libri con la scritta: Elemento non presente in cache... lo carico

Successivamente viene riportata una scritta che indica come il caricamento venga eseguito dalla cache:

Tabella di libri con la scritta: Elemento già presente in cache

La funzione PopolaCache (riportata qui sotto), si preoccupa di trasformare il documento Xml con il foglio Xslt e di memorizzare il risultato nella cache, con il metodo Insert. Viene utilizzata la classe CacheDependency per creare una dipendenza tra l’elemento in cache e il file fisico del documento Xml.

 42 Public Sub PopolaCache(strFileXml As String)
 43 
 44  Dim objXml As New XmlDocument
 45 
 46  objXml.Load(Server.MapPath(strFileXml))
 47 
 48  Dim objCDep as new CacheDependency(Server.MapPath(strFileXml))
 49 
 50  Cache.Insert(strFileXml, objXml, objCDep)

Se la cache è vuota viene richiamata la funzione PopolaCache:

 26   If (IsNothing(Cache("xml.xml"))) Then
 27     risposta.innerText = "Elemento non presente in cache…lo carico"
 28     PopolaCache("xml.xml")
 29   Else
 30     risposta.innerText = "Elemento già presente in cache"
 31   End If

In entrambi i casi, l’oggetto viene caricato prelevandolo dalla cache:

 33   objXsl.Load(Server.MapPath("xsl.xsl"))
 34 
 35   objXml = CType(Cache("xml.xml"), XmlDocument)
 36 
 37   libri.Document = objXml
 38   libri.Transform = objXsl

Se a questo punto modifichiamo (ad esempio con un editor di testo) il documento Xml, Asp.Net esegue nuovamente la trasformazione eliminando il precedente contenuto dalla cache.

Session, Application e Cache

Nel memorizzare un oggetto, lo sviluppatore ha a disposizione 3 strade: utilizzare le sessioni, l’oggetto application o la cache

In linea generale, ecco le situazioni in cui usarle:

  • Le sessioni dovrebbero essere impiegate quando è necessario registrare l’attività dell’utente nel sito, come ad esempio un carrello di commercio elettronico
  • L’oggetto application va utilizzato per memorizzare informazioni puntuali e comuni a tutto il progetto, come ad esempio la stringa di connessione ad un database. E’ un oggetto che andrebbe usato con parsimonia
  • La cache si presta ad ospitare pagine od oggetti di cui è possibile prevedere l’obsolescenza (al passare del tempo e al verificarsi di una certa condizione). Va impiegata nelle situazioni in cui c’è un effettivo guadagno in termini prestazionali o di risparmio delle risorse.

ASP.NET: I file di configurazione – Codice sorgente dell’esempio

Sorgenti: config_errore.aspxweb.configerrorpage.aspxglobal.asax

Scarica i sorgenti: aspnet12.zip

Articolo a cui si riferisce il codice: ASP.NET: I file di configurazione

config_errore.aspx

  1 <%@ Page Language="VB" %>
  2 
  3 <!
  4 # nome: Config_errore.aspx #
  5 # scritto da: Antonio Volpon #
  6 # data creazione: 30 Novembre 2001 #
  7 # ultima modifica: 30 Novembre 2001 #
  8 # copyright: Antonio Volpon #
  9 >
 10 
 11 <script runat="server" language="VB">
 12 
 13 Sub Page_Load()
 14 
 15   Dim strSelect As String
 16   Dim objDataSet As New DataSet()
 17   Dim objDataReader As OleDbDataReader
 18   
 19 End Sub
 20 
 21 </script>
 22 

web.config

  1 <?xml version="1.0" encoding="utf-8" ?>
  2 <configuration>
  3  <appSettings>
  4  <add key="ConnectionString" value="Provider=SQLOLEDB.1;data source=antoniov;initial catalog=Biblioteca;uid=anon;pwd=;" />
  5  </appSettings>
  6  <system.web>
  7  <customErrors mode="On" defaultRedirect="errorpage.aspx" />
  8  <sessionState mode="Off" />
  9  </system.web>
 10 </configuration>

errorpage.aspx

  1 <%@ Page Language="VB" %>
  2 
  3 <!
  4 # nome: errorpage.aspx #
  5 # scritto da: Antonio Volpon #
  6 # data creazione: 30 Novembre 2001 #
  7 # ultima modifica: 30 Novembre 2001 #
  8 # copyright: Antonio Volpon #
  9 >
 10 
 11 <script runat="server" language="VB">
 12 </script>
 13 
 14 <html>
 15   <head>
 16     <link rel="stylesheet" href="css/aspnet.css" type="text/css">
 17     </link>
 18     <title>Errore</title>
 19   </head>
 20   <body>
 21   
 22     <div class="titolo">
 23       Errore
 24     </div>
 25     
 26     <hr noshade="true" size="1" width="100%">
 27     
 28     <div class="txtb" id="risposta">Si e’ verificato un errore durante il caricamento della pagina. Ci scusiamo per l’inconveniente</div>
 29     
 30   </body>
 31 </html>
 32 
 33 <html>
 34 <body>

global.asax

  1 <%@ Import Namespace="System.Diagnostics" %>
  2 
  3 <script language="VB" runat="server">
  4 
  5 Sub Application_Error(objSender as Object, objArgs as EventArgs)
  6 
  7   Dim strLogName As String = "Errori Web"
  8   Dim strMessage As String = "Url " & Request.Path & " Errore: " & Server.GetLastError.ToString
  9 
 10   If (Not EventLog.SourceExists(strLogName)) Then
 11     EventLog.CreateEventSource(strLogName, strLogName)
 12   End if
 13 
 14   Dim ELLog as New EventLog
 15   ELLog.Source = strLogName
 16   ELLog.WriteEntry(strMessage, EventLogEntryType.Error)
 17   
 18 End Sub
 19 
 20 </script>

ASP.NET: I file di configurazione

Corso ASP.NET: dodicesima puntata

Esempio funzionante | Sorgente | Scarica il sorgente (zip)

Chi di voi ha realizzato in passato vere e proprie applicazioni con Asp, si è certamente scontrato con la difficoltà di prendere il progetto sviluppato in locale e portarlo in produzione. Le differenze di configurazione tra i server (in particolare Iis) dà a volte risultati imprevisti, che magari si manifestano quando il sito è già stato avviato.

ASP.NET risolve questa problematica gestendo le configurazioni dei server e degli applicativi utilizzando due file in formato Xml:

  • web.config – può essere utilizzato per ogni applicazione e definisce la configurazione e le politiche di sicurezza delle pagine componenti l’applicazione
  • machine.config – è un unico file che contiene la configurazione comune a tutto il server

Con ASP.NET viene anche ridiscusso il ruolo di Global.asa (Global.asax da questa versione), che non si occupa più di contenere informazioni sulla configurazione dell’applicazione, ma contiene piuttosto parti di codice comune.

Web.config

Web.config facilita la sincronizzazione tra ambiente di prova e ambiente di produzione. Può contenere:

  • variabili comuni a tutte le applicazioni
  • configurazioni per le sessioni
  • opzioni per la gestione degli errori
  • informazioni per la sicurezza

Vediamo la configurazione in azione con un semplice esempio: il reindirizzamento ad una pagina in caso di errore.

Abbiamo creato una semplice pagina che genera un errore (è dichiarato un DataSet ma non sono importati i namespace di ADO.NET).

Il semplice file di configurazione, che ospitiamo nella stessa cartella della pagina, ha una forma del tipo:

  1 <?xml version="1.0" encoding="utf-8" ?>
  2 <configuration>
  3  <appSettings>
  4  <add key="ConnectionString" value="Provider=SQLOLEDB.1;data source=antoniov;initial catalog=Biblioteca;uid=anon;pwd=;" />
  5  </appSettings>
  6  <system.web>
  7  <customErrors mode="On" defaultRedirect="errorpage.aspx" />
  8  <sessionState mode="Off" />
  9  </system.web>
 10 </configuration>

Nell’esempio sono presenti due elementi di interesse:

  • è aggiunta una chiave che permette di centralizzare l’uso della stringa di connessione utilizzata per connettersi ad un database
  • il tag customErrors definisce la pagina da richiamare in caso di errore

Per accedere alla chiave da una pagina aspx è sufficiente utilizzare una sintassi del tipo ConfigurationSettings.AppSettings(“ConnectionString”)

Global.asax

Abbiamo detto che il file global.asax da questa versione non ospiterà più elementi di configurazione: questa eredità viene presa da web.config.

Global.asax è ora un “contenitore” di codice comune ad un’applicazione web. Viene impiegato tra l’altro per:

  • importare dei namespace a livello di applicazione per non doverli dichiarare in ogni pagina
  • eseguire operazioni all’avvio e al termine delle sessioni e dell’applicazione (come già accadeva in parte con Asp)
  • eseguire del codice al verificarsi di una condizione di errore

Nel prossimo esempio vediamo proprio come è possibile gestire una condizione di errore salvando un log nel registro degli eventi.

La struttura di global.asax è la seguente:

  1 <%@ Import Namespace="System.Diagnostics" %>
  2 
  3 <script language="VB" runat="server">
  4 
  5 Sub Application_Error(objSender as Object, objArgs as EventArgs)
  6 
  7   Dim strLogName As String = "Errori Web"
  8   Dim strMessage As String = "Url " & Request.Path & " Errore: " & Server.GetLastError.ToString
  9 
 10   If (Not EventLog.SourceExists(strLogName)) Then
 11     EventLog.CreateEventSource(strLogName, strLogName)
 12   End if
 13 
 14   Dim ELLog as New EventLog
 15   ELLog.Source = strLogName
 16   ELLog.WriteEntry(strMessage, EventLogEntryType.Error)
 17   
 18 End Sub
 19 
 20 </script>

Al verificarsi di un errore (se questo non viene già intercettato dal codice presente nella pagina), viene scatenato l’evento Application_Error. A questo punto viene verificata la presenza di un log “Errori Web” che viene eventualmente creato e popolato con la descrizione dell’errore verificatosi.

L'event viewer con gli errori scatenati

ASP.NET e Xml – Codice sorgente dell’esempio

Sorgenti: LeggiXml.aspx

Scarica i sorgenti: aspnet11.zip

Articolo a cui si riferisce il codice: ASP.NET e Xml

LeggiXml.aspx

  1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3 
  4 <%@ Page Language="VB" Debug="True" %>
  5 
  6 <%@ Import Namespace="System.Data" %>
  7 <%@ Import Namespace="System.Data.OleDb" %>
  8 
  9 <%@ Register TagPrefix="ANet" TagName="Footer" Src="includes/footer.ascx"%>
 10 
 11 <!
 12 # nome: XMLLeggi.aspx
 13 # scritto da: Antonio Volpon
 14 # data creazione: 23 Novembre 2001
 15 # ultima modifica: 23 Novembre 2001
 16 # copyright: Antonio Volpon
 17 >
 18 
 19 <script language="vb" runat="server">
 20 
 21 Sub CaricaXml()
 22   
 23   Dim objDataSet As New DataSet()
 24   Dim objTableLibro As DataTable
 25   Dim objTableView As DataView
 26   
 27   Dim strUrlPath As String
 28   Dim strLocPath As String
 29   
 30   strUrlPath = Left(Request.Path,InStrRev(Request.FilePath,"/")) & "Xml/"
 31   
 32   strLocPath = Request.MapPath(strUrlPath)
 33   
 34   objDataSet.ReadXmlSchema(strLocPath & "XmlSchema.xml")
 35 
 36   risposta.innerHtml += "Caricato il file <a target=‘_blank’ href=’"& strUrlPath & "XmlSchema.xml’>" & strUrlPath & "XmlSchema.xml</a><br>"
 37 
 38   objDataSet.ReadXml(strLocPath & "XmlDocument.xml")
 39   
 40   risposta.innerHtml += "Caricato il file <a target=‘_blank’ href=’"& strUrlPath & "XmlDocument.xml’>" & strUrlPath & "XmlDocument.xml</a><br>"
 41   
 42   objTableLibro = objDataSet.Tables("Libro")
 43     
 44   objTableView = objTableLibro.DefaultView
 45   
 46   libri.DataSource = objTableView
 47   libri.DataBind()
 48   
 49 End Sub
 50 
 51 Sub Change_Index(objSender As Object, objArgs As DataGridPageChangedEventArgs)
 52 
 53   libri.CurrentPageIndex = objArgs.NewPageIndex
 54   CaricaXml()  
 55   
 56 End Sub
 57   
 58 Sub Page_Load()
 59 
 60   If Not Page.IsPostBack() Then
 61 
 62     CaricaXml()          
 63   
 64   End If
 65 
 66 End Sub
 67 
 68 </script>
 69 
 70 <html>
 71 
 72   <head>
 73     <link rel="stylesheet" href="css/aspnet.css" type="text/css">
 74     </link>
 75     <title>Da XML a DataSet</title>    
 76   </head>
 77   
 78   <body>
 79     <div class="titolo">
 80       Da XML a DataSet
 81     </div>
 82     
 83     <hr noshade="true" size="1" width="100%">  
 84     
 85     <center>
 86     
 87     <form runat="server">
 88     
 89  <asp:DataGrid id="libri" runat="server"
 90  AutoGenerateColumns="False"
 91  HeaderStyle-BackColor="#CCCCCC"
 92  HeaderStyle-HorizontalAlign="center"
 93  Width="80%"
 94  AllowPaging="True"
 95  PageSize="10"
 96  PagerStyle-HorizontalAlign="Right"
 97  PagerStyle-Mode="NumericPages"
 98  OnPageIndexChanged="Change_Index"
 99  AllowSorting="True">

100      
101       <SelectedItemStyle BackColor="Yellow"></SelectedItemStyle>
102       <AlternatingItemStyle BackColor="LightGreen"></AlternatingItemStyle>     
103       <Columns>
104 
105         <asp:TemplateColumn HeaderText="Seleziona" ItemStyle-HorizontalAlign="Center">
106           <ItemTemplate>
107             <asp:Button CommandName="Select" Text="x" runat="server" />
108           </ItemTemplate>
109         </asp:TemplateColumn>
110   
111         <asp:BoundColumn DataField="IdLibro" HeaderText="Id" ItemStyle-HorizontalAlign="Left" SortExpression="IdLibro" ReadOnly="True"/>
112         
113         <asp:TemplateColumn HeaderText="Titolo" ItemStyle-HorizontalAlign="Left" SortExpression="Titolo">
114           <ItemTemplate>
115             <%# Container.DataItem("Titolo")%>  
116           </ItemTemplate>
117           <EditItemTemplate>
118             <asp:TextBox id="titolo" text=’<%# Container.DataItem("Titolo") %>‘ runat="server"/>
119             <asp:RequiredFieldValidator ControlToValidate="titolo" Display="Dynamic" runat="server" >
120               Valore obbligatorio
121             </asp:RequiredFieldValidator>            
122           </EditItemTemplate>          
123         </asp:TemplateColumn>
124         
125         <asp:BoundColumn DataField="EdizioneAnno" HeaderText="Anno" ItemStyle-HorizontalAlign="Left" SortExpression="EdizioneAnno" />
126         <asp:BoundColumn DataField="Collana" HeaderText="Collana" ItemStyle-HorizontalAlign="Left" SortExpression="Collana" />
127         
128       </Columns>
129 
130    </asp:DataGrid>
131     
132     <div id="risposta" class="txt" runat="server" EnableViewState="false"></div>
133 
134     </form>
135 
136     </center>
137 
138  <ANet:Footer id="Menu" runat="server" />
139     
140   </body>
141   
142 </html>

ASP.NET e Xml

Corso ASP.NET: undicesima puntata

Esempio funzionante | Sorgente | Scarica il sorgente (zip)

ASP.NET utilizza Xml in modo trasparente, come vedremo nel nostro esempio.

Sono molti gli oggetti di documenti Xml a disposizione dello sviluppatore in ambiente ASP.NET e che sono figli del namespace System.Xml:

  1. XmlDocument: utilizzato per accedere ai file Xml come previsto dallo standard W3c per il Dom Xml
  2. XmlDataDocument: estende il precedente oggetto con caratteristiche che consente di trattare un documento Xml come fosse una sorgente dati relazione (e viceversa) e quindi di “connettersi” ad un documento Xml
  3. XPathDocument: è un oggetto molto prestazionale utilizzato per eseguire interrogazioni XPath sul documento (così da “navigarlo”)

Non ci soffermiamo ulteriormente su questi oggetti, né su quelli (come l’XmlTextReader e l’XmlTextWriter) che creano documenti nodo dopo nodo oltre a leggerli da disco fisso o convertendoli da altri oggetti. Per questo vi rimandiamo alla esauriente documentazione del .Net Framework.

Nel prossimo esempio vediamo piuttosto come sia possibile caricare un documento Xml da un DataSet e visualizzarlo, in modo trasparente, in un DataGrid.

Caricare un DataSet da un file Xml

Lo scopo ultimo dell’esempio è di visualizzare in una DataGrid pagina dei dati provenienti da un file Xml:

È stata realizzata una funzione CaricaXml contenente il codice per popolare il DataSet.

 34   objDataSet.ReadXmlSchema(strLocPath & "XmlSchema.xml")

Con il metodo ReadXmlSchema del DataSet viene caricato da disco il file di definizione dell’Xml, così da poter verificare la conformità del documento Xml che verrà successivamente aperto.

 38   objDataSet.ReadXml(strLocPath & "XmlDocument.xml")

Con altrettanta semplicità viene caricato il documento Xml, utilizzando questa volta il metodo ReadXml.

 42   objTableLibro = objDataSet.Tables("Libro")
 43     
 44   objTableView = objTableLibro.DefaultView
 45   
 46   libri.DataSource = objTableView
 47   libri.DataBind()

A questo punto, tra tutti i nodi, viene scelto quello che rappresenta i libri (cioè i nodi identificati dal tag Libri).

Come per un normale DataBind viene poi associata la vista di default al controllo DataGrid.