HowTo – Guida ASP.NET (Parte 8)

PARTE 3 – CAPITOLO 8 – LINQ

LINQ (acronimo di Language INtegrated Query) è un set di estensioni del linguaggio che permettono di effettuare query su diversi tipi di entità senza abbandonare il linguaggio C# ed i suoi costrutti.
Esistono diverse estensioni per gestire differenti componenti: LINQ to Object (query su collection di oggetti in memoria come, ad esempio, le liste), LINQ to DataSet (query su collection di DataSet in memoria), LINQ to SQL (interroga un SQL Server senza scrivere Data Access Code), LINQ to XML (manipola XML senza usare le classi ed i metodi dedicati).
LINQ-To-Object (forse il tipo più usato insieme a LINQ-To-SQL) è utile per sostituire i cicli (tipicamente i foreach) sugli oggetti in memoria (ad esempio su una lista). Come viene indicato subito sotto è necessario memorizzare i risultati di una query LINQ in un oggetto di tipo IEnumerable.
Di norma si crea una variabile di tipo IEnumerable (in generale IEnumerable) e si lancia la query nella forma var = from CAMPO in TABELLA where CAMPO.METODO.SOTTOMETODO() select CAMPO (più eventuali proiezioni).
Nella SELECT è possibile rinominare i campi con SELECT NEW {NEWNAME = CAMPO (più eventuali sottocampi)}.
È possibile ordinare i valori ottenuti aggiungendo la direttiva orderby dopo la FROM e prima della SELECT. È oltretutto possibile, nel caso si utilizzi una entità come sorgente, selezionare solamente alcune proprietà con Entità.Proprietà (ad esempio employee.FirstName + employee.LastName). Riepilogando è possibile procedere con una Anonymous Class o con una Entità definita: con var (non posso definire un IEnumerable in questo caso) matches = from employee in employees select new {First = employee.FirstName, Last = employee.LastName} creo una nuova anonymous class che contiene I parametric First e Last e che può essere usata localmente e/o per un binding (foreach employee {…First, Last…}). Se definissi una classe con First e Last potrei usare IEnumerable matches = from employee in employees select new EmployeeName {FirstName = employee.FirstName, LastName = employee.LastName}.
Le clausole where possono essere dichiarate inline, prima della select, oppure tramite un metodo (ad esempio private bool TestEmployee(EmployeeDetails employee) { return employee.LastName.StartsWith(“D”) }) da inserire poi in matches = from employee in employees where TestEmployee(employee) select employee;
È possibile raggruppare i valori ottenuti aggiungendo la direttiva group CAMPO by CAMPO.PROPRIETA dopo la FROM e prima della SELECT (di solito i gruppi così creati hanno alias “g”).
L’ordinamento si effettua con una o più “orderby” separate da virgola prima della “select” (se l’oggetto implementa IComparable).

LINQ mette in atto la Deferred Execution: gli operatori vengono eseguiti non durante la loro costruzione ma nel momento in cui vengono enumerati (tipicamente con il costrutto ToList()).
Gli Extension Methods vengono utilizzati quando si richiamano proprietà direttamente sugli oggetti LINQ invece che sugli oggetti C# (ad esempio il .Count()).
Un Extension Method deve essere statico e come primo parametro deve accettare una referenza all’oggetto su cui viene chiamato (preceduto da this).
Le nuove versioni di Microsoft .NET Framework permettono di eseguire anche “Lambda Expressions”, ovvero query LINQ nella forma matches = employees.Select(employee => employee).
In generale le Lambda Expressions permettono di aggiungere parametri con (p => p.UnitPrice). employee => employee (il primo è la referenza all’oggetto, il secondo è ciò che viene fatto su ogni elemento o valore di ritorno).
Quando uso LINQ-To-DataSet devo usare l’Extension Method dataRow.Field(“FirstName”); per ovviare al problema dei dati non tipizzati del dataset. Inoltre devo implementare l’Extension Method “AsEnumerable” sugli oggetti datatable per renderli IENumerable-compatibili.
Per rendere possibile il Data Bind occorre dichiarare var matches = from employee in s.Tables[“Employees”].AsEnumerable() where employee.Field(“LastName”).StartsWith(“D”) select employee; gridEmployees.DataSource = matches.AsDataView(); gridEmployees.DataBind().
LINQ-To-(Sql)Server: traduce istruzioni LINQ in istruzioni SQL Server. In generale non offre alcuna feature che non sia disponibile anche con ADO.NET, ma si scrive meno codice, si usa la stessa sintassi su più entità e si possono batchare le istruzioni.
È necessario creare gli attributi tables e columns nella classe in cui si vogliono mappare gli elementi. [Table(Name=”Employees”)] public class EmployeeDetails { [Column(IsPrimaryKey=true)] public int EmployeeID { get; set; } public EmployeeDetails(int employeeID, string firstName, string lastName, string titleOfCourtesy) { EmployeeID = employeeID; FirstName = firstName; LastName = lastName; TitleOfCourtesy = titleOfCourtesy; } public EmployeeDetails(){} }
DataContext è la classe che si preoccupa di effettuare il fetch dei dati dal DB all’oggetto al momento dell’enumerazione.
Non tutta la sintassi di LINQ ha corrispondenze con SQL. In questo caso si ottengono i dati con LINQ To Sql e poi si effettuano le query con LINQ To Object (occorre dichiarare un cast per le “table” da IQueriable a IEnumerable con ASEnumerable()).
Con .Single() o SingleOrDefault() è possibile ricercare una particolare tupla (o ricevere un valore nullo).
EntitySet permette di definire le associazioni [Association(Storage=”orders”, OtherKey=”CustomerID”, ThisKey=”CustomerID”)] che vanno dichiarate prima del costruttore.
Per forzare il load immediato dei dati bisogna settare l’opzione LoadOptions del DataContext.
Con AssociateWith è possibile associare una entità ad un’altra, di solito per filtrare una query (esempio: clienti con ordini superiori a…).
Di default quando viene chiamato un “submitchanges” su un oggetto dopo averlo modificato in-memory, questa operazione viene eseguita in transazione, annullando tutto se si verifica anche un solo errore. Inserimento e aggiornamento si effettuano con “insertonupdate” e “deleteonupdate”. Il cambiamento di eventuali relazioni viene fatto in automatico.
Per gestire la concorrenza esistono 4 modi e sono gli stessi già visti in altre occasioni: match-all-value (attributo di colonna >> UpdtateCheck = always), match-timestamp (proprietà timestamp), last-in-wins (UpdateCheck = never) e merge (updatecheck = WhenChanged).
Usando LinqDataSource posso automatizzare la maggior parte dei processi legati all’allineamento con il DB.
Posso poi mostrare i dati in un “<asp:TemplateField HeaderText=”# Linked Territories”>  <ItemTemplate> <%# Eval(“EmployeeTerritories.Count”) %> </ItemTemplate></asp:TemplateField>”.
Il modello DBML offre tre possibilità per effettuare la validazione: quando si setta una proprietà (ONXXXChanging), quando si inviano i dati (OnValidate) o in risposta a specifiche operazioni di aggiornamento.

[Omnia / Luca Zaccaro]

  • Share on OkNotizie
  • Share on Twitter
  • Share on Facebook

HowTo – Guida ASP.NET (Parte 7)

PARTE 3 – CAPITOLO 7 – DATA BINDING

