TextBox ReadOnly in .NET 2.0 e successivi

Il controllo TextBox di una web application dispone della proprietà ReadOnly che, ovviamente, impedisce l’interazione dell’utente con il controllo quando è impostata a True.

Ma c’è un particolare importantissimo da considerare: a partire dalla versione 2.0 del .NET Framework il contenuto di un textbox in modalità “ReadOnly” è inviato al server durante un postback della pagina, ma il server ignora questo valore; in altre parole il contenuto del textbox viene perso durante un postback. Questo comportamento mira ad impedire attacchi alla sicurezza, che potrebbero modificare un valore che dovrebbe essere mantenuto inalterato.

La perdita del valore del textbox può essere inaccettabile in certi contesti applicativi e potrebbe essere necessario applicare il comportamento in essere prima del Framework 2.0. Per far ciò è necessario impostare la proprietà ReadOnly come attributo del controllo, in questo modo:

TextBox1.Attributes.Add("readonly","readonly")

e non impostando a True la relativa proprietà.

Così facendo il valore del textbox (ovvero la sua proprietà Text) viene inviato al server durante il postback ed è altresì disponibile per l’elaborazione.

UPDATE: questo aggiornamento è, diciamo così, dovuto: il “copyright” di questa scoperta che ha portato via parecchio tempo prima di venirne a capo non è mio ma della mia collega di lavoro Ines. Io ho solo raccolto il troubleshooting per aiutare altri programmatori come un tempo altri programmatori hanno aiutato me

Eccezioni non gestite in ASP .NET 2.0

Le eccezioni non gestite generate da una applicazione ASP .NET compilata con la versione 2.0 del .NET Framework sono trattate diversamente da quanto avveniva con le applicazioni ASP .NET compilate con la versione 1.0/1.1. Queste ultime semplicemente ignoravano le eccezioni non gestite sollevate all’esterno del contesto corrente, es. un thread diverso da quello principale, mentre le eccezioni sollevate all’interno del contesto erano trattate normalmente come qualsiasi eccezione non gestita. Con il .NET Framework 2.0 questo comportamento è cambiato: le eccezioni non gestite sollevate fuori dal contesto provocano l’immediata interruzione del worker process e conseguentemente dell’applicazione. L’unica traccia è un laconico messaggio nell’event viewer  (System Log) del tipo “DefaultAppPool terminated unexpected”, seguito da un ancor più generico messaggio nell’Application Log (Event Source: .NET Runtine 2.0 Error Reporting).

Ma questo comportamento (il default) è legato ad una precisa policy di gestione delle eccezioni non gestite e può essere modificato in 2 modi:

-Aggiungendo le seguenti righe nel file Aspnet.config:

per fare in modo che le eccezioni non gestite siano trattate come nel .NET Framework 1.0/1.1, ovvero ignorate (scelta non
raccomandata da Microsoft)

-Creando un opportuno httpModule che si registra per l’evento AppDomain.CurrentDomain.Unhandledexception, attraverso il quale loggare i dettagli dell’eccezione  non gestita verificatasi.

Il tutto è documentato in questo articolo, con un esempio di httpModule.

Metriche del codice e SourceMonitor

Ho provato SourceMonitor, un interessante tool freeware per effettuare metriche sul codice sorgente scritto in vari linguaggi di programmazione, tra cui C#, C, C++, VB .NET, Delphi.

Attraverso una interfaccia di gestione molto semplice acquisisce una serie di informazioni, le metriche appunto, analizzando il codice sorgente di un progetto. Queste informazioni possono essere salvate in diversi momenti e nominate (checkpoints), onde poter mettere a confronto metriche di uno stesso progetto create in momenti diversi.

Analizzare le metriche del proprio codice aiuta ad evidenziare eventuali colli di bottiglia, ovvero parti dello stesso da sottoporre a code review, e a migliorare quindi la qualità del codice scritto.

