Ing. Felice Pescatore
felice.pescatore@poste.it
Microsoft .Net Framework
DotNet FRAMEWORK
Architettura e Dettagli
Quale versione del Framework.NET?
Questo corso sarà incentrato sulla versione 2 del dotNet
Framework,nonostante sia stata ...
Certificazioni Microsoft: i percorsi
Application
Development
Foundation
Esame 70-536
Windows Based
Client Development
Esam...
Certificazioni Microsoft: testi ufficiali
Certificazioni Microsoft: SQL Server
Esame 70-431
Certificazioni Microsoft: Compendi Consigliati
Serie Passo-Passo, di base
Serie Programming
• msdn2.microsoft.com/it-it/li...
Architettura del dotNet Framework
CONCETTI INTRODUTTIVI
Cos’ è il dotNet Framework
Il Framework .NET e' la piattaforma di sviluppo di riferimento per il
mondo Windows, grazie all...
dotNet presenta un’architettura a strati. Al suo interno possiamo
distinguere gli elementi portanti dell’intero framework:...
Il dotNET Framework: il CLR (1)
Il COMMON LANGUAGE RUNTIME (CLR) è uno strato posto al di sopra dei
servizi del sistema op...
Il .NET Framework: il CLR (2)
•Semplificare lo sviluppo
• Definire standard per il riuso del codice
• Fornire servizi come...
Il dotNET Framework: il CLR (3)
Volendo fare un paragone con il mondo JAVA, il CLR è l’equivalente .NET della
Java Virtual...
Tutti i linguaggi .NET, attraverso il CLR, accedono al medesimo sistema di tipi e
alle stesse classi base, ottenendo cosi ...
Il dotNET Framework: la BCL
Difatti, prima del dotNet Framework, gli
Ingegneri del Software dovevano
pianificare la realiz...
Il dotNET Framework: ADO.NET
Praticamente tutte le applicazioni hanno la necessità di interrogare o aggiornare
dati persis...
Il dotNET Framework: XML
XML svolge un ruolo fondamentale in nel .NET framework, sin dalla sua prima
versione, essendo uti...
ASP.NET fornisce un modello applicativo sotto forma di CONTROLLI che
semplifica la creazione di applicazioni Web.
L’infras...
Il dotNET Framework: WindowsForms
Le WindowsForms sono praticamente le classiche finestre di
un’applicazione windows che c...
Il dotNET Framework: ASP.NET - WebForms
Le WebForms sono l’equivalente delle WindowsForms,
eccetto che il loro ambiente di...
Il dotNET Framework: ASP.NET – XML Web Services
I Web Services sono una sorta di piccoli
servizi disponibili in rete, che ...
Il dotNET Framework: CTS
Il COMMON TYPE SYSTEM (CTS) definisce un insieme standard di tipi di dato e di regole
necessarie ...
Il dotNET Framework: CTS, Tipi a Valore
I Tipi a Valore non possono essere null (tranne i NULLABLE che sono un
discorso a ...
Il dotNET Framework: CTS, Tipi a Riferimento
I Tipi a Riferimento rappresentano il riferimento ad oggetti allocati nell’He...
Il dotNET Framework: CLS
Le COMMON LANGUAGE
SPECIFICATION, definiscono le
regole che un linguaggio deve
avere per essere g...
Esecuzione di applicazioni dotNET
Compilazione ed Esecuzione di codice dotNET
Source code
C++, C#, Visual
Basic o Altria
language .NET
es: Csc.exe o Vbc.exe
Compilatore
Assembly
DLL o EXE
L’applicativ...
Un ASSEMBLY rappresenta il costituente fondamentale di un'applicazione .NET.
Si tratta dell’unità elementare di rilascio d...
Type Descriptions
Classes
Base classes
Implemented interfaces
Data members
Methods
Name
Version
Culture
Assembly Manifest
...
Assembly Manifest: Uso dei Metadati
I METADATI sono indipendenti dal linguaggio, consentendo a quelli che vi accedono
di i...
Assembly: Execution Model, Intermediate Language
Come detto il Codice Sorgente viene compilato nel linguaggio intermedio I...
Assembly: Execution Model
Gli assembly sono caricati in memoria dal CLR solo all’occorrenza:
• prima viene determinata la ...
Assembly: Execution Model Schema
Compilazione
Esecuzione
JIT
Compiler
Native
Code
MSIL
Code
Metadata
Source
Code
Language
...
Assembly: Deployment semplificato
Sicuramente il Deployment rappresenta uno dei grossi vantaggi di dotNet,
permettendo:
• ...
Assembly Location
Avendo parlato di deployment è utile specificare le location che gli assembly
possono assumere in base a...
Oggetti “vivi” Oggetti non raggiungibili Spazio libero
Garbage Collection(1)
Fase 1: Mark
Durante l’esecuzione del codice ...
www.devleap.it
Oggetti “vivi”
Spazio libero
NextObjPtr
Root set
Spazio recuperato
Garbage Collection (2)
Fase 2: Compact
Non sempre ci si può affidare in modo “cieco” al Garbage Collector, ma in alcuni
casi serve un comportamento di finalizzaz...
Linguaggi del dotNet Framework
Come più volte ribadito fin ora , il dotNet Framework è LANGUAGE-
INDEPENDED, ovvero non di...
Base Class ed Interfacce
Le Classi e le Interfacce della BCL
Base Class ed Interfacce: Namespaces
Base Class Library
Data Xml
Web Services User Interface
Base Class ed Interfacce: Namespaces
System
System.Data System.Xml
System.Web
Globalization
Diagnostics
Configuration
Coll...
Base Class ed Interfacce: Namespaces
System
Threading
Text
Security
Resources
Reflection
IO
Globalization
Diagnostics
Conf...
Base Class ed Interfacce: Namespaces
System.Data
System.Xml
OracleClient
OleDb
Sql/SqlClient
Common
Serialization
Schema
X...
System.Web
Caching
Configuration
UI
SessionState
HtmlControls
WebControls
Security
Handlers
Hosting
Compilation
Management...
System.Drawing
Drawing
Design
Printing
Text
System.Windows.Forms
Design ComponentModel
dotNet Framework: Namespaces
Visual...
Input / Output
Input e Output con dotNet
dotNet Framework: Input / Output
Una delle principali attività che ci si trova a realizzare è l’interazione con il (i) fil...
dotNet Framework: I/O, ottenere informazioni dal File System
FileInfo ourFile = new FileInfo(@"c:boot.ini ");
if (ourFile....
Per effettuare le operazioni di lettura e scrittura, il.Net Framework fornisce gli
STREAM (letteralmente flussi), che perm...
dotNet Framework: aprire uno Stream su file
L’apertura degli Stream, relativi alla lettura/scrittura file, avviene attrave...
dotNet Framework: Leggere/Scrivere da un file
FileStream theFile = File.Open(@"C:boot.ini", FileMode.Open, FileAccess.Read...
dotNet Framework: Usare il MemoryStream
MemoryStream memStrm = new MemoryStream();
StreamWriter writer = new StreamWriter(...
dotNet Framework: Stream Speciali
Oltre agli stream che permetto una normale lettura/scrittura da file o memoria,
esistono...
FileStream sourceFile = File.OpenRead(inFilename);
FileStream destFile = File.Create(outFilename);
GZipStream compStream =...
dotNet Framework: Working with Text
Lavorare con le Stringhe ed il Testo
dotNet Framework: Working with Text
 Lavorare con le stringhe di testo è un task comune per tutti
gli sviluppatori
 .Net...
dotNet Framework: La classe StringBuilder e la classe String
• Normalmente si è portati ad utilizzare la classe String per...
dotNet Framework: Regular Expression
• Le Espressioni Regolari (Regular Expression) sono una eredità del mondo Unix
e del ...
dotNet Framework: Codifica del Testo
• Vista l’eterogeneità dei sistemi informatici esistenti, non meraviglia che esistano...
dotNet Framework: Collection & Generics
Lavorare su insiemi di oggetti
dotNet Framework: Collection & Generics
Ogni framework che si rispetti deve avere un’ampia serie di collezioni (collection...
dotNet Framework: Collection Classiche
Le Collection Classiche sono contenute nel NameSpace System.Collections e
annoveran...
La System.Collctions prevede tre interfacce di base:
•IEnumerable (rende enumerabile la lista),
•ICollection (rende omogen...
 I generics sono stati introdotti
dalla versione 2 del framework
e sono formati da classi e
metodi che lavorano in modo
u...
dotNet Framework: Generics
Tra le implementazioni si annoverano:
• List<>, ovvero una semplice lista di elementi;
• Queue<...
ArrayList myList = new ArrayList();
myList.Add(1); // Viene effettuato il boxing (value -> refernce)
myList.Add(2); // Vie...
Rappresentazione senza Generics Rappresentazione con Generics
intobject
intobject
intobject
intobject intobject
int int
in...
dotNet Framework: Serialization
Persistere lo Stato di un Oggetto
dotNet Framework: Serialization
La Serializzazione permette di salvare un oggetto (e, quindi, il suo attuale stato)
in mod...
dotNet Framework: Serialization
Il dotNet framework utilizza un modo semplice ed immediato per rendere
serializzabile un o...
dotNet Framework: Serialization, IDeserializationCallback
Nel caso in cui si abbiano dei membri (variabili di istanza) cal...
dotNet Framework: Binary Serialization
Come detto, la serializzazione avviene mediante le classi prima descritte e
riversa...
dotNet Framework: XML Serialization
Nel caso in cui si voglia rendere il risultato della serializzazione il più portabile
...
dotNet Framework: Custom Serialization
Se le precedenti forme di serializzazione non sono adeguate ai nostri scopi (caso
m...
dotNet Framework: Graphics
Grafica elementare
dotNet Framework: Graphics
dotNet offre gli strumenti base per la creazione di semplici elementi grafici (linee,
cerchi, e...
dotNet Framework: Graphics
Per disegnare una linea o una figura base, bisogna eseguire tre passi
fondamentali:
•Creare un ...
dotNet Framework: Graphics
Invece di utilizzare l’oggetto Pen, in abbinamento con il metodo graphics.drawXXX,
è possibile ...
dotNet Framework: Graphics
Grazie alle implementazioni della classe astratta System.Drawing.Image, è
possibile elaborare i...
dotNet Framework: Graphics
Attraverso le funzionalità di System.Drawing è possibile creare anche testo sotto
forma di imma...
dotNet Framework: Threading
Esecuzione Concorrente di Attività
dotNet Framework: Threading
Grazie all’utilizzo dei Thread è possibile dotare l’applicazione di più flussi paralleli
che p...
dotNet Framework: Threading
In sintesi ecco il codice per avviare un thread:
Se è necessario passare informazioni al threa...
dotNet Framework: richiamo
I DELEGATI (Delegate) sono una sorta di CallBack (per chi conosce C++) o più
semplicemente punt...
dotNet Framework: Threading
La classe Thread fornisce i metodi necessari per gestire in modo corretto il flusso di
elebora...
dotNet Framework: Threading
Per consentire la condivisione di memoria (quindi dei parametri) tra i vari thread
evitando co...
dotNet Framework: Threading
Se abbiamo bisogno di “blindare” più istruzioni in modo da renderle atomiche,
possiamo ricorre...
dotNet Framework: Threading
Non è sempre necessario creare un nuovo thread per avviare attività in parallelo.
Infatti il f...
dotNet Framework: Threading
L’utilizzo del modello APM pone una domanda fondamentale: quando verificare la
fine del flusso...
dotNet Framework: Threading
…..
// Make the asynchronous call
strm.Read(buffer, 0, buffer.Length);
IAsyncResult result = s...
….
// Make the asynchronous call
IAsyncResult result = strm.BeginRead(buffer, 0, buffer.Length, new
AsyncCallback(Complete...
dotNet Framework: Application Domain & Services
Isolare il Codice Sconosciuto
Spesso è necessario lavorare con assembly esterni, che possono impattare sia
sulle performace/stabilità del nostro applica...
La classe che permette la gestione degli Application Domain è la
System.AppDomain. Vediamo ora alcuni esempi concreti di u...
Come ci si aspetterebbe, per poter controllare il livello di isolamento di un
Application Domain (quindi utilizzarlo come ...
I Windows Services (servizi di windows) sono una gamma di applicativi privi di UI
che, funzionando in background, svolgono...
dotNet Framework: Configuring Application
Rendere dinamica un’applicazione attraverso la
sua configurazione
dotNet Framework: Configuring Application
Parola d’ordine: evitare le configurazioni HardCoding, ovvero quelle inserite
al...
dotNet Framework: Configuring Application
Vediamo un esempio di file di configurazione:
<?xml version="1.0" encoding="utf-...
dotNet Framework: Configuring Application
In esso possiamo distinguere tre sezioni principali:
• <runtime>, in cui sono ri...
dotNet Framework: Configuring Application
La sezione ConnectionStrings è leggermente diversa poiché può contenere
dichiara...
dotNet Framework: Configuring Application
Oltre al file di configurazione dell’applicazione dotNET prevede la possibilità ...
dotNet Framework: Configuring Application
Per definire un nuovo file di configurazione ed auto-generare la relativa classe...
dotNet Framework: Configuring Application
Salvando il nuovo file di settaggio, troveremo due nuovi elementi nel nostro
pro...
dotNet Framework: Instrumentation
Ottimizzare la propria Applicazione
dotNet Framework: Instrumentation
Sotto il nome Instrumentation Micorsoft ha raccolto tutti gli strumenti (ovviamente
parl...
dotNet Framework: Instrumentation
Praticamente è impossibile conoscere tutti gli scenari in cui la nostra applicazione
ver...
dotNet Framework: Instrumentation
La fase di Debugging è una delle più importanti nello sviluppo di un nuovo
applicativo, ...
dotNet Framework: Instrumentation
La classe Debug consente un controllo fine sul processo di debugging, attraverso
metodi ...
dotNet Framework: Instrumentation
Il dotNet framework permette di personalizzare la visualizzazione delle informazioni
che...
dotNet Framework: Instrumentation
Anche l’applicazione scritta in modo perfetto (teroricamente) non troverà
gradimento da ...
dotNet Framework: Instrumentation
L’ultimo set di strumenti messi a disposizione dal namespece Systems.Diagnostics
sono i ...
dotNet Framework: Instrumentation
Vediamo un esempio concreto che consente l’enumerazione dei drive presenti nel sistema:
...
dotNet Framework: Application Security
Garantire la Sicurezza delle proprie Applicazioni
dotNet Framework: Application Security
Realizzare applicazioni SICURE che non effettuino operazioni indesiderate e non
con...
dotNet Framework: Application Security
Prima di continuare è utili far presente che la difficoltà maggiore nell’apprendere...
dotNet Framework: Application Security
Per riconoscere e classificare un assembly CAS utilizza l’EVIDENCE (ovvero: chi
sei...
dotNet Framework: Application Security
CAS utilizza le PERMISSION (ovvero: cosa vuoi fare?) per consentire ad un
assembly ...
dotNet Framework: Application Security
Il dotNet framework prevede 7 Permission Sets di default:
Permission Set Descriptio...
dotNet Framework: Application Security
In pratica grazie all’evidenze ed ai permission il codice gestito viene prima
contr...
dotNet Framework: Application Security
Grazie ai Code Groups è possibile collegare indirettamente i Permission Sets agli
A...
dotNet Framework: Application Security
L’ultimo elemento che compone le CAS è la SECURITY POLICY un insieme di
code group ...
Al runtime viene fatto il calcolo dei permessi effettivi:
1.
2.
Unione
Intersezione
void SetAppDomainPolicy(PolicyLevel do...
dotNet Framework: Application Security
CAS può essere configurato sia tramite riga di comando, attraverso l’utility CasPol...
dotNet Framework: Application Security
Fin ora abbiamo visto come gestire/impostare le CAS attraverso gli strumenti di sis...
Lo strumento principale sono le classi xxxPermission e relativi attributi che
permettono di chiedere alla CAS di eseguire ...
Nel caso si voglia applicare la CAS ad un assembly (obbligatoriamente in modo
Dichiarativo), bisogna definire la Action Pr...
SecurityException
• Demand
• disponibile anche come attributo
• verifica il permesso richiesto eseguendo lo
stack walk
• n...
• Assert e RevertAssert
• Impediscono che la richiesta di permesso
si propaghi ai chiamanti
• Assert si chiama al più tard...
dotNet Framework: Application Security
[FileIOPermission(SecurityAction.Demand, Write = @"C:Program Files")]
public static...
dotNet Framework: Application Security
Fin qui il discorso relativo alle CAS.
Poniamoci però un dubbio: cosa accade se il ...
dotNet Framework: Application Security
Abbiamo detto che il CAS è applicato al codice managed e agli assembly Partially Tr...
dotNet Framework: Interoperation
Interoperare con altre tecnologie
dotNet Framework: Interoperation
Se si decide di utilizzare le potenzialità del dotNet Framework possiamo affidarci
tranqu...
dotNet Framework: Interoperation
Mettiamo che la nostra software house abbia impiegato mesi per sviluppare uno
specifico c...
dotNet Framework: Interoperation
Per creare RCW possiamo servirci di Visual Studio o del tool da riga di comando
TlbImp.ex...
dotNet Framework: Interoperation
Nell’uso di oggetti COM in .NET bisogna fare attenzione in particolare a due aspetti:
• C...
dotNet Framework: Interoperation
Best practices
' VB
Module Module1
Private OptionalParamHandler As Object = Type.Missing
...
dotNet Framework: Interoperation
Il Secondo aspetto da tenere presente è la Gestione delle Eccezioni, ovvero come catturar...
dotNet Framework: Interoperation
Private Sub IllustrateExceptions()
Try
‘Something that throws an exception
Catch ex As Ex...
dotNet Framework: Interoperation
Oltre ad avere la necessità di riutilizzare componenti COM, potremmo trovarci nella situa...
dotNet Framework: Interoperation
Per creare correttamente un componente esportabile in COM, bisogna seguire alcune regole:...
dotNet Framework: Interoperation
Abbiamo parlato fin ora di oggetti COM, ma cosa accade se abbiamo bisogno di utilizzare u...
dotNet Framework: Interoperation
Il modo migliore per lavoare con P/Invoke, è quello di creare una classe wrapper per ogni...
dotNet Framework: Reflection
Scoprire il codice
dotNet Framework: Reflection
Attraverso la Reflection dotNET mette a disposizione un elaborato strumento che permette di
e...
dotNet Framework: Reflection
La domanda è: a cosa serve la Reflection?
Attraverso la Reflection è possibile ottenere infor...
dotNet Framework: Globalization
Rendere internazionali le proprie Applicazioni
dotNet Framework: Globalization
Il contesto geografico in cui un software verrà utilizzato è spesso un fattore sottovaluta...
dotNet Framework: Globalization
L’utilizzo della cultura appropriata è fondamentale quando, su sistemi internazionali, si
...
dotNet Framework: Globalization
Vediamo alcune situazioni pratiche.
Per rilevare la cultura corrente possiamo procedere ne...
dotNet Framework: Globalization
CurrentCulture rappresenta la cultura con cui vengono effettuate le manipolazioni durante
...
dotNet Framework: Globalization
Il risultato della
comparazione può essere
modificato passando alla
compare,come terzo
par...
dotNet Framework: Globalization
Nel caso in cui avessimo bisogno di creare una nostra cultura (caso molto raro ma non
assu...
Dot net framework 2
Upcoming SlideShare
Loading in...5
×

Dot net framework 2

2,168

Published on

Dot net framework 2 overview

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
2,168
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
17
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Dot net framework 2

  1. 1. Ing. Felice Pescatore felice.pescatore@poste.it Microsoft .Net Framework DotNet FRAMEWORK Architettura e Dettagli
  2. 2. Quale versione del Framework.NET? Questo corso sarà incentrato sulla versione 2 del dotNet Framework,nonostante sia stata rilasciata in versione definitiva la 3 e sia quasi pronta la 3.5. Ciò perché la versione 3 non modifica, sostanzialmente, l’architettura della versione 2, ma aggiunge uno strato superiore con funzionalità specifiche. Inoltre la maggior parte del software attualmente sviluppato, la maggior parte del materiale didattico, così come le Certificazioni Microsoft (MCTS e MCPD) si basano proprio sulla versione 2. Anche se non esplicitamente evidenziato tutto quanto presentato di seguito sarà comunque riferito alla versione 2. A conclusione del corso verrà dedicato uno spazio proprio per presentare le novità del dotNet 3.5, la cui uscita è prevista per gli inizi del 2008.
  3. 3. Certificazioni Microsoft: i percorsi Application Development Foundation Esame 70-536 Windows Based Client Development Esame 70-526 Design e Developing Windows Based Application Esame 70-548 Web Based Client Development Esame 70-528 Design e Developing Web Based Application Esame 70-547 Distribuited Applicatin Development Esame 70-529 Design e Developing Enterprise Application Esame 70-549
  4. 4. Certificazioni Microsoft: testi ufficiali
  5. 5. Certificazioni Microsoft: SQL Server Esame 70-431
  6. 6. Certificazioni Microsoft: Compendi Consigliati Serie Passo-Passo, di base Serie Programming • msdn2.microsoft.com/it-it/library/default.aspx • www.ugidotnet.org • www.aspitalia.com • www.dotnet2themax.it Autori: •Francesco Balena •Dino Esposito •Marco Bellinaso •David Sheppa
  7. 7. Architettura del dotNet Framework CONCETTI INTRODUTTIVI
  8. 8. Cos’ è il dotNet Framework Il Framework .NET e' la piattaforma di sviluppo di riferimento per il mondo Windows, grazie alla quale e' possibile realizzare soluzioni software a 360° in grado di rispondere alle esigenze più complesse. I Punti di forza sono da ricercarsi nella sconfinata libreria di base, in un architettura a strati che permette una evoluzione natura (.Net 3/3.5), nell’indipendenza dal linguaggio di programmazione e nella disponibilità del più evoluto ambiente di sviluppo attualmente esistente (Visual Studio)
  9. 9. dotNet presenta un’architettura a strati. Al suo interno possiamo distinguere gli elementi portanti dell’intero framework: Il dotNET Framework  CLR - Common Language Runtime  BCL - Base Class Library  ADO.NET & XML  Windows Forms  ASP.Net, Web Forms & Web Services  CLS – Common Language Specification  CTS – Common Type System
  10. 10. Il dotNET Framework: il CLR (1) Il COMMON LANGUAGE RUNTIME (CLR) è uno strato posto al di sopra dei servizi del sistema operativo. Esso è responsabile dell'esecuzione vera e propria delle applicazioni: assicura che vengano rispettate tutte le dipendenze, gestisce la memoria, la sicurezza, l'integrazione del linguaggio e così via. Il runtime fornisce numerosi servizi che consentono di semplificare la stesura del codice, la distribuzione dell'applicazione e di migliorare l'affidabilità della stessa.
  11. 11. Il .NET Framework: il CLR (2) •Semplificare lo sviluppo • Definire standard per il riuso del codice • Fornire servizi come gestione della memoria e garbage collection • Semplificare deployment delle applicazioni •I componenti usano i metadati anzichè la registrazione •Supportare più versioni • Deployement da riga di comando XCOPY e disinstallazione DEL • Eliminare l’uso del registro per i componenti e la necessità di codice extra per la loro gestione. • Supportare i linguaggi di sviluppo •Fornendo classi di base per gli strumenti e i linguaggi degli sviluppatori • Supportare più linguaggi di programmazione •Definire i CTS utilizzati da tutti i linguaggi .NET Con il CLR, Microsoft ha posto alcuni obiettivi cardine della propria tecnologia:
  12. 12. Il dotNET Framework: il CLR (3) Volendo fare un paragone con il mondo JAVA, il CLR è l’equivalente .NET della Java Virtual Machine (JVM): attiva gli oggetti, li sottopone a controlli di sicurezza, li dispone in memoria. Gli eseguibili .NET sono composti da Codice e Metadati. Questi ultimi contengono la definizione di tipo, informazione sulla versione e riferimenti ad Assembly esterni. Il Class Loader utilizza i metadati per il caricamento delle classi .NET, mentre i compilatori Just in Time (JIT) li utilizzano per compilare l’ Intermediate Language (IL)
  13. 13. Tutti i linguaggi .NET, attraverso il CLR, accedono al medesimo sistema di tipi e alle stesse classi base, ottenendo cosi una convergenza tra Linguaggi e Modelli di Programmazione Il codice eseguito dal CLR viene detto CODICE GESTITO (MANAGED CODE) ed è memorizzato come Codice+Metadati in un formato standard Windows PE (portable executable) che consente di: • Leggere i metadati • Fornire lo stack del codice • Gestire le eccezioni • Recuperare informazioni di sicurezza • Esistono “versioni del CLR” anche sotto Linux e Mac Os X (vedi MONO) che consentono di eseguire il codice in formato PE anche in macchine non Windows rendendo .NET un framework multipiattaforma Il dotNET Framework: il CLR (4)
  14. 14. Il dotNET Framework: la BCL Difatti, prima del dotNet Framework, gli Ingegneri del Software dovevano pianificare la realizzazione di una applicazione scegliendo preventivamente il linguaggio e di conseguenza si limitavano le librerie in base a quelle supportate dallo stesso. La BCL permette invece di scegliere, teoricamente anche in fase di sviluppo, il linguaggio più opportuno per il task da eseguire, permettendone una sostanziale interoperabilità, al patto di rispettare le specifiche minime necessarie. La Base Class Library (BCL) è l’insieme delle librerie funzionali comuni ad ogni linguaggio basato sulla piattaforma dotNet, e comprende: Tipi dato complessi (collezioni), Networking, Accesso al file system, Interfaccia utente, Sicurezza,Programmazione concorrente, XML e molto altro
  15. 15. Il dotNET Framework: ADO.NET Praticamente tutte le applicazioni hanno la necessità di interrogare o aggiornare dati persistenti memorizzati in file piatti, database relazionali o altri tipi di supporto di memorizzazione. Per ovviare a tale necessità, il .NET Framework include ADO.NET, un sottosistema per l'accesso ai dati ottimizzato per ambienti N-tier ed interoperabile con l'XML ed i documenti XML. ADO.NET è stato progettato per gli ambienti debolmente accoppiati e per fornire servizi per l'accesso ai dati ad applicazioni scalabili e servizi basati sul Web. ADO.NET mette a disposizione API ad elevate Prestazioni per modelli di dati sia connessi sia Disconnessi particolarmente adatti alla restituzione di dati alle applicazioni Web.
  16. 16. Il dotNET Framework: XML XML svolge un ruolo fondamentale in nel .NET framework, sin dalla sua prima versione, essendo utilizzato per descrivere la applicazioni (metadati) in modo analogo ai deployment descriptor di Java. Inoltre è spesso la base di comunicazione per lo scambio dei dati tra due applicazioni (marshaling e serializzazione)
  17. 17. ASP.NET fornisce un modello applicativo sotto forma di CONTROLLI che semplifica la creazione di applicazioni Web. L’infrastruttura include un insieme di Controlli Lato Server che ricalcano gli oggetti Widget delle tipiche interfacce utente HTML (tra cui, caselle di riepilogo, caselle di testo e pulsanti), ed un insieme aggiuntivo di Controlli Web Evoluti (come calendari e rotator). Essi sono posizionati attraverso drag&drop sulle pagine, indicate in gergo Web Form. I controlli vengono eseguiti in realtà sul server Web ed inviano la propria interfaccia utente ad un browser sotto forma di HTML. Sul server, i controlli espongono un modello di programmazione orientato all'oggetto che mette a disposizione degli sviluppatori Web tutta la ricchezza di questo tipo di programmazione. Il dotNET Framework: ASP.NET
  18. 18. Il dotNET Framework: WindowsForms Le WindowsForms sono praticamente le classiche finestre di un’applicazione windows che contengono i classici elementi come bottoni,combobox, aree di testo ecc. Tutti i controlli posizionati su una WindowsForm (e la WindowsForm stessa, che è ugualmente un controllo) risponde ad una serie di eventi che lo sviluppatore può gestire attraverso l’implementazione di appositi Handler.
  19. 19. Il dotNET Framework: ASP.NET - WebForms Le WebForms sono l’equivalente delle WindowsForms, eccetto che il loro ambiente di esecuzione è il Browser Web. Esse vengono elaborate sul server e successivamente passate al browser nel classico formato HTML La fase di implementazione di una WebForm non si discosta molta da quella di una classica WindowsForm.
  20. 20. Il dotNET Framework: ASP.NET – XML Web Services I Web Services sono una sorta di piccoli servizi disponibili in rete, che forniscono funzionalità specializzate. Essi vengono interrogati attraverso il protocollo SOAP basato su XML.
  21. 21. Il dotNET Framework: CTS Il COMMON TYPE SYSTEM (CTS) definisce un insieme standard di tipi di dato e di regole necessarie per la realizzazione di nuovi tipi, consentendo ai vari linguaggi di interoperare correttamente tra loro CTS fornisce due tipi principali entrambi ereditati da System.Object: •Tipi a Valore, utili per rappresentare tipi di dati semplici e quelli definiti dall’utente (ovvero le strutture); •Tipi a Riferimento, ovvero: tipi di oggetti, tipi di interfacce e tipi di puntatori Da notare che in .NET tutti i tipi sono orientati agli oggetti (ogni elemento è un oggetto) e i tipi a valore possono essere convertiti in tipi a riferimento mediante il boxing CTS definisce, inoltre, un modello uniforme per la gestione delle eccezioni, indipendentemente dal linguaggio utilizzato (ovviamente con sintassi diverse). Si tratta in praticamente di definire i seguenti passi:  Lanciare un’eccezione  Catturare un’eccezione  Codice di uscita da un blocco controllato (finally)
  22. 22. Il dotNET Framework: CTS, Tipi a Valore I Tipi a Valore non possono essere null (tranne i NULLABLE che sono un discorso a parte) e devono sempre contenere dei dati. Possono essere: : primitivi, strutture e enumerazioni; Per creare un tipo a valore personalizzato anche derivandolo da una classe System.ValueType, proprio come fa dotNet per i tipi primitivi. Prendendo ad esempio il tipo int, si vede che esso non è nient’altro che un alias di System.Int32 derivato appunto da Sysem.ValueType. E’ utile sottolineare che il passaggio di un Tipo a Valore in una funzione avviene per copia
  23. 23. Il dotNET Framework: CTS, Tipi a Riferimento I Tipi a Riferimento rappresentano il riferimento ad oggetti allocati nell’Heap (a differenza dei tipi a valore allocati sullo Stack), ed ammettono il valore Null. Il passaggio a funzioni avviene per riferimento, cioè viene passato un indirizzo o un puntatore ad un oggetto. Questi tipi vengono gestiti dal CLR e sottoposti a GARBAGE COLLECTION. CTS promuove la sicurezza di tipi in modo da migliorare la stabilità del codice, attraverso definizioni dei tipi completamente note e che non possono essere alterate. Ciò si traduce nel fatto che i riferimenti agli oggetti siano strongly-typed,ovvero durante la fase di assegnazione di un oggetto ad un reference viene verificato se sono di tipo compatibile.
  24. 24. Il dotNET Framework: CLS Le COMMON LANGUAGE SPECIFICATION, definiscono le regole che un linguaggio deve avere per essere gestito dal framework, permettendo l’interoperabilità tra i vari linguaggi supportati dal dotNet Framework. In pratica descrivo come il compilatore deve trasformare il codice sorgente nel codice intermedio (Intermediate Language – IL), per essere compatibile con le specifiche del framework. Il CLS, inoltre, definisce le API dei componenti .NET
  25. 25. Esecuzione di applicazioni dotNET Compilazione ed Esecuzione di codice dotNET
  26. 26. Source code C++, C#, Visual Basic o Altria language .NET es: Csc.exe o Vbc.exe Compilatore Assembly DLL o EXE L’applicativo, scritto in uno dei linguaggi supportati, viene compilato, generando così un ASSEMBLY, che nonostante l’estensione,è un packaging composto da più elementi. Compilazione e Generazione dell’Assembly
  27. 27. Un ASSEMBLY rappresenta il costituente fondamentale di un'applicazione .NET. Si tratta dell’unità elementare di rilascio del codice e di gestione delle versioni, ed è composto da: •Un manifesto (Manifest); •Un insieme di uno o più moduli (dll o exe); •Un insieme opzionale di risorse Tutti i tipi e le risorse gestiti sono contrassegnati in uno dei seguenti modi: • accessibili solo all'interno della propria unità implementativa • esportabili per essere utilizzati dal codice al di fuori di tale unità. Assembly dotNet
  28. 28. Type Descriptions Classes Base classes Implemented interfaces Data members Methods Name Version Culture Assembly Manifest Other assemblies Security permissions Exported types Assembly Manifest: Descrizione • Stabilisce l'identità dell'assembly in termini di nome, versione, livello di condivisione tra applicazioni diverse, firma digitale. •Definisce quali file (nome e file hash) costituiscono l'implementazione dell'assembly. •Specifica le dipendenze in fase di compilazione da altri assembly. •Specifica i tipi e le risorse che costituiscono l'assembly, inclusi quelli che vengono esportati dall'assembly. •Specifica l'insieme dei permessi necessari al corretto funzionamento dell'assembly. Gli assembly si autodescrivono tramite il proprio MANIFEST (manifesto), che costituisce una parte integrante di ogni assembly stesso:
  29. 29. Assembly Manifest: Uso dei Metadati I METADATI sono indipendenti dal linguaggio, consentendo a quelli che vi accedono di interpretarli in modo univoco. Questo permette di creare progetti (assistiti da IDE come Visual Studio) che contengono al loro interno codice sorgente di linguaggi diversi, proprio grazie alle informazioni contenute nei metadati dei componenti; Il compilatore genera i metadati di un componente dal codice sorgente che vengono memorizzati nel codice compilato in un formato PE (Portable Executable); Un tools per la visualizzazione dei metadati è ildasm.exe
  30. 30. Assembly: Execution Model, Intermediate Language Come detto il Codice Sorgente viene compilato nel linguaggio intermedio IL, spesso indicato anche come MSIL (Microsoft IL) e CIL (Common IL). Vediamo un esempio di IL: .method private hidebysig static void Main() cil managed { .entrypoint // Code size 11 (0xb) .maxstack 8 IL_0000: ldstr "Hello, world!" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method HelloWorld::Main
  31. 31. Assembly: Execution Model Gli assembly sono caricati in memoria dal CLR solo all’occorrenza: • prima viene determinata la versione • poi viene cercato l’assembly nella Global Assembly Cache (GAC) oppure nel percorso locale indicato dal codice base; Prima dell’esecuzione il CLR deve procedere alla compilazione dell’ IL (non eseguibile direttamente dal processore) per la generazione di codice nativo. Ci sono due possibilità: • Compilazione del Metodo a Tempo di Esecuzione, Just In Time (JIT); • Compilazione di tutto l’Assembly prima dell’esecuzione Come già accennato in precedenza, il CLR permette di limitare le funzionalità del codice eseguito.
  32. 32. Assembly: Execution Model Schema Compilazione Esecuzione JIT Compiler Native Code MSIL Code Metadata Source Code Language Compiler Assembly (.exe o .dll) Compilazione Just in Time
  33. 33. Assembly: Deployment semplificato Sicuramente il Deployment rappresenta uno dei grossi vantaggi di dotNet, permettendo: • Un’installazione senza effetti collaterali (dll Hell), le applicazioni e i componenti possono sempre essere condivisi o privati; • L’esecuzione Side-by-Side, diverse versioni dello stesso componente possono coesistere, anche nello stesso processo Il Deployment può avvenire in modi diversi: • XCOPY, per le applicazioni ASP.NET • .CAB, per le applicazioni • Windows Forms - Code Download • .MSI (Windows Installer), per le Applicazioni Windows Forms l’ installazione in GAC di assembly condivisi, la Configurazione di shortcut
  34. 34. Assembly Location Avendo parlato di deployment è utile specificare le location che gli assembly possono assumere in base alla loro tipologia:  Assembly privati, directory applicazione (e sub-directory)  Assembly condivisi, Global Assembly Cache (GAC) (c:windowsassembly)  Assembly scaricati da URL, download cache (c:Documents and Settings%USERNAME% Local SettingsApplication Dataassemblydl2) Il Tool per esaminare GAC e download cache è GACUTIL.EXE
  35. 35. Oggetti “vivi” Oggetti non raggiungibili Spazio libero Garbage Collection(1) Fase 1: Mark Durante l’esecuzione del codice gli oggetti non più utilizzati come vengono deallocati dalla memoria? dotNet distrugge automaticamente gli oggetti quando non sono più referenziati, utilizzando un sofisticato algoritmo di Mark-and-Compact NextObjPtr Root set
  36. 36. www.devleap.it Oggetti “vivi” Spazio libero NextObjPtr Root set Spazio recuperato Garbage Collection (2) Fase 2: Compact
  37. 37. Non sempre ci si può affidare in modo “cieco” al Garbage Collector, ma in alcuni casi serve un comportamento di finalizzazione deterministica. In particolare quando si hanno:  Riferimenti a oggetti non gestiti  Utilizzo di risorse che devono essere rilasciate appena termina il loro utilizzo Non si possono usare i finalizzatori (come si fa in C++), che sono richiamabili direttamente, ma bisogna utilizzare l’interfaccia IDisposable, implementando il metodo Dispose. Garbage Collection(3)
  38. 38. Linguaggi del dotNet Framework Come più volte ribadito fin ora , il dotNet Framework è LANGUAGE- INDEPENDED, ovvero non dipende dal linguaggio scelto. Microsoft fornisce direttamente il supporto (ed il compilatore) per: •C++, C#, J#, VB 2005, Jscript Esistono, comunque, implementazione di terze parti che spesso permettono di portare sulla piattaforma dotNet linguaggi molto utilizzati: •Perl, Ruby, Python, Pascal, APL, COBOL, Eiffel, Haskell, ML, Oberon, Scheme, Smalltalk… Chiunque, rispettando le CLS può realizzare (in teoria) il proprio linguaggio dotNet Ready
  39. 39. Base Class ed Interfacce Le Classi e le Interfacce della BCL
  40. 40. Base Class ed Interfacce: Namespaces Base Class Library Data Xml Web Services User Interface
  41. 41. Base Class ed Interfacce: Namespaces System System.Data System.Xml System.Web Globalization Diagnostics Configuration Collections Resources Reflection IO Threading Text Security SqlClient OleDb SQLTypes Common Runtime InteropServices Remoting Serialization Configuration SessionState Caching Security UI HtmlControls WebControls System.Drawing Imaging Drawing2D Text Printing System.Windows.Forms Design ComponentModel XPath Xsl Serialization Schema Hosting Handlers Compilation
  42. 42. Base Class ed Interfacce: Namespaces System Threading Text Security Resources Reflection IO Globalization Diagnostics Configuration Collections Runtime Serialization Remoting InteropServices
  43. 43. Base Class ed Interfacce: Namespaces System.Data System.Xml OracleClient OleDb Sql/SqlClient Common Serialization Schema XPath Xsl Odbc Messaging
  44. 44. System.Web Caching Configuration UI SessionState HtmlControls WebControls Security Handlers Hosting Compilation Management Profile Services dotNet Framework: Namespaces
  45. 45. System.Drawing Drawing Design Printing Text System.Windows.Forms Design ComponentModel dotNet Framework: Namespaces VisualStyles
  46. 46. Input / Output Input e Output con dotNet
  47. 47. dotNet Framework: Input / Output Una delle principali attività che ci si trova a realizzare è l’interazione con il (i) file system. dotNet mette a disposizione un insieme di classi raccolte nel NameSpace System.IO, che permettono di effettuare operazioni di vario genere su file, directory,ecc:  FILEINFO and DIRECTORYINFO (base class: FileSystemInfo), permettono di interrogare ogni elemento del file system per ottenerne informazioni di vario genere  DRIVEINFO, permette di ottenere informazione sulle periferiche di I/O  FILE, DIRECTORY, PATH sono le “utility class” che permettono, attraverso metodi statici, di effettuare varie operazioni sui corrispettivi elementi
  48. 48. dotNet Framework: I/O, ottenere informazioni dal File System FileInfo ourFile = new FileInfo(@"c:boot.ini "); if (ourFile.Exists) { Console.WriteLine("Filename : {0}", ourFile.Name); Console.WriteLine("Path : {0}", ourFile.FullName); } Ottenere informazione su un file FileInfo ourFile = new FileInfo(@"c:boot.ini"); ourFile.CopyTo(@"c:boot.bak"); Copiare un file Enumerare I file in una directory DirectoryInfo ourDir = new DirectoryInfo(@"c:windows"); Console.WriteLine("Directory: {0}", ourDir.FullName); foreach (FileInfo file in ourDir.GetFiles()) { Console.WriteLine("File: {0}", file.Name); }
  49. 49. Per effettuare le operazioni di lettura e scrittura, il.Net Framework fornisce gli STREAM (letteralmente flussi), che permettono un accesso sequenziale e random ai dati. La classe base (di tipo astratta) è Stream,che fornisce una serie di funzionalità comuni a tutti gli stream specializzati. Tra gli Stream Personalizzati: •FileStream, specializzato nelle operazioni di lettura/scrittura dei file •Memory Stream, crea un flusso in memoria (utili per operazioni temporanee) •Buffered Stream, crea un wrapper per lo stream specifico allo scopo di migliorarne le performance; •StreamReader (base class: TextReader), consente operazioni di lettura su stream generici •StreamWriter (base class: TextWriter), consente operazioni di scrittura su stream generici dotNet Framework: Gli Stream
  50. 50. dotNet Framework: aprire uno Stream su file L’apertura degli Stream, relativi alla lettura/scrittura file, avviene attraverso una serie di classi statiche ed enumeratori presenti nel Namespace System.IO: •File, fornisce le funzionalità di base per leggere e scrivere da file; •Directory, per effettuare operazioni sulle directory •FileAccess Enumeration, che specifica i diritti (Read, Write, ReadWrite) da applicare all’apertura di un file; •FileMode Enumeration specifica i diritti sui file che si andranno ad aprire. File.Open(@"C:boot.ini", FileMode.Open, FileAccess.Read); File.Create(@"c:somefile.txt"); Aprire un file per la lettura Creare un file
  51. 51. dotNet Framework: Leggere/Scrivere da un file FileStream theFile = File.Open(@"C:boot.ini", FileMode.Open, FileAccess.Read); StreamReader rdr = new StreamReader(theFile); Console.Write(rdr.ReadToEnd()); rdr.Close(); theFile.Close(); StreamReader rdr = File.OpenText(@"C:boot.ini"); Console.Write(rdr.ReadToEnd()); rdr.Close(); FileStream theFile = File.Create(@"c:somefile.txt"); StreamWriter writer = new StreamWriter(theFile); writer.WriteLine("Hello"); writer.Close(); theFile.Close(); File.WriteAllText(@"c:somefile.txt", "Hello"); Leggere da file Scrivere su file
  52. 52. dotNet Framework: Usare il MemoryStream MemoryStream memStrm = new MemoryStream(); StreamWriter writer = new StreamWriter(memStrm); writer.WriteLine("Hello"); writer.WriteLine("Goodbye"); writer.Flush(); FileStream theFile = File.Create(@"c:inmemory.txt"); memStrm.WriteTo(theFile); writer.Close(); theFile.Close(); memStrm.Close(); Scrittura su uno Stream in Memoria e successivo riversamento su file
  53. 53. dotNet Framework: Stream Speciali Oltre agli stream che permetto una normale lettura/scrittura da file o memoria, esistono una speciale categoria di stream definiti Compression Stream Attualmente sono disponibili due Compression Stream: •GZipStream, che permette la compressione compatibile con lo standard de- facto zip; •DeflateStream, che crea una compressione proprietaria. In realtà entrambi gli stream usano lo stesso algoritmo per la compressione. La differenza sta nel fatto che la compatibilità con lo standard zip richiede un header apposito e quindi un ulteriore (anche se lieve) aggravio di risorse. Una sostanziale differenza con gli stream classici, come vedremo dagli esempi, è che i compression stream scrivono i dati su stream di appoggio (file, memoria). Infine, è da precisare, che entrambi i compression stream possono gestire al massimo 4Gb di dati. L’esempio che segue mostra la compressione/decompressione con la classe GZipStream. Per utilizzare il DelfateStream basta sostituire l’istruzione di creazione dell‘oggetto
  54. 54. FileStream sourceFile = File.OpenRead(inFilename); FileStream destFile = File.Create(outFilename); GZipStream compStream = new GZipStream(destFile, CompressionMode.Compress); int theByte = sourceFile.ReadByte(); while (theByte != -1) { compStream.WriteByte((byte)theByte); theByte = sourceFile.ReadByte(); } FileStream sourceFile = File.OpenRead(inFilename); FileStream destFile = File.Create(outFilename); GZipStream compStream = new GZipStream(sourceFile, CompressionMode.Decompress); int theByte = compStream.ReadByte(); while (theByte != -1) { destFile.WriteByte((byte)theByte); theByte = compStream.ReadByte(); } dotNet Framework: Comprimere/Decomprimere con gli stream Compressione Decompressione
  55. 55. dotNet Framework: Working with Text Lavorare con le Stringhe ed il Testo
  56. 56. dotNet Framework: Working with Text  Lavorare con le stringhe di testo è un task comune per tutti gli sviluppatori  .Net mette a disposizione un insieme di classi raccolte nel NameSpace System.Text, che permettono di effettuare operazioni di vario genere sulle stringhe:  StringBuilder, permette una manipolazione efficiente delle stringhe;  Regex, Match, Group, permettono l’elaborazione delle stringhe attraverso le Espressioni Regolari;  Encode/Decode, sono specializzate nella codifica/decofica delle stringhe nei vari formati internazionali.
  57. 57. dotNet Framework: La classe StringBuilder e la classe String • Normalmente si è portati ad utilizzare la classe String per le operazioni sulle stringhe. • In realtà un oggetto di tipo String è un oggetto atipico, perché ogni operazione su di esso (tipo l’aggiunta di nuovi caratteri alla stringa), non modifica l’oggetto esistente, bensì ne crea uno nuovo aggiornando il reference. • Per migliorare le performance (ed evitare inutili sprechi di memoria) il .Net framework prevede la classe StringBuilder, che crea un oggetto stringa dinamico System.Text.StringBuilder sb = new System.Text.StringBuilder(30); sb.Append("wombat"); sb.Append(" kangaroo"); sb.Append(" wallaby"); sb.Append(" koala"); string s = sb.ToString(); Console.WriteLine(s);
  58. 58. dotNet Framework: Regular Expression • Le Espressioni Regolari (Regular Expression) sono una eredità del mondo Unix e del linguaggio PERL. • Rappresentano un modo efficiente per effettuare elaborazioni complesse sulle stringhe di testo. Come esempio, la seguente Regular Expression, permette di validare un indirizzo email: • Nella pratica l’utilizzo di Espressioni Regolari può risultare anche molto complesso e non approfondiremo uteriormente l’argomento. •Comunque il modo più semplice per verificare se una stringa supera la verifica rispetto ad una Espressione Regolare (MATCH) è quello di usare la classe Regex e il metodo statico IsMatch: ^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$ Regex.IsMatch("pattern", @"ApatternZ")
  59. 59. dotNet Framework: Codifica del Testo • Vista l’eterogeneità dei sistemi informatici esistenti, non meraviglia che esistano diversi modi di codificare (o meglio, rappresentare) le stringhe. • La codifica più utilizzata nello scorso decennio è stata quella ASCII (7bit), ormai insufficiente per codificare adeguatamente anche caratteri speciali (come le lettere degli alfabeti orientali). •Oggi la codifica più utilizzata è la Unicode UTF-16 (16 bit), che è anche la codifica base utilizzata dal framework .Net. •Nel caso si renda necessario lavorare con codifiche differenti, è possibile utilizzare le classi Encode/Decode come mostrato dall’esempio seguente: // Get Korean encoding Encoding e = Encoding.GetEncoding("Korean"); // Convert ASCII bytes to Korean encoding byte[] encoded; encoded = e.GetBytes("Hello, world!"); // Display the byte codes for (int i = 0; i < encoded.Length; i++) Console.WriteLine("Byte {0}: {1}", i, encoded[i]);
  60. 60. dotNet Framework: Collection & Generics Lavorare su insiemi di oggetti
  61. 61. dotNet Framework: Collection & Generics Ogni framework che si rispetti deve avere un’ampia serie di collezioni (collection) che permettono di gestire un insieme di oggetti, più o meno omogeneei, attraverso i classici costrutti dei moderni linguaggi. dotNet contempla al suo interno l’implementazione delle COLLECTION CLASSICHE e dei GENERICS La differenza sostanziale tra le due è che le Collection Classiche memorizzano al loro interno gli oggetti attraverso il casting, mentre nel caso dei Generics la categoria di oggetti contenuti nella collection è tipizzata. Le Generics portano in dote vantaggi di performance (molto limitati in realtà), ma soprattutto una programmazione type-safe, in cui è il compilatore a verificare il corretto utilizzo della collezzione.
  62. 62. dotNet Framework: Collection Classiche Le Collection Classiche sono contenute nel NameSpace System.Collections e annoverano: •ArrayList, una semplice collezione ridimensionabile ed indicizzata; •SortedList, una collezione ordinata composta da coppie nome/valore; •Queue, la classica coda; struttura FIFO (first in first out); •Stack, ovvero last in last out, LIFO; •Hashtable, una collezione nome/valore; •BitArray, una collezione compatta di valorie Boolean; •StringCollection, collezione specializzata per le stringhe; •StringDictionay, ovvero una hashtable specializzata per le stringhe; •ListDictionary, una collezione nome/valore ottimizzata per piccole quantità di dati; •HybridDictionary, una collezione nome/valore ibrida. Per piccole quantità di dati si comporta come una ListDictionary, altrimenti come una Hashtable La System.Collctions prevede tre interfacce di base: •IEnumerable (rende enumerabile la lista), •ICollection (rende omogenee le funzionalità di base), •IList (estende le funzionalità di base comuni).
  63. 63. La System.Collctions prevede tre interfacce di base: •IEnumerable (rende enumerabile la lista), •ICollection (rende omogenee le funzionalità di base), •IList (estende le funzionalità di base comuni). Grazie a queste tre interfacce è possibile operare uniformemente sulle varie Collection Classiche, attraverso i classici metodi: insert, remove, add, e così via. dotNet Framework: Collection Classiche Nota a parte merita la possibilità di effettuare l’ordinamento (collection.Sort) di una Collezione. Infatti l’ordinamento varia in base al tipo di oggetto inserito nella collezione Per questo è possibile definire un propria classe di ordinamento (che deve implementare l‘interfaccia IComparer) e della quale un’istanza può essere passata al metodo Sort: coll.Sort(new CaseInsensitiveComparer());
  64. 64.  I generics sono stati introdotti dalla versione 2 del framework e sono formati da classi e metodi che lavorano in modo uniforme su tipi differenti  Benefici  Le variabili sono di un tipo ben preciso e non Object  Non è necessario un cast (errori in fase di compilazione)  Riutilizzo reale del codice class Stack<T> { private T[] store; private int size; public Stack() { store = new T[10]; size = 0; } public void Push(T x) { // push code goes here } public T Pop() { return store[--size]; } } void Add(Stack<int> s) { int x = s.Pop(); int y = s.Pop(); s.Push(x+y); } dotNet Framework: Generics
  65. 65. dotNet Framework: Generics Tra le implementazioni si annoverano: • List<>, ovvero una semplice lista di elementi; • Queue<>, la coda (FIFO); • Stack<>, lo stack (LIFO); • Dictionary<>, collezione nome/valore; • SortedList<>, lista di elementi ordinati; • SortedDictionay <>, collezione nome/valore ordinata; • NameValuePair<>, coppia nome/valore (in pratica è ritornato dall’iterazione sul dictionary); • LinkedList<>, lista linkata; Tra le interfacce troviamo: •IList<ItemType> •IDictionary<K, V> •IEnumerable<ItemType> •IComparable<OperandType>
  66. 66. ArrayList myList = new ArrayList(); myList.Add(1); // Viene effettuato il boxing (value -> refernce) myList.Add(2); // Viene effettuato il boxing (value -> refernce) myList.Add(“3"); // Provocherà un errore a runtime int i = (int)myList[0]; // Necessario effettuare il cast List<int> myList = new List<int>(); myList.Add(1); // Nessun boxing myList.Add(2); // Nessun boxing // myList.Add(“3"); // Errore a tempo di compilazione int i = myList[0]; // Nessun casting richiesto Non-generic Generic dotNet Framework: Generics vs. Collection Classiche
  67. 67. Rappresentazione senza Generics Rappresentazione con Generics intobject intobject intobject intobject intobject int int int int int int int Push Pop Box Unbox Push Pop dotNet Framework: Generics vs. Collection Classiche
  68. 68. dotNet Framework: Serialization Persistere lo Stato di un Oggetto
  69. 69. dotNet Framework: Serialization La Serializzazione permette di salvare un oggetto (e, quindi, il suo attuale stato) in modo persistente su un supporto di memorizzazione, ma anche di inviare lo stesso oggetto attraverso le reti per un utilizzo remoto. Il dotNet Framework permette la serializzazione attraverso opportune classi contenute nel namespace System.Runtime.Serialization: •BinayFormatter, permette di serializzare un oggetto in formato binario e trasferirlo su uno stream; •SoapFormatter , permette di serializzare un oggetto in formato XML aderente allo standard SOAP e nel namespace System.Xml.Serialization •XmlSerializer, permette di serializzare un oggetto in formato XML
  70. 70. dotNet Framework: Serialization Il dotNet framework utilizza un modo semplice ed immediato per rendere serializzabile un oggetto: [Serializable] class ShoppingCartItem { public int productId; public decimal price; … … <Serializable()> Class ShoppingCartItem Public productId As Integer Public price As Decimal … … VBC# basta, in pratica, inserire l’attributo [serializable] per rendere la classe serializzabile. La serializzazione comunque può essere parziale, escludendo alcuni elementi, come di seguito mostrato: ' VB <NonSerialized()> Public total As Decimal // C# [NonSerialized] public decimal total;
  71. 71. dotNet Framework: Serialization, IDeserializationCallback Nel caso in cui si abbiano dei membri (variabili di istanza) calcolati, si può decidere di non serializzarne il valore (per risparmiare spazio), facendolo ricalcolare durante la serializzazione attraverso l’interfaccia IDeserializationCallback ed il relativo metodo IDeserializationCallback.OnDeserialization [Serializable] class ShoppingCartItem : IDeserializationCallback { public int productId; public decimal price; public int quantity; [NonSerialized] public decimal total; public ShoppingCartItem(int _productID, decimal _price, int _quantity) { productId = _productID; price = _price; quantity = _quantity; total = price * quantity; } void IDeserializationCallback.OnDeserialization(Object sender) { / / After deserialization, calculate the total total = price * quantity; } }
  72. 72. dotNet Framework: Binary Serialization Come detto, la serializzazione avviene mediante le classi prima descritte e riversando i dati ottenuti su uno stream. Vediamo alcuni esempi: string data = "This must be stored in a file."; FileStream fs = new FileStream("SerializedString.Data", FileMode.Create); BinaryFormatter bf = new BinaryFormatter(); // Use the BinaryFormatter object to serialize the data to the file bf.Serialize(fs, data); fs.Close(); FileStream fs = new FileStream("SerializedString.Data", FileMode.Open); BinaryFormatter bf = new BinaryFormatter(); // Create the object to store the deserialized data string data = ""; data = (string) bf.Deserialize(fs); fs.Close(); Serializzazione Deserializzazione Se si volesse utilizzare la serializzazione compatibile con lo standard SOAP, basta sostiture BinaryFormatter con SoapFormatter
  73. 73. dotNet Framework: XML Serialization Nel caso in cui si voglia rendere il risultato della serializzazione il più portabile possibile, si può ricorrere alla serializzazione XML. L’oggetto da serializzare, in questo caso, deve seguire regole più stringenti: • la classe deve essere pubblica • tutti i membri da serializzare devono essere pubblici • deve esistere un costruttore senza parametri espressamente dichiarato // Create file to save the data to FileStream fs = new FileStream("SerializedDate.XML", FileMode.Create); // Create an XmlSerializer object to perform the serialization XmlSerializer xs = new XmlSerializer(typeof(DateTime)); xs.Serialize(fs, System.DateTime.Now); fs.close(); // Open file to read the data from FileStream fs = new FileStream("SerializedDate.XML", FileMode.Open); // Create an XmlSerializer object to perform the deserialization XmlSerializer xs = new XmlSerializer(typeof(DateTime)); DateTime previousTime = (DateTime)xs.Deserialize(fs); fs.close(); Serializzazione Deserializzazione
  74. 74. dotNet Framework: Custom Serialization Se le precedenti forme di serializzazione non sono adeguate ai nostri scopi (caso molto raro) possiamo procedere a realizzare una serializzazione personalizzata. Ciò si può ottenere implementando l’Interfaccia Iserializable (conseguentemente il metodo GetObjectData) ed applicando l’attributo [serializable] alla classe. Tuttavia esiste un metodo più immediato, ma ovviamente meno flessibile, per controllare la serializzazione e quindi personalizzarla: i Serialization Events. Si tratta di eventi che si scatenano utilizzando il BinaryFormatter e sono: •Serializing, scatenato prima di inizializzare la serializzazione; •Serialized, scatenato dopo la serializzazione; •Deserializing, scatenato prima della deserializzazione; •Deserialized, scatenato dopo la deserializzazione; è possibile catturare questi eventi, e gestirli nel modo più opportuno, creando degli appositi metodi all’interno della classe da serializzare e applicandovi l’attributo corrispondente all’evento da catturare: [OnDeserialized] void CheckTotal(StreamingContext sc) { if (total == 0) { CalculateTotal(sc); } }
  75. 75. dotNet Framework: Graphics Grafica elementare
  76. 76. dotNet Framework: Graphics dotNet offre gli strumenti base per la creazione di semplici elementi grafici (linee, cerchi, ecc.), tutti contenuti nel namespace System.Drawing. Attraverso gli strumenti offerti è possibile: •Aggiungere forme all’UI in modo dinamico; •Creare diagrammi; •Editare e ridimensionare immagini; •Cambiare il grado di compressione di una immagine; •Zoommare immagini; •Aggiungere un logo di copyright o del testo ad una immagine. Tra le classi primarie di questo namespace troviamo: Bitmap, Brush, Font, Graphics, Icon, Image e Pen. Un ruolo importante rivestono inoltre le strutture di questo namespace (ad es. Color o Point), che permettono di impostare o modificare gli elementi del disegno.
  77. 77. dotNet Framework: Graphics Per disegnare una linea o una figura base, bisogna eseguire tre passi fondamentali: •Creare un oggetto Graphics, partendo dalla form o dal controllo attuale, attraverso il metodo System.Windows.Forms.Control.CreateGraphics; •Creare un oggetto Pen; •Chiamare un metodo dell’oggetto Graphics per disegnare sul controllo usando l’oggetto Pen // Create a graphics object from the form Graphics g = this.CreateGraphics(); // Create a pen object with which to draw Pen p = new Pen(Color.Red, 7); // Draw the line g.DrawLine(p, 1, 1, 100, 100); Graphics g = this.CreateGraphics(); Pen p = new Pen(Color.Blue, 3); g.DrawPie(p, 1, 1, 100, 100, -30, 60);
  78. 78. dotNet Framework: Graphics Invece di utilizzare l’oggetto Pen, in abbinamento con il metodo graphics.drawXXX, è possibile utilizzare un oggetto Brush (e il metodo graphics.fillXXX) per poter creare figure con riempimento. Graphics g = this.CreateGraphics(); Brush b = new SolidBrush(Color.Maroon); Point[] points = new Point[] {new Point(10, 10), new Point(10, 100), new Point(50, 65), new Point(100, 100), new Point(85, 40)}; g.FillPolygon(b, points);
  79. 79. dotNet Framework: Graphics Grazie alle implementazioni della classe astratta System.Drawing.Image, è possibile elaborare immagini esistenti o crearne di nuove. Questa classe astratta trova nel framework due implementazione: •System.Drawing.Bitmp, per le immagini; •System.Drwaing.Imaging.Metafile, per le immagini animate; Nonostante Image sia una abastract class è possibile utilizzare i metodi implementati per ottenerne un’istanza: Image i = Image.FromFile(@"C:windowsgone fishing.bmp"); pictureBox1.BackgroundImage = i; Se si vuole creare e salvare una nuova immagine si lavoro pressappoco come negli esempi precedenti, eccetto che la creazione dell’oggetto graphics avviene attraverso un metodo apposito: Bitmap bm = new Bitmap(600, 600); Graphics g = Graphics.FromImage(bm); Brush b = new LinearGradientBrush(new Point(1, 1), new Point(600, 600), Color.White,Color.Red); Point[] points = new Point[] {new Point(10, 10), new Point(77, 500), new Point(590, 100), new Point(250, 590), new Point(300, 410)}; g.FillPolygon(b, points); bm.Save("bm.jpg", ImageFormat.Jpeg);
  80. 80. dotNet Framework: Graphics Attraverso le funzionalità di System.Drawing è possibile creare anche testo sotto forma di immagine, utile, ad esempio, se si desidera “marchiare” una foto con un proprio identificativo. Graphics g = this.CreateGraphics(); Font f = new Font("Arial", 40, FontStyle.Bold); g.DrawString("Hello, World!", f, Brushes.Blue, 10, 10); Infine il namespace in esame prevede una classe apposita per disegnare/visualizzare le icone di sistema: Graphics g = this.CreateGraphics(); g.DrawIcon(SystemIcons.Question, 40, 40);
  81. 81. dotNet Framework: Threading Esecuzione Concorrente di Attività
  82. 82. dotNet Framework: Threading Grazie all’utilizzo dei Thread è possibile dotare l’applicazione di più flussi paralleli che possono portare ad un sostanziale miglioramento prestazionale della stessa ed a una migliore interazione utente-applicazione. Il namespace di riferimento è il System.Threading, che annovera la classe Thread e l’enumerazione ThreadState. La creazione di un nuovo thread, effettuabile in qualsiasi parte del codice, avviene attraverso i seguenti passi: 1. Creare un metodo senza parametri e senza argomenti di ritorno: 2. Creare un delegato ThredStart, specificando il metodo creato nel passo 1 3. Creare un nuovo oggetto Thread, specificando il treadstart creato al passo 2 4. Chiamare il metodo Thred.Start per avviare il thread static void SimpleWork() { Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId); }
  83. 83. dotNet Framework: Threading In sintesi ecco il codice per avviare un thread: Se è necessario passare informazioni al thread è possibile utilizzare il delegate ParameterizedThreadStart: ThreadStart operation = new ThreadStart(SimpleWork); // Creates, but does not start, a new thread Thread theThread = new Thread(operation); // Starts the work on a new thread theThread.Start(); ThreadStart operation = new ThreadStart(SimpleWork); for (int x = 1; x <= 5; ++x) { Thread theThread = new Thread(operation); theThread.Start(); } static void WorkWithParameter(object o) { string info = (string) o; for (int x = 0; x < 10; ++x) { Console.WriteLine("{0}: {1}", info, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(10); } } ParameterizedThreadStart operation = new ParameterizedThreadStart(WorkWithParameter); Thread theThread = new Thread(operation); theThread.Start("Hello"); hread newThread = new Thread(operation); newThread.Start("Goodbye"); Il parametro passato deve essere sempre un oggetto.
  84. 84. dotNet Framework: richiamo I DELEGATI (Delegate) sono una sorta di CallBack (per chi conosce C++) o più semplicemente puntatori a funzione (C). Essi vengono ampiamente usati in .Net per la gestione degli eventi, quindi per la definizione dell’Handler. La grande differenza rispetto ai linguaggi non gestiti è che i Delegati sono type- safe, ovvero vengono gestiti esattamente come un oggetto la cui signature è ben definita.
  85. 85. dotNet Framework: Threading La classe Thread fornisce i metodi necessari per gestire in modo corretto il flusso di eleborazione: • Thread.Start, avvia il thread • Thread.Join, ferma l’esecuzione del chiamante finchè il nuovo thread non termina; • Thread.Abort, abortisce l’esecuzione del thread e solleva una ThreadAbortException; • Thread.IsAlive, verifica se il thread corrente è in esecuzione; • Thread.Priority, ritorna/setta la priorità del thread; • Thread.IsBackground, ritorna/setta lo stato di background del thread;
  86. 86. dotNet Framework: Threading Per consentire la condivisione di memoria (quindi dei parametri) tra i vari thread evitando collisioni, il dotNet framework fornisce opportuni strumenti che ne regolano l’accesso. Se stiamo lavorando con variabili condivise ed abbiamo necessità di fare operazioni di in(de)cremento possiamo avvalerci delle funzionlità della classe Interlocked: la classe interlocked “blinda” il parametro su cui opera, rendendo le operazioni atomiche static void UpdateCount() { for (int x = 1; x <= 10000; ++x) { Interlocked.Increment(ref Counter.Count); } }
  87. 87. dotNet Framework: Threading Se abbiamo bisogno di “blindare” più istruzioni in modo da renderle atomiche, possiamo ricorre al lock: in realtà il lock è basato sulla classe Monitor che permette un più fine controllo sul codice da blindare. Il dotNet framework supporta inoltre i seguenti metodi di sincronizzazione: • Mutex class • Semaphore class • AutoResetEvent class • ManualResetEvent class public void UpdateCount() { lock (this) { count = _count + 1; if (Count % 2 == 0) evenCount = evenCount + 1; } }
  88. 88. dotNet Framework: Threading Non è sempre necessario creare un nuovo thread per avviare attività in parallelo. Infatti il framework dotNet implementa l’ Asynchronous Programming Model (APM), che permette l’esecuzione di porzioni di codice in thread separati. Molte classi supportano APM fornendo le versioni BeginXXX e EndXXX di metodi classici. Come esempio immaginiamo la lettura di un file: potremmo voler realizzare la lettura (lenta) attraverso un flusso parallelo per non bloccare la fruibilità dell’applicativo. Invece di creare un thread separato, possiamo procedere come di seguito: byte[] buffer = new byte[100]; string filename = string.Concat(Environment.SystemDirectory, "mfc71.pdb"); FileStream strm = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous); // Make the asynchronous call IAsyncResult result = strm.BeginRead(buffer, 0, buffer.Length, null, null); // Do some work here while you wait // Calling EndRead will block until the Async work is complete int numBytes = strm.EndRead(result); // Don't forget to close the stream strm.Close(); Console.WriteLine("Read {0} Bytes", numBytes); Console.WriteLine(BitConverter.ToString(buffer));
  89. 89. dotNet Framework: Threading L’utilizzo del modello APM pone una domanda fondamentale: quando verificare la fine del flusso parallelo avviato? Possiamo individuare tre stili: •Wait-until-done, consiste nell’avviare la richiesta, eseguire (eventualmente) altre operazioni ed attendere il termine della richiesta; •Polling, simile al precedente solo che c’è un controllo ciclico del termine della richiesta; •Callback, si crea un delegato che viene passato alla BeginXXX e viene invocato dal framework al termine della richiesta. L’ultimo aspetto da rilevare è che eventuali exception vengono sollevate solo in seguito alla chiamata della EndXXX e non nel momento in cui si verificano
  90. 90. dotNet Framework: Threading ….. // Make the asynchronous call strm.Read(buffer, 0, buffer.Length); IAsyncResult result = strm.BeginRead(buffer, 0, buffer.Length, null, null); // Do some work here while you wait // Calling EndRead will block until the Async work is complete int numBytes = strm.EndRead(result); ….. // Make the asynchronous call IAsyncResult result = strm.BeginRead(buffer, 0, buffer.Length, null, null); // Poll testing to see if complete while (!result.IsCompleted) { // Do more work here if the call isn't complete Thread.Sleep(100); } // Finished, so we can call EndRead and it will return without blocking int numBytes = strm.EndRead(result); ….
  91. 91. …. // Make the asynchronous call IAsyncResult result = strm.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(CompleteRead), strm); } … //Callback Metod static void CompleteRead(IAsyncResult result) { Console.WriteLine("Read Completed"); FileStream strm = (FileStream) result.AsyncState; // Finished, so we can call EndRead and it will return without blocking int numBytes = strm.EndRead(result); // Don't forget to close the stream strm.Close(); Console.WriteLine("Read {0} Bytes", numBytes); Console.WriteLine(BitConverter.ToString(buffer)); } dotNet Framework: Threading
  92. 92. dotNet Framework: Application Domain & Services Isolare il Codice Sconosciuto
  93. 93. Spesso è necessario lavorare con assembly esterni, che possono impattare sia sulle performace/stabilità del nostro applicativo, sia sulla sicurezza. Il modo migliore per utilizzare un assembly esterno è quello di utilizzare un Application Domain. dotNet Framework: Application Domain & Services Processo AppDomain Assembly Shared Assembly AppDomain Assembly Shared Assembly Grazie agli Application Domain è possibile caricare, all’interno dello stesso processo, più assembly separatamente tra di loro, in modo che eventuali anomalie non vadano ad impattare l’intero processo o gli altri assembly
  94. 94. La classe che permette la gestione degli Application Domain è la System.AppDomain. Vediamo ora alcuni esempi concreti di utilizzo degli Application Domain: dotNet Framework: Application Domain & Services AppDomain d = AppDomain.CreateDomain("NewDomain"); AppDomain d = AppDomain.CreateDomain("NewDomain"); d.ExecuteAssemblyByName("Assembly"); AppDomain d = AppDomain.CreateDomain("NewDomain"); ….. AppDomain.Unload(d) Creazione Caricamento di un Assembly Unload di un Assembly E’ bene notare che se sa in anticipo di voler effettuare l’unload dell’assembly che si va a caricare, l’unico modo per farlo è attraverso un Application Domain
  95. 95. Come ci si aspetterebbe, per poter controllare il livello di isolamento di un Application Domain (quindi utilizzarlo come una sandbox) il dotNet framework mette a disposizione una serie di strumenti per configurarlo, attraverso gli Evidence, di cui discuteremo in seguito. Basti sapere che essi permettono di classificare l’AppDomain ed assegnargli delle restrizioni e dei permessi sulle attività da svolgere. Possiamo applicare le restrizioni sia per un singolo assembly e sia per l’intero Application Domain: dotNet Framework: Application Domain & Services object [] hostEvidence = {new Zone(SecurityZone.Internet)}; Evidence internetEvidence = new Evidence(hostEvidence, null); AppDomain myDomain = AppDomain.CreateDomain("MyDomain"); myDomain.ExecuteAssembly("SecondAssembly.exe", internetEvidence); object [] hostEvidence = {new Zone(SecurityZone.Internet)}; Evidence appDomainEvidence = new Evidence(hostEvidence, null); AppDomain d = AppDomain.CreateDomain("MyDomain", appDomainEvidence); d.ExecuteAssembly("SecondAssembly.exe"); Attraverso la classe System. AppDomainSetup è infine possibile controllare ogni ulteriore aspetto di configurazione (dir di base, configuration file, ecc.)
  96. 96. I Windows Services (servizi di windows) sono una gamma di applicativi privi di UI che, funzionando in background, svolgono attività cicliche monitorando lo stato del sistema. La creazione di un servizio avviene utilizzando il template di VS ServiceBase, ed implementando il metodi OnStart e OnStop come minimo. Successivamente bisogna creare un’Installer per il servizio che non può essere avviato come semplici applicativo. Una volta installato, il servizio può essere gestito sia attraverso il classici Strumenti di Amministrazione di Windows che attraverso codice (quindi da un assembly esterno) attraverso la classe System.ServiceProcess.ServiceController: dotNet Framework: Application Domain & Services // Connect to the Server service ServiceController sc = new ServiceController("Server"); sc.Stop(); // Stop the service // Wait two seconds before starting the service Thread.Sleep(2000); sc.Start(); // Start the service
  97. 97. dotNet Framework: Configuring Application Rendere dinamica un’applicazione attraverso la sua configurazione
  98. 98. dotNet Framework: Configuring Application Parola d’ordine: evitare le configurazioni HardCoding, ovvero quelle inserite all’interno del codice e quindi impossibili da modificare se non attraverso i sorgenti. Sarà capitato a tutti, ad esempio, di inserire direttamente all’interno della propria classe la stringa di connessione ad un DB e di dover poi rimettere mano al codice perché l’RDBMS di rilascio usa credenziali diverse di quelle del sistama di Test . Ebbene, grazie agli strumenti messi a disposizione dal namespace System.Configuration e ai file di confirgurazione XML sarà davvero semplice evitare queste situazioni. Questo namespace include due classi principali: ConfigurationManager e Configuration. Di default ogni applicazione ha un proprio file di configurazione utilizzato per la sua inizializzazione: nomeapplicazione.exe.conf
  99. 99. dotNet Framework: Configuring Application Vediamo un esempio di file di configurazione: <?xml version="1.0" encoding="utf-8" ?> <configuration> <runtime> <supportedRuntime version="v1.1.4322" /> </runtime> <appSettings> <add key="Foo" value="Hello World!"/> </appSettings> <connectionStrings> <clear/> <add name="AdventureWorksString" providerName="System.Data.SqlClient“ connectionString="Data Source=localhost; Initial Catalog=AdventureWorks; Integrated Security=true"/> </connectionStrings> </configuration>
  100. 100. dotNet Framework: Configuring Application In esso possiamo distinguere tre sezioni principali: • <runtime>, in cui sono riportate le impostazioni riguardanti l’esecuzione dell’assemby . Nel caso in esempio la versione del framework supportata. •<appSettings>, sono parametri di cui si serve l’applicazione e che vengono recuperati durante la sua esecuzione •<connectionStrings>, questa sezione è dedicata a contenere esclusivamente le stringhe di connessione alle base dati (possono essere più di una) // C# NameValueCollection AllAppSettings = ConfigurationManager.AppSettings; Console.WriteLine(AllAppSettings["Foo"]); Console.WriteLine(AllAppSettings[0]); ' VB Dim AllAppSettings As NameValueCollection = ConfigurationManager.AppSettings Console.WriteLine(AllAppSettings("Foo")) Console.WriteLine(AllAppSettings(0)) Vediamo ora come recuperare i valori appSettings salvati nel file di Configurazione:
  101. 101. dotNet Framework: Configuring Application La sezione ConnectionStrings è leggermente diversa poiché può contenere dichiarazioni multiple: possiamo sia recuperare la prima connectionString: <?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <clear/> <add name="AdventureWorksString“ providerName="System.Data.SqlClient“ connectionString="Data Source=localhost;Initial Catalog=AdventureWorks; Integrated Security=true"/> <add name="MarsEnabledSqlServer2005String“ providerName="System.Data.SqlClient“ connectionString= "Server=Aron1;Database=pubs; Trusted_Connection=True;MultipleActiveResultSets=true" /> </connectionStrings> </configuration> ConnectionStringSettings MySettings = ConfigurationManager.ConnectionStrings[0]; sia iterare su esse ottenendole la collection: ConnectionStringSettingsCollection ConnectionStrings = ConnectionStringsSection.ConnectionStrings;
  102. 102. dotNet Framework: Configuring Application Oltre al file di configurazione dell’applicazione dotNET prevede la possibilità di creare molteplici file XML per evitare proprio l’hard coding e quindi contenere coppie parametri/valori. Tali file vengono poi gestiti direttamente da una classe wrapper specifica. <userSettings> <WindowsApplication2.SampleSettings /> </userSettings> <applicationSettings> <WindowsApplication2.SampleSettings> <setting name="WebServiceUrl" serializeAs="String"> <value>http://www.adatum.com/myservice.asmx</value> </setting> </WindowsApplication2.SampleSettings> </applicationSettings> nell‘esempio sono visibili 2 aree userSettings e applicationSetting che suddividono lo scope dei parametri.
  103. 103. dotNet Framework: Configuring Application Per definire un nuovo file di configurazione ed auto-generare la relativa classe è conveniente affidarsi a VS: Aggiungere un nuovo elemento al progetto di tipo Settings File Dopo la creazione del Settings File, VS aprirà un apposito Application Settings Designer, che potrà essere utilizzato per definire i parametri in ogni loro aspetto (nome, tipo, visibilità-scope, valore).
  104. 104. dotNet Framework: Configuring Application Salvando il nuovo file di settaggio, troveremo due nuovi elementi nel nostro progetto: 1. Sample.settings, il file XML 2. Sample.cs (.vb), la relativa classe autogenerata Per usare i parametri basta creare una nuova classe del tipo al punto 2 e richiamarne le proprietà: ' VB Dim mySettings as new SampleSettings() Debug.WriteLine(mySettings.WebServiceUrl) // C# SampleSettings mySettings = new SampleSettings(); Debug.WriteLine(mySettings.WebServiceUrl);
  105. 105. dotNet Framework: Instrumentation Ottimizzare la propria Applicazione
  106. 106. dotNet Framework: Instrumentation Sotto il nome Instrumentation Micorsoft ha raccolto tutti gli strumenti (ovviamente parliamo di classi, interfacce, enumeratori, ecc.) utilizzabili per: • Gestire i Log • Effettuare il Debugging ed il Tracing • Monitorare le Performance • Controllare i Device di Sistema, le Applicazioni ed il Sistema stesso Tutti questi “strumenti” sono contenuti nel namespace System.Diagnostics Da notare che operando direttamente a contatto con il sistema e siano di semplice utilizzo, essi possono impattare sulle performance del sistema ed inoltre provocare problemi di sicurezza nelle classi partial-trust (in particolare per i Log). Quindi essi vanno utilizzati con parsimonia e molta attenzione.
  107. 107. dotNet Framework: Instrumentation Praticamente è impossibile conoscere tutti gli scenari in cui la nostra applicazione verrà eseguita, vista l’infinita possibilità di combinazioni Hw/Sw oggi possibili. Inoltre nonostante ci si sforzi di creare applicazioni prive di bug, qualcuno, prima o poi, ne verrà fuori. Il problema è che sono sempre gli utenti finali ad accorgersi dei bug più insidiosi, e difficilmente essi riescono a segnalare il problema in modo corretto (in fin dei conti perché dovrebbero saperlo farlo, non sono certo dei tecnici!). Proprio in questo scenario ci vengono in aiuto gli strumenti di Logging Events, che permettono alla nostra applicazione di inserire informazioni specifiche all’interno dei log (siano essi quelli di sistema o quelli proprietari dell’applicazione). Tutto il meccanismo si basa sulla classe EventLog, attraverso la quale scrivere o legge un evento in un log è un’operazione banale: public static void CreateEventLog() { EventLog DemoLog = new EventLog("Chap10Demo"); DemoLog.Source = "Chap10Demo"; DemoLog.WriteEntry("CreateEventLog called", EventLogEntryType.Information); } public static void ReadEventLog() { EventLog DemoLog = new EventLog(); DemoLog.Log = "Chap10Demo"; foreach (EventLogEntry DemoEntry in DemoLog.Entries) { Console.WriteLine(DemoEntry.Source + ":" + DemoEntry.Message); }}
  108. 108. dotNet Framework: Instrumentation La fase di Debugging è una delle più importanti nello sviluppo di un nuovo applicativo, in quanto permette di analizzarne il comportamento alla ricerca di errori nella logica di funzionamento. Il dotNet framework basa l’azione di debugging su due classi fondamentali (sempre del namespace Systems.Diagnostics): Debugger e Debug Debugger permette di abilitare la connessione ad un debugger (operazione svolta automaticamente dall’IDE VS). Infatti difficilmente si utilizzerà in modo diretto tale classe, essendo possibile utilizzare gli strumenti integrati dell’IDE. Ad esempio uno dei metodi di Debugger è debugger.Break() che permette di inserire un punto di break-point all’interno del codice, esattamente come si fa cliccando al lato sinistro in Visual Studio. Prima di proseguire con la più interessante classe Debug è utile sottolineare che tutte le operazioni connesse vengono eseguite solo se l’ambiente si è in fase di debugging. In fase di compilazione per deployment, le righe di codice relative vengono scartate. Nel caso si vogliano utilizzare tali funzionalità anche in ambiente di deployment si fa ricorso alla classe Trace funzionalmente identica.
  109. 109. dotNet Framework: Instrumentation La classe Debug consente un controllo fine sul processo di debugging, attraverso metodi diretti, tra cui il più importante è sicuramente Debug.Assert. Assert permette di testare se una determinata condizione è vera e, in caso affermativo, generare un alert: Similare ad Assert è Fail che permette di lanciare un alert senza verificare una condizione. Altri metodi presenti sono: debug.write, debug.writeif, debug.writeline, debug.writelineif, debug.print, debug.flush. NameValueCollection MySettings = ConfigurationManager.AppSettings; Debug.Assert(MySettings != null && MySettings["Foo"] != null, "There was a problem with either the configuration file or the Foo Setting"); Console.WriteLine(MySettings["Foo"]);
  110. 110. dotNet Framework: Instrumentation Il dotNet framework permette di personalizzare la visualizzazione delle informazioni che il debugger visualizza e come esso si comporta attraverso opportuni attributi, che andiamo ad elencare: •DebuggerBrowsableAttribute •DebuggerDisplayAttribute •DebuggerHiddenAttribute •DebuggerNonUserCodeAttribute •DebuggerStepperBoundaryAttribute •DebuggerStepThroughAttribute •DebuggerTypeProxyAttribute •DebuggerVisualizerAttribute la loro utilità dipende dal grado di dettaglio che lo sviluppatore vuole ottenere durante il debugger e una loro padronanza è possibile solo con l’utilizzo pratico.
  111. 111. dotNet Framework: Instrumentation Anche l’applicazione scritta in modo perfetto (teroricamente) non troverà gradimento da parte del cliente se non risponde in modo tempestivo alle sue richieste: ecco il concetto di performace. Non ci addentreremo nel dettaglio di queste funzionalità (gestite attraverso le classi Process e il componente/oggetto PerformanceCounter) anche perché si tratta di attività di ottimizzazione dell’applicazione che vengono, purtroppo, raramente effettuate. La cosa da tener presente è che quando si verifica un problema non sempre esso è dovuto ad un errore o un flusso di istruzioni errate, ma può anche essere dovuto a scarse performance dell’ambiente che il cliente sente come errore dell’applicativo.
  112. 112. dotNet Framework: Instrumentation L’ultimo set di strumenti messi a disposizione dal namespece Systems.Diagnostics sono i Windows Management Instrumentation (WMI). Attraverso di essi è possibile ottenere informazioni riguardanti ogni aspetto delle risorse del computer, come: Drive, Adattatori di Rete, Servizi, ecc. WMI utilizza una serie di passi ed un linguaggio di interrogazione simile alle query SQL, attraverso la classe DirectoryObjectSearcher. Infatti per ottenere informazioni specifiche bisogna: 1. Dichiarare un’istanza di ConnectionOptions, e settare le proprietà UserName e Password (per motivi di security di accesso); 2. Dichiarare un’istanza di DirectoryObjectSearcher; 3. Creare un oggetto ManagementScope e settarne le proprietà PathName e ConnectionOptions 4. Creare un oggetto ObjectQuery e specificare la query da eseguire; 5. Creare un oggetto ManagementObjectCollection, e assegnargli il valore di ritorno del metodo DirectoryObjectSearcher.Get;
  113. 113. dotNet Framework: Instrumentation Vediamo un esempio concreto che consente l’enumerazione dei drive presenti nel sistema: ConnectionOptions DemoOptions = new ConnectionOptions(); DemoOptions.Username = "Bill"; DemoOptions.Password = "mp99!!swa0"; ManagementScope DemoScope = new ManagementScope("machinename", DemoOptions); ObjectQuery DemoQuery = new ObjectQuery("SELECT Size, Name FROM Win32_LogicalDisk where DriveType=3"); ManagementObjectSearcher DemoSearcher = new ManagementObjectSearcher(DemoScope, DemoQuery); ManagementObjectCollection AllObjects = DemoSearcher.Get(); foreach (ManagementObject DemoObject in AllObjects) { Console.WriteLine("Resource Name: " + DemoObject["Name"].ToString()); Console.WriteLine("Resource Size: " + DemoObject["Size"].ToString()); } In modo altrettanto semplice è possibile ottenere informazioni riguardanti i Servizi di Sistema: private static void ListPausedServices() { ManagementObjectSearcher DemoSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_Service WHERE Started = FALSE"); ManagementObjectCollection AllObjects = DemoSearcher.Get(); foreach (ManagementObject PausedService in AllObjects) { Console.WriteLine("Service = " + PausedService["Caption"]); }}
  114. 114. dotNet Framework: Application Security Garantire la Sicurezza delle proprie Applicazioni
  115. 115. dotNet Framework: Application Security Realizzare applicazioni SICURE che non effettuino operazioni indesiderate e non consentite sui sistemi degli utilizzatori è ormai diventato un must. Attraverso le CAS, Code Access Security, è possibile limitare in modo granuale quello che il managed code può fare. Il concetto è simile ai diritti applicati ai ruoli degli utenti/gruppi (Role Based Security – RBS) all’interno del Sistema Operativo. Con CAS è possibile controllare l’accesso a: • File System • Registro • Stampanti • Log degli Eventi • Accesso al Web • … CAS è utilizzabile solo per controllare managed code, mentre il codice non gestito (come, tra l’altro, il codice gestito Full-Trust) non è soggetto alle restrizioni. Inoltre in nessun caso il codice eseguito può avere più permessi di quelli concessi all’utente che lo esegue. CAS si compone di 5 elementi fontamentali: Evicende, Permission, Permission Sets, Code Group e Security Policy.
  116. 116. dotNet Framework: Application Security Prima di continuare è utili far presente che la difficoltà maggiore nell’apprendere le CAS è nella terminologia usata, piuttosto che negli strumenti in se. • Evidence Prove di protezione • Strong name Nome sicuro • Code Group Gruppi di codice • Full trust Attendibilità totale • Partial trust Attendibilità parziale • Security Policy ... • Permission Autorizzazioni • Permission Set Set di autorizzazioni • Stack Walk ... • Assert ... • Demand ... • ... ...
  117. 117. dotNet Framework: Application Security Per riconoscere e classificare un assembly CAS utilizza l’EVIDENCE (ovvero: chi sei?), una sorta di identificativo dell’assembly. Evidence è la prova oggettiva per sapere di chi è o da dove proviene il codice managed La CAS può identificare un assembly basandosi su: •Cartella dove risiede •Sito o Url da cui viene scaricato •Zona in cui si trova •Strong Name presente nel suo manifest •Hash dell'assembly •Firma digitale (Authenticode, stessa degli Activex) Al caricamento dell'assembly in memoria, viene subito ricavata l'evidence. È possibile da codice associare una evidence ad un AppDomain in modo da isolare degli assembly.
  118. 118. dotNet Framework: Application Security CAS utilizza le PERMISSION (ovvero: cosa vuoi fare?) per consentire ad un assembly di porter effettuare determinate operazioni (per esempio l’apertura di una File Dialog Box). Il dotNet framework ne predefinisce un certo numero, trasversali a quelli più noti come NTFS, SQL, etc. Per ciascun permesso è possibile definire dei valori molto dettagliati, come mostra l’empio relativo all’accesso ai socket: dotNet prevede 19 permessi base contenuti nel namespace System.Security.Permissions, realative ad altrettante attività che possono impattare sulla sicurezza del sistema. Questi 19 permessi vengono spesso combinati tra loro per creare i Permission Sets ovvero set di permessi da applicare unitariamente ad un assembly.
  119. 119. dotNet Framework: Application Security Il dotNet framework prevede 7 Permission Sets di default: Permission Set Description FullTrust Esenta l’Assembly dall’essere sottoposto alle restirzioni CAS SkipVerification Permette all’Assembly di baipassare i controlli, aumentando le performance a scapito della sicurezza. Execution Garantisce all’Assembly solo il permesso di esecuzione e nessun altro Nothing Nessun permesso concesso, nemmeno quello di esecuzione LocalIntranet Garantisce un consistente numero di permessi, compreso quello di stampa e di accesso ai logo. L’accesso al File System è invece limitato alla sola apertura delle Open/Save dialog Box Internet Garantisce un ristretto numero di permessi, proprio in virtù della provenienza dell’assembly (internet) da un ambiente potenzialmente ostile. Everithing Garantisce tutti i permessi, ma a differenza del FullTrust l’assembly è comunque soggetto al controllo CAS.
  120. 120. dotNet Framework: Application Security In pratica grazie all’evidenze ed ai permission il codice gestito viene prima controllato e se le autorizzazioni di cui dispone sono sufficiente all’attività che si appresta a svolgere, ciò viene concesso. Esecuzione Permission Evidence CodiceAutenticazione Autorizzazione CAS
  121. 121. dotNet Framework: Application Security Grazie ai Code Groups è possibile collegare indirettamente i Permission Sets agli Assembli, consentendo in tal modo di riflettere una modifica del Pemission Sets applicato al Code Groups a tutti gli assembly relativi. Lo schema segue l’assegnazione degli utenti ai gruppi a cui sono associati i permessi (RBS Role Based Security). Permissi on Sets Code Grups Assembly (assegnati al gruppo attraverso l’evidence) Di default esistono 5 Code Groups: Code Group Evidence Permission Set My_Computer_Zone Zone: My Computer FullTrust LocalIntranet_Zone Zone: Local Intranet LocalIntranet Internet_Zone Zone: Internet Internet Restricted_Zone Zone: Untrusted sites Nothing Trusted_Zone Zone: Trusted sites Internet Ovviamente un assemby può appartenere a più Code Grups. In tal caso i permessi sono Il risultato dell’unione dei permessi dei singoli gruppi.
  122. 122. dotNet Framework: Application Security L’ultimo elemento che compone le CAS è la SECURITY POLICY un insieme di code group e permission sets che definiscono le politiche (policy) di sicurezza del sistema. Per default esistono 4 policy level di defalut: Enterprise, Machine (o Computer), User (o Utente) e Application Domain, che consentono un controllo minuto dei diritti concessi. Come è facile intuire dai nomi essi vanno dal livello più alto dell’ambiente (Enterprise) a quello più ristretto (Application Domain). Volendo essere semplici possiamo dire che le restrizioni Enterprise si applicano a tutto l’ambiente fino a giungere alle restrizioni di Application Domain specifiche del dominio di esecuzione. I diritti di cui un assembly dispone sono il risultato dell’intersezione delle policy dei vari livelli Enerprise Machine User App. Domain
  123. 123. Al runtime viene fatto il calcolo dei permessi effettivi: 1. 2. Unione Intersezione void SetAppDomainPolicy(PolicyLevel domainPolicy); dotNet Framework: Application Security
  124. 124. dotNet Framework: Application Security CAS può essere configurato sia tramite riga di comando, attraverso l’utility CasPol, sia attraverso il Framework Configuration Toolkit Code Groups Permission Set Security Policy Policy Assemblies
  125. 125. dotNet Framework: Application Security Fin ora abbiamo visto come gestire/impostare le CAS attraverso gli strumenti di sistema forniti dal framework. Ovviamente esiste la possibilità di impostare le permission di un assembly in modo esplicito direttamente dal codice. Per fare ciò è possibile ricorre a due soluzioni: 1. Declarative Security, fa uso di attributi ed è l’unico applicabile all’intero assembly; 2. Imperative Security, fa uso di apposite classi ed è utilizzabile per proteggere specifiche porzioni di codice. L’utilizzo degli attributi (quindi declarative) è utile anche all’amministratore di sistema per determinare di quali diritti ha bisogno il nostro assembly. [assembly:FileIOPermissionAttribute(SecurityAction.RequestMinimum, Read=@"C:boot.ini")] namespace DeclarativeExample { class Program { …. Dichiarativo Try { // Assembly logic } Catch { EventLogPermission errorPerms = new EventLogPermission(PermissionState.Unrestricted); errorPerms.PermitOnly(); // Log event CodeAccessPermission.RevertPermitOnly(); } Imperativo
  126. 126. Lo strumento principale sono le classi xxxPermission e relativi attributi che permettono di chiedere alla CAS di eseguire controlli e, se necessario lanciare la SecurityException ISecurityEncodable IStackWalk IPermission FileIOPermission UIPermission EnvironmentPermssion PermissionSet FileIOPermission Attribute UIPermission Attribute EnvironmentPermssion Attribute CodeAccessPermission Attribute CodeAccessPermission dotNet Framework: Application Security
  127. 127. Nel caso si voglia applicare la CAS ad un assembly (obbligatoriamente in modo Dichiarativo), bisogna definire la Action Property secondo uno dei seguenti valori dell’enumerazione SecurityAction: • RequestMinimum. La permission indicata è indispensabile per l'assembly altrimenti l'assembly non viene caricato. • RequestOptional. Permessi aggiuntivi rispetto al minimo indispensabile. Vengono dati all'assembly solo se disponibili. • RequestRefuse. Permessi che questo assembly decide di togliersi per evitare di essere usato da codice malicious. Se sono specificati RequestOptional e RequestRefuse allora verranno attribuiti all'assembly solo quei permessi anche se le policy sono più alte. Il tool PermView permette di vedere nell'assembly i requisiti di security dotNet Framework: Application Security
  128. 128. SecurityException • Demand • disponibile anche come attributo • verifica il permesso richiesto eseguendo lo stack walk • notare che Metodo4 non è soggetto ad alcun controllo. Il controllo è sui chiamanti • LinkDemand • solo come attributo • verifica il permesso richiesto solo sul chiamante senza eseguire stack walk • il controllo viene eseguito dal jitter • InheritanceDemand • solo come attributo • verifica il permesso richiesto sulle classi che derivano da quella su cui è applicato l'attributo • il controllo viene eseguito al load OK Demand Stack walk Metodo1 Metodo2 Metodo3 Metodo4 permission negata Stack walk // Richiesta imperativa ... FileIOPermission perm = new FileIOPermission( FileIOPermissionAccess.AllAccess, @"c:"); perm.Demand(); // ... oppure dichiarativa (classe/metodo) [assembly:FileIOPermission( SecurityAction.Demand, All = @"C:") ] dotNet Framework: Application Security Nel caso si voglia applicare la CAS a elementi del codice come classi, metodi o parte di esso (in modo Diarativo o Imperativo), bisogna definire i cosiddetti stack walk modifiers:
  129. 129. • Assert e RevertAssert • Impediscono che la richiesta di permesso si propaghi ai chiamanti • Assert si chiama al più tardi e RevertAssert al più presto • Utile per evitare perdite di performance dovute al controllo della CAS • Deny e RevertDeny • Impedisce che tutti i metodi chiamati da questo possano accedere alla risorsa (...) • PermitOnly e RevertPermitOnly • Permette a tutti i metodi chiamati da questo di poter accedere solo alla risorsa specificata (...) Gli stack walk modifiers vengono rimossi automaticamente alla fine del metodo che li chiama oppure chiamando esplicitamente il corrispondente Revert Deny e PermitOnly si usano su un metodo chiamante mentre RequestRefuse solo sull'assembly chiamato OK Demand Stack walk Metodo2 Metodo3 Metodo4 permission negata Assert dotNet Framework: Application Security Metodo1
  130. 130. dotNet Framework: Application Security [FileIOPermission(SecurityAction.Demand, Write = @"C:Program Files")] public static void createProgramFolder() { // Method logic } [WebPermission(SecurityAction.Demand, ConnectPattern = @"http://www.microsoft.com/.*")] public static void requestWebPage() { public static void createProgramFolder() { try { FileIOPermission filePermissions = new FileIOPermission(FileIOPermissionAccess.Write, @"C:Program Files"); filePermissions.Demand(); // Method logic } catch { // Error-handling logic } } public static void requestWebPage() { try { Regex connectPattern = new Regex(@"http://www.microsoft.com/.*"); WebPermission webPermissions = new WebPermission(NetworkAccess.Connect, connectPattern); webPermissions.Demand(); // Method logic } catch { // Error-handling logic } } Vediamo due esempi di una stessa restrizione attraverso l’uso dichiarativo e imperativo: Dichiarativo Imperativo
  131. 131. dotNet Framework: Application Security Fin qui il discorso relativo alle CAS. Poniamoci però un dubbio: cosa accade se il nostro applicativo ha bisogno di uno spazio temporaneo su disco ma non ha sufficienti permission? In tal caso si ricorre all’Isolated Storage, ovvero un area protetta e riservata su disco su cui l’assembly può lavorare senza problemi. Si può definire uno storage isolato sulla base di: • Identità del codice dell'applicazione • Identità dell'utente e gestirlo attraverso il namespace dedicato: System.IO.IsolatedStorage Come è prevedibile la lettura/scrittura nello storage isolato avviene tramite stream: IsolatedStorageFile userStore = IsolatedStorageFile.GetUserStoreForAssembly(); IsolatedStorageFileStream userStream = new IsolatedStorageFileStream("UserSettings.set", FileMode.Create, userStore); StreamWriter userWriter = new StreamWriter(userStream); userWriter.WriteLine("User Prefs"); userWriter.Close();
  132. 132. dotNet Framework: Application Security Abbiamo detto che il CAS è applicato al codice managed e agli assembly Partially Trusted. Se vogliamo, invece, rendere un assemply Full Trusted, dobbiamo firmarlo, ovvero assegnargli uno Strong Name Le specifiche ECMA raccomandano l'uso dello strong name (che dovrebbe essere "aziendale" e ben custodito) solo per il versioning e MAI per sicurezza, questo perché esistono sistemi per ingannare il CLR e far caricare un Assembly tampered anche se firmato con strong name. Comunque lo Strong Name è necesarrio qualora si voglia registrare l’assembly nella GAC (Global Assembly Cache) Infine, se un assembly partially trusted chiama un full trusted con strong name, questo necessita dell'attributo: [assembly:AllowPartiallyTrustedCallers]
  133. 133. dotNet Framework: Interoperation Interoperare con altre tecnologie
  134. 134. dotNet Framework: Interoperation Se si decide di utilizzare le potenzialità del dotNet Framework possiamo affidarci tranquillamente alla sua infrastruttura e guardare con convinzione al managed code. Esiste tuttavia la possibilità che, per svariati motivi, ci si trovi in una delle situazioni seguenti: • necessità di riutilizzare componenti COM (Component Object Model) proprietari; • necessità di creare componenti COM da integrare in sistemi legacy preesistenti • necessità lavorare direttamente con le API di sistema; Per assisterci in tutti e tre i casi, dotNet ci viene in aiuto con gli strumenti messi a disposizione dal namespace: System.Runtime.InteropServices
  135. 135. dotNet Framework: Interoperation Mettiamo che la nostra software house abbia impiegato mesi per sviluppare uno specifico componente COM (analisi, progettazione, sviluppo, testing, collaudo,ecc.), myCom. Ora nuove necessità hanno portato l’azienda a sposare il dotNet Framework. In questo nuovo contesto si desidera però recuperare myCom. Come si può procedere? Anche in questo caso il dotNet Framework ci da una mano, mettendoci a disposizione gli strumenti per creare un wrapper chiamato Runtime Callable Wrapper (RCW) che lavoro secondo il pattern proxy. Detto in soldoni: si esegue un automatismo del framework (o Visual Studio), si ottiene il wrapper e lo si usa come una normale l libreria dotNet. Purtroppo non sempre i tool automatizzati riescono a generare l’RCW.In tal caso bisogna procedere manualmente come mostrato a breve.
  136. 136. dotNet Framework: Interoperation Per creare RCW possiamo servirci di Visual Studio o del tool da riga di comando TlbImp.exe. Nel caso si usi VS, basta selezionare il progetto (nella finestra Esplora Soluzioni), clicckare con il tasto destro e scegliere Aggiungi Riferimento. Nella finestra che si aprirà scegliere il Tab “COM” e quindi il proprio componente. Una volta confermata l’operazione VS, se tutto va a buon fine,aggiunge il riferimento dell’oggetto COM alla libreria e a quel punto è possibile utilizzarlo come un normale componete/libreria dotNET. Se si desidera operare attraverso TlbImp, basta procedere dando il seguente comando: il risultato sarà una libreria .dll con lo stesso nome dell’originale, da referenziare nel nostro progetto dotNet. tlbimp <dllname>.dll
  137. 137. dotNet Framework: Interoperation Nell’uso di oggetti COM in .NET bisogna fare attenzione in particolare a due aspetti: • COM supporta i parametri opzionali (così come VBASIC),mentre ciò non è vero per C#. Per poter essere eseguito bisogna, in C#, comunque passare tutti i parametri, anche se opzionali. dotNet in tal senso introduce un oggetto vuoto attraverso la classe Type.Missing, che è possibile utilizzare allo scopo ed evidenziare subito il suo significato (evitando la confusione che si creerebbe con oggetti “dummy” ovvero creati solo per sopperire al problema). In realtà una best-practices è quella di usare tali oggetti anche in VB, poiché Microsoft sembra intenzionata ad eliminare il supporto ai parametri opzionali ' VB Imports Microsoft.Office.Core Imports Microsoft.Office.Interop.Excel Dim NewExcelApp As New Microsoft.Office.Interop.Excel.Application 'This works fine NewExcelApp.Worksheets.Add() // C# using Microsoft.Office.Core using Microsoft.Office.Interop.Excel Application NewExcelApp = new Application(); // This will not comipile. NewExcelApp.Worksheets.Add();
  138. 138. dotNet Framework: Interoperation Best practices ' VB Module Module1 Private OptionalParamHandler As Object = Type.Missing Sub Main() Dim NewExcelApp As New Microsoft.Office.Interop.Excel.Application NewExcelApp.Worksheets.Add(OptionalParamHandler, OptionalParamHandler, _ OptionalParamHandler, OptionalParamHandler) End Sub End Module // C# class Program { private static Object OptionalParamHandler = Type.Missing; static void Main(string[] args) { Application NewExcelApp = new Application(); NewExcelApp.Worksheets.Add(ref OptionalParamHandler, ref OptionalParamHandler, ref OptionalParamHandler, ref OptionalParamHandler); } }
  139. 139. dotNet Framework: Interoperation Il Secondo aspetto da tenere presente è la Gestione delle Eccezioni, ovvero come catturare e rispondere alle eccezioni generate da un oggetto COM – RCW. A differenza di quanto accedeva con la versione 1.x del dotNet Framework, nella versione 2 è stata introdotta la classe RuntimeWrappedException appartenente al namespace System.Runtime.CompilerServices, che permette di gestire le eccezioni COM esattamente come se fossero eccezioni standard del CLS. Al verificarsi di un’eccezione COM, dotNet crea un oggetto di tipo RuntimeWrappedException, ed assegna alla sua proprietà WrappedException l’oggetto stesso che ha catturato l’eccezione per consentire di gestirlo in modo appropriato. Se per qualsiasi motivi si dovesse avere la necessità di gestire eventuali eccezioni COM attraverso il nuovo formato, è possibili disabilitarle attraverso appositi attributi: ' VB Imports System.Runtime.CompilerServices [assembly: runtimeCompatibility(WrapNonExceptionThrows=false)] // C# using System.Runtime.CompilerServices; [assembly: RuntimeCompatibility(WrapNonExceptionThrows=false)]
  140. 140. dotNet Framework: Interoperation Private Sub IllustrateExceptions() Try ‘Something that throws an exception Catch ex As Exception ' In the previous versions this will catch only CLS-Compliant ' In the current version both CLS and Non CLS-Compliant will be caught by this block. End Try ' There is no equivalent for Catch without an exception ' because it's considered unreachable. End Sub private static void IllustrateExceptions() { try{ // Something that throws an exception } catch (Exception ex){ // In the previous versions this will catch only CLS-Compliant // In the current version both CLS and Non CLS-Compliant will be caught by this block. }} Gestione Eccezioni COM “2.0”
  141. 141. dotNet Framework: Interoperation Oltre ad avere la necessità di riutilizzare componenti COM, potremmo trovarci nella situazione di doverne creare di nuovi, per poter aggiungere funzionalità ad applicazioni esistenti. Anche i tal caso dotNet ci viene in aiuto con un wrapper apposito: COM Callable Wrapper (CCW), attraverso il quale possiamo esportare il componente scritto in dotNet in modo che sia compatibile con COM. Per creare la nostra nuova libreria COM-Compatibile usando VS, dobbiamo : 1. Creare un nuovo progetto 2. Aprire la dialog box “Propietà del Progetto”, clicckando con il tasto destro sul progetto e scegliendo proprietà. 3. Spuntare l’opzione Registra per COM 4. Compilare il tutto Creato il componente sarà il compilatore a preoccuparsi di aggiungere le necessarie informazioni per renderlo compatibile con COM.
  142. 142. dotNet Framework: Interoperation Per creare correttamente un componente esportabile in COM, bisogna seguire alcune regole: • Tutte le classi devono avere un costrutto senza parametri esplicitamente dichiarato; • Tutti i tipi che si vuole rendere visibili devono essere pubblici; • Tutti i metodi che si vuole rendere visibili devono essere pubblici; • Le classi Astratte non possono essere esportate; Public Class ComVisiblePerson Private _firstName As String Private _lastName As String Public Property FirstName() As String Get Return Me._firstName End Get Set(ByVal value As String) Me._firstName = value End Set End Property Public Property LastName() As String Get Return Me._lastName End Get Set(ByVal value As String) Me._lastName = value End Set End Property End Class namespace NetForComDemoCS { class ComVisiblePerson { private String firstName; private String lastName; public String FirstName { get { return firstName; } set { firstName = value; } } public String LastName { get { return lastName; } set { lastName = value; } } } } Attraverso appositi attributi è poi possibile indicare quali Assembly e Metodi devono essere visibili o meno come COM: ' VB <Assembly: ComVisible(False)> // C# [assembly: ComVisible(false)] ' VB <ComVisible(False)> _ Public Class ComVisiblePerson // C# [ComVisible(false)] class ComVisiblePerson
  143. 143. dotNet Framework: Interoperation Abbiamo parlato fin ora di oggetti COM, ma cosa accade se abbiamo bisogno di utilizzare una libreria non conforme allo standard COM o API di sistema non supportate direttamente dal framework? Utilizziamo il cosiddetto Platform Invoke (P/Invoke), ovvero andiamo a wrappare manualmente la nostra dll: Imports System.Text Imports System.Runtime.InteropServices Public Class WindowExample Private Const BufferSize As Int32 = 256 <DllImport("user32.dll")> _ Private Shared Function GetForegroundWindow() As IntPtr End Function <DllImport("user32.dll")> _ Private Shared Function GetWindowText(ByVal _ hWnd As IntPtr, ByVal textValue As StringBuilder, ByVal counter As Int32) As Int32 End Function … using System.Runtime.InteropServices; namespace OptionalCS { class WindowExample { private const Int32 BufferSize = 256; [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] private static extern Int32 GetWindowText(IntPtr hWnd, StringBuilder textValue, Int32 counter); ….
  144. 144. dotNet Framework: Interoperation Il modo migliore per lavoare con P/Invoke, è quello di creare una classe wrapper per ogni dll che si vuole utilizzare (Encapsulating) e utilizzare solo quest’ultima all’interno del codice. Questo “incapsulamento” porta a oggettivi vantaggi, quali: • Gli utilizzatori della classe non si renderanno conto del fatto che sia una classe- wrapper di una dll • L’utilizzo nel proprio progetto della dll sarà nascosto, evitando di usare i formalismi di P/Invoke che possono confondore Nell’uso di P/Invoke bisogna fare molta attenzione alla tipologia dei dati trattati: infatti non è detto che i vari tipi corrispondano tra loro. Bisogna quindi prendere le necessarie contromisure (Data Type Converting e Marshaling) per ovviare ai problemi. Inoltre bisogna ricordarsi che le CallBack (ovvero le chiamate a funzione) devono essere mappate attraverso opportuni Delegati, da definire in base alla signature della callback stessa.
  145. 145. dotNet Framework: Reflection Scoprire il codice
  146. 146. dotNet Framework: Reflection Attraverso la Reflection dotNET mette a disposizione un elaborato strumento che permette di effettuare ad un programma l’auto analisi della sua struttura. Attraverso la reflection è possibile, ad esempio, conoscere i tipi contenuti nell’assembly o il Modulo a cui appartengono o ancora i suoi metadati. Tutto questo è possibile attraverso le funzionalità messe a disposizione dal namespace System.Reflection e dalla classe statica Assembly
  147. 147. dotNet Framework: Reflection La domanda è: a cosa serve la Reflection? Attraverso la Reflection è possibile ottenere informazioni da un assembly a runtime e quindi, ad esempio, invocare un metodo costruendone dinamicamente la chiamata. Tutti noi utilizziamo il completamento automatico dei metodi (e non solo) messo a disposizione di VS: ebbene l’IDE Microsoft riesce a fare ciò proprio grazie alla reflection. Questo strumento ha anche un’ulteriore potenzialità: creare un assembly runtime e addirittura salvarlo su disco. Per quanto riguarda la Reflection non andiamo oltre, essendo un argomento avanzato e che necessita di approfondimenti ad-hoc.
  148. 148. dotNet Framework: Globalization Rendere internazionali le proprie Applicazioni
  149. 149. dotNet Framework: Globalization Il contesto geografico in cui un software verrà utilizzato è spesso un fattore sottovalutato durante la sua realizzazione. Immaginate però quanti problemi sorgono se il nostro prodotto inizialmente pensato solo per il mercato italiano deve essere adattato a quello francese o a quello inglese. dotNET viene incontro ai problemi di internazionalizzazione grazie al namespace System.Globalization. Partiamo però dal chiarire cosa intendiamo per Cultura (culture): per cultura si intendono un insieme di elementi (calendario, valuta, lingua, ecc.) specifici di un determinata nazione o area geografica. Esistono tre tipologie di culture: • Invariant Culture: è una cultura invariante (basata sul linguaggio inglese) da utilizzare nel caso in cui si voglia garantire una sorta di consistenza internazionale degli elementi culturali (es: data e ora di una trial application); • Neutral Culture: una cultura è neutrale quando è associata solo ad una lingua (Francese, Inglese, Tedesco) ma non alla rispettiva nazione o area geografica. Essa viene indicata con le iniziali minuscole della lingua: fr, en, sp, it; •Specific Culture: una cultura specifica è relativa ad una nazione e viene rappresentata dalla cultura neutrale più l’abbreviazione maiuscola di quella specifica: fr-FR (francia) en-US (stati uniti), en-EN (inghilterra);
  150. 150. dotNet Framework: Globalization L’utilizzo della cultura appropriata è fondamentale quando, su sistemi internazionali, si desidera che i valori analizzati siano interpretati allo stesso modo. Prendiamo ad esempio una data italiana composta da gg/mm/aa: 05/11/2007 (5 novembre 2007). Per noi è chiaro che le prime due cifre rappresentano il giorno, ma se la facciamo leggere ad un americano la interpreterà come: l’11 Maggio 2007 (mm/gg/aa). Stesso problema relativo al significato del (.) e della (,) nei numeri. La soluzione dotNET passa attraverso 2 classi principali CultureInfo e RegionInfo ed un enumeratore CultureTypes.
  151. 151. dotNet Framework: Globalization Vediamo alcune situazioni pratiche. Per rilevare la cultura corrente possiamo procedere nel modo seguente: Dim UsersCulture As CultureInfo = Thread.CurrentThread.CurrentCulture Console.WriteLine("The currentculture of this application is : “ + UsersCulture.Name) CultureInfo UsersCulture = Thread.CurrentThread.CurrentCulture; Console.WriteLine("The current culture of this application is : “ + UsersCulture.Name); allo stesso modo è semplice cambiare la cultura attuale: ' VB tbSalary.Text = Format(100000, "Currency") // C# tbSalary.Text = (100000).ToString("C"); Thread.CurrentThread.CurrentCulture = new CultureInfo("es-VE"); Per formattare correttamente una stringa (ad esempio un valore monetario variando il punto con la virgola, ecc.) dobbiamo usare appositi strumenti di formattazione:
  152. 152. dotNet Framework: Globalization CurrentCulture rappresenta la cultura con cui vengono effettuate le manipolazioni durante l’esecuzione del programma. Dualmente esiste CurrentUICulture che rappresenta la cultura utilizzata per l’Interfaccia Utente, il cui valore può essere letto/variato esattamente come CurrentCulture (sostituendo ovviamente CurrentUICulture). La cosa importante da evidenziare è che CurrentUICulture può essere settata solo nella fase di start dell’applicazione (nel main), al contrario di CurrentCulture Alla classe CultureInfo il framework affianca RegionInfo che fornisce informazioni relative all’area geografica specifica: ' VB Dim UsersCulture As CultureInfo = Thread.CurrentThread.CurrentCulture Dim DemoRegion As RegionInfo = New RegionInfo(UsersCulture.LCID) Or: Dim DemoRegion As RegionInfo = New RegionInfo(UsersCulture.Name) // C# CultureInfo UsersCulture = Thread.CurrentThread.CurrentCulture; RegionInfo DemoRegion = new RegionInfo(UsersCulture.LCID); Or: RegionInfo DemoRegion = new RegionInfo(UsersCulture.Name);
  153. 153. dotNet Framework: Globalization Il risultato della comparazione può essere modificato passando alla compare,come terzo parametro, uno dei valori di CompareOptions ' VB Dim FirstString = "Coté" Dim SecondString = "coté" Dim DemoInfo As CompareInfo = New CultureInfo("fr-FR").CompareInfo DemoInfo.Compare(FirstString, SecondString) // C# String FirstString = "Coté"; String SecondString = "coté"; CompareInfo DemoInfo = new CultureInfo("fr-FR").CompareInfo; DemoInfo.Compare(FirstString, SecondString); Quando abbiamo introdotto la globalization abbiamo fatto riferimento, come esempio, al problema della rappresentazione delle date. Per risolvere il relativo problema di internazionalizzazione si può far ricorso alla classe DateTimeFormatInfo così come nel caso delle valute si può utilizzare la classe NumberFormatInfo L’ultima classe che evidenzieremo è la CompareInfo che unitariamente all’enumerator CompareOptions permette di fare comparazioni tra stringhe. La comparazione tra stringhe può avere esiti diversi in base alla cultura utilizzata. Ad esempio alcune culture potrebbero ignorare la differenza di maiuscole e minuscole in una stringa,mentre altre ritenerle fondamentali:
  154. 154. dotNet Framework: Globalization Nel caso in cui avessimo bisogno di creare una nostra cultura (caso molto raro ma non assurdo), possiamo far ricorso alla classe CultureRegionAndInfoBuilder e all’enumerator CultureAndRegionModifiers. In generale è possibile partire da una cultura esistente e variarne alcuni elementi di base: ' VB Dim DemoBuilder As new CultureAndRegionInfoBuilder("en-US", CultureAndRegionModifiers.Neutral) // C# CultureAndRegionInfoBuilder DemoBuilder = new CultureAndRegionInfoBuilder("en-US", CultureAndRegionModifiers.Neutral);
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×