Il Data-binding è una funzione che permette di associare un Data-source con un web-control che mostrerà i dati prelevati dal Data-Source in modo autonomo.
Usando i Data Source Controls è possibile definire un collegamento (dichiarativo) tra la pagina e il data-source. In seguito possono essere agganciati a design-time.
La caratteristica chiave del data-binding è che si tratta di una feature dichiarativa e non programmatica (definita nella pagina).
Molti web-controls supportano Single-Value Data Binding. In questi casi è possibile associare una control property ad un data source, ma il controllo può mostrare solo un singolo valore (ad esempio la classica pagina di “dettaglio prodotto”).
I Single-Value Bindning si dichiarano all’inizio della pagina aspx all’interno dei tag (ci sono anche le espressioni racchiuse tra e tali espressioni possono anche essere personalizzate).
Con Repeated-value binding è possibile creare liste e griglie di elementi. Se un controllo supporta Repeated-value-binding offre anche la proprietà DataSource (che accetta un oggetto come parametro).
I Rich Data Control sono sviluppati solo per il Data-Binding, per mostrare diverse proprietà o campi da ciascun Data Item, spesso in un layout table-based.
Tra i Rich Data Control più noti offerti da ASP.NET ci sono gli oggetti GridView (una particolare tabella che supporta operazioni di selezione, modifica, cancellazione, paginazione e ordinamento), DetailsView (una tabella che mostra un elemento alla volta) e FormView (un controllo che, grazie ai templates, può visualizzare, editare e creare un singolo elemento di un Data Source).
SqlDataSource, in combinazione con una GridView, può essere usato, come abbiamo appena visto, anche per aggiornare/eliminare i valori (basta usare il comando XXXCommand nell’etichetta SqlDataSource). Anche in questo caso potrebbe essere necessario evitare concorrenze: basta settare il parametro SqlDataSource.ConflictDetection a ConflictOptions.CompareAllValues e inserire la clausola OldValuesParameterFormatString=”original_{0}” per poi permettere l’update solo in caso di matching completo di tutti i valori (Una alternativa per utilizzare meno risorse è il già citato confronto del timestamp mediante un controllo nascosto).
ObjectDataSource permette di creare link dichiarativi tra i controlli della pagina web e un componente di accesso ai dati che lancia comandi (SQL). Si tratta di un costrutto molto flessibile ma per utilizzarlo la classe di accesso ai dati deve rispettare alcune regole: tutta la logica deve essere contenuta in una singola classe, deve offrire i risultati della query quando viene chiamato un singolo metodo, i risultati di una query devono essere rappresentati in una struttura che implementi l’interfaccia IEnumerabel (collection array, DataSet, DataTable, DataView), ogni record deve essere un oggetto che offre i propri dati tramite proprietà pubbliche, possono essere usati instance o static method e deve essere stateless.
Con il comando DataTextFieldè possibile passare ad un Data Source il valore corrente come parametro (si pensi, ad esempio, all’implementazione di una doppia Drop Down con la dipendenza regione-provincia).

[Omnia / Luca Zaccaro]

  • Share on OkNotizie
  • Share on Twitter
  • Share on Facebook

HowTo – Guida ASP.NET (Parte 6)

PARTE 3 – CAPITOLO 6 – ADO.NET

Le applicazioni, che siano esse Windows o Web, hanno sempre più la necessità di collegarsi ad un Database per ricevere, modificare, inserire e/o cancellare dati.
A prescindere da quale sia il Data Store sottostante, si sentiva la necessità di un nuovo sistema di accesso ai dati che superasse per semplicità e funzionalità tutte le diverse soluzioni attualmente esistenti. È da queste esigenze che è nato ADO.NET, ovvero un insieme di classi che permettono a ASP.NET di connettersi con Data Source (Database) per eseguire comandi. La semplicità di ADO.NET sta nel fatto che vengono gestiti quasi allo stesso modo per qualsiasi scenario di connessione.
ADO.NET lavora su quattro concetti principali: Connection (per stabilire una connessione), Command (per eseguire comandi SQL), DataSet (fornisce un rapido accesso read-only e forward-only ai dati ottenuti con una query) e DataAdapter (per riempire un Dataset con informazioni prese da un Data Source e modificare un Data Source seguendo le modifiche di un DataSet).
Il Data Provider è l’oggetto che fornisce un set di classi ADO.NET che permettono di connettersi ad uno specifico tipo di database.
Per aprire la connessione con un database occorre specificare una stringa di connessione (ConnectionString). Date le molteplici possibilità per dichiarare una stringa di connessione si farà riferimento alla metodologia standard: “Data Source=(address);Initial Catalog=nome-tabella;Integrated Security=SSPI;”. Nel caso si volesse interagire con un database SQL Express basta inserire come address il nome della macchina seguito dallo statement “\SQLExpress”. Bisogna inoltre verificare, tramite gli opportuni pannelli di gestione, che i servizi dei relativi agent siano attivi sulla macchina.
Una stringa di connessione può essere ripetuta nel codice ogni volta che ce n’è la necessità oppure memorizzata in una risorsa esterna: il caso più frequente è quello di utilizzare il file Web.Config, assegnando un nome a tale ConnectionString che sarà richiamabile da codice a patto di includere “System.Web.Configuration” e di specificare il comando “< % $ ConnectionStrings:NomeDellaConnection % >”. La stringa va inserita all’interno della sezione “< connectionStrings >< add name=’nome’ connectionString=’stringa-di-connessione’ providerName=’System.Data.SqlClient (o il relativo provider)’ / >< /connectionStrings >”.
Le eccezioni che possono essere sollevate sono di due tipi: InvalidOperationException (connessione già aperta o parametri di connessione mancanti/errati) e SqlException (problemi specifici di accesso ad un database).
Quando si tratta di codice hard-coded le metodologie di connessione sono generalmente due: la prima è quella del blocco try (in cui inserire il comando connessione.Open())/catch/finally (in cui inserire il comando connessione.Close()) mentre la seconda è quella di includere tutta la porzione di codice che usa la connessione all’interno del blocco using(connessione). In quest’ultimo caso non sarà necessario chiudere esplicitamente la connessione stessa.
Un comando SQL può essere parametrizzato (ovvero ricevere i parametri da altri controlli presenti sulla pagina). È sufficiente inserire all’interno del controllo di selezione (ipotizzando che sia di tipo selezione) il parametro ‘< selectparameters >< asp:controlparameter name=”Title” controlid=”DropDownList1″ propertyname=”SelectedValue”/ >< /selectparameters >’ e specificare quindi il parametro con @Title. In questo esempio il valore del parametro “Title” verrà prelevato dal valore selezionato della DropDown con ID DropDownList1. Altre “risorse” da cui prelevare parametri (e che funzionano a grandi linee allo stesso modo) sono offerti dai controlli QueryStringParameter, SessionParameter, CookieParameter, ProfileParameter, FormParameter e Parameter.
A livello di database (SQL Server) è utile conoscere la pratica del Connection Pooling che permette di mantenere aperte un set di connessioni da condividere tra le sessioni che usano gli stessi Data Source (si può aggiungere il parametro Max/Min Pool Size alla stringa di connessione) e le Connection Statistics che possono essere abilitate (sono disabilitate di default).
La classe Command permette di eseguire tutti i comandi SQL. È possibile eseguire anche comandi di Data Definition (creare e alterare database e tabelle) anche se spesso questi vengono eseguiti direttamente sul DB e naturalmente sono incluse le Data Manupulation (Select, Update, Insert, Delete ecc..). I valori della CommandType Enumeration sono CommandType.Text (eseguire query SQL dirette), CommandType.StoredProcedure (per eseguire Stored Procedures) e CommandType.TableDirect (funzioni legacy).
Segue un esempio di connessione ad un Database (Northwind) e di selezione dati da una tabella (Employees):