Ecco un elenco delle metriche a mio avviso più importanti:

-% delle linee di codice commentate rispetto al totale delle linee di codice presenti in un file;
-Numero delle classi, interfacce o strutture definite in un file;
-Numero medio di metodi per classe, interfaccia o struttura;
-Valore di complessità per tutti i metodi, ovvero numero totale dei diversi percorsi di esecuzione che ogni metodo  possiede (maggiore è questo valore, più “complesso” è il metodo). Questo valore si puo’ ottenere sia per singolo  metodo, sia come media della complessità di tutti i metodi presenti.

Come detto, analizzare le metriche del codice può aiutare a scrivere codice di qualità, e quindi ad essere uno sviluppatore migliore.

Implementazione esplicita di membri di interfaccia

L’implementazione esplicita di una interfaccia presenta caratteristiche significative rispetto ad una implementazione per così dire non esplicita. Ad esempio, si consideri l’interfaccia:

public interface IExplicitImplementation 
{ 
   string Method1(string par); 
}

e la seguente classe che la implementa in modo esplicito:

public class Class1 : IExplicitImplementation  
{
    string IExplicitImplementation.Method1(string par) 
    {
       return “Hello world “ + par;
    }
}

Le caratteristiche salienti sono:

– Il client che consuma la classe Class1 utilizzando una istanza di quest’ultima è impossibilitato a richiamare il metodo Method1 in quanto quest’ultimo NON fa parte dell’interfaccia pubblica della classe (non è visibile con l’intellisense ed il tentativo di richiamare comunque il metodo genera un errore di compilazione).

Questo codice genera un errore di compilazione:

Class1  cl1 = new Class1();
cl1.Method1();

– Il client che consuma la classe Class1 può invocare il metodo Method1 solo attraverso una istanza dell’interfaccia IExplicitImplementation che la classe stessa implementa esplicitamente. Vale a dire:

ExplicitImplementation i = new Class1();
Console.WriteLine( i.Method1(“Maurizio”));

Quindi un metodo che implementa esplicitamente una interfaccia è, per così dire, privato e pubblico nello stesso tempo. E’ privato perchè non compare nell’interfaccia pubblica della classe e non può essere richiamato attraverso una  istanza della classe stessa; è pubblico perchè può comunque essere richiamato utilizzando una istanza dell’interfaccia.

– Un metodo che implementa esplicitamente un membro di una interfaccia non può contenere alcun modificatore di accesso, nè i modificatori static, abstract, override e virtual. L’ultima caratteristica determina anche l’impossibilità di effettuare l’override di una implementazione esplicita di un membro di una interfaccia. Questo ostacolo è comunque raggirabile dichiarando un altro metodo virtuale (e quindi ridefinibile) e richiamando quest’ultimo metodo nel codice che implementa esplicitamente un membro di una interfaccia.

Come terminare un processo corrotto in .NET

Da .NET 2.0 in poi è possibile terminare un processo corrotto irreparabilmente attraverso il medodo Environment.Failfast(string message), il quale provvede a:

  1. Scrivere una entry nell’Application Event Log con il messaggio specificato
  2. NON eseguire alcun blocco try-finally ancora in sospeso
  3. NON esegue alcun finalizer sugli oggetti ancora in memoria
  4. Esegue un dump dell’applicazione
  5. Termina il processo

I punti 2-3 sono necessari in un contesto simile in quanto la loro esecuzione potrebbe danneggiare risorse usate dall’applicazione stessa. Tuttavia gli oggetti CriticalFinalizerObject (di cui magari parlerò in un post a parte) sono comunque eseguiti prima di terminare il processo.

XML Serializer Generator Tool

