Concetti di base
Transcript
Concetti di base
Parte I Concetti di base In questa parte: Capitolo 1: Introduzione al Microsoft .NET Framework............................................... 3 Capitolo 2: Concetti di base del linguaggio........................................................... 15 Capitolo 3: Flusso di controllo e gestione degli errori............................................... 85 Capitolo 4: Utilizzo di Visual Studio 2005............................................................ 125 Capitolo 5: Debugging di applicazioni Visual Basic................................................ 181 Capitolo 1 Introduzione al Microsoft .NET Framework In questo capitolo: Un glossario .NET........................................................................................... 3 Nelle prime due edizioni di questo libro, che trattano le versioni 2002 e 2003 del linguaggio Visual Basic .NET, ho utilizzato questo primo capitolo sul .NET Framework per spiegare perché Microsoft ha deciso di investire così tante risorse ed energie in questa nuova piattaforma di programmazione e perché dovrebbe causare una rivoluzione silenziosa nel modo in cui si scrivono le applicazioni Windows e Web. Tuttavia, sono passati tre anni e mezzo dal lancio del .NET Framework, e per questa edizione del libro mi rendo conto che una tale introduzione sarebbe quasi superflua, visto che molto è stato scritto sul .NET Framework nel frattempo. Dopo tutto, è probabile che stiate leggendo questo libro perché avete già utilizzato Visual Basic .NET in precedenza o che, come minimo, abbiate letto abbastanza sull’iniziativa .NET da non aver più necessità di un ulteriore capitolo introduttivo. D’altra parte, uno dei miei obiettivi è rendere questo libro il più consistente e completo possibile, pertanto ho necessità di introdurre alcuni concetti che verranno spiegati più in dettaglio in seguito nel libro. Alla fine, ho deciso di compilare una sorta di glossario da poter leggere rapidamente per orientarvi nel labirinto .NET. Se non si è nuovi al .NET Framework, si può certamente saltare questa parte o limitarsi semplicemente a una rapida lettura. A differenza di un glossario tradizionale, tuttavia, questi termini sono organizzati in un ordine logico piuttosto che in ordine alfabetico. Ciascun termine rappresenta un concetto importante che spesso si basa su termini già introdotti precedentemente. Un glossario .NET Assembly Una applicazione .NET può essere costituita da uno o più assembly. Ciascun assembly è di solito un singolo file eseguibile EXE o DLL. Un assembly può anche comprendere altri file, tra cui file .html, .gif o altri file non eseguibili. Gli assembly rappresentano l’unità di versioning nel senso che tutti i file in un assembly hanno lo stesso numero di versione. L’assembly è anche la più piccola unità logica di deployment poiché non si distribuisce mai un sottoinsieme dei file che costituiscono l’assembly. Tipicamente, una applicazione utilizza diversi assembly esterni, compreso quelli che appartengono al .NET Framework stesso. Un assembly può comprendere un file eseguibile o un file eseguibile più altri file di dati, ma gli assembly a file singolo rappresentano di gran lunga il tipo più comune di assembly. Visual Studio 2005 può creare 3 4 Parte I Concetti di base solo assembly a file singolo, pertanto per creare assembly multi-file è necessario eseguire a mano il compilatore a riga di comando e il linker. Common Language Runtime (CLR) Il .NET Framework utilizza una architettura stratificata, alla base della quale risiede la API di Windows, come si vede in Figura 1-1. Il .NET Framework offre una vista object-oriented delle funzioni del sistema operativo ma non le sostituisce, pertanto gran parte delle invocazioni al .NET Framework vengono in definitiva risolte come invocazioni a una delle DLL del kernel di Windows. Il CLR è il primo strato che appartiene al .NET Framework. Questo strato è responsabile dei servizi di base .NET, tra cui la gestione della memoria, la garbage collection, la gestione strutturata delle eccezioni, e il multithreading. Il CLR si può considerare come il supervisore di tutte le applicazioni .NET: non si interagisce mai direttamente con il CLR, ma tutte le proprie applicazioni vengono controllate da esso. VB C++ C# JScript ... Common Language Specification ASP.NET Windows Forms Data and XML Base Class Library Common Language Runtime Windows COM+ Services Figura 1-1 Gli strati del .NET Framework Codice managed e unmanaged Si dice che le applicazioni .NET vengono eseguite come codice managed poiché vengono eseguite sotto il controllo del CLR e ad essa è impedito eseguire codice non sicuro che può mandare in crash la macchina o compromettere i propri dati. Ad esempio, il CLR può impedire a una applicazione di accedere al filesystem o al registry di sistema se l’applicazione è stata lanciata da una locazione su Internet che non è fully trusted (si veda la definizione in seguito nel glossario). Per contro, si dice che le applicazioni non-.NET, come le applicazioni Visual Basic 6, vengono eseguite come codice unmanaged, o codice nativo. Di tutti i linguaggi prodotti da Microsoft, solo il C++ può produrre sia codice managed sia codice unmanaged, ma anche gli sviluppatori C++ dovrebbero ricorrere al codice unmanaged solo se strettamente necessario: ad esempio, per svolgere operazioni a basso livello o per motivi di prestazioni, poiché solo il codice managed gode di tutti i vantaggi della piattaforma .NET. Classi e tipi In gergo .NET, il concetto di tipo è più generico del concetto di classe. Più precisamente, il .NET Framework definisce migliaia di tipi; i tipi .NET possono essere suddivisi in due categorie generali: tipi reference (o classi) e tipi value. La gran parte dei tipi .NET sono classi, pertanto il più delle volte si possono utilizzare indifferentemente i due termini. Si legga il paragrafo “Tipi reference e tipi value” del Capitolo 2 per ulteriori dettagli. Capitolo 1 Introduzione al Microsoft .NET Framework Base Common Library (BCL) Il .NET Framework è costituito da diverse migliaia di tipi, raggruppati in circa 30 assembly. Questi tipi permettono di eseguire pressoché ogni compito immaginabile, compresa la visualizzazione di finestre, la lettura di file e l’invio di testo HTML a un browser via Internet. La BCL è la parte del .NET Framework che definisce tutti i tipi di dati di base, tra cui System.Object (la radice della gerarchia degli oggetti .NET), tipi numerici e date, il tipo String, gli array e le collection. La BCL contiene anche i tipi per la gestione delle caratteristiche principali di .NET, come l’I/O su file, il threading, la serializzazione e la sicurezza. La maggior parte dei tipi appartenenti alla BCL sono compilati negli assembly mscorlib.dll e System.dll. Linguaggi .NET Gran parte delle funzionalità inglobate nei linguaggi tradizionali come Visual Basic 6 ora fanno parte del .NET Framework e vengono esposte come tipi .NET. Tutti i linguaggi .NET possono utilizzare questi tipi, e perciò tutti i linguaggi hanno le stesse funzionalità. Ad esempio, anche se Visual Basic 2005 e Visual C# 2.0 hanno una sintassi differente e keyword differenti, sono grosso modo equivalenti, ed entrambi permettono di sfruttare la piena potenza del .NET Framework. Inoltre, tutti linguaggi disponibili per il .NET Framework vengono compilati in codice IL (si veda la voce successiva del glossario), che a sua volta viene infine compilato in codice nativo. Per questo motivo, non si noterà alcuna differenza osservabile in termini di prestazioni tra linguaggi differenti. Un’eccezione a questa regola pratica è che una applicazione C# che utilizza puntatori e codice unsafe può essere eseguita in modo notevolmente più veloce rispetto all’equivalente applicazione Visual Basic. D’altro canto, gli sviluppatori C# sono vivamente scoraggiati dall’utilizzare codice unsafe, poiché l’assembly non è verificabile e potrebbe non essere eseguito a causa delle limitazioni imposte dalla Code Access Security (si veda in seguito nel glossario). Intermediate Language (IL) A differenza dei tradizionali linguaggi di programmazione, i compilatori .NET non producono codice nativo che può essere dato in pasto direttamente, ed essere eseguito, dalla CPU. Invece, producono il cosiddetto codice IL, che rappresenta una sorta di linguaggio macchina per un processore virtuale che non corrisponde ad alcuna CPU ad oggi disponibile. Mentre il codice IL è di livello più basso rispetto a gran parte dei moderni linguaggi di programmazione, è di livello più alto rispetto al puro linguaggio assembly. IL è un linguaggio stack-oriented che non indirizza direttamente i registri della CPU ed è dotato di concetti di alto livello come le stringhe, le eccezioni e la creazione di oggetti. ILDASM Visual Studio 2005 è dotato di un tool denominato ILDASM, o IL Disassembler. (In una installazione di default di Visual Studio, si può trovarlo nella cartella C:\Program Files\ Microsoft Visual Studio 8\SDK\v2.0\Bin). Come fa intendere il nome, questa utility consente di visualizzare il codice IL memorizzato all’interno di un assembly .NET permettendo di trascinare semplicemente il file .exe o .dll da Windows Explorer nella finestra principale di ILDASM. (Si veda la Figura 1-2). Per far sì che ILDASM visualizzi il codice sorgente originale che ha prodotto l’assembly analizzato bisogna abilitare l’opzione Show Source Lines dal menu View. (Il codice effettivo Visual Basic si vede solo se l’eseguibile ha un file .pdb allegato che contiene informazioni simboliche). Utilizzerò spesso ILDASM in questo libro per mostrare ciò che accade dietro le quinte e per commentare il codice che il compilatore Visual Basic produce. 5 6 Parte I Concetti di base Figura 1-2 Il tool ILDASM Compilatore Just-in-Time (JIT)Poiché nessuna CPU può eseguire codice IL, il CLR deve convertire questo codice in codice nativo mentre il programma è in esecuzione, lanciando il compilatore JIT e passandogli l’indirizzo del metodo entry point (tipicamente, la procedura Sub Main in una applicazione Visual Basic). Quando la procedura principale invoca altro metodi, il runtime .NET utilizza il compilatore JIT per trasformare il codice IL all’interno di questi metodi in codice nativo e poi esegue il codice nativo. Questa compilazione al volo viene svolta solo una volta per metodo durante la durata dell’applicazione poiché il codice nativo viene mantenuto in memoria e viene riutilizzato quando quel metodo specifico viene invocato nuovamente. Metadati e Manifest Oltre al codice IL, un assembly comprende un insieme di tabelle che contengono i cosiddetti metadati, ossia informazioni su quali tipi vengono compilati nell’assembly, quali sono i relativi metodi, da quali assembly dipende questo assembly, e via dicendo. Nel mondo del .NET Framework, i metadati sono importanti quanto l’effettivo codice eseguibile poiché il CLR utilizza i metadati in molte occasioni. L’insieme più importante di tabelle di metadati è noto come assembly manifest. L’aspetto notevole dei metadati è che si possono estendere per mezzo di attributi custom, che offrono un modo standard per includere ulteriori informazioni metadati in un assembly che non dipende da uno specifico linguaggio di programmazione o da uno specifico compilatore. Reflection La reflection è un insieme di tipi che consentono a una applicazione scritta per il .NET Framework di leggere e utilizzare i metadati memorizzati in un assembly. Molte parti del .NET Framework sono pesantemente basate sulla reflection, compresa la capacità di serializzare il valore corrente di un oggetto su un file o di inviare oggetti a una applicazione in esecuzione su un differente computer. La reflection verrà trattata in modo esaustivo nel Capitolo 18. Native Image Generator (NGen) Il .NET Framework comprende l’utility NGen, che permette di precompilare una applicazione .NET in codice nativo. Si noti che la precompilazione di Capitolo 1 Introduzione al Microsoft .NET Framework una applicazione non comporta necessariamente migliori prestazioni e, in alcuni casi, può anche produrre codice più lento. L’utility NGen è più efficace con le applicazioni lato client (ad esempio, le applicazioni Windows Forms), poiché riduce il tempo di avvio, ma è meno utile con le applicazioni lato server, come i progetti Web Forms e Web Services, in cui il tempo di avvio non è un fattore critico. Si noti che non si può utilizzare l’utility NGen per impedire che un assembly venga decompilato (si veda il termine successivo), poiché un assembly precompilato da NGen richiede comunque la presenza dell’assembly originale che contiene il codice IL leggibile. Ulteriori informazioni sull’utility NGen sono disponibili nel Capitolo 17. Decompilatori Alcune utility sul mercato permettono di analizzare un assembly .NET compilato e di ricostruire il codice sorgente originale C# o Visual Basic. A mio avviso, il tool migliore di questa categoria è Reflector (http://www.aisto.com/roeder/dotnet/), distribuito come freeware e che offre l’opzione di decompilare il codice sia in Visual Basic sia in C#. Il processo di decompilazione funziona così bene tanto da poter utilizzare questo tool come tool di conversione inter-linguaggio: si compila un blocco di codice sorgente in Visual Basic e poi lo si decompila in C#, o viceversa. Un ulteriore decompilatore molto diffuso è Anakrino (http://www.saurik.com/net/exemplar/), anch’esso distribuito come freeware. Obfuscator Poiché è così facile sbirciare in un assembly .NET, molte aziende sono molto attente nel proteggere il proprio software da un decompilatore. Sfortunatamente, non si può realmente proteggere un assembly dalla decompilazione. Tuttavia, si può “offuscare” un assembly rinominando i nomi dei tipi e dei membri in stringhe prive di significato. Gli utenti subdoli che decompilano il vostro assembly leggerebbero semplicemente un elenco di sequenze di caratteri privi di senso. Inoltre, sarebbero ancora in grado di comprendere cosa fa il vostro codice, ma questo compito richiederebbe molto più tempo e si può quindi sperare che desistano. Visual Studio 2005 comprende il prodotto Dotfuscator Community Edition della PreEmptive Solutions, che è più che adeguato per gran parte dei compiti di “offuscamento”. (Si può eseguire questa utility dal menu Tools, si veda la Figura 13). Se si è alla ricerca di un prodotto più potente, andrebbe considerato l’acquisto della Professional Edition di questo prodotto o di un ulteriore obfuscator in versione full come Demeanor (www.wiseowl.com). Per ulteriori informazioni sugli obfuscator e sulle relative caratteristiche (e anche di altri tool di programmazione freeware e commerciali) si visiti la pagina http://www.howtoselectguides.com/dotnet/obfuscators/. Figura 1-3 Il tool Dotfuscator Community Edition della PreEmptive Solutions 7 8 Parte I Concetti di base Global Assembly Cache (GAC) Gli assembly del .NET Framework possono essere suddivisi in due categorie: assembly privati e assembly pubblici. Gli assembly privati vengono memorizzati nella cartella principale dell’applicazione e possono essere utilizzati solo da questa applicazione (o da altri assembly della stessa cartella). Gli assembly condivisi di solito vengono memorizzati nella Global Assembly Cache (GAC) e possono essere utilizzati da tutte le applicazioni .NET in esecuzione sul computer locale. La GAC è un’area dell’hard disk (posizionata nella directory C:\Windows\Assembly) in cui il .NET Framework memorizza tutti gli assembly che possono essere condivisi tra tutte le applicazioni .NET in esecuzione sul computer locale. Ad esempio, tutti gli assembly che fanno parte del .NET Framework stesso vengono memorizzati nella GAC. Nella GAC possono coesistere più versioni dello stesso assembly. Versioning Il versioning rappresenta il problema di installare una nuova versione di un componente su un computer senza influenzare il corretto funzionamento di altre applicazioni che utilizzano una versione differente dello stesso componente. Il versioning ha afflitto per anni gli sviluppatori Visual Basic 6 e COM, ma il .NET Framework lo ha risolto in un modo molto raffinato. Per prima cosa, si possono evitare i problemi di versioning utilizzando gli assembly privati: ciascuna applicazione può utilizzare una versione differente di un assembly privato poiché gli assembly privati non vengono condivisi con altre applicazioni .NET. In secondo luogo, si può installare un assembly condiviso nella GAC poiché la GAC può sicuramente contenere più versioni dello stesso assembly. Ciascuna applicazione compilata con la versione X.Y di un determinato componente continua a funzionare correttamente anche se l’utente installa una versione più recente (o più vecchia) dello stesso componente. Il versioning del .NET Framework è più flessibile del versioning in COM. Infatti, uno sviluppatore o un amministratore di sistema può utilizzare un file di configurazione per redirigere una richiesta per un determinato componente a una ulteriore versione dello stesso componente. L’autore del componente può rilasciare una nuova versione che corregge dei bug o che è più efficiente, e così facendo migliora indirettamente la robustezza e la velocità di tutte le applicazioni che utilizzano quel componente senza introdurre problemi di incompatibilità di versione. Il versioning si estende anche al .NET Framework stesso. Quando diviene disponibile una nuova versione del .NET Framework, si può installarla su un computer senza rimuovere le versioni precedenti del framework, e le applicazioni che utilizzano le versioni precedenti continueranno a funzionare. (Si veda la Figura 1-4.) Deployment XCOPY Se una applicazione .NET utilizza solo assembly privati, si può installarla semplicemente copiando la cartella (compresa qualsiasi cartella figlia) dalla propria macchina di sviluppo alla macchina del proprio cliente. Questo meccanismo è noto come deployment XCOPY. Questa caratteristica non implica il dover utilizzare questo semplice metodo di installazione al posto di una completa procedura di installazione. Tipicamente, è necessario creare dei collegamenti nel menu Avvio e abilitare l’utente finale a selezionare quali parti delle applicazioni verranno installate. Tuttavia, pur considerando questi compiti ausiliari, l’installazione di una applicazione .NET è molto più semplice dell’installazione di una analoga applicazione COM a causa del minor numero di cose che possono non andare a buon fine. Capitolo 1 Introduzione al Microsoft .NET Framework Figura 1-4 La directory Windows\Assembly di un computer su cui sono state installate entrambe le versioni 1.1 e 2.0 del .NET Framework. File di configurazione Le applicazioni .NET memorizzano le proprie impostazioni nei file di configurazione, che vengono posizionati nella stessa directory dell’assembly principale dell’applicazione. Il nome di un file di configurazione si forma accodando l’estensione .config al nome dell’assembly. Ad esempio, l’applicazione myapp.exe utilizza il file di configurazione myapp.exe.config. Essendo memorizzati nella cartella dell’applicazione, i file di configurazione vengono installati correttamente quando si distribuisce l’applicazione utilizzando il deployment XCOPY. Un file di configurazione utilizza la sintassi XML per memorizzare dati gerarchici e perciò è più flessibile, ad esempio, dei file .ini. Le applicazioni ASP.NET possono utilizzare ulteriori file di configurazione, uno per ciascuna sottodirectory che contiene una parte dell’applicazione; ciascuno di questi file di configurazione secondari influenza le impostazioni della parte corrispondente dell’applicazione. Uno speciale file machine.config influenza tutte le applicazioni .NET in esecuzione su un determinato computer. Ereditarietà La progettazione del .NET Framework è imperniata sul concetto di ereditarietà. Tutti gli oggetti del .NET Framework formano una gerarchia con un’unica radice comune, la classe System.Object, da cui derivano tutti gli altri tipi .NET. Questi tipi forniscono funzionalità quasi in ogni area immaginabile, compresa l’interfaccia utente, l’accesso ai dati, la programmazione Internet, l’elaborazione XML, la sicurezza, e la comunicazione intermacchina. Programmare in .NET spesso significa estendere uno di questi tipi. Ad esempio, si può creare un controllo textbox che accetta solo numeri derivando una nuova classe dalla classe System.Windows.Forms.TextBox e aggiungendo tutto il codice necessario che rigetta gli inserimenti non validi. Le classi che non derivano da una specifica classe .NET ereditano in modo implicito da System.Object e perciò traggono vantaggio in altri modi dal far parte della gerarchia di oggetti .NET. Si noti che .NET supporta solo l’ereditarietà singola (il che significa che una classe non può derivare da due o più classi). Common Type Specifications (CTS) Questo set di specifiche stabilisce come un tipo espone campi, proprietà, metodi e eventi; le CTS definiscono anche come un tipo può derivare da un 9 10 Parte I Concetti di base ulteriore tipo e anche ridefinirne i membri. Poiché tutti i linguaggi .NET si attengono a queste specifiche, possono scambiarsi dati, utilizzare tipi scritti in un linguaggio differente, e anche ereditare da essi. Ad esempio, si può derivare una classe Visual Basic 2005 da una classe C#, e si può scrivere una classe C# che implementa un’interfaccia definita in Visual Basic. Common Language Specifications (CLS) Questo set di specifiche stabilisce le caratteristiche minime che un linguaggio di programmazione deve avere per essere qualificato come linguaggio .NET. Ad esempio, tutti i linguaggi .NET devono essere in grado di gestire tipi primitivi, come le stringhe, gli interi, e gli array con base zero, e devono essere in grado di processare una eccezione .NET lanciata quando si verifica un errore. Alcuni tipi del .NET Framework non sono conformi alle specifiche CLS: ad esempio, gli array di array e gli array con indice inferiore diverso da 0. Se la propria applicazione espone al mondo esterno degli oggetti non CLS-compatibili, potrebbe essere inutilizzabile da altre applicazioni, in base al linguaggio .NET utilizzato per svilupparle. AppDomain Tradizionalmente, una applicazione Windows viene eseguita in un processo Win32 distinto. Ciascun processo viene isolato da un altro processo per mezzo delle caratteristiche hardware della CPU in modo che un processo non possa corrompere accidentalmente la memoria e i dati che appartengono ad altri programmi. Nel mondo del .NET Framework, tuttavia, le applicazioni vengono eseguite in un “dominio applicativo”, o AppDomain. In uno stesso processo Win32 può essere in esecuzione uno o più AppDomain, ma un assembly in un determinato AppDomain non può influenzare gli assembly in altri AppDomain, anche se tutti gli AppDomain si trovano nello stesso processo Win32. (Si veda la Figura 1-5). L’isolamento dell’AppDomain è ottenuto a livello software poiché tutti i compilatori .NET producono codice “safe” che non può accedere a locazioni arbitrarie di memoria. L’utilizzo di un unico processo che contiene più AppDomain consuma meno risorse rispetto al suddividere l’applicazione in più processi e rende più agevole e più efficiente la comunicazione tra assembly in AppDomain distinti. Process 1 Process 2 AppDomain A AppDomain D AppDomain B AppDomain E AppDomain C Figura 1-5 Un processo Win32 può ospitare più AppDomain. Gli AppDomain in esecuzione nello stesso processo possono comunicare in modo più efficiente rispetto a degli AppDomain in processi differenti. Applicazioni Console Le applicazioni Console sono programmi .NET che leggono i dati di input e visualizzano l’output nella finestra console. Sono utili per la creazione di semplici utility che si possono invocare da file batch ma rappresentano raramente una scelta Capitolo 1 Introduzione al Microsoft .NET Framework idonea per scrivere applicazioni commerciali. D’altro canto, le applicazioni Console sono molto concise e per questo motivo gran parte degli esempi di codice di questo libro sono progettati per essere eseguiti come applicazioni Console. Windows Forms Windows Forms è la parte del .NET Framework che permette di creare le tradizionali applicazioni Win32 in esecuzione su computer stand-alone o su computer che fungono da client in una grossa applicazione client-server. Al contrario delle applicazioni Web Forms, che sono programmi .NET che vengono eseguiti su un server e che inviano l’output come testo HTML ai browser in esecuzione sui computer client (si veda in seguito in questo glossario). La creazione di un progetto Windows Forms è simile alla creazione di un progetto Visual Basic 6: si rilascia uno o più controlli sulla superficie del form, si assegnano le proprietà nella finestra Properties, e si scrive il codice che deve essere eseguito quando il controllo scatena un evento. In questo libro, mostro occasionalmente esempi di applicazioni Windows Forms per illustrare le tecniche di programmazione che non possono essere dimostrate per mezzo di progetti console. Applicazioni ClickOnce ClickOnce è una nuova caratteristica della versione 2.0 .NET Framework. In sintesi, un progetto ClickOnce genera una applicazione Windows Forms che può essere lanciata da un computer remoto, o dalla intranet locale o da Internet. Le applicazioni ClickOnce hanno un grande vantaggio rispetto a una ordinaria applicazione Windows Forms: la facilità del deployment. L’utente finale deve solo cliccare su un hyperlink nel browser per lanciare l’applicazione remota o per installarla sulla macchina locale, in base a come il progetto ClickOnce è stato compilato. I programmi ClickOnce possono essere eseguiti come applicazioni parzialmente trusted soggette alle restrizioni della Code Access Security (si veda in seguito in questo glossario). GDI+ Tutti i tipi del .NET Framework inerenti alla creazione di immagini e alla grafica sono raccolti in GDI+. Si possono utilizzare le funzionalità GDI+ sia nelle applicazioni Windows Forms sia nelle applicazioni ASP.NET. Ad esempio, si può creare un grafico a istogramma sul server e inviarlo al client in una pagina HTML con una applicazione Web Forms, o inviarlo a un client remoto attraverso un Web service. ADO.NET ADO.NET è la parte del .NET Framework che consente di lavorare con i database ed è perciò l’equivalente .NET della tecnologia ActiveX Data Objects (ADO). Nonostante i nomi simili, ADO e ADO.NET sono molto differenti. Mentre ADO “classico” gestisce virtualmente tutte le tecniche di database disponibili (compresi i cursori lato server e lato client, i resultset disconnessi, e i batch update), ADO.NET si concentra principalmente sui resultset disconnessi (detti DataSet nella terminologia ADO.NET) e non offre alcun supporto per i cursori lato server. L’oggetto DataSet è molto più potente dell’oggetto Recordset di ADO e può memorizzare dati provenienti da più tabelle dello stesso database o da database differenti. Si possono creare relazioni tra differenti tabelle di dati, e si possono importare o esportare sia i dati sia i metadati come XML. ASP.NET ASP.NET è la parte del .NET Framework che permette di creare applicazioni Internet e intranet. Le applicazioni ASP.NET possono essere suddivise in due categorie: 11 12 Parte I Concetti di base applicazioni Web Forms e applicazioni Web Services (si vedano i due termini successivi). Entrambi i tipi di applicazione condividono l’infrastruttura ASP.NET e utilizzano gli stessi servizi: ad esempio, i servizi di caching e di sicurezza. ASP.NET permette di creare applicazioni potenti e flessibili in una frazione del tempo necessario con le tecnologie pre-.NET, come Active Server Pages (ASP). Questo parte del .NET Framework è stata estesa e migliorata considerevolmente nella versione 2.0. Non tratterò le applicazioni ASP.NET in questo libro. Web Forms I progetti ASP.NET Web Forms creano applicazioni Internet e intranet che producono una interfaccia utente e che “sembrano” venir eseguite all’interno di un browser. Più precisamente, le applicazioni Web Forms vengono eseguite all’interno di Microsoft Internet Information Services (IIS) e producono testo HTML che viene inviato al browser del client. Grazie alla presenza di molti controlli utente (compresi controlli complessi come griglie, calendari e treeview) si può scrivere una applicazione Web Forms utilizzando lo stesso approccio a eventi che si utilizza per le applicazioni Windows Forms. Web Service I progetti Web Service permettono di creare componenti che vengono eseguiti su un computer remoto accessibile attraverso Internet. A differenza delle applicazioni Web Forms, una applicazione Web Service non produce testo HTML: invece, le applicazioni client comunicano con un servizio Web inviando una richiesta codificata in una grammatica XML nota come Simple Object Access Protocol (SOAP). L’infrastruttura ASP.NET cattura la richiesta, invoca l’oggetto in esecuzione all’interno di IIS, codifica il valore di ritorno nuovamente in SOAP, e la restituisce al client. L’aspetto notevole dei progetti Web Service è che Visual Studio genera automaticamente una classe proxy per il client. Il codice dell’applicazione client utilizza questa classe proxy e ne invoca i metodi come farebbe con un oggetto standard, ma la classe proxy converte in modo trasparente queste invocazioni in invocazioni SOAP attraverso la rete. Il risultato finale è che si può lavorare con un componente remoto come se fosse un oggetto locale. Per ulteriori informazioni sulla libreria Web Services Enhancements (WSE), che estende la tecnologia standard Web Services con caratteristiche come la sicurezza e le transazioni si visiti l’indirizzo http://msdn.microsoft.com/webservices/webservices/building/wse/ default.aspx. Remoting Il remoting è una tecnologia che abilita una applicazione .NET Framework a invocare un metodo di un oggetto definito in un’altra applicazione in esecuzione in un differente AppDomain, in un differente processo sullo stesso computer, o in un computer differente della LAN o su Internet, utilizzando un canale di trasporto come TCP o HTTP. Il remoting è estremamente efficiente poiché i dati vengono scambiati in formato binario (al contrario dei Web Service, che scambiano dati sotto forma di testo XML). Componenti Serviced I componenti serviced sono oggetti del .NET Framework che possono interoperare con le applicazioni Component Services (COM+). I Web service, il remoting, e i componenti serviced rappresentano le tre tecnologie del .NET Framework che permettono di eseguire codice su un computer remoto, ma ciascuna di esse espone vantaggi e difetti. I Web service consentono di comunicare anche con Capitolo 1 Introduzione al Microsoft .NET Framework piattaforme diverse da Windows ma sono relativamente inefficienti. Il remoting è la tecnologia più efficiente del gruppo, ma può funzionare solo con altre applicazioni .NET Framework. I componenti serviced sono a metà strada tra questi estremi poiché possono interagire con altre applicazioni Windows (non necessariamente applicazioni .NET Framework) e supportano appieno le transazioni e la sicurezza COM+. Platform Invoke e COM Interop Il CLR consente a una applicazione .NET Framework di interagire con applicazioni legacy, non .NET. Sono supportati due tipi principali di interazioni: Platform Invoke (nota anche come PInvoke) e COM Interop. La prima permette di invocare una funzione compilata in una DLL “classica”, scritta tipicamente in C, C++ o in Borland Delphi. Ad esempio, grazie a Platform Invoke si possono invocare i metodi dell’API di Windows. COM Interop consente sia di invocare sia di essere invocata da un componente COM, compresi i componenti scritti in Visual Basic 6. COM Interop è una funzionalità critica nella migrazione di una applicazione legacy ad un linguaggio supportato dal .NET Framework poiché permette di migrare un blocco di applicazione per volta pur essendo ancora in grado di poter interagire con i blocchi dell’applicazione implementati con la tecnologia più vecchia. Code Access Security (CAS) Il codice managed viene sempre eseguito sotto la supervisione del CLR. Ad ogni invocazione al .NET Framework, il CLR verifica che il codice chiamante soddisfi le regole della Code Access Security e se ha il diritto di eseguire l’operazione richiesta. Questi diritti dipendono dalla identità dell’assembly e dalla locazione da cui viene eseguito. Più specificamente, solo agli assembly caricati dal disco rigido locale vengono concessi tutti i permessi. (Questi assembly sono detti essere totalmente trusted). Alle applicazioni lanciate da una condivisione di rete o da una locazione intranet viene impedita l’esecuzione di operazioni potenzialmente pericolose, come la lettura e la scrittura di file. Alle applicazioni che vengono eseguite da Internet vengono concessi pochi o nessun permesso, in base a se l’URL di origine viene considerato un sito trusted o meno. (Per definizione, si dice che gli assembly con permessi limitati vengono eseguiti in un contesto di sicurezza parzialmente trusted.) Il codice in esecuzione in un contesto parzialmente trusted non ha accesso al filesystem locale, il che può rappresentare un serio problema se l’applicazione deve salvare i dati tra le sessioni (ad esempio, le preferenze dell’utente). Per questo motivo, il .NET Framework può gestire una piccola parte dell’hard disk locale come se fosse del tutto isolata dalle altre cartelle. Questo parte è nota come isolated storage e ad essa si può accedere anche da applicazioni che vengono eseguite da una locazione della intranet o da un sito Internet. 13