String connectionString = WebConfigurationManager.ConnectionStrings[“Northwind”].ConnectionString;
SqlConnection con = new SqlConnection(connectionString);
String sql = “SELECT * FROM Employees”;
SqlCommand cmd = new SqlCommand(sql, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
StringBuilder htmlStr = new StringBuilder(“”);
while (reader.Read()) //.NextResult() restituisce se c’è un record successivo
{
htmlStr.Append(reader[“TitleOfCourtesy”]); //dato recuperato dal nome di colonna
htmlStr.Append(reader.GetString(1)); //recupera il primo valore di tipo String
htmlStr.Append(reader.GetString(2)); //recupera il secondo valore di tipo String
htmlStr.Append(reader.GetDateTime(6).ToString(“d”)); //recupera la 6° data
}
reader.Close();
con.Close();

Quando si utilizzano i Data Reader bisogna controllare e gestire manualmente gli eventuali dati nulli visto che non esiste un supporto nativo. In particolare andrebbero fatti i seguenti controlli:

int? nullableInteger = null;
if (nullableInteger.HasValue) { }

oppure

int? numberOfHires;
if (reader[“NumberOfHires”] == DBNull.Value)
{
numberOfHires = null;
}
else
{
numberOfHires = (int?)reader[“NumberOfHires”];
}

I comandi diversi dalla Select vanno eseguiti con ExecuteNonQuery().
Le Query da e verso un database sono uno dei punti di una applicazione più soggetti ad attacchi informatici: il fenomeno in particolare è noto con il nome di SQL Injection: SQLInjection è un tipo di attacco che manomette l’esecuzione di una query introducendo parametri non previsti dallo sviluppatore. Spesso sfruttano debolezze sul controllo dei dati (tipicamente presi da QueryString). Le soluzioni più comuni sono trattare con Replace gli apici singoli e gli spazi, limitare i privilegi dell’utente sui vari DB e usare Parametrized Commands (@CustomerID) al posto di (‘MyCustId’).

Per migliorare la gestione della comunicazione tra applicazione e DB è spesso utile ricorrere all’uso di Stored Procedures. Le SP sono delle strutture preconfezionate per lavorare sulle tabelle (simili alle funzioni). Prima si scrive la SP DB-side, poi nel codice, per ogni componente della SP, va indicato il tipo e il valore da assegnare. In particolare:
cmd.Parameters.Add(new SqlParameter(“@LastName”, SqlDbType.NVarChar, 20));
cmd.Parameters[“@LastName”].Value = lastName;
A questo punto si procede con la normale esecuzione con il comando ExecuteNonQuery().

Capita che si renda necessario controllare se un insieme di istruzioni sia stato completato con successo e, in caso contrario, riportare i dati allo stato iniziale. Per compiere questa operazione sono disponibili le Transaction. Le Transactions sono set di operazioni che possono avere esito positivo o negativo per singola unità. La Transaction tipicamente consegna le modifiche al Data-Source solo se tutte le azioni sono state completate con successo. Le proprietà di una Transaction sono elencate in un acronimo: ACID (Atomic, Consistent, Isolated,Durable).
Sempre all’interno della definizione di una Transaction si trovano i concetti di Isolation Level e Savapoint.
Isolation level è un concetto che permette di impostare il livello di “sensibilità” alle modifiche operate da altre Transactions. Nelle SP scritte lato Server uso la direttiva SET TRANSACTION ISOLATION LEVEL, mentre in ADO.NET devo passare un valore dall’enumerazione IsolationLevel.
I Savepoints sono dei marker che memorizzano un certo istante nel flow della Transaction e sono in grado di riportare indietro la situazione a quel punto. Si utilizzano chiamando il metodo Save() su un oggetto di tipo SqlTransaction. Per tornare ad un Savepoint uso, sempre sullo stesso oggetto, il comando Rollback() e per confermare Commit().

In una applicazione professionale il codice di comunicazione con i database non è incluso direttamente nel codice di una pagina ma salvato in apposite classi. Per compiere operazioni sui database sarà necessario creare una istanza di questa classe e chiamare i metodi appropriati.
Le strategie di concorrenza per risolvere il problema dell’accesso contemporaneo ai dati possono essere, come già accennato in precedenza, di tipo Last-in-wins updating (clausola WHERE sull’ID), Match-All updating (clausola WHERE su tutti i campi per evidenziare eventuali cambiamenti), Timestamp-based-updating (in cui vengono confrontati i timestamp per evidenziare le modifiche) e Changed-value-updating (permette update contemporanei se su attributi diversi).
L’oggetto DataSet permette di lavorare con copie “locali” dei dati presenti nel DB (dopo averli scaricati dal DB stesso) fornendo poi la possibilità di salvare l’insieme di dati modificati in un’unica operazione batch. È prevista una funzione built-in per serializzare i dati in formato XML.
DataSet permette di lavorare su una collezione di zero o più tabelle e una di zero o più relazioni.
DataAdapter è la classe che si occupa di gestire i DataSet, recuperando i dati con il metodo Fill().
La ricerca, resa possibile da un array di tipo DataRow[], viene effettuata chiamando il metodo Select(/*condizione*/)
DataView permette di creare delle View su sugli oggetti DataTable.
Typed DataSet sono una serie di classi specializzate derivati dalla base-class DataSet, DataTable o DataRow. Il vantaggio è che sono molto più “integrati” con il data-source con cui vanno a lavorare.
Se dovessimo fare un tour “virtuale” partendo dalla applicazione fino ad arrivare al dato avremmo la User interface che comunica con le Classi per tabelle, che a loro volta si legano ad un sistema di lettura/scrittura (come può essere una query o una Stored Procedure) per poi andare direttamente a lavorare con i dati presenti nel database.
Un esempio di utilizzo è quello seguente (in cui si fa riferimento al database “Northwind”):

string connectionString =
WebConfigurationManager.ConnectionStrings[“Northwind”].ConnectionString;
SqlConnection con = new SqlConnection(connectionString);
string sql = “SELECT * FROM Employees”;
SqlDataAdapter da = new SqlDataAdapter(sql, con);
DataSet ds = new DataSet();
da.Fill(ds, “Employees”);

  • Share on OkNotizie
  • Share on Twitter
  • Share on Facebook

HowTo – Guida ASP.NET (Parte 5)

PARTE 3 – CAPITOLO 5 – Files e Xml

Anche se in misura e con modalità diverse, anche le Web Application spesso interagiscono con files esterni che necessitano di essere letti e/o scritti.
Non è mie intenzione, in questa mini-guida, perdere troppo tempo a parlare della gestione classica dell’I/O: sappiate che il comportamento della Web Application è identico a quello di una Windows Application. Vi basterà includere la risorsa “System.IO” e utilizzare a dovere le risorse File, Directory, FileInfo, DirectoryInfo, DriveInfo e derivati. Bisogna solamente assicurarsi che l’utente impersonato dalla Web Application abbia i permessi per accedere in lettura e/o scrittura alla risorsa sulla partizione NTFS. Le cose da aggiungere sono davvero poche: degno di nota è il controllo per effettuare in modo semplice ed intuitivo l’upload dei files sul server, così come la gestione della eventuale concorrenza (risolvibile o con il lock e l’unlock della risorsa o con l’utilizzo di GUID univoci).
È utile invece spendere qualche parola in più sulla gestione dei files XML.
XML è un metalinguaggio (descrive le regole per creare linguaggi customizzati con keyword personali). Questa possibilità porta ad una assoluta flessibilità ma anche alla necessità di interpretare spesso in modo diverso files XML provenienti da fonti diverse.
Ci sono tre scenari in cui è particolarmente indicato utilizzare file XML: manipolare dati XML già esistenti, creare file di dati per permettere in futuro l’integrazione con servizi diversi e utilizzare una tecnologia che dipende da XML (ad esempio molti web services).
Esistono regole precise per creare un XML valido: ogni tag di apertura deve avere un tag di chiusura, un elemento vuoto deve finire con ‘/>’, le pile di apertura e chiusura devono essere rispettate, i tag devono essere uguali (è un linguaggio case sensitive), un elemento non può avere due attributi con lo stesso nome, un documento può avere un solo elemento root, tutti gli attrubuti devono avere le doppie virgolette e non ci possono essere commenti all’interno dei tags.
Per dichiarare un Namespace (insieme di regole di formattazione) basta inserire l’indirizzo URI-like nel tag ”.
Uno Schema (”) è un documento formale in cui vengono esposte le regole di un particolare linguaggio XML-based.
Per scrivere un file XML uso un XmlTextWriter su cui vengono aggiunti, nell’ordine, il WriteStartDocument(), i WriteStartElement(), i WriteAttributeString(), i WriteElemenString() e infine WriteEndElement().
Il linguaggio utilizzato per manipolare file XML è detto XSL (eXtensible Stylesheet Language).
La lettura di un file XML è molto semplice: dopo aver aperto un XmlTextReader e aver dichiarato una StringBuilder (per aggiungere dinamicamente i risultati letti dall’xml) basta dichiarare un ciclo “while reader.Read()” e switchare tra i vari “case”: XmlNodeType.XmlDeclaration, XmlNodeType.Element, XmlNodeType.Text. Per leggere gli attributi uso un “if (reader.AttributeCount > 0)” all’interno del quale ciclo (sempre con un while, reader.MoveToNextAttribute())”.
XmlDocument memorizza informazioni come un albero di nodi.
XDocument è un modello all-purpose per gestire gli XML in memoria. È molto flessibile in quanto permette di scrivere XML in modo semplice e veloce aggiungendo via via nuovi “new XElement” in cui verranno passati la chiave e il contenuto.
Per gestire al meglio la ricerca in un XML uso Xpath. “/” cerca nodi figli, “//” cerca figli ricorsivi, “@” seleziona un attributo su un nodo, “*” seleziona tutti i nodi figli, “|” combina path multipli, “.” Indica il nodo corrente, “..” indica il nodo padre, “[]” definisce i criteri di ricerca.
Grazie agli stylesheet xsl è possibile definire uno stile di base per l’XML.

[Omnia / Luca Zaccaro]

  • Share on OkNotizie
  • Share on Twitter
  • Share on Facebook

HowTo – Guida ASP.NET (Parte 4)

PARTE 2 – CAPITOLO 4 – La Gestione dello Stato

Come già ampiamente introdotto, HTML non offre alcun meccanismo per il mantenimento dello stato. I linguaggi Server Side vengono in aiuto dello sviluppatore proponendo le proprie soluzioni per colmare questa mancanza.
ASP.NET mette a disposizione diverse tecniche per mantenere traccia dello stato di una pagina internet. Alcuni di questi meccanismi (come il ViewState) sono già stati introdotti, altri sono probabilmente già noti perché universalmente utilizzati. Segue una lista di tutte le possibilità a disposizione del programmatore con una breve descrizione per ciascuna di esse.
VIEWSTATE
Il ViewState, come già anticipato, è una dictionary collection (valida solo all’interno della pagina corrente) con comportamento di sovrascrizione in caso di dati già presenti. Quando si salva un dato nel ViewState viene automaticamente generato un dato di tipo Object. Sarà quindi necessario operare un opportuno Cast quando lo si vuole utilizzare di nuovo.
Se si vuole usare il ViewState con oggetti Custom va aggiunta la direttiva [Serializable] prima della dichiarazione della classe. Se all’interno della classe sono definite proprietà non serialzzabili vanno caratterizzate dalla direttiva NonSerialized e verranno ignorate (torneranno cioè allo stato originale dopo ogni Postback).
QUERYSTRING
La QueryString è semplicemente l’insieme dei parametri che vengono passati ad una pagina al momento del suo caricamento.
Essendo di fatto un indirizzo URL in essa possono essere inseriti solo caratteri html validi (o opportunamente trattati con l’oggetto Server.HtmlEncode).
Per accedere ad un oggetto contenuto nella QueryString basta usare il comando Response.QueryString[“attributo”]. Prima di utilizzare un dato ottenuto in questo modo occorre sempre verificare che sia diverso da null e che sia valido nel contesto di utilizzo.
PostBackUrl permette di trasmettere i dati da una pagina all’altra con l’utilizzo della QueryString (Cross Page Postback). Nella pagina “di arrivo”, con lo statement Page.PreviousPage, controllo se effettivamente la navigazione proviene da un’altra pagina. Nella pagina padre i controlli sono protected. Devo dichiarare, come già visto per gli User Control, un metodo pubblico che espone il dato (tipicamente con un get { return …}).
Un metodo alternativo per muoversi all’interno dell’applicazione è utilizzando Server.Transfer(“nuovo indirizzo”). È possibile riconoscere un Cross Page Postback grazie a PreviousPage.IsCrossPagePostBack.
Se nella pagina di origine erano presenti validatori occorre verificare se sono stati eseguiti o meno con il comando PreviousPage.IsValid.
COOKIE
Il funzionamento dei Cookie è universalmente noto: si tratta di piccolissimi file di testo creati da una applicazione web sul computer dell’utente molto utili per memorizzare le sue preferenze di navigazione.
In ASP.NET è possibile impostare (e leggere) il valore di un Cookie con i comandi Request e Response. Occorre includere il file System.Net.
SESSION STATE
L’oggetto Session State è molto simile al ViewState ma molto più potente e versatile (ad esempio è utilizzabile con tutti i tipi di oggetto). Tuttavia il suo utilizzo non è molto diffuso per via dell’eccessivo carico che porta sul Server.
APPLICATION STATE
Le Application State sono Session non limitate al singolo utente ma all’intera applicazione. È utile usare i lock per evitare concorrenza sulle risorse e richiamare l’unlock quando la modifica è finita in modo da rilasciare l’oggetto e permettere altre modifiche.

[Omnia / Luca Zaccaro]

  • Share on OkNotizie
  • Share on Twitter
  • Share on Facebook

HowTo – Guida ASP.NET (Parte 3)

PARTE 2 – CAPITOLO 3 – Server Control

I Server Control sono classi di ASP.NET create con lo scopo di mappare I rispettivi elementi visuali di una Web Form. Tutti i Server Control derivano dalla classe Control da cui ereditano metodi e proprietà di base come ClientID (per trovare l’ID univoco assegnato lato server), i controlli sul ViewState, sul data binding e il metodo FindControl per ricercare elementi. I Server Control più importanti sono HTML server controls, Web controls, Rich controls e Validation controls. Gli HTML server controls servono per mappare ed estendere i classici elementi HTML, i Web controls (come abbiamo visto nel capitolo precedente) dispongono delle stesse potenzialità delle HTML Server Controls offrendo allo stesso tempo molti controlli in aggiuntivi, i Rich controls servono per gestire controlli avanzati (ad esempio: Calendar) mentre i Validation controls servono per validare gli input presenti su una pagina. Ci sono altri controlli più specifici come Data controls, Navigator controls, Login controls, Web parts controls, AJAX controls, Mobile controls e molti altri ancora. Alcuni di questi verranno ripresi in seguito mentre altri vanno oltre lo scopo di questa mini-guida. HTML (e nemmeno ASP.NET) offrono soluzioni per impostare il focus di una pagina (definire dove si trova il primo controllo attivo dopo il caricamento della pagina). Fortunatamente all’interno della dichiarazione del form è possibile impostare la proprietà DefaultFocus con l’id dell’oggetto desiderato. ASP.NET si preoccuperà di aggiungere una porzione di codice Javascript capace di soddisfare questa richiesta. I controlli offrono anche la proprietà TabIndex che indica, con una numerazione crescente, come si sposterà il focus all’interno dei controlli sulla pagina quando viene premuto il tasto Tab.
HTML Server Control
Questo tipo di oggetti possiedono i metodi particolari innerText e innerHtml per modificare programmaticamente il contenuto di un controllo. La differenza tra i due comandi è che il primo convertirà i caratteri html in modo da mostrarli a video mentre il secondo inietta puro html all’interno del controllo. Tutti i controlli di questa classe espongono i metodi ServerClick e ServerChange per tentare di colmare il gap che li separa dai più completi Web Controls. La classe HTMLInputControl è la base da cui derivano tutti gli elementi input presenti in una form e che condividono gli attributi type e value. Naturalmente (come per qualsiasi altra classe) tutti questi oggetti possono essere creati programmaticamente, indicando la classe corretta che li definisca.
WEB CONTROLS
Che cosa sia un Web Control lo abbiamo spiegato nel precedente capitolo e lo riproponiamo velocemente prima di proseguire: si tratta di un controllo customizzato creato con lo scopo di mappare uno o più oggetti presenti nel vocabolario dell’html ed estenderne le potenzialità.
I Web Control si dichiarano con il rispettivo ClassName (ad esempio ”) invece che con i classici tag html. Altre differenze sono date dal contenuto, non più memorizzato nell’attributo Value ma in Text e dagli stili, con alcune caratteristiche definibili direttamente (ad esempio le dimensioni) lasciando comunque la possibilità di associare una classe CSS. Per quanto riguarda le dichiarazioni esplicite è necessario indicare l’unità di misura (ad esempio Width=”190px”).
A differenza dei classici HTML Server Control, questo nuovo tipo di controlli può essere definito solamente all’interno di un form HTML dichiarato con l’opzione ‘runat=”server”’.
Come già accennato precedentemente, i Web Control di tipo input possono avere associata una proprietà per impostare il focus (grazie all’uso di una funzione Javascript).
La gestione degli eventi è simile a quanto visto per gli HTML Server Control: l’evento ‘OnClick’ va a sostituire ‘ServerClick’ e, al posto di ‘ServerChange’ si introduce una personalizzazione con ‘OnXXXChange’ (dove XXX è lo specifico nome del controllo).
Tutti i Web Control supportano l’AutoPostback.
Una delle ultime innovazioni nel mondo dei Web Control riguarda le ListBox: si tratta di controlli che generano liste di oggetti (ad esempio CheckBox) tipicamente con una dichiarazione di Bind o con impostazioni hard-coded.
VALIDAZIONE
Per una corretta e sicura gestione dell’applicazione è necessario validare ogni tipo di input ricevuto. Pensando soprattutto ad applicazioni pratiche quali, ad esempio, un modulo di contatti, viene istintivo pensare che sia sufficiente un controllo Client-Side (svolto cioè mediante funzioni Javascript direttamente sul browser dell’utente) per assicurarsi che i dati siano corretti. Questo è uno degli errori più grossi che si possono compiere durante lo sviluppo di una applicazione: il controllo Client-Side è utilissimo perché permette di informare con un riscontro immediato l’utente circa dati inseriti in modo errato (evitando il Postback) ma è assolutamente necessario che ogni controllo svolto in questa maniera abbia un corrispondente Server-Side. I controlli effettuati grazie a funzioni Javascript sono infatti facilmente aggirabili se non addirittura eliminabili (disabilitando tale funzione dalle proprietà del browser). Dopo che i dati hanno superato (in qualsiasi modo) i controlli lato Client sarà il Server ad effettuare il controllo decisivo e, nel caso di errori, a prendere provvedimenti.
Scrivere controlli di validazione può rapidamente diventare un operazione noiosa visto che molti di tali controlli si ripetono in modo identico in diverse applicazioni ed addirittura all’interno di uno stesso progetto (un esempio su tutti: la validazione di un indirizzo e-mail). Fortunatamente ASP.NET viene in soccorso dei programmatori offrendo un set di validatori Client e/o Server preconfezionati che andranno solamente personalizzati. Di seguito un elenco con una breve descrizione per ogni elemento.
” è il più classico dei validatori e serve per controllare che un campo di testo non sia vuoto o, impostando a dovere la proprietà InitialValue, uguale ad un valore di default. In aggiunta questo controllo invalida un campo di testo in cui siano contenuti solo spazi bianchi.
”controlla che il dato inserito dall’utente cada all’interno di un range ben definito. Spesso si usa questo controllo in concomitanza di numeri o date. È possibile definire il tipo (Type) di dato e gli estremi del range (MinimumValue e Maximum Value).
” effettua un confronto tra il contenuto di un campo di testo e quello di un altro campo di testo o un valore prefissato. È possibile impostare uno dei classici operatori quali ‘maggiore’, ‘minore’, ‘uguale’, ‘diverso’ ecc..
” serve per testare l’aderenza di un input con un pattern definito dal programmatore.
” permette di definire controlli personalizzati. A differenza dei controlli precedenti, che vengono eseguiti automaticamente lato Client e lato Server, con il Custom Validator è necessario specificare manualmente la funzione di validazione Client-Side (ClientValidationFuncion) e/o quella lato Server (OnServerValidate). Sarà ovviamente necessario definire e programmare tali funzioni in modo da personalizzare il controllo. Le funzioni accetteranno in ingresso un sender e un argument e restituiranno True o False impostando lo stato di args.IsValid.
Ogni validatore possiede la proprietà Text in cui inserire il testo da mostrare all’utente in caso di errore di validazione (tipicamente un asterisco) e, in aggiunta, una proprietà ErrorMessage che contiene una spiegazione dell’errore da mostrare in un eventuale Validation Summary.
” è un raggruppamento logico all’interno della pagina all’interno del quale racchiudere i messaggi di errore di un ValidationGroup. Il ValidationGroup è un a proprietà definibile in ogni validatore che permette di raggruppare i validatori e gestirli in modo separato (per esempio associandoli a due bottoni diversi).
Gli elementi di tipo Button hanno la proprietà CausesValidation impostata a True di default. È possibile cambiare questo comportamento ed indicare solo un sottoinsieme (ValidationGroup) di validatori da far scattare.
I validatori possono essere abilitati o disabilitati programmaticamente agendo sulla proprietà Enabled. È possibile inoltre decidere se assegnare uno spazio fisso all’eventuale testo di errore (Display=”Static”) o calcolare questo spazio dinamicamente (Dispplay=”Dynamic”).
Per controllare (lato Server) che un controllo sia valido si può richiamare il rispettivo metodo IsValid mentre con Page.IsValid posso sapere se tutti i validatori che sono scattati hanno avuto esito positivo.
Quando si definisce una nuova classe è possibile preporre alla sua definizione l’attributo [ValidationProperty(“nome-proprietà”)] che indicherà la proprietà da validare.
Naturalmente ogni controllo di valutazione ha i propri metodi/proprietà.
Ogni controllo può avere associati più controlli di validazione diversi.
CUSTOM SERVER CONTROL
Quello del Custom Server Control è in realtà un concetto che in parte è già stato presentato.
Il Custom Server Control è un controllo lato Server che genera HTML ed eventi collegati in modo programmatico (ad esempio il Calendar). Questo tipo di controlli ereditano o dalla classe Control o da WebControls.WebControl (che fornisce qualche opzioni in più, soprattutto sulla personalizzazione grafica).
Il metodo utilizzato per generare il codice del controllo è Render. Non è possibile generare al suo interno Web Control in quanto supporta in output solo codice HTML puro.
ASP.NET, grazie alle potenzialità del Framework, può confrontare lo User-Agent del Client-Browser con quelli mappati per capire quali sono le funzionalità supportate e decidere, per esempio, con che Doctype e HTML-Version formattare il codice. In realtà non è un controllo sicuro perché un browser può supportare Javascript ma l’utente può averlo disabilitato. Si possono quindi intraprendere due strade: o si fanno dei test a basso livello o si deve tollerare un margine di errore. È possibile definire degli alias per identificare più velocemente un browser (sempre grazie allo User-Agent).
I Composite Controls sono quelli che generano html ricco ed indentato. Si rende necessario l’override del metodo CreateChildControls.

[Omnia / Luca Zaccaro]

  • Share on OkNotizie
  • Share on Twitter
  • Share on Facebook

HowTo – Guida ASP.NET (Parte 2)

PARTE 2 – CAPITOLO 2 – Web Forms

Grazie alle Web Forms è possibile creare una pagina web utilizzando le stesse interfacce Control-Based delle Windows Applications. In particolare è possibile utilizzare la funzionale ToolBox di Visual Studio per trascinare i controlli direttamente sulla pagina *.aspx e lasciare che sia il programma ad inserire il codice utile a creare il controllo. Sempre utilizzando la modalità “Design” e il tab “Proprietà” è possibile customizzare l’aspetto del controllo e creare nuovi eventi in risposta a particolari condizioni che potrebbero venire a crearsi durante l’utilizzo dell’applicazione (ad esempio, con riferimento ad un bottone, è possibile associare un evento che scatti nel momento in cui l’utente clicca con il mouse sopra il controllo). A questo punto bisogna introdurre una separazione a livello di markup: con ASP.NET è possibile far coesistere nella stessa pagina i classici controlli HTML e i così detti Web Control. Al primo gruppo fanno riferimento i classici tag del linguaggio html (come, ad esempio, “<p>” per indicare un paragrafo). Nello specifico è possibile fare in modo che questi controlli “classici” siano accessibili e modificabili dal codice server-side aggiungendovi il parametro runat=”server” e assegnando ad ognuno di essi un ID univoco con l’attributo id=”testUnicoID”. Con il termine Web Control invece si fa riferimento ad oggetti custom offerti da ASP.NET e nella maggior parte dei casi spesso mappabili ai classici tag HTML. Ad esempio, se voglio inserire un testo non modificabile dall’utente in una pagina *.aspx posso racchiuderlo tra i tag “<p>” e “</p>” oppure utilizzare il Web Control “<asp:Label ID=”mioID” runat=”server” Text=”testo” />”. Fermiamoci un attimo ad analizzare questo controllo: per prima cosa notiamo che la formattazione di base è simile a quella di qualsiasi altro tag, con il capertura “<” e quello di chiusura “>” (in questo caso “/>” perché il tag è chiuso in sé stesso). Dopodiché, come detto poco fa per i tag html, abbiamo la definizione di un ID univoco e l’istruzione, questa volta obbligatoria, che obbliga il compilatore ad elaborare l’oggetto lato server. La proprietà “Text”, così come le altre proprietà che ogni Web Control possiede, consentono un alto livello di personalizzazione (in questo caso permettono di specificare nient’altro che il testo del messaggio che avremmo altrimenti racchiuso tra i tag “<p>” e “</p>”). Quello che ancora non abbiamo detto è che il compilatore, prima di inviare la pagina *.aspx al browser dell’utente, si preoccuperà di esaminare ogni Web Control e di “convertirlo” in una entità HTML classica (in questo caso ad esempio un semplice paragrafo). Il vantaggio sta nel fatto che uno Web Control è più facilmente manipolabile dal linguaggio Server Side e solleva quasi sempre il programmatore dall’onere di verificare che in tutti i browser il contenuto venga renderizzato in modo corretto. È in fatti il compilatore che, in base al browser del visitatore, rielaborerà nel modo migliore possibile i contenuti del Web Control per evitare spiacevoli incompatibilità. In generale, l’uso di tag HTML classici con l’aggiunta dell’ID e dell’istruzione runat=”server” è percorribile nel caso in cui si stia aggiornando una applicazione già esistente (magari non basata in origine su ASP.NET), mentre l’uso dei Web Control è sicuramente consigliato nel caso in cui si stia sviluppando una nuova applicazione. Appare chiaro fin da subito quanto sia possibile realizzare in una Web Application grazie al motore di ASP.NET. Rimane tuttavia invariata una delle più grandi limitazioni presenti nell’originale protocollo http: quello di essere “stateless”. Quando un visitatore viene rediretto da una pagina web ad un’altra tutte le informazioni che aveva inserito nella prima pagina vengono inevitabilmente perse. Questa limitazione è stata pensata agli albori di Internet soprattutto per favorire una scalabilità pressoché infinita, tuttavia risulta quasi impossibile progettare al giorno d’oggi una applicazione web senza memorizzare le informazioni inserite dagli utenti. Questa è una delle principali ragioni per cui sono nati i linguaggi “Server-Side” (come ASP e PHP): grazie all’oggetto form presente su una pagina e alla rielaborazione della stessa da parte del server dopo l’invio del modulo è possibile recuperare i dati presenti nei campi e salvarli (temporaneamente) altrove prima che vengano definitivamente eliminati. ASP.NET non fa eccezione in questo senso. Non è in grado di superare la natura stateless di http ma, nel corso delle sue diverse edizioni, ha fornito agli sviluppatori comodi strumenti per aggirare questo problema e ottenere i dati dell’utente prima che la pagina venga ri-processata. Il metodo più classico, come abbiamo detto, è quello del form. Tutte le pagine aspx che richiedono una qualsiasi interazione con il Server posizionano i loro controlli all’interno dei tag “<form id=”Form1” runat=”server”>” e “</form>”. La dichiarazione di questa struttura può avvenire pagina per pagina oppure, nel caso si stesse utilizzando una Master Page (concetto spiegato di seguito) all’interno della stessa in modo che venga automaticamente posizionata in tutte le pagine che ne ereditano il codice. Per recuperare una variabile presente in un form è possibile ricorrere all’oggetto Request.Form[]. Se in una pagina era presente un form con un campo caratterizzato dall’ID “nome”, il contenuto di tale campo sarà recuperabile, dopo l’invio della pagina stessa, con l’istruzione Request.Form[“nome”]. Riprendiamo ora un concetto già esposto in precedenza: le pagine ASP.NET non vengono “eseguite” dal server riga per riga (come avviene in ASP) ma, aggiungendo i relativi controlli, è possibile decidere programmaticamente a quali eventi devono rispondere. Il meccanismo con il quale ASP.NET si “accorge” di questi eventi è quello del “PostBack”. Un postback non è nient’altro che la replicazione di ciò che avviene quando si preme il classico pulsante “Invia” presente in tutti i form: la pagina viene rispedita al Server che potrà leggere il contenuto dei suoi campi. Al contrario di altri linguaggi, ASP.NET estende il meccanismo di postback a molti controlli, anche diversi dal classico pulsante. In ogni caso, grazie ad alcuni meccanismi che verranno spiegati tra poche righe, ogni volta che viene generato un postback ASP.NET salva una copia dei dati presenti nella pagina e in base alla lettura di questi dati lancia gli eventi associati. Immaginiamo ad esempio una pagina in cui siano presenti un campo di testo ed un pulsante. Al pulsante sarà associato il classico evento “Click()” che genera il postback, mentre al campo di testo è associato un evento che controlla se il testo al suo interno è stato modificato. Durante l’elaborazione del Postback ASP.NET si accorge che il testo contenuto nel campo è diverso da quello che aveva memorizzato in precedenza e decide quindi di eseguire la porzione di codice presente nel metodo “OnTextChanged”. Ad ogni Web Control è possibile associare un cospicuo numero di eventi, che verranno segnalati in automatico da Visual Studio grazie alla funzione di Intellisense. Prima abbiamo detto che ASP.NET estende il meccanismo del postback. Questo avviene grazie alla proprietà AutoPostBack presente in molti controlli (e settata di default a true per i pulsanti). Tutti gli altri controlli hanno questa proprietà settata a false di default, tuttavia aggiungendo alla dichiarazione la voce “AutoPostBack=true” sarà possibile scatenare un postback in corrispondenza di praticamente qualsiasi evento. Pensiamo ad una checkbox: è possibile causare un postback quando questa viene selezionata o desezionata. Oppure, nel caso di una dropdown, è possibile generare il postback quando viene modificata la selezione. Per riassumere: ad ogni controllo sono associabili una grande quantità di eventi che vengono valutati nel momento in cui viene scatenato un postback, azione che viene causata in automatico dopo il click su un pulsante o in modo programmatico interagendo con molti altri controlli (solo quelli appartenenti alla famiglia dei Web Control). Naturalmente un postback richiede un certo carico di lavoro da parte del server che inevitabilmente si tramuta in una (seppur breve) attesa. Per questo motivo la tecnica del postback non è applicabile a tutti gli eventi in generale. Si pensi, ad esempio, a tutte le azioni compiute con il mouse. In una normale applicazione Windows potremmo decidere di eseguire del codice quando il cursore del mouse viene portato all’interno o all’esterno di una certa area. Questo tipo di reazioni sono semplicemente non applicabili quando si ragiona nella logica Client-Server. Per implementare questo tipo di controlli è necessario usufruire di un linguaggio client-side (che viene eseguito direttamente nel browser dell’utente) capace di rispondere in tempo reale agli eventi. Seppur esistano una serie di strumenti capaci di compiere queste operazioni, il linguaggio attualmente più utilizzato per questo scopo è Javascript (a cui si farà un accenno nel primo extra in fondo). Abbiamo detto che ASP.NET offre una metodologia per “aggirare” la natura stateless di html e non perdere i dati immessi dall’utente su una pagina. Lo strumento più importante che realizza questa funzione è chiamato ViewState. Quando un form viene rispedito al server questo effettua delle operazioni e poi ricarica la pagina html originale. Prima di inviarla al client , il server reagisce agli eventuali eventi scatenati sulla pagina ed eventualmente modifica alcuni controlli in seguito a questi eventi. Ma questo non è sufficiente a mantenere lo stato originale della pagina. Il ViewState si preoccupa di memorizzare in una collection il contenuto di ogni controllo e di serializzare il tutto con un encode in Base64 (per evitare i caratteri non validi) all’interno di un campo hidden che viene inviato insieme al form di cui fa parte. Naturalmente questa collecion viene mantenuta costantemente aggiornata in modo da poter essere deserializzata e fornire esattamente il contenuto che era presente in precedenza in ogni controllo. Questa incredibile comodità ci viene offerta da ASP.NET a patto di accettare che il peso della pagina ricevuta aumenti in modo più o meno considerevole: bisogna infatti tenere conto che, come abbiamo detto, il viewstate viene serializzato e deserializzato ad ogni postback grazie ad un campo hidden che, seppur nascosto, deve necessariamente inviare/ricevere dati. Se all’interno di una pagina non c’è ragione per cui un controllo debba memorizzare il suo stato è possibile ridurre (anche sensibilmente) il peso della pagina stessa impostando la proprietà EnableViewState dell’oggetto a false. In questo modo l’oggetto verrà ricreato con le sue caratteristiche originali ogni volta che verrà scatenato un postback. Capita (e non di rado) che, a furia di abusare del ViewState, il contenuto di un campo hidden superi la quota massima imposta da molti Proxy/Firewall. In questo caso è necessario separare il contenuto in due campi di dimensioni più piccole. È possibile abilitare in modo automatico questa funzione (ViewState Chuncking) inserendo la direttiva “” nel file web.config. Un’ultima nota sugli eventi: nelle pagina principali è possibile dichiarare gli eventi come “private” mentre negli user control, per via del livello di accesso fornito dalle partial classes, è necessario dichiararli come protected. Spesso, per questioni di comodità, si usa dichiarare come protected anche i metodi delle pagine principali. Se avete la necessità di trasferire il navigatore su un’altra pagina (e se proprio non riuscite ad aspettare il capitolo sulla gestione dello stato..) basta invocare il metodo Server.Transfer(). Per realizzare collegamenti esterni all’applicazione va invece utilizzata la direttiva Server.Redirect(). Prima di chiudere questo capitolo è utile accennare al fatto che anche la sezione head di una pagina è gestibile come se fosse un controllo: grazie infatti alla direttiva Page.Header e a tutti i suoi metodi/proprietà è possibile modificare programmaticamente il contenuto di tale sezione impostando, ad esempio, un titolo diverso in base alla pagina caricata.

[Omnia / Luca Zaccaro]

  • Share on OkNotizie
  • Share on Twitter
  • Share on Facebook

HowTo – Guida ASP.NET (Parte 1)

Inizio con questo post una serie di interventi con cui cercherò di dare una sommaria introduzione al mondo di ASP.NET in C# (v4.0) dal punto di vista di un “apprendista in corso d’opera”. Al termine di questa serie di interventi pubblicherò il PDF conclusivo. A proposito, sto inaugurando la categoria “Programmazione” 😉

INTRODUZIONE

A scrivere di ASP.NET ci si sente un po’ come chi inizia a dettagliare le primissime voci di una enciclopedia. Il tema da trattare è così vasto e la mia esperienza talmente breve che sperare di produrre qualcosa di veramente utile a qualcuno è già di per sé una impresa. Ma io ci provo. Ho iniziato ad addentrarmi in questo nuovo mondo all’incirca un anno fa. Leggendo libri (in Inglese, soprattutto), documentandomi su Internet (in particolare MSDN) e attingendo all’immenso sapere dei miei colleghi più “Skillati”. Ma, in fin dei conti, si impara ad utilizzare qualcosa solamente con la pratica. Ecco quindi che vi lascio con una sorta di mini (ma molto mini) guida al mondo di ASP.NET in C#, realizzata al tempo della mia formazione teorica “mixando” conoscenze provenienti dalle fonti sopra citate. Se avete voglia di spendere qualche ora della vostra vita date una lettura a questo documento e iniziate a fare qualche esperimento sulla vostra copia Trial di Visual Studio 2010. Vi ricordo che questa è la primissima edizione e pertanto sarà piena di errori 😉 Se avete voglia, segnalatemeli in qualche modo. Ricordo inoltre che la guida è liberamente distribuibile a patto di non modificarla (se ci sono cose da cambiare fatemelo sapere e le cambieremo insieme!) e di citare sempre la fonte. Eventuali marchi registrati (o cose simili) citati in queste pagine appartengono ai relativi proprietari.
Detto questo..
Buona lettura 😉

PARTE 1 – CAPITOLO 1 – ASP.NET

Che cos’è ASP.NET? Il modo migliore di iniziare una guida è quello di partire dai concetti essenziali. ASP.NET è la soluzione offerta da Microsoft nell’ambito dello sviluppo di applicazioni Web, a partire dal classico sito “statico” (o “sito-vetrina”) fino alla più complessa soluzione. Ma cos’è una applicazione Web? Tutti noi abbiamo chiaro il concetto di “Programma”: riferendoci in particolare al sistema operativo Microsoft Windows un programma (o applicazione) è un prodotto, spesso identificato dall’estensione *.exe, che si trova sul nostro PC, che si installa sul nostro sistema e che si richiama ogni volta che ce n’è la necessità cliccando sul comodo collegamento presente sul desktop. Spesso l’applicazione ha bisogno di altre risorse per funzionare correttamente, come ad esempio un file di testo, un database o una libreria. Se l’installazione è andata a buon fine, il programma sarà in grado di comunicare correttamente con queste risorse per svolgere al meglio il compito per cui è stato progettato. Bene, nell’era di Internet i classici programmi stanno velocemente cedendo il passo alle applicazioni web, che altro non sono che speciali “programmi” in esecuzione su un computer remoto e accessibili da più utenti contemporaneamente e da qualsiasi luogo. Anche le risorse di cui una applicazione web ha bisogno vengono spostate su computer remoti, in modo da essere universalmente accessibili. Una volta compreso cosa si intende con applicazione web torniamo all’argomento di questa guida: ASP.NET. Cos’è ASP? E cosa vuol dire il suffisso .NET? ASP, almeno fino a qualche anno fa, stava per Active Server Page e si trattava della prima soluzione proposta da Microsoft per creare delle pagine dinamiche che ampliassero le funzionalità dell’HTML. Il suffisso .NET invece fa riferimento al Framework (che si chiama appunto .NET) presentato da Microsoft agli albori del nuovo millennio e che si comporta come una sorta di macchina virtuale capace di astrarsi dal sistema operativo e di compilare applicazioni scritte anche in linguaggi diversi. Per fare un paragone, Microsoft .NET è qualcosa di molto simile a JAVA. Ok, quindi ASP.NET è la nuova versione di ASP in cui è stato integrato il Framework.NET? Assolutamente no. ASP.NET è qualcosa di totalmente nuovo, il tentativo di rendere indolore il passaggio da “Programma” a “Web Application”. La possibilità di utilizzare (quasi) gli stessi paradigmi e perfino gli stessi linguaggi che normalmente accompagnano lo sviluppo di una Windows Application anche mentre si progetta una applicazione Web. Dopo questa lunga ma doverosa introduzione proviamo a spiegare davvero quali sono i punti di forza di questa nuova soluzione: ASP.NET combina i pilastri del Web (HTML e XML, ma anche CSS e Javascript) con il paradigma Object Oriented (C#, VB.NET e gli altri linguaggi del .NET Framework). E qui risulta fin da subito chiaro che tra ASP.NET e il classico ASP non c’è davvero molto in comune: il primo, come abbiamo appena visto, è un linguaggio completamente orientato agli oggetti mentre il secondo no. ASP.NET, così come i programmi “fratelli” scritti in C# o VB.NET ed eseguibili sui nostri PC è un linguaggio compilato e non scriptato ed interpretato ad ogni richiesta come ASP. Questo significa che l’operazione di compilazione avviene una sola volta (alla prima richiesta) e le pagine vengono ricompilate solo in seguito ad una modifica. Con il “vecchio” ASP invece, la pagina veniva ricaricata ad ogni esecuzione e, in maniera lineare, tutto il codice veniva interpretato dal Server e “mischiato” al normale markup HTML. A differenza delle pagine ASP, dove codice e HTML dovevano per forza di cose “coesistere”, in ASP.NET il livello di presentazione e quello di codice sono separati sia logicamente che fisicamente: per ogni pagina della Web Application vengono infatti creati un file *.aspx che contiene il markup della pagina e un file *.aspx.cs che contiene il codice scritto in C# che reagisce agli eventi che occorrono sulla relativa pagina (l’estensione si modifica in *.aspx.vb nel caso in cui il linguaggio utilizzato sia VB.NET). In questo caso, come nel seguito di questa guida, si farà riferimento solamente al linguaggio C#. In ogni caso è ancora possibile inserire porzioni di codice C# in una pagina aspx racchiudendole tra i tag. Prendiamoci solo un minuto per fare una brevissima digressione sul funzionamento del .NET Framework, indipendentemente dal fatto che si parti di Windows o di Web Applications: Il primo passo è quello di scrivere il codice in ciò che viene definito “Managed Application”. Come più volte ripetuto, questo codice sarà diverso in base al linguaggio scelto. Il codice viene poi convertito in Intermediate Language dal relativo compiler, e questa volta è uguale a prescindere dal linguaggio scelto in precedenza. A questo punto il CLR si occupa di compilare l’IL in modo che possa poi essere eseguito. Abbiamo visto cosa si intende per pagina ASP.NET. Ora non resta che capire da dove iniziare. Per sviluppare una applicazione Web lo strumento in assoluto più versatile è sicuramente Microsoft Visual Studio, disponibile in varie edizioni e derivati (alcuni, limitati, in versione gratuita e altri a pagamento). Il perché di questa affermazione risiede nell’intrinseco legame esistente tra il prodotto di sviluppo e il Framework, capace di offrire in modo intuitivo funzioni davvero utili come Intellisense, che permette di segnalare in tempo reale gli errori e offrire suggerimenti sul completamento di una dichiarazione. In Visual Studio ci sono due modalità in cui è possibile sviluppare una applicazione: Project-Based Developement e Project-Less Developement, a seconda che sia presente o meno un file di progetto identificato dall’estensione *.csproj. Durante lo sviluppo di una applicazione è possibile creare diversi tipi di risorse. Le più comuni sono i WebForm (sono le pagine vere e proprie, caratterizzate dall’estensione *.aspx), gli User Control (sono porzioni di pagina, caratterizzate dall’estensione *.ascx, utili per racchiudere funzioni che verranno richiamate in pagine diverse) e i Web Services (con estensioni *.asmx o i più recenti *.svc). Ognuna di queste risorse avrà un file di codice correlato e identificato dallo stesso nome del file con l’aggiunta dell’estensione *.cs. Ci sono alti due file particolari: il Global.asax (e il suo file di codice) che serve per definire eventi globali a livello di applicazione e il file Web.Config che altro non è che un file di configurazione per la applicazione. Questo file risiede nella stessa cartella della applicazione, ma è possibile crearne altri nelle varie sottocartelle per definire configurazioni particolari valide solo per la relativa sezione. Il funzionamento di questi file di configurazione verrà spiegato nel capitolo dedicato. È possibile aggiungere ad una pagina o all’intera applicazione componenti (tipicamente assembly in formato *.dll) sviluppati da terzi. Se vi è la necessità di utilizzare questi componenti in una singola pagina è possibile registrarli direttamente nella pagina *.aspx con la direttiva Register (spiega come), mentre se li si vuole estendere a tutta l’applicazione è necessario registrarli direttamente nel file Web.Config principale. A questo proposito è utile aprire una parentesi: aggiungendo una “referenza” ad un file esterno all’interno di un file *.cs con la semplice direttiva “using *assembly name*” sarà possibile accedervi senza riscrivere l’intero percorso, ma non sarà èpossibile utilizzare le sue classi se l’assembly non viene prima correttamente registrato come spiegato in precedenza. Visual Studio, con la sua modalità di Debug, offre un’ottima soluzione per testare “passo per passo” l’applicazione osservando cosa accade in risposta ad ogni evento e, grazie all’uso dei Watch, come cambiano i valori assegnati alle variabili durante l’esecuzione dell’applicazione.

Alla prossima 😉

[Omnia / Luca Zaccaro]

  • Share on OkNotizie
  • Share on Twitter
  • Share on Facebook