La serializzazione XML in .NET è una operazione onerosa in termini di risorse di sistema a causa della creazione a runtime di un assembly temporaneo contenente funzionalità fortemente tipizzate di “reader” e “writer” del tipo da serializzare, le quali comportano un utilizzo intensivo di CodeDom e Reflection. Osservando con il tool Reflector il codice del costruttore della classe XmlSerializer (comprendente vari overloads) è possibile notare tutto ciò unito all’utilizzo del meccanismo di caching dell’assembly temporaneo creato (sembra però che non tutti gli overloads del costruttore facciano uso della cache con conseguente creazione dell’assembly ad ogni utilizzo). Questo meccanismo è poco performante sia a causa dell’utilizzo delle classi di CodeDom e Reflection, sia per il rischio di creare più assembly temporanei in funzione del numero di classi da serializzare, che resterebbero in memoria fino allo scaricamento del relativo AppDomain o fino a che non termina il processo. Tutto ciò si riflette negativamente soprattutto sulle applicazioni lato server, ed a lungo andare potrebbe provocare eccezioni fatali, es. una OutOfMemoryException. Per ovviare a questo inconveniente il .NET Framework mette a disposizione il tool a riga di comando SGEN (XML Serializer Generator Tool), il quale, lanciato sull’assembly che contiene i tipi da serializzare, genera un nuovo assembly contenente lo stesso codice che verrebbe generato a runtime con la creazione dell’assembly temporaneo. In definitiva è anticipata la creazione dell’assembly, in questo caso non più temporaneo ma definitivo, poichè basta aggiungere un riferimento ad esso, evitando quindi l’overhead della sua creazione a runtime ed eliminando il rischio di crescita incontrollata delle dimensioni dell’AppDomain.

Tra le opzioni del comando SGEN:

-/compiler permette di aggiungere qualsiasi opzione da passare al compilatore C#. Utile per firmare con strong name l’assembly da generare.

-/keep permette di eliminare la cancellazione dei files sorgenti dell’assembly generato. In altre parole lascia i files sorgenti a disposizione dello sviluppatore

-/proxytypes genera il codice di serializzazione solo per i tipi proxy di un XML Web Service

-/reference permette di specificare eventuali assembly referenziati dalle classi oggetto di serializzazione

-/type permette di filtrare i tipi da serializzare che si vogliono includere nell’assembly da generare

Il comando crea un assembly dal nome <proprio assembly>.XlmSerializers.dll che è possibile aggiungere come riferimento alla propria applicazione.

Naturalmente qualsiasi aggiunta/cancellazione/modifica ai membri pubblici della classe da serializzare necessiterà della ricreazione dell’assembly attraverso il comando SGEN (la serializzazione XML serializza solo i campi pubblici di una classe, a differenza della serializzazione standard, binaria o SOAP,  che invece serializza anche i campi privati).

Deserializzazione in .NET 2.0

Il meccanismo di deserializzazione ha subito una modifica (a mio avviso migliorativa) in .NET 2.0 rispetto a quanto avveniva in .NET 1.1. La versione 2.0 ha la capacità di deserializzare un oggetto anche se questo presenta nella sua forma serializzata informazioni aggiuntive (es. membri pubblici) non presenti invece nella particolare versione dell’oggetto che  stiamo deserializzando. Mi spiego meglio. Supponiamo che abbiamo la nostra onnipresente classe Person con 3 campi pubblici, ovvero FirstName, LastName e Age, e che alcune istanze di questa classe siano serializzate in formato binario attraverso l’uso della classe BinaryFormatter utilizzando una applicazione scritta in .NET 2.0, e che il risultato della serializzazione sia memorizzato nel file BinaryPerson.dat. Un’altra applicazione, questa volta scritta in .NET 1.1, deserializza gli oggetti Person contenuti nel file binario, utilizzando però una vecchia versione dell’oggetto Person contenente solo 2 campi pubblici e non 3 (es. FirstName e LastName). In tale scenario il Framework 1.1 quando esegue il metodo Deserialize solleva una eccezione e precisamente:

An unhandled exception of type ‘System.Runtime.Serialization.SerializationException’ occurred in mscorlib.dll

Additional information: È possibile che la versione non corrisponda. Il tipo Person ha 2 membri, di cui 3 deserializzati.

In pratica in .NET 1.1 non è possibile deserializzare un oggetto (Person, nell’esempio) se lo stesso è serializzato con un numero eccedente di membri. Questo comportamento è cambiato in .NET 2.0, in quanto tutti i membri eccedenti riscontrati sono ignorati e nessuna eccezione viene sollevata.

Per completezza, nel caso di uno scenario esattamente opposto a quello descritto, cioè l’applicazione A serializza l’oggetto Person con 3 campi e l’applicazione B cerca di deserializzarlo mentre nel frattempo all’oggetto Person è stato aggiunto il quarto campo, si avrà sempre una eccezione a prescindere dalla versione del Framework utilizzata, tranne se il campo appena aggiunto viene decorato con l’attributo OptionalField. Il tal caso il nuovo campo è deserializzato con il valore null impostato.

Uso di reflection per invocare metodi interni

In un post precedente ho parlato dell’uso dell’attributo AllowPartiallyTrustedCallers a proposito della sicurezza applicata all’invocazione di metodi pubblici definiti all’interno di un assembly strong-named.  Rimanendo sempre sullo stesso tema, un altro attributo utile a “limitare” i possibili chiamanti di un determinato metodo è StrongNameIdentityPermissionAttribute, usato in questo modo:

[StrongNameIdentityPermissionAttribute(SecurityAction.LinkDemand, PublicKey = “public key”)]
public string MyMethod(string parameter) {}

La presenza di questo attributo permette la chiamata al metodo MyMethod dell’esempio solo al codice contenuto in un assembly firmato con strong name e che presenta la chiave pubblica specificata nell’attributo stesso. Qualsiasi altro codice che tentasse di invocare il metodo in questione provoca una eccezione del tipo SecurityException. Questa forma di sicurezza è la più affidabile a disposizione se vogliamo proteggere ad esempio metodi sensibili dall’invocazione da parte di codice maligno. Se invece il metodo in questione non è invocato dall’esterno dell’assembly, in altre parole non è public, potremmo pensare che basterebbe limitare il suo ambito di visibilità (es.: private, internal in C# oppure friend in VB.NET) per renderlo sicuro da chiamate da parte di codice non affidabile. Putroppo questa convinzione è errata, poichè attraverso l’uso delle tecniche di reflection può essere invocato qualsiasi metodo con qualsiasi ambito di visibilità, quindi anche i metodi marcati come internal o private. Infatti, utilizzando il tool Reflector oppure semplicemente ildasm è possibile leggere la firma di metodi con qualsiasi visibilità (quindi public, private, protected ed internal). Se il metodo MyMethod fosse “internal”, conoscendo la sua firma è possibile invocarlo da un altro assembly via reflection in questo modo:

object x = Activator.CreateInstanceFrom(“MyAssembly.dll”, “MyAssembly.MyNamespace”).Unwrap();
string result = x.GetType().InvokeMember(“MyMethod”, System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Instance  
      | System.Reflection.BindingFlags.NonPublic, null, x, new object[] { “string parameter” }) as string;

bypassando quindi la protezione imposta dal livello di visibilità.

Da notare che richiamare un metodo non pubblico attraverso reflection richiede il permesso ReflectionPermission, impostabile attraverso l’uso dell’attributo ReflectionPermissionAttribute (in modo dichiarativo), oppure in modo programmatico.

In assenza di questo permesso è possibile invocare via reflection solo i metodi pubblici.

String intern pool

L’Intern pool, di cui non è la prima volta che ne parlo, è un hashtable mantenuto internamente dal CLR contenente stringhe generalmente usate per memorizzare valori costanti. In questo hashtable sono memorizzate le costanti stringa a livello di compilazione ed ogni stringa aggiunta esplicitamente attraverso l’utilizzo del metodo string.Intern, il quale aggiunge una stringa nell’intern pool (quindi nell’hashtable) e ne ritorna il riferimento se la stessa non è già presente, in caso contrario  ritorna sempicemente il riferimento ad essa. In questo modo è garantito che se due stringhe (o più) contengono gli stessi valori letterali sarà utilizzato (e quindi sarà presente in memoria) un unico riferimento, con evidente risparmio di risorse. Oltre a questo metodo, il metodo string.IsInterned ritorna il riferimento alla stringa nell’intern pool se presente, null in caso contrario.

L’intern pool è utile in opportuni scenari, ma ha un grosso svantaggio: poichè ogni stringa memorizzata nel pool è mantenuta all’interno di un hashtable interno del CLR, ne consegue che ogni stringa risulterà sempre raggiungibile dall’applicazione e quindi sopravviverà ad ogni garbage collector (poichè l’hashtable ne mantiene un riferimento). L’hashtable (e le stringhe in esso memorizzate) sarà distrutto e la memoria occupata reclamata solo quando il relativo appDomain (o processo) terminerà.

Come già detto, tutte le stringhe costanti sono inserite nell’intern pool automaticamente e quindi la memoria occupata non sarà reclamata fino a che il processo termina.  Questo comportamento è dimostrato dal seguente codice:

string a = “teststring”;
string b = “teststring”;
string x = string.IsInterned(a);
string y = string.IsInterned(b);
if (x != null)
    Console.WriteLine(“string a is interned”);
if (y != null)
    Console.WriteLine(“string b is interned”);
Console.WriteLine(object.ReferenceEquals(a,b));

L’output prodotto è il seguente:

string a in interned
string b is interned
true

Se questo comportamento non è quello desiderato è possibile utilizzare l’attributo a livello di assembly CompilationRelaxationsAttribute (namespace System.Runtime.CompilerServices), il quale permette disabilitare l’utilizzo dell’intern pool di stringhe da parte dell’assembly in cui l’attributo è definito, in questo modo:

[assembly: CompilationRelaxations(CompilationRelaxations.NoStringInterning)]

Applicando questo attributo sarebbe lecito aspettarsi che l’intern pool di stringhe non sia più gestito. Invece non è così, nonostante la documentazione MSDN affermi il contrario. Sembra che questo attributo non abbia alcun effetto pratico se non negli assembly precompilati in codice nativo con l’utility NGEN. In altre parole, inserendo o non inserendo l’attributo, l’intern pool è comunque gestito dal CLR, a meno che non si precompili l’assembly con NGEN.

Come controprova di quanto affermato è possibile eseguire il codice sopraindicato con o senza l’attributo CompilationRelaxations. L’output sarà in ogni caso identico, e dimostrerà che le 2 stringhe sono inserite nell’intern pool.

Mi piacerebbe conoscere pareri di eventuali altri sviluppatori che hanno già riscontrato questo comportamento.

Verificare che il .NET Framework sia installato e relative versioni

Per verificare che il .NET Framework sia installato ed eventualmente in quali versioni è possibile procedere in questo modo:

  • La semplice presenza del file MSCOREE.DLL (Microsoft .NET Runtime Execution Engine) nella directory %SYSTEMROOT\system32 è sintomo che almeno una versione del CLR è installata
  • La chiave del registry HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\policy contiene delle sottochiavi, una per ogni versione installata, nella forma vX.X (es. v2.0)
  • La versione 2.0 del  .NET Framework contiene una nuova utility denominata CLRVer.exe, che, come il suo nome lascia intuire, elenca tutte le versioni del CLR installate sulla macchina su cui viene eseguita. Molto interessanti sono i parametri -all, che elenca tutte le applicazioni managed in esecuzione con la relativa versione del CLR con cui girano, e -PID, con cui è possibile ottenere lo stesso risultato ma relativamente ad un singolo processo identificato dal suo process ID

App_offline.htm e i 512 byte

Nonostante qualche commento negativo letto in Rete, a me il comportamento di ASP .NET 2.0 in presenza del file app_offline.htm nella root della web application mi sembra abbastanza comodo e funzionale. Ricordo che questo file è utile quando si è in fase di manutenzione della propria applicazione web e si vuol fornire un messaggio “user friendly” agli utenti informandoli che l’applicazione non è momentaneamente disponibile, o qualsiasi cosa si voglia. In presenza di un file con tale nome infatti, l’engine di ASP .NET 2.0 effettua lo shutdown dell’applicazione, scarica l’appDomain e risponde ad ogni richiesta dei files normalmente gestiti dallo stesso engine con il file app_offline.htm appunto, permettendo in questo modo di non far incorrerere in errori eventuali richieste che avvengono mentre il sito è in manutenzione. Basterà poi rinominare, cancellare o spostare il suddetto file affinchè le pagine richieste siano elaborate nel modo consueto. Comodo no ? Ma cè un problema, aggirabile, ma pur sempre un problema. Internet Explorer 6.0 ha una impostazione chiamata “Mostra messaggi di errore HTTP brevi”. Questa impostazione di default è vera, e significa che qualsiasi messaggio HTTP diverso da 200 il cui contenuto non eccede il 512 byte, verrà mostrato da IE in modo cosiddetto “user frendly” per l’utente, fornendo un messaggio generico di errore che non lascia capire nulla circa la vera causa dell’errore. Qui nasce il problema: se il file app_offline.htm è più piccolo di 512 byte non è correttamente visualizzato ma al suo posto viene ritornato un errore HTTP (quindi un codice diverso da 200) che, in presenza della impostazione “Mostra messaggi HTTP brevi” su “on” provoca un errore generico. Non capisco come un messaggio di errore generico possa essere ritenuto “user friendly” per l’utente. Per la mia esperienza non fa altro che disorientarlo ancor di più. La soluzione al problema è ovviamente creare il file app_offline con una dimensione maggiore di 512 byte (oppure fare in modo che lo sia aggiungendo ad esempio commenti fittizi nel codice HTML), oppure disabilitare l’impostazione “mostra messaggi di errore http brevi”

LinkDemands, il corretto modo di utilizzarlo

Una cosa che non sapevo, e che desidero condividerla con gli (eventuali) lettori di questo blog: un link demand a livello di metodo sovrascrive sempre un link demand a livello di classe anche se trattasi di permessi differenti.

Esempio, data questa classe:

[FileIOPermission(SecurityAction.LinkDemand, Unrestricted=true)]
public class ClassA
{
    [EnvironmentPermission(SecurityAction.LinkDemand, Read="VAR1" )]
    public void Method1)
    {
    }
}

Il link demands a livello di metodo effettua l’override di quello a livello di classe, anche se si tratta di permessi differenti. In questo caso il link demands EnvironmentPermission sostituisce il link demands FileIOPermission, con la conseguenza che quest’ultimo permesso non viene richiesto per il metodo in questione.

Morale, occorre esplicitamente re-indicare i link demands a livello di classe su un metodo, se quest’ultimo è decorato già con un link demands.

Esempio corretto:

[FileIOPermission(SecurityAction.LinkDemand, Unrestricted=true)]
public class ClassA
{
   [FileIOPermission(SecurityAction.LinkDemand, Unrestricted=true)]
   [EnvironmentPermission(SecurityAction.LinkDemand, Read="VAR1" )]
   public void Method1)
   {
   }
}

Array bound check: operazione onerosa ?

Questa è una domanda che mi sono posto anch’io parecchie volte: il controllo dei limiti inferiore e superiore di un array che il compilatore JIT opera durante l’esecuzione di una tipica applicazione .NET è una operazione onerosa o no, e se si di quanto ? Ci si può fare una idea abbastanza significativa leggendo questo post di Rico Mariani, il quale ha effettuato dei test comparati su una applicazione .NET che utilizza il compilatore JIT tradizionale e la stessa applicazione che invece utilizza un compilatore JIT da lui stesso modificato, e precisamente senza il controllo dei limiti degli array (mscorjit.dll). Dal post si evince che il controllo sui limiti di un array non introduce un overhead significativo, anche se ritengo che la valutazione dipende dal tipo di applicazione. Comunque, aggiungo, se si programma in C# è possibile costruirsi routine di codice unsafe che permettono, tra le altre cose, di gestire array ad alte prestazioni memorizzate sullo stack e non sull’heap gestito, i cui membri sono acceduti sfruttando la semplice aritmetica dei puntatori,  senza alcun controllo di nessun tipo. Questo argomento è stato da me già trattato (spero esaurientemente :)) in un articolo pubblicato sul sito xplayn.org.

NDOC 2.0 ? No, Sandcastle

La versione di NDOC per il Framework 2.0 sembra che non vedrà mai la luce, almeno leggendo le ultimissime notizie. Peccato, ho usato NDOC su parecchi progetti e devo dire che sono sempre stato soddisfatto dei risultati raggiunti con l’utilizzo di questo tool, soprattutto quando manca il tempo per documentare un progetto usando classiche soluzioni alternative. Però potremo produrre docuntazione “MSDN like” usando Sandcastle, il tool usato internamente da Microsoft per la documentazione tecnica dei progetti che la stessa ha deciso di rendere disponibile al download. Si tratta di un tool che via reflection ottiene le informazioni sui vari assembly integrandole con la eventuale documentazione inserita direttamente nel codice sorgente, producendo un contenuto che, manipolato via XSL, permette di ottenere la classica documentazione style MSDN che siamo abituati a vedere ogni giorno.

.NET Pet Shop 4.0

E’ disponibile per il download la versione 4.0 di .NET Pet Shop, una applicazione “benchmark” di esempio per confrontare le prestazioni di una applicazione ASP .NET di classe enterprise con una equivalente applicazione J2EE. La versione 4.0 è focalizzata su ASP .NET 2.0 e mostra come ottenere una applicazione robusta riducendo il numero di righe di codice sorgente necessarie.

In questa versione è possibile vedere all’opera le seguenti caratteristiche della versione 2.0 di ASP .NET e del .NET Framework:

  1. Uso del nuovo namespace System.Transaction per la gestione di applicazioni distribuite senza ricorrere a COM+, aumentando le prestazioni
  2. Uso dei generics
  3. Master Pages, Profile e Memberships
  4. Controllo Wizards
  5. Elaborazione asincrona attraverso MSMQ e System.Messaging
  6. Caching dei contenuti con dipendenza da tabelle SQL 2005

Accedere alla porta seriale in .NET 2.0

Nella versione 1.1 del .NET Framework accedere alla porta seriale per poter leggere/scrivere dei dati richiede l’uso delle API di Windows preposte allo scopo. Pertanto è necessario creare una classe wrapper che incapsula l’accesso alle API e fornisce i metodi pubblici necessari alla gestione della porta ed all’invio/ricezione delle informazioni. Nel .NET Framework 2.0 questa classe wrapper è già presente e ne viene fornito un esempio di utilizzo attraverso uno snippet code presente nell’elenco degli snippet code di Visual Studio 2005.

Pertanto, questa operazione, prima non certamente banale, è diventata di una semplicità disarmante nel Framework .NET 2.

Enterprise Library 2.0

Finalmente ha visto la luce la versione 2.0 della famosissima Enterprise Library, completamente rivista e ridisegnata in funzione della versione 2.0 del .NET Framework. Coloro che come me hanno utilizzato la versione disegnata per il .NET Framework 1.1 avranno certamente apprezzato la flessibilità e facilità di utilizzo che questi componenti forniscono allo sviluppatore e, caratteristica molto importante, la capacità di integrarsi in modo estremamente rapido in applicazioni reali