VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET,...

518

Transcript of VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET,...

Page 1: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è
Page 2: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

VISUALBASIC2015

Page 3: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DanieleBochicchio,CristianCivera,MarcoDeSanctis,AlessioLeoncini,MarcoLeoncini,StefanoMostarda

VISUALBASIC2015Guidacompleta

perlosviluppatore

EDITOREULRICOHOEPLIMILANO

Page 4: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Copyright©UlricoHoepliEditoreS.p.A.2016viaHoepli5,20121Milano(Italy)

tel.+3902864871–fax+39028052886

[email protected]

www.hoepli.itSeguicisuTwitter:@Hoepli_1870

Tuttiidirittisonoriservatianormadilegge

eanormadelleconvenzioniinternazionali

ISBNEBOOK978-88-203-7340-5Progettoeditorialeerealizzazione:MaurizioVedovati-Servizieditoriali([email protected])

Impaginazioneecopertina:SaraTaglialegne

Realizzazionedigitale:Promedia,Torino

Page 5: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Indice

Contenutidellibro

ASPItalia.com

Gliautori

Capitolo1-Introduzioneal.NETFrameworkCos’èil.NETFramework

.NET2015

Icomponentidel.NETFramework

CommonLanguageRuntime(CLR)

Ilconcettodicodicemanaged

CommonTypeSystem

CommonLanguageSpecification

LaCross-LanguageInteroperability

Tipidivaloreetipidiriferimento

Conversionitratipi,boxingeunboxing

Lagestionedellamemoria:ilGarbageCollector

IlconcettodiAssembly

Interoperabilitàtra.NETFrameworkeCOM

Conclusioni

Capitolo2-VisualStudio2015L’IDEdiVisualStudio

TextEditor,designereIntellisense

Toolbox

PropertyEditor

Altreareedell’IDE

Creareunprogetto

Ilmulti-targetingdel.NETFrameworkinVisualStudio

Page 6: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Ilconcettodiprogettoesoluzione

Gestiresoluzioneeprogetto

Aggiungereunprogettoallasoluzione

Gestionedellereferenze

Gestionedidirectorynellasolution

Gestionedelcodicesorgente

Compilareunprogetto

Gestireleconfigurazioni

Debugdiunprogetto

Usareildebugger

Breakpointewatch

Intellitraceehistoricaldebug

Refactoring

Conclusioni

Capitolo3-SintassidibaseIntroduzioneallinguaggio

Commenti

Tipidibase

Namespace

Dichiarazionedivariabili

Espressionieoperatori

Conversionedeitipi

Array

Enumerazioni

Funzionieprocedure

Istruzionicondizionali

IstruzioneIf…Then…Else

IstruzioneSelect…Case

Operatorenull-conditional

Istruzionid’iterazione

Istruzionewhile

Page 7: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IstruzioneDo…Loop

IstruzioneFor…Next

IstruzioneForEach

Istruzionidisalto

IstruzioneExit

Istruzionecontinue

IstruzioneContinue

IstruzioneReturn

IstruzioneGoTo

Formattazionedistringhe

Conclusioni

Capitolo4-LaprogrammazioneorientataaglioggettiVantaggidell’ObjectOrientedProgramming

PrincipifondamentalidiOOP

Ereditarietà

Polimorfismo

Incapsulamento

Classi

Membridiunaclasse

Livellidiaccessibilità

Creazionedelleistanzediclasse

Classistaticheeparziali

Partialclass

Ereditarietàepolimorfismo

Interfacce

Strutture

Regoledinomenclatura

Conclusioni

Capitolo5-CollectionseGenericsIntroduzioneallecollection

LaclasseArraylist

Page 8: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dizionariin.NETtramitelaclasseHashtable

LeinterfacceinSystem.Collections

Ulterioritipologiedicollection

IGenericselatipizzazioneforte

Lecollezionigeneriche

Lalistanelmondodeigenerics:List(OfT)

Leinterfaccenellecollezionigeneriche

Undizionariofortementetipizzato:Dictionary(OfTKey,TValue)

Unacollectionconelementiunivoci:HashSet(OfT)

Altretipologiedicollezionigeneriche

Creazioneditipigenerici

Impostaredeivincolisultipogenerico

Unparticolaretipogenerico:Nullable(OfT)

Assegnazionitratipigenerici:covarianzaecontrovarianza

Creazionediinterfaccecovariantiecontrovarianti

Conclusioni

Capitolo6-DelegateedEventiIDelegatenel.NETFramework

Definizioneeutilizzodiundelegate

Modelloaoggettideidelegate

Combinazionedidelegate:laclasseMulticastDelegate

Cennisull’esecuzioneasincronadiundelegate

Idelegateeigenerics

Delegateinunarigadicodice:lelambdaexpression

Idelegatecomestrumentodinotifica:glieventi

Definizioneeusodiuneventoinunoggetto

Creareeventipersonalizzati

Scambiaredatitramiteeventi:laclasseEventArgselesuederivate

Definizioneesplicitadieventi

Conclusioni

Capitolo7-Approfondimentodellinguaggio

Page 9: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Gestionedelleeccezioni

Glierroriprimadel.NETFramework

Gestionestrutturatadeglierroritramiteleexception

LaclasseSystem.Exception

Realizzarecustomexception

Lavorareconleeccezioninelcodice

Intercettareleeccezioni

IlbloccoFinally

L’interfacciaIDisposableeilbloccoUsing

Sollevareeccezioninelcodiceebestpractice

Gestioneerilanciodelleeccezioni

UtilizzodelleInnerException

Considerazioniprestazionalisull’usodelleException

EsplorareitipiaruntimeconReflection

LaclasseSystem.Type

Scritturadicodicedinamico

Realizzazionedicodicedinamicoconreflection

CodicedinamicoconilLateBindingdiVisualBasic

LeclassiDynamicObjecteExpandoObject

Codicedichiarativotramitegliattributi

Costruireeusareattributicustom:laclasseSystem.Attribute

Ilcompilatorecomeservizio:Roslyn

InstallazioneeprimipassiconRoslyn

Analisidellasintassi

Conclusioni

Capitolo8-EseguirequerynelcodiceconLINQIperchédiLINQ

ComefunzionaLINQ

Introduzioneall’esempiodelcapitolo

GliextensionmethoddiLINQ

LafilosofiaallabaseLINQ

Page 10: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Anatomiadiunaquery

Glioperatoridirestrizione

OfType

Glioperatoridiproiezione

Select

SelectMany

Glioperatoridiordinamento

OrderBy,OrderByDescending,ThenByeThenByDescending

Reverse

Glioperatoridiraggruppamento

Glioperatoridiaggregazione

Average,Min,Max,Sum

Count,LongCount

Glioperatoridielemento

Glioperatoridipartizionamento

TakeeSkip

TakeWhileeSkipWhile

Operatoridiinsieme

Except

Intersect

Distinct

Union

LaQuerySyntax

Conclusioni

Capitolo9-MultithreadingedesecuzioneparallelaProcessiethread

LaclasseSystem.Threading.Thread

Passareparametriaunworkerthread

Controllareilflussodiesecuzionediunthread

IlThreadPoolperapplicazionimultithreading

Asynchronousprogrammingmodel

Page 11: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

UtilizzodelmetodoEndInvoke

SincronizzazionetramiteIAsyncResultepolling

Utilizzodiunmetododicallback

EsecuzioneparallelaconParallelExtensions

LaTaskParallelLibrary

Composizioneditask

Nestedtaskechildtask

ParallelLINQ

ProgrammazioneasincronaconAsynceAwait

EseguireoperazioniinparalleloconAsynceAwait

Realizzaremetodiasincroni

Concorrenzaethreadsafety

Sincronizzarel’accessoallerisorse

Collezioniconsupportoallaconcorrenza

Conclusioni

Capitolo10-L’accessoaidaticonADO.NETManagedDataProvider

Connessioneaunasorgentedati

Esecuzionediuncomando

Letturadelrisultatodiunaquery

ProviderFactory

SupportospecificoperSQLServer

ModalitàdisconnessainADO.NET

Conclusioni

Capitolo11-Oltrel’accessoaidati:EntityFrameworkCosaèunO/RM

Mappareilmodelloaoggettisuldatabase

MappingconCode-First

Disegnareleclassi

Creareilcontesto

Mappingtramiteconvenzioni

Page 12: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

MappingtramiteAPI

Mappingtramitedataannotation

Configurarelastringadiconnessione

UtilizzareVisualStudio

MappingconDatabase-First

Recuperareidatidaldatabase

Ottimizzareilfetching

Salvareidatisuldatabase

Persistereunnuovooggetto

Persisterelemodificheaunoggetto

Cancellareunoggettodaldatabase

FunzionalitàaggiuntivediEntityFramework

EntityFramework7

Conclusioni

Capitolo12-XMLeLINQtoXMLIlsupportoadXMLnel.NETFramework

Gestirel’XMLconlaclasseXmlDocument

Letturaescritturarapidaeleggera

LeggereconXmlReader

ScrivereconXmlWriter

LINQtoXML

InterrogareinodiconLINQ

Manipolazionedeinodi

LINQtoXMLconVisualBasic

XMLdinamicoconVisualBasic14

InterrogarerapidamenteconXPathDocument

Navigaretrainodi

Modificareinodi

TrasformareidocumenticonXSLT

Conclusioni

Capitolo13-IntroduzioneaXAML

Page 13: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IntroduzioneaXAML

L’ambientedisviluppo

IlmarkupXAML

Lasintassi

LasintassiObjectelement

LasintassiPropertyattribute

LasintassiPropertyElement

Inamespace

Illayoutsystem

Elementifisicielogici

Ladisposizionedeglielementi

Ipannelli

Icontrolli

Leclassiprincipali:UIElementeFrameworkElement

Icontrolli

Lagrafica

Ipennelli:ilBrush

Letrasformazionisuglioggetti

Leanimazioni

Conclusioni

Capitolo14-SviluppareconXAML-ConcettiavanzatiDefinireeriutilizzarelerisorse

CreareegestiregliStyle

ModellareillayoutconiTemplate

PersonalizzareuncontrolloconilControlTemplate

Ildatabinding

Mostrareleinformazioniconildatabinding

Scenarimaster/detailconildatabinding

Lefontidatiperildatabinding

Laformattazionedeidati

Lemodalitàdidatabinding

Page 14: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Gestireglieventi

Conclusioni

Capitolo15-UsareXAML:WindowsStoreapp,WPFeSilverlightApplicazioniUniversal

Itoolpersviluppare

LaprimaappperilWindowsStore

ApplicazionidesktopconWindowsPresentationFoundation

Creazionediunprogetto

Gestirelefinestre

Lebrowserapplication

Conclusioni

Capitolo16-ApplicazioniwebconASP.NETLaprimapaginaASP.NET

CreareunprogettoASP.NET

SviluppareconWebForms

Glieventi,ilPostBackeilViewState

Interagireconlapagina

Validazionedelleform

Mantenereillayoutconlemasterpage

Visualizzaredati:ildatabinding

Ilistcontrol

Utilizzareitemplate

CreareURLperlaSEO

Gestionedelleareeprotette

ASP.NETMVC

CreareformconASP.NETMVC

Conclusioni

Capitolo17-CreareapplicazionidistribuiteIserviziRESTfulconASP.NETWebAPI

Laserializzazioneeilmodelbinding

LeactioneimetodiHTTP

Page 15: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Letipologiedirisultatodelleaction

LoscaffoldingdelleWebAPI

SupportareilprotocolloOData

EffettuareloscaffoldingperOData

Createservizireal-timeattraversoSignalR

L’hubcomeserviziobidirezionale

UtilizzareSignalRdaJavaScript

Conclusioni

Capitolo18-Lasicurezzanelleapplicazioniperil.NETFrameworkProgettareapplicazionisicure

Sicurezzaby-design

IlmodellodisicurezzadelCLR

Transparencymodel

IlconcettodiPermission

DefinizionedellePermissioninmododichiarativo

Creareunasandboxperisolarecodiceesterno

Principidicrittografia

WindowsDataProtection

Crittografiasimmetrica

Crittografiaasimmetrica

Cifraturairreversibile:hashing

Firmaregliassembly

Validazionedeidatiimmessidall’utente

ProteggersidaattacchiSQLInjection

Conclusioni

Capitolo19-Gestionedifile,registryenetworkingGestionedelFilesystem

Organizziamoleinformazioni:DirectoryeFile

Creazionediunadirectory

Eliminareunadirectory

Spostareunadirectory

Page 16: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Copiareunadirectory

Eseguirericerchesulfilesystem

Creareemodificareunfile

IsolatedStorage

IlRegistry

Principidicomunicazionedirete

Architetturaalivelli:ilmodelloditrasporto

Porteeprotocolliapplicativistandard

IprotocolliTCPeUDP

Isocketelacomunicazioneabassolivello

InviareunsemplicetestoconunclientUDP

RicevereimessaggiconunminiserverUDP

InviareericeveredaticonlaclasseTcpClient

IlnamespaceSystem.Net

LaclasseWebClient

Inviaredatialserver

ComunicazioneconiwebserverattraversoHTTP

HttpClient:un’evolutainterfacciaHTTPperapplicazionimoderne

ScambiarefileconilprotocolloFTP

Conclusioni

AppendiceA-MicrosoftAzureIntroduzioneaMicrosoftAzure

HelloWorld,daMicrosoftAzure

AppendiceB-InteroperabilitàconDLLeCOMCreareundocumentoExcel

ChiamareleAPIdiWindows

AppendiceC-SviluppareWindowsServiceSviluppodiunWindowsService

Creazionedell’Installereconfigurazione

InstallazionediunWindowsService

AppendiceD-Distribuzionedelleapplicazioni

Page 17: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Assemblyprivatiepubblici

DistribuzionedelleapplicazioniWindowstradizionali

Distribuzionedelleapplicazioniweb

Distribuzioneconcodeinline

Distribuzioneconcodebehind

Distribuzioneconcodefile

One-ClickDeployment

AppendiceE-IlnamespaceMyAccessoallerisorsedelcomputer

Accessoalleimpostazionidell’utente

Altreinformazioni

InformazionisulLibro

Page 18: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Contenutidellibro

Questa guida completa a Visual Basic 2015 è l’espressione corale di un gruppo disviluppatori, che utilizza questo linguaggio sin dalla prima versione, per costruireapplicazionidiognitipo,daquellewebfinoacomplessisistemienterprise.

Il libro include le ultime novità introdotte dal linguaggio e dal framework: vengonotrattate le basi del linguaggio e illustrati i concetti più avanzati, viene spiegato l’usodell’OOPinVisualBasic,perpoipassarealletecnologie:LINQ,EntityFramework,WPF,ASP.NET,XAML,Windows10eservizi.

VisualBasic2015Guidacompletaper losviluppatoreè l’idealesiaper ilnoviziosiaperchinecessitadiapprenderetuttelenovitàdiVisualBasic2015.

GliautorifannopartedellostaffdiASPItalia.com,storicacommunityitalianachedal1998sioccupadisvilupposupiattaformeMicrosoft.

Il libro è suddiviso in cinque parti, ciascuna delle quali risponde a un insieme diesigenzedisviluppospecifiche.

Le informazioni di base, riguardanti il .NET Framework, Visual Studio e una primaintroduzioneallinguaggiocompongonolaprimaparte.

Nella seconda parte viene approfondito il linguaggio, con tre capitoli che entranomaggiormente nel dettaglio, dopo aver introdotto i principi della programmazioneorientataaglioggetti.ChiudequestapartelatrattazionediLINQ.

L’accessoelapersistenzadeidatisonoinvecel’argomentotrattatonellaterzapartedellibro,cheincludeADO.NET,EntityFrameworkeLINQtoXML.

La quarta parte comprende una serie di capitoli completamente dedicata alletecnologiechefannousodel linguaggio:cisonoduecapitolidedicatiaXAML,chepoiviene approfondito anche per creare app per Windows 10. Ci sono anche un capitolodedicatoadASP.NET(WebFormseMVC),percreareapplicazioniweb,eunodedicatoallacreazionediapplicazionedistribuite.

Laquintaparteèdedicataagliargomentipiùavanzati,inmolticasifondamentaliperlo sviluppo di un’applicazione: parliamo di distribuzione, sicurezza e accesso al filesystem,allareteealregistry,oltrechedisviluppodiWindowsService.

PerchièquestolibroL’idea che sta alla base di questo libro è quella di fornire un rapido accesso alleinformazioni principali che caratterizzano la versione 6 di Visual Basic. Quando sono

Page 19: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

presenti,lenovitàrispettoalleversioniprecedentisonomesseinrisaltomaquestolibroèindicatoancheperchineèdigiunoedesideraimpararel’usodiquestatecnologiapartendodazero.Sonopresentatealcunenozionirelativeallaprogrammazioneobjectoriented,maè consigliabile avere già una base di programmazione. Inoltre, all’interno del libro latrattazionedegliargomentièfattainmanieraclassicaenonutilizzandounapproccioperesempi(chesonocomunquedisponibiliasupportodegliargomentiteorici).

Il libroèstatoorganizzato inmodotaledaaverenellaprimaparteun’introduzioneal.NET Framework, allo scopo di fornire al lettore un’infarinatura generaledell’infrastruttura e della tecnologia su cui andare a costruire le applicazioni. Contienequindiunatrattazionecompletadellinguaggiomanonapprofondisceinmanieraspecificatutte le tecnologie inclusenel .NETFramework,soffermandosisolosuquelleprincipali,perlequaliabbiamoinclusoun’introduzione.

Percomprendereappienomoltidegliesempiedegliambiticheincontreremonelcorsodel libro, potrebbe essere necessario per il lettore approfondire maggiormente alcuniaspetti,chedivoltainvoltasonocomunqueevidenziatieperiqualiforniamoopportunilinkarisorseonline.

ConvenzioniAll’internodiquestovolumeabbiamoutilizzatostilidifferentisecondo il significatodeltesto,cosìdarenderepiùnettaladistinzionetratipologiedicontenutidifferenti.

I termini importanti sono spesso indicati in grassetto, così da essere più facilmentericonoscibili.

Il testo contenuto nelle note è scritto in questo formato. Le note contengonoinformazioniaggiuntive relativamenteaunargomentooadaspettiparticolariaiqualivogliamodareunacertarilevanza.

Gliesempicontenenticodiceomarkupsonorappresentatisecondoloschemariportatodiseguito. Ciascun esempio è numerato in modo tale da poter essere referenziato piùfacilmenteneltestoerecuperatodagliesempiacorredo.

Esempio1.1-LinguaggioCodice

Codiceimportante,sucuisivuoleporrel'accento

Altrocodice

Per namespace, classi, proprietà, metodi ed eventi viene utilizzato questo stile.Qualora vogliamo attirare la vostra attenzione su uno di questi elementi, per esempioperchéèlaprimavoltachevienemenzionato,lostilecheuseremoèquesto.

Page 20: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

MaterialedisupportoedesempiA supporto del libro è presente una nutrita quantità di esempi, che riprendono sia gliargomenti trattati siaquellinonapprofonditi. Il codicepuòessere scaricatoall’indirizzohttp://books.aspitalia.com/VisualBasic-2015/, dove saranno anche disponibili gliaggiornamenti e il materiale collegato al libro, e dahttp://www.hoeplieditore.it/7100-5.

RequisitisoftwarepergliesempiQuestoèunlibrodedicatoaVisualBasic,percuièsufficientecheillettoreabbiainusounaqualsiasiversionediVisualStudioperpoterlosfruttare.

Conl’eccezionedipochicasiparticolari,comunqueevidenziati,pervisionareetestaregli esempi potete utilizzare una delle versioni Express o Community di Visual Studio2015, scaricabili gratuitamente senza limitazioni particolari e utilizzabili liberamente,anche per sviluppare applicazioni a fini commerciali. Le trovate all’indirizzo:http://www.visualstudio.com/.

Perquantoconcerne l’accessoaidati,nel librofacciamoriferimentoprincipalmenteaSQLServer.ViraccomandiamodiutilizzarelaversioneSQLServerExpress,liberamentescaricabile all’indirizzo http://www.microsoft.com/express/sql/. Il tool per gestirequestaversionesichiamaSQLServerManagementToolExpress,disponibileallostessoindirizzo.

Contatti,domandeagliautoriPerrenderepiùagevoleilcontattocongliautori,abbiamopredispostounforumspecifico,raggiungibile all’indirizzo http://forum.aspitalia.com/, in cui saremo a vostradisposizioneperchiarimenti,approfondimentiedomandelegateallibro.

Potete partecipare, previa registrazione gratuita, alla community di ASPItalia.comNetwork,dicui fannoparteancheHTML5Italia.com,chesioccupadeglistandardweb,LINQItalia.com, che tratta in maniera specifica LINQ e Entity Framework,WindowsAzureItalia.com, che tratta di cloud e di Microsoft Azure, WinFXItalia.com,completamentededicataal.NETFramework,WinRTItalia.com,chesioccupadiWindows10.

Viaspettiamo!

Page 21: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ASPItalia.com

ASPItalia.comNetwork,natadallapassionedellostaffperlatecnologia,èsupportatadaquasi 20 anni di esperienza con ASPItalia.com per garantirvi lo stesso livello diapprofondimento,aggiornamentoequalitàdeicontenutisututteletecnologiedisviluppodelmondoMicrosoft.Con70.000iscrittiallacommunity,iforumrappresentanoilmigliorluogoincuiporrelevostredomanderiguardantituttigliargomentitrattati!

ASPItalia.comsioccupaprincipalmenteditecnologiededicatealWeb,daASP.NETaIIS,con un’aggiornata e nutrita serie di contenuti pubblicati nei dieci anni di attività chespazianodaASPaWindowsServer,passandopersecurityeXML.

Ilnetworkcomprende:

HTML5Italia.com con HTML5, CSS3, ECMAScript 5 e tutto quello che ruotaintorno agli standard web per costruire applicazioni che sfruttino al massimo ilclientelespecificheweb.

LINQItalia.com,conlesuepubblicazioni,approfondiscetuttigliaspettidiLINQ,passandoperivariflavourLINQtoSQL,LINQtoObjects,LINQtoXMLoltreaEntityFramework.

WindowsAzureItalia.com, che tratta di cloud computing e diMicrosoftAzure inparticolare,dalpuntodivistsadellosviluppo.

WinFXItalia.com, in cui sono presenti contenuti su Windows PresentationFoundation, Windows Communication Foundation, Windows WorkflowFoundation e, più in generale, su tutte le tecnologie legate allo sviluppo perWindowseil.NETFramework.

WinRTItalia.com copre gli aspetti legati alla creazione di applicazioni perWindows10,intuttelesuedeclinazioni,dall’UXfinoallosviluppo.

Page 22: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Gliautori

DanieleBochicchio

E-mail:[email protected]

Twitter:http://twitter.com/dbochicchio

Blog:http://blogs.aspitalia.com/daniele/

Danielesioccupadeiprogettilegatialweb,almobile,alcloudealdigitale,ricoprendoilruolodiChiefDigitalOfficerecoordinandoleattività legateallosviluppodi iCubed.ÈMicrosoftRegionalDirector per l’Italia, un ruoloche fada tramite traMicrosoft eglisviluppatori, edMVP per ASP.NET dal 2002, a riconoscimento del suo impegno nellecommunity.

Nel1998ha ideatoe sviluppatoASPItalia.com, ricoprendoprima lacaricadicontentmanagere,attualmente,quelladicoordinatoredelnetwork.

Partecipa spesso come speaker a diverse prestigiose conferenze, anche per conto diMicrosoftItalia,e tieneabitualmentecorsidiformazionepressoleaziende.Èideatoreeorganizzatore deiCommunityDays, una delle conferenze dimaggior successo in Italia,capace di attrarre ogni anno migliaia di partecipanti. Appassionato di scrittura, haall’attivo diverse pubblicazioni per Hoepli e scrive abitualmente contenuti perASPItalia.com.

CristianCivera

Page 23: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

E-mail:[email protected]

Twitter:http://twitter.com/CristianCivera

Blog:http://blogs.aspitalia.com/ricciolo/

Cristian Civera è senior software architect e opera nello sviluppo di applicazioni web,mobileeWindows.Lesuecompetenzesibasanosull’intero.NETFramework,dicuisièsempre interessato fin dalla prima versione e, in particolare, sulla piattaforma cloudMicrosoftAzureesututteletecnologiebasatesuXAML.ContribuisceallacommunitydiASPItalia.com ed è Microsoft MVP per ASP.NET dal 2004. Ha partecipato a diversieventi,ancheperMicrosoftItalia,inqualitàdispeaker.

MarcoDeSanctis

E-mail:[email protected]

Twitter:http://twitter.com/crad77

Blog:http://blogs.aspitalia.com/cradle

MarcoDe Sanctis è un consulente libero professionista e si occupa di progettazione diapplicazionienterpriseinambitoWeb,mobileeWindows8.Dasempreappassionatodel

Page 24: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

.NET Framework e in particolare di ASP.NET, che segue dalle primissime release, nelcorso degli anni si è specializzato anche in tematiche architetturali e nello sviluppo diservizi.èautoredi libriespeakeralleprincipaliconferenzenazionali.SvolgeilruolodicontentmanagerdiASPItalia.com.Perisuoicontributiallacommunity,èdaalcunianniMicrosoftMostValuableProfessionalsuASP.NET.

AlessioLeoncini

E-mail:[email protected]

Twitter:http://twitter.com/aleoncini

Blog:http://blogs.aspitalia.com/novecento/

AlessioLeoncinièUXArchitect,InteractiveDesigneresviluppatore.NETdiapplicazioniweb, mobile e desktop, in ambienti ASP.NET, Silverlight, WPF, Windows Phone eWindows 8. Autore di libri e speaker nelle maggiori conferenze italiane, è Contentmanager di WinPhoneItalia.com e WinRTItalia.com ed è Microsoft MVP e MCTS suSilverlight.

MarcoLeoncini

Page 25: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

E-mail:[email protected]

Blog:http://blogs.aspitalia.com/nostromo/

MarcoLeoncini sioccupadiUser eXperiencee sviluppodi applicazioniweb,mobile edesktop,inambientiASP.NET,Silverlight,WPF,WindowsPhoneeWindows8.

È autore di libri, speaker, content manager di SilverlightItalia.com,WinPhoneItalia.com,WinRTItalia.com.

StefanoMostarda

E-mail:[email protected]

Twitter:http://twitter.com/sm15455

Blog:http://blogs.aspitalia.com/sm15455/

StefanoMostardaèSeniorArchitectpressoSoluzioni4Ddovesioccupadiprogettazioneesviluppodiapplicazioniwebemobile.

Dal2004èmembrodellostaffdelnetworkASPItalia.comeContentManagerdelsitoLINQItalia.comdedicatoall’accessoeallafruibilitàdeidati.ÈMicrosoftMVPdal2007edèautoredidiversilibridiquestacollanaedilibriinlinguainglese,semprededicatiallosviluppo.NET,oltrechespeakernellemaggioriconferenzeitaliane.

Page 26: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

RingraziamentiDanieleringraziacomesempreNoemi,AlessioeMatteo(chesonolasuaguida),tuttalasuafamiglia,ilteameditorialeHoeplieicoautori,coniqualilacollaborazioneèsemprepiùriccadisoddisfazioni.

Cristian ringraziaChiara chepiùdi tutti hadovutopazientare eha capito comequestaattivitàsiaperluionerosamaanchemoltogratificante.

MarcoDesdesideraringraziarelasuafamigliaeBarbara,perilsupportoelapazienza,eglialtriautoriperlastimaprofessionalericevutael’ottimolavorosvolto.

AlessioringraziaAlessandraelasuafamigliaperesseresempreunpuntodiriferimento.Erinnovalastimaprofessionaleepersonaleaisuoiamicicoautori.

MarcoLeo ringrazia il piccolo Stefano eManuela, i genitoriMario e Fosca, le sorelleMonicaeSandraegliamicieautoridiquestolibro.

Stefano ringraziatutta lasuafamiglia, isuoiamici.Grazieinmanieraspecialeaglialtriautoriperaverpresoparteaquest’avventura.Aho!Ungrazieinfineallamusachelohaispiratodurantelastesuradellibro.

IlteamtieneparticolarmentearingraziarelacommunitydiASPItalia.comNetwork,acuianchequest’ultimolibroè,comesempre,idealmentededicato!

Gliautori ringraziano tutte lepersoneche inMicrosoftCorpeMicrosoft Italia lihannosupportatidurantequestimesi,nell’attesadell’uscitadiVisualStudio2015.

Page 27: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

1

Introduzioneal.NETFramework

Dallaprimaversionedel.NETFramework,rilasciatanel2002,letecnologiehannosubitoun’evoluzione che le ha portate a includere funzionalità sempre più innovative e aintrodurrecostantimiglioramentiaquantogiàpresentefindall’inizio.

VisualBasic,comelinguaggio,nasceinrealtàmoltianniprima,conl’obiettivodidarelapossibilitàaquantipiùutentipossibiledisfruttarelasuasemplicesintassipercostruireapplicazioni. Nel secolo scorso ha goduto di diverse migliorie, per poi assumere unanuova vita con la versione 7.0, chiamata VB.NET, in corrispondenza della quale èdivenutounodeilinguaggiprincipalidellatecnologia.NET.

Questa evoluzione, nel corso degli anni, è stata caratterizzata dal rilascio di diverseversioni del .NET Framework a cui si sono aggiunti miglioramenti anche dal punto divista del linguaggio. La release 2.0, rilasciata nel novembre del 2005 insieme aVisualStudio2005,hasenz’altrorappresentatouneventoimportanteeunveropuntodisvolta,introducendo novità significative e numerosi cambiamenti alle funzionalità già esistentinelleversioni1.0e1.1.Successivamente, la release3.0,uscitaacavallo tra il2006e il2007 insieme aWindowsVista, e la versione 3.5, rilasciata ufficialmente nel corso del2008 con Visual Studio 2008, hanno rappresentato un ulteriore passo in avanti,introducendo a loro volta nuove tecnologie finalizzate amigliorare la produttività deglisviluppatorinellarealizzazionediapplicazionibasatesuservizieadaltoimpattoestetico.L’obiettivoprimariodellaversione4.5del.NETFrameworkedelrelativoVisualStudio2012èstatoquellodicontinuarelatradizionedi.NETFramework4eVisualStudio2010di semplificareepotenziare,allostesso tempo, lo sviluppodiapplicazionidi tutti i tipi.VisualStudio2013hacontinuatoamigliorarelefunzionalitàoffertedallaversione2012,senzal’introduzionediunaversionemajordelframework.

Inquestianniillinguaggiohasubitonumerosicambiamenti,perlopiùlegatiallenovitàintrodottenellasintassi,persupportarealmegliolacomparsanelleversionipiùrecentidinuovetecnologiecomeLINQ,AJAX,WCFoilcloudcomputing.

VisualStudio2015èunaversioneimportante,perchéintroducenuovilinguaggi,nuoviparadigmieunnuovoapproccioalladistribuzionedel.NETFramework.

Questo libroè focalizzato su tuttoquantoVisualBasic, come linguaggio, consentedifare, sfruttando il .NET Framework come base. Nel corso dei prossimi capitoliimpareremolasintassidibaseecostruiremoapplicazionidi tutti i tipi.Primadipartire,però, è necessario che analizziamo quello che il .NET Framework stesso è in grado di

Page 28: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

offrirci.

Cos’èil.NETFrameworkVisualBasicsibasasullapiattaforma.NETFrameworkedèquindiimportanteconoscerneidettaglidifunzionamento.

La release più recente del .NET Framework, a cui questo libro fa riferimento, è laversione 4.6, che includeVisual Basic 14, a cui spesso si fa riferimento anche comeVisualBasic2015,permantenereunriferimentoaVisualStudio2015.

Essendoillinguaggioattraversoilqualesviluppareapplicazioni,VisualBasicconsentedifaretuttoquellocheil.NETFrameworkmetteadisposizione.Solopercitarnealcune,sipartedaASP.NET,dedicatoalweb,passandoperWPFeWindowsForms, tecnologieperlosviluppodiapplicazioniperWindows,finoadarrivareaWindowsCommunicationFoundation,perlarealizzazionediserviziweb(enonsolo),continuandoconWinRT,unavariantepensatapercreateappperWindows10.Oltreaquesto,abbiamolapossibilitàdicreare Windows Service, applicazioni per Office e molto altro ancora: per esempio,applicazioniperilcloudcomputing,conMicrosoftAzure.

Datequestepremesse,nonc’èdubbiocheil.NETFrameworkrappresentil’indiscussatecnologiasullaqualesipoggianolepiattaformeMicrosoftdioggiesucuisibaserannoquelledelprossimofuturo.

Graziealfattochelespecifichedel.NETFrameworksonostandardISO, sipossonocreare alternative al .NET Framework, per cui oggi imparare a sfruttarne i vantaggirappresenta un ottimo modo di investire il proprio tempo, anche in proiezione futura.Questoperò,almomento,nonèveroperVisualBasic,cherestaconfinatoallosviluppoperpiattaformeWindows.

La versione attuale viene denominata .NET 2015 e comprende, oltre al .NETFramework4.6,ancheunanuovaversione,chiamata.NETCore.

.NET2015

.NET Core e .NET Framework possiedono molti aspetti in comune: sono l’unol’evoluzioneinchiavemodernadell’altro.Il.NETFrameworkèconfinatosoloaWindowsecontienetuttociòacuisiamoabituatitradizionalmente..NETCore,invece,èunanuovaversione,pensatasoprattuttoperilcloudeingradodifunzionare,oltrechesuWindows,anche su Mac OSX e Linux. Rappresenta un radicale cambio di strategia da parte diMicrosoft,cheperlaprimavoltasupportanativamenteilproprioRuntimesupiattaformedifferenti,rispettoalclassicoWindows.

.NETCore1è limitatoalsupportodiASP.NETCore1,quindinonèpossibilecrearetutte le applicazioni che, invece, è in grado di garantire il .NET Framework e questalimitazioneèvoluta:.NETCoreèpensatoperleperformanceeperesserecrossplatform,

Page 29: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

inun’otticacloudbased,quindiprincipalmenteweb.Inrealtà,.NETCore,comevedremonei capitoli specifici, è sfruttato anche per ilWindows Runtime, insieme a una nuovatecnologia, chiamata .NETNative, che compila il nostro codice inmodo nativo, e chemiglioraleperformanceinotticaapp.

Che cosa hanno in comune .NET Core e .NET Framework? Tutto quello chepresenteremo in questo libro: linguaggi, compilatori e una serie di funzionalità comuni.Grazie a questo approccio, diventa possibile sfruttare .NET Core conoscendo .NETFramework (e viceversa). Per questo motivo, nel corso del libro generalmente ciriferiremo al .NETFramework e, eventualmente, sottolineeremo eventuali specificità di.NETCore.

.NETCore 1 non è ancora stato rilasciato in versione definitiva nelmomento in cuiquestolibrovienepubblicatoedèdisponibilecomePreview.Ilrilasciodefinitivoavverrànelcorsodel2016.

Icomponentidel.NETFrameworkIl.NETFrameworkècompostodaunaseriedifunzionalitàchesiincastranoinmanieraperfetta all’interno di un immaginario puzzle, per rendere lo sviluppo più semplice, aprescinderedallatipologiadiapplicazionesviluppata.

Questanuova releasedel .NETFrameworkèevolutiva: sibasa, infatti, sullaversione4.5, di cui è un aggiornamento. Installando la versione 4.6 possiamo godere di tutti ibenefici introdottidallaversione4.5,potendocontareanche sullenovitàcheandremoapresentare nel corso di questo libro.Di fatto, installando il .NETFramework 4.6 vieneinstallato anche il Service Pack del .NET Framework 4.5, che resta la base su cui sipoggianolefunzionalità.

Unodegliobiettividel.NETFrameworkèinfattiquellodiunificarelemetodologiediprogettazione e sviluppo nell’ambito delle piattaforme Microsoft, offrendo uno stratocomune sul quale gli sviluppatori possano basare le proprie applicazioni,indipendentementedallalorotipologia.

I concetti esposti in questo capitolo (come in quelli immediatamente successivi)rimangono del tutto validi in presenza di applicazioni di tipo differente.Questo aspettorappresenta un vero vantaggio anche in termini produttivi per lo sviluppatore, dalmomento che può imparare a sviluppare applicazioni .NET in modo più semplice eimmediato,utilizzandolostessolinguaggio,lastessatecnologiaeilmedesimoapproccioperscopidifferenti.

Indipendentemente dalla versione, il .NET Framework presenta una serie dicaratteristiche e componenti che, nel tempo, sono rimasti sostanzialmente invariati oquasi,ossia:

Common Language Runtime (CLR): è il cuore della tecnologia, la parteresponsabiledigestirel’esecuzionedelleapplicazioni;

Page 30: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

CommonLanguageSpecification (CLS): èun insiemedi specifiche che rendonopossibilel’interoperabilitàtralinguaggidifferenti;

CommonTypeSystem(CTS):rappresentadellespecificheperuninsiemecomuneditipiscrittiinlinguaggidifferenti,cherendepossibileloscambiod’informazionitra le applicazioni .NET, fornendo un meccanismo di rappresentazione dei daticondivisodalruntime;

linguaggi:èciòcheconsentedisviluppareleapplicazioni,cioèprincipalmenteC#6eVisualBasic14;

un insieme di tecnologie diverse: come ASP.NET, WinForms, WindowsCommunication Foundation, Windows Presentation Foundation, WindowsRuntimeeADO.NET,ingeneralecontenutiall’internodicomponenti,concettosucuiavremomododitornareabreve.

Figura1.1–Letecnologieallabasedel.NETFramework.

Questa caratteristica comporta indubbiamente vantaggi nella creazione del software: inparticolare,diventamoltopiùsemplicepassaredallosviluppowebaquelloperWindows(oviceversa),vistocheil .NETFrameworkoffrelemedesimefunzionalitàaprescindere“dall’interfacciagrafica”chesiutilizza,oppureriutilizzare lemedesimecomponentipertipologieeterogeneediapplicazioni.

Ivantagginonfinisconoperfarsisentiresolonellafasedisviluppo,masonoimportantianche in quella di progettazione. Se quest’aspetto è spesso sottovalutato, esso rivesteinveceun’importanzastraordinariaquandoabbiamoachefareconprogetticomplessi.

Ilpercorsodiapprendimentoiniziale,pertuttiquestimotivi,èpraticamentelostesso,aprescinderedallatipologiadiapplicazionecheandremoacreare,perpoidifferenziarsiperquanto riguarda le problematiche specifiche di ogni ambiente, dato che un’applicazionewebhapeculiaritàdifferentidaquellediun’applicazioneWindows.

Page 31: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

All’interno di un ambiente del genere, anche il linguaggio rappresenta (quasi) undettaglio.Di fatto, ciascun linguaggio supportato dal .NETFramework (nel nostro casoVisual Basic, ma il concetto è identico anche per C#) accede alle stesse funzionalitàofferte dalla piattaforma applicativa, utilizzando semplicemente notazioni sintattichediverse,ognunadotatadipropriemotivazionistoricheetecniche.

Una classe non è nient’altro che un insieme di funzionalità offerte allosviluppatore, tali da non dover essere implementate ogni volta da zero, madisponibiliperessereriutilizzateinfasedisviluppoladdoverisultinecessario.

Nel corso del libro, impareremo a utilizzare le classi in maniera del tuttonaturale,tantochequestitermini,allafine,sembrerannoscontati.

IduecomponentiutilizzatimaggiormentesonoilCommonLanguageRuntime(CLR),chesaràapprofonditonellaprossimasezionediquestocapitolo,elaBaseClassLibrary(BCL)che, come il nome stesso suggerisce, contiene alcune tipi di base comuni a tuttol’ambiente.

CommonLanguageRuntime(CLR)Ognilinguaggiodiprogrammazionesibasasuuncomponentedenominato“runtime”che,asecondadellediversesituazioni,puòesserepiùsemplice,comenelcasodiC++dovelasua funzione è quella di fornire un’infrastruttura comune all’esecuzione del codicemacchina, o più complesso, come nel caso di VB6, dove il runtime esegue il codicecompilato inp-code,odi Java, incui lavirtualmachinesioccupadi servizianaloghiaquellioffertidal .NETFramework. IlCommonLanguageRuntime(CLR)rappresenta ilruntimeperil.NETFramework.

Il ruolo del CommonLanguageRuntime è semplicemente quello di eseguire tutte leapplicazioni.NETscritteinunodeilinguaggisupportatidallapiattaforma(siparlaintalcaso di linguaggi managed o gestiti) e di fornire un insieme di servizi affinché leapplicazioni possano sfruttare e condividere una serie di funzionalità tali da renderel’ambientediesecuzionepiùstabileedefficiente.

Nel caso specifico, durante la fase di esecuzione, il CLR provvede a caricare edeseguireilcodice,offrendocaratteristichequalilagestionedellamemoria,l’allocazionedithreade,piùingenerale,politichediaccessoallerisorsedelcomputer.

Per poter eseguire un pezzo di codice scritto in Visual Basic o in uno qualsiasi deilinguaggisupportatidalCLR,occorreutilizzareuncompilatorespecificochenonproduceilclassicocodicemacchinamaunaformaibridaeparziale,denominataMSIL(MicrosoftIntermediateLanguage)oCIL(CommonIntermediateLanguage),piùcomunementedettapersemplicitàIL(IntermediateLanguage).Sitrattadiuninsiemed’istruzioniindipendentidal linguaggio e dall’architettura dell’hardware su cui esso verrà poi eseguito. All’attodell’esecuzione,questeistruzionisonogestitedaunJIT-ter,cioèdauncompilatoreJust-In-Timechehailcompitoditrasformarlefinalmenteincodicemacchina,ottimizzandoleper il tipo di hardware in uso e fornendo al tempo stesso funzionalità di gestione

Page 32: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

dell’accessoallerisorsedisistema.

Ilmeccanismodescritto è possibile perché il codice, per essere eseguito, deve essereconvertito in qualcosa che l’architettura per la quale viene compilato è in grado dicomprendere, cioè codice macchina. L’IL per questo motivo è solo un linguaggiointermedio,chenecessitadiunaconversioneperessereeseguito.

Esistono JIT-ter specifici per ognuna delle piattaforme hardware supportate. Almomento,Microsoftfornisceimplementazionidel.NETFrameworkperambientia32bit(x86)ea64bit(x64eia64).Apartiredaquestarelease,èstatointrodottounnuovoJITcompiler,chiamatoRyuJIT.

Questo nuovo compilatore nasce all’evolversi della tecnologia cui abbiamo assistitonegli ultimi anni: in unmondo in cui si va sempre di più verso i 64 bit, RyuJIT va asopperire a una mancanza storica del .NET Framework, in cui il compilatore era piùveloce per 32 bit che per 64 bit, garantendo, a parità di codice, performance superiorianchedi20volteeuntempodistartuppiùrapidodelleapplicazioni.Possiamoscaricaregratuitamentel’ultimaversionedel .NETFrameworkperlanostrapiattaformadaquestoURL:http://msdn.microsoft.com/netframework/.

Il .NET Framework viene distribuito in due versioni, una chiamataRedistributable,perchécontienesoloilnecessarioperfarfunzionareleapplicazioni(siinstallatipicamentesui server di testing e produzione) e una che, invece, contiene anche il SoftwareDevelopmentKit (SDK), composto da un insieme di strumenti utili per lo sviluppo edalla documentazione di supporto.Quest’ultima è quella di cui facciamo uso in fase disviluppo.

Come abbiamo anticipato, nel corso del 2016 verrà rilasciato anche .NET Core, inversioneperWindows,LinuxeMacOSX.

Quando il compilatore produce IL, aggiunge una serie di metadati, che servono perdescrivereilcontenutodell’entitàrisultantedallacompilazione.Imetadatirappresentanoinformazioni aggiuntive che sono allegate al codice IL per descriverne meglio ilcontenuto.

La presenza di queste informazioni aggiuntive consente al codice di auto-descriversi,cioèdiessereingradodifunzionaresenzalibrerieditipiolinguaggicomeIDL(InterfaceDefinitionLanguage).

I metadati del CLR sono contenuti all’interno del file che viene generato inseguitoallacompilazionedelsorgente,scrittoinVisualBasic.Ilcontenutodelfile,cheèchiamatoassembly,èstrettamentelegatoall’ILprodottoeconsentealCLR di caricare ed estrarre i metadati in fase di esecuzione, quando sononecessari. In questo modo può essere ricavata la definizione di ogni tipocontenuto,lafirmadiognimembro,eventualiriferimentialibrerieesterneeadaltre informazioni, necessarie a runtime affinché il codice venga eseguito almeglio.

Internamente,ilCommonLanguageRuntimeècompostodidueelementiprincipali:

Page 33: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

MSCOREE.DLL;

MSCORLIB.DLL.

MSCOREE.DLLèilcomponenteall’internodelCLRresponsabiledicompilareilcodiceIL nel codicemacchina, secondo ilmeccanismo che abbiamo analizzato finora, ovverotramite un JIT-ter specifico per ogni architettura hardware. È anche responsabiledell’allocazioneedelladisallocazionedeglioggetti inmemoria,oltre chedellagestionedellasicurezzaedellepolitichediaccessoallerisorsedapartedelcodice.

MSCORLIB.DLLcontienelelibreriedisistemachecompongonoilcosiddetto“core”,ilcuore del .NET Framework, su cui si basa ogni applicazione gestita dal CommonLanguageRuntime.Questelibreriediventanodifacileutilizzodopounpo’dipratica,datoche consentono di effettuare le operazioni più comuni. Avremomodo di usare la BaseClass Library (BCL), di cui anche MSCORLIB.DLL fa parte, nel corso dei prossimicapitoli.

Figura1.2–IlCommonLanguageRuntime(CLR)indettaglio.

IlconcettodicodicemanagedNondi rado capiterà di imbatterci nel concetto di codicemanaged (spesso anche dettocodicegestito).ConquestoterminesiindicanotuttequelleapplicazionieseguitetramiteilCLR.Ilcodicemanagedbeneficiadifunzionalitàcomel’integrazionedeilinguaggi,conlarelativagestionedelleeccezioni,lasicurezza,ilversioningeildeployment,favorendol’interazionetracomponentiscrittiinlinguaggidifferenti,dalmomentoche,all’attodellacompilazione,tuttoilcodiceècomunquetrasformatoinIL.

Iltermine“managed”nonèstatosceltoacaso,datocheilCommonLanguageRuntimeprevedeunmeccanismodisandboxing,cioèdiinscatolamento,chefasìcheilcodicesiaeseguito isolato da altri contesti e con la possibilità per il CLR, attraversoMSCOREE.DLL, di gestire anche le politiche di accesso alle risorse, la gestione dellamemoriaegliaspettidisicurezza.

Page 34: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Viceversa, il codice che non viene eseguito dal Common Language Runtime vienecomunementechiamatounmanaged(nongestito).UnprogrammascrittoinVB6oC++èun’applicazioneunmanaged,percapircimeglio.

Quandoscriviamoun’applicazioneinunodeilinguaggimanaged,comeVisualBasic,inrealtà, il processo di esecuzione che sta dietro è molto più complesso di quello chepossiamo immaginare, benché venga tutto consumato nell’arco di poche frazioni dimillesimi di secondo. Nella figura 1.3 viene schematizzato il funzionamento di questoprocesso.

Comeabbiamogiàdetto,durantelaprimafasedicompilazionevieneprodottocodiceIL.All’attodell’esecuzioneilpassosuccessivodapartedelCLRconsistedapprimanellacompilazionedelcodicedaMSILinlinguaggiomacchina(operazionesvoltadalJIT-ter)e, successivamente, nel controllo della congruenza dei tipi e nell’applicazione dellepolitichedi sicurezza. Infine, ilCLRcreaunApplicationDomain (spesso chiamatopersemplicitàAppDomain),cherappresentailcontestodiesecuzioneveroeproprio.

IlpercorsocompiutodalCommonLanguageRuntime,quandoeseguecodicemanaged,puòessereschematizzatocomesegue:

cercaimetadatiassociatialmembrorichiesto;

scorrelostackdiesecuzione;

gestisceleeventualieccezionisollevate;

gestisceleinformazionirelativeallasicurezza.

Page 35: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura1.3–IlprocessodiesecuzionedicodicedapartedelCLR.

Laseriedioperazionimostrateinfigura1.3avvienesoloallaprimarichiestamentre,perlevoltesuccessive,esisteunmeccanismochefasìchequestafasevengasaltata,andandoa recuperare direttamente il risultato della compilazione, inmodo da evitare sprechi dirisorseeottenereperformancedi tutto rispetto.Questovuoldirecheunachiamataauncertometododi una classe fa sì che il JITter compili l’IL soltanto laprimavolta: dallesuccessiverichieste,verràutilizzatalaversionegiàcompilata.

PeravereaccessoaiservizioffertidalCLR,icompilatoridevonofareaffidamentosuuna serie di regole che rendano possibile l’interazione tra componenti. Questa partedell’architetturadel.NETFrameworkprendeilnomediCommonTypeSystem.

CommonTypeSystemIlCommonTypeSystem(CTS)rappresentaun’altraparteimportantedell’architetturadel.NET Framework, dato che stabilisce come i tipi debbano essere dichiarati, utilizzati egestiti dal Common Language Runtime; si tratta di un elemento di importanzafondamentale per garantire il supporto e l’integrazione multi-linguaggio, poiché ognilinguaggio ha la propria struttura e le proprie regole, che si basano su convenzioni chespessostannoagliantipodileunerispettoallealtre.

Page 36: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IlCommonTypeSystemhailcompitodirenderepossibilecheuncomponentescrittoinVisualBasic(cheutilizzailtipoInteger)eunoinC#(chefausodeltipoint)possanoscambiarsiinformazionieragionaresullostessoidenticoconcetto,cheèappuntoquellodinumerointero.Questoèpossibilepoichéentrambiitipi,inteInteger,sonoconvertitiinfasedicompilazioneneltipoSystem.Int32,cheèlarappresentazionedelnumerointeroall’internodel.NETFramework.

IlCommonTypeSystem consente di scrivere codice senza dover far riferimento perforza al tipodel .NETFramework.Per denotare i tipi, lo sviluppatore può continuare autilizzareleparolechiavespecifichedellinguaggioinuso(intalpostodiSystem.Int32inC#;IntegeralpostodiSystem.Int32inVisualBasic),datochequestenonsonoaltrochealiasdeltipoeffettivo.

IlCommonType System garantisce inoltre che, in fase di compilazione, la tipologiainizialevengapreservata.TuttoquestoèpossibilegraziealfattocheilcompilatoreVisualBasicèCLS-compliant,ilchesignificachegeneracodicecompatibileconlespecificheCLS,cheverrannotrattatenellaprossimasezione.

CommonLanguageSpecificationLa Common Language Specification (CLS) rappresenta una serie di specifiche che ilcompilatoreeilrelativolinguaggiodevonorispettareperfareinmodocheuncomponentesia in grado di integrarsi con componenti scritti in linguaggi diversi. In pratica, stiamoparlando del sistema attraverso il quale il compilatore espone i tipi affinché il codicerisultantepossaessereeseguitodalCommonLanguageRuntime.

Perchétuttociòavvenga,itipieimetodipubblicidevonoessereCLS-compliant,cioècompatibili con tali specifiche. Quelli privati, che non vengono esposti all’esterno,possonoanchenonesserlo,dalmomentochesoloi tipie imetodipubblicisonoespostidirettamentealCLR.

Datoche ilCommonLanguageRuntimeè ingradosolodieseguire IL, i compilatoridevono essere ingradodi produrre codice IL corretto, tale dapermettere alCLRdi farparlarecomponentidifferenti,grazieall’uniformitàgarantitadallaCLS.ÈquicheentraingiocoilCommonTypeSystem,ilqualeconsentelaportabilitàdeitipi,inuncontestodoveil codice ILègeneratoapartiredaaltri linguaggi.L’esempiopiù semplicediquanto laCLS sia importante è rappresentato dal fatto che C#, come altri linguaggi, è “casesensitive”, cioè fa differenza tra le letteremaiuscole eminuscole nella nomenclatura enelle parole chiave, laddove invece, in Visual Basic, questo non rappresenta unadifferenza.Inuncontestodelgenere,ladefinizioneinC#diunavariabiledinomeMiaVarha un significato differente rispetto a Miavar, mentre in Visual Basic i due nomiidentificanolostessooggetto.ÈproprioincasicomequestochelespecifichedellaCLSentranoingiocopoiché,proprioperquestapotenzialeambiguità,essevietanodiesporremembripubbliciconlostessonomee“case”differente.

SeilcodiceèCLS-compliant,cioèrispettatutteleregoleprevistedallaCLS,avremola

Page 37: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

certezzachel’accessoaimembripubblicipossaesserefattodauncomponentemanaged,anche se scritto in un linguaggiodifferente.D’altra parte, laBCL, che contiene tutte leclassi di base del .NET Framework, è interamente scritta in C#, ma può esseretranquillamenteutilizzatadaapplicazioniscritteinVisualBasic.LaCLSregolapertantole modalità in cui i tipi devono essere esposti, strutturati ed organizzati. In primaapprossimazione, possiamo identificare due gruppi principali di tipi: i cosiddetti tipiprimitivi elencati in tabella 1.1 (tra cui il tipo System.Object) e i tipi derivati, cheereditanodal tipobaseSystem.Object.Tutti gli elementi definiti tramite un linguaggiomanaged sono, infatti, oggetti. Il Common Language Runtime capisce solo oggetti e,pertanto, il .NET Framework favorisce l’utilizzo di tecniche e linguaggi diprogrammazione chiamati object oriented, cioè orientati agli oggetti. Il concetto diereditarietà e la programmazione orientata agli oggetti verranno trattati nel corso deiprossimicapitoli.

Tabella1.1–ItipidellaCLS.

Tipo Descrizione

System.BooleanRappresenta un valore boleano (True o False). La CLS non prevede conversioni implicite da altri tipiprimitivi,cioèdabooleanastringaoviceversa,senzaun’operazioneesplicitadiconversione.

System.Byte Rappresentauntipobytesenzasegno,cioèintericompresitra0e255.

System.Char RappresentauncarattereUNICODE.

System.DateTime Rappresentauntipodataeora,inunintervallocompresotra01/01/01e31/12/9999e0:00:00e23:59:59.

System.Decimal RappresentauntipoDecimal,conunnumeromassimodiventottocifre.

System.Double Rappresentauntiponumericoa64bit,adoppiaprecisioneeinvirgolamobile.

System.Int16 Rappresentauninteroa16bitconsegno.

System.Int32 Rappresentauninteroa32bitconsegno.

System.Int64 Rappresentauninteroa64bitconsegno.

System.Single Rappresentauntiponumericoa4byte,adoppiaprecisioneeinvirgolamobile.

System.TimeSpan Rappresentaunintervalloditempo,anchenegativo.

System.String Rappresentauninsieme,anchevuoto,dicaratteriUNICODE.

System.Array Rappresentaunarray(vettore)dioggettimonodimensionale.

System.Object Iltipobasedacuituttiglialtriderivano.

LaCross-LanguageInteroperabilityLaCross-LanguageInteroperability(CLI)èlapossibilitàdelcodicediinteragireconaltrocodicescrittoinunlinguaggiodifferente.Questacaratteristicaconsentediscriveremenocodice,riutilizzandoquellogiàpresenteefavorendounosviluppononripetitivo.

IlcodicemanagedbeneficiadellaCLIperchéidebuggereivaristrumentidisviluppodevonoessereingradodicapiresolamentel’ILeisuoimetadati,piuttostocheognunodeidiversi linguaggicon lesuepeculiarità. Inoltre, lagestionedelleeccezioniviene trattatanellostessomodopertuttiilinguaggi,inmodocheunerrorepossaessereintercettatodauncomponentescrittoinunlinguaggiodiversodaquellochel’hasollevato.Infine,poiché

Page 38: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ognilinguaggiopoggiasuunmodellodidaticomune,diventapossibile,senzaparticolarivincoli,scambiareoggettitracomponentiscrittiinlinguaggidifferenti.

L’integrazione tra i linguaggi è dovuta primariamente alla Common LanguageSpecification, in base alla quale i compilatori generano il codice. La CLS garantisce,infatti,unabasediregolecondivisetalidapermetterel’interoperabilitàrichiesta.

TipidivaloreetipidiriferimentoA questo punto è ormai chiaro che i tipi sono alla base del CLR, poiché sono ilmeccanismo attraverso il quale lo sviluppatore rappresenta nel codice le funzionalitàderivanti dall’ambito logico e pratico dell’applicazione. Un tipo serve per descrivere ilruolodiunavariabilenell’ambitodelcodiceenecaratterizzalefunzionalità.

All’interno del Common Language Runtime troviamo il supporto per due categoriefondamentaliditipi:

tipi di valore: sono rappresentati dalla maggior parte dei tipi primitivi (comeSystem.Int32, System.Boolean, System.Char, System.DateTime, ecc.), dalleenumerazioniodatipidefinitidallosviluppatorecomestrutture;

tipidi riferimento: sono rappresentati dalleclassi. Il loro scopo è di fornire unmeccanismo di strutturazione del codice e memorizzazione dei dati in un’otticaobjectoriented.

Ladifferenzatratipidivaloreetipidiriferimentoècheiprimicontengonodirettamenteilvalore dei dati, mentre i secondi contengono solo un riferimento a una locazione inmemoria (sono, inpratica, unpuntatore auna regionedimemoria). I tipi di valorenondevono essere istanziati esplicitamente tramite un’azione di creazione e non possonocontenere un valore nullo. Per i tipi di riferimento vale, in entrambi i casi, l’esattocontrario.ItipidivalorederivanodallaclasseSystem.ValueType(odaSystem.Enumnelcasodelleenumerazioni)e,traquesti,sipossonocontemplaregranpartedeitipiprimitivi,comeSystem.Int32 oSystem.Boolean. System.Object e, in generale, i suoi derivati,come pure System.String, sono tipi di riferimento. Analizzeremo entrambi questiconcettinelquartocapitolo.

Tecnicamenteparlando,ladifferenzaprincipaletraleduetipologieèrappresentatadalfattocheitipidivaloresonoallocatidirettamentenellostack,mentreitipidiriferimentosonogestitinelmanagedheapdelCommonLanguageRuntime.

Comedetto,ilmanagedheapèutilizzatoperallocaretipidiriferimento,mentrelostackèusatosoloperitipidivalore.L’accessoallostackèpiùvelocemaglioggetti al suo interno vengono sempre copiati, quindi non sarebbe adatto neicasiincuiglioggettisianocomplessielarelativacopiarisultidispendiosa.Ilmanagedheap,d’altrocanto,ègestitodalGarbageCollector,uncomponenteingrado di deallocare in automatico lamemoria, per cui i vantaggi, in caso dioggetticomplessilacuicopiasiadispendiosa,sifannosentiremaggiormente.

Page 39: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Il capitolo 4 contiene una trattazione più esaustiva circa l’uso dei tipi di riferimento eaffrontal’argomentodaunpuntodivistamenoteoricoepiùorientatoall’utilizzodiquesticoncettiall’internodel.NETFramework.

Conversionitratipi,boxingeunboxingIlfattocheilCommonLanguageRuntimesupportiungenericotipobaseSystem.Objectrappresenta,dalpuntodivistadellosviluppo,unvantaggiodinonpococonto.Datochetutti gli oggetti derivano da System.Object, possiamo scrivere codice che utilizzi ungenericoObjecteassociareaquest’ultimoun’istanzaqualsiasidiunaclasseodiuntipodivalore.Ineffetti,nel .NETFrameworkesistonomoltissimefunzionalitàchesibasanoproprio su questa caratteristica dato che, dal punto di vista della programmazione aoggetti,èperfettamentelecitopassareunoggettoderivatodaObjectladdoveunmembrosiaspettiquest’ultimo.Questacaratteristicaèparticolarmenteimportanteperchéconsentediscriverecodicecheèingradodigestirediversetipologieditipiconlestesseistruzioni.

DatochetuttiglioggettiderivanodaObject,èassolutamentelecitoassegnareuninteroa una variabile di tipo Object. Dato che Integer è un tipo valore (e quindi sta nellostack),incorrispondenzadiunataleoperazioneilCLRècostrettoacopiareilcontenutonelmanagedheap,doverisiedonoitipiriferimentocomeObject.

Quest’operazioneelasuacontraria,sonochiamaterispettivamenteboxingeunboxinge hanno un costo non trascurabile in termini di performance, per cui bisogna fareattenzioneanonabusarne.

Inconclusione,ancheselatentazionediscriverecodiceutilizzandoungenericoObjectpotrebbe essere forte, l’utilizzodiretto del tipo specifico, laddovepossibile, consente dievitare queste due operazioni e dunque equivale a garantire maggiori performanceall’applicazioneoltreacomportareilbeneficioimplicitodiscriverecodicetypesafe,cioèche usa direttamente il tipo più corretto, evitando problemi derivanti da codice nonstronglytyped.

Lagestionedellamemoria:ilGarbageCollectorUna delle tante funzionalità interessanti offerte dal CLR è la gestione automatica dellamemoria,checonsenteallosviluppatoredievitare icosiddettimemory leak (ossiaqueicasiincuidimentichiamodicompiereleoperazionilegatealladeallocazionedell’oggettodalla memoria). Nelle applicazioni del mondo COM (Visual Basic 6 o ASP) questeproblematiche sono più che diffuse e hanno come effetto quello di peggiorare leperformance,senondibloccarel’interaapplicazione.

Perovviareaquestiproblemi,tuttiglioggettiallocatinelmanagedheapvengonogestitidauncomponenteparticolare,ilcuiruoloèquellodiliberarelamemoriadaglioggettinonpiùutilizzatisecondounalgoritmonondeterministico,perché,ingenerale,nonpossiamocontrollareilmomentoincuiquest’ultimoeseguiràlesuefunzionalità.

Page 40: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IlGarbageCollector(GC)entrainazioneogniqualvoltavisialanecessitàdiaveremaggiori risorseadisposizione.Peraltro,unoggettononvienenecessariamente rimossonelmomentoincuinonèpiùutilizzatodall’applicazione,mapuòessereeliminatoinunafasesuccessiva.

Schematizzando,ilGarbageCollectoragisceseguendoquestipassaggi:

segnatuttalamemoriamanagedcome“garbage”,cioèspazzatura;

cercaiblocchidimemoriaancorainusoelimarcacomevalidi;

scaricaiblocchinonutilizzati;

infine,compattailmanagedheap.

Il Garbage Collector, per ottimizzare le sue prestazioni, utilizza un algoritmo di tipogenerazionale.

Nella cosiddetta generation zero, che è la prima di cui viene fatto il collecting (ilprocesso di raccolta spiegato sopra), vengono inseriti gli oggetti appena allocati.Quest’area è certamente il posto dove incontriamo la più alta probabilità di trovare unbloccodimemorianonutilizzatoe,al tempostesso,èanchequellaconunadimensioneminore, quindi più rapida da analizzare. È talmente piccola che è l’unica delle tregeneration a stare dentro la cache L2 della CPU. Quando un oggetto sopravvive a uncollecting, perché raggiungibile, viene promosso alla generation successiva. Inoltre, ilGarbage Collector lavora sulla generation 0, ma se la memoria dovesse non esseresufficiente,passaallageneration1,ecosìvia.

IlGarbageCollector alloca lamemoria inmodo tale che ilmanagedheap rimanga ilmenopossibileframmentato.Questorappresentaunagrossadifferenzarispettoaiclassiciunmanaged heap, dove la dimensione e la frammentazione possono crescere moltorapidamente.

Glioggettidigrandidimensionimeritanoperaltroundiscorsoaparte.Questioggetti,una volta allocati, rimangono di solito inmemoria per lunghi periodi di tempo, per cuivengonomantenutiinun’areaspecialedelmanagedheap,chenonvienemaicompattata.Tenerli separatidal restooffremaggioribenefici rispetto aquanto sipossa immaginare,perché il costo di spostare un oggetto di grandi dimensioni è ripagato dal fatto che ilmanagedheapnonvienepiùframmentato.

I concetti appena esposti valgonoper quegli oggetti che fannouso esclusivamentedirisorsemanaged. Spesso invece, come nel caso di utilizzo di connessioni a database ohandlediWindows(accessoafilesudiscooadaltrerisorsedisistema),lerisorsesfruttateinternamentesonoditipounmanaged.

Nelcasodiutilizzodi risorseunmanaged,aspettareche ilGarbageCollectorfaccia il proprio lavoro comporta un serio degradodella performance.A talescopo è stato introdotto il cosiddetto pattern Dispose, cioè un approcciounificato al problema del rilascio delle risorse unmanaged. Attraversol’implementazione di un’apposita interfaccia (il concetto di interfaccia èspiegato nel capitolo 4), chiamata IDisposable, si fa in modo che tutti gli

Page 41: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

oggetti che la implementano abbiano un metodo Dispose, che deve essereinvocatoallafinedell’utilizzodell’oggettostesso.Ilmetodohalaresponsabilitàdichiudereedeallocarelerisorseunmanagedinuso.

Il ruolo delGarbageCollector èmolto importante, poiché consente allo sviluppatore dinoncurarsidell’allocazionedellamemoria,chevienecosìgestita inautomatico, inbasealle reali necessità di risorse. Dilungarsi troppo nella sua analisi in questa fasecostringerebbeafareunosforzoinutile,datochedovrebberoesseredatiperscontatimolticoncettiche,invece,sarannooggettodeiprossimicapitoli.

ComponentichefannousodirisorseunmanageddevonoancheavereunFinalizerpernonincorrereinfenomenidimemoryleakche,loripetiamo,aldifuoridelcodicegestitosonocomunqueprobabili.InVisualBasicquestoèpossibile,utilizzandounoverridedelmetodoFinalizedellaclasseSystem.Objectoppurecreandoundistruttoredellaclasse.È peraltro utile sottolineare che non è possibile utilizzare contemporaneamente siaFinalizesiaDispose.IlruolodelFinalize,rispettoaquellodelDispose,èdiliberarelerisorsequandol’oggettovienerimossodalmanagedheap.Perquestomotivononvamaiimplementatoquandononcen’èdavverobisogno,datochequestaoperazioneconsumarisorse. Inoltre,FinalizeeDispose vengono invocati inmomentidifferenti.Tuttavia, èutilesottolinearecome,adifferenzachenelmondoCOM,un’applicazionemanagednonabbiabisognodiavereun’appositasezione,generalmentecollocataallafinediunbloccodi codice in cui vengono deallocati e chiusi gli oggetti gestiti, poiché questo servizio èoffertodalRuntimeattraversoilCLRe,inparticolare,tramiteilGarbageCollector.Tuttoquestooffreilduplicevantaggiodirenderepiùsemplicelosviluppoedimigliorare,comeabbiamogiàdetto,leperformanceelastabilitàdelleapplicazioni.

IlconcettodiAssemblyUno dei problemi più grandi del mondo COM è, senza dubbio, la forte presenza delconcetto di dipendenza e di versione di un componente. Spesso, l’installazione diun’applicazione che aggiorna la versione di un certo componente può avere effettidevastantisullealtre,portandoancheaunbloccototale.

Queste situazioni accadono perché, nel mondo COM, può esistere una e una solaversione di uno stesso componente caratterizzato da un identificativo univoco, dettoProgID.LasovrascritturadiuncomponenteCOMhaeffettoglobale,ossiariguardatutteleapplicazionichepuntanoalsuoidentificativo.

Per fareunesempio,una tipicasituazionedimalfunzionamentopuòriguardareADO,l’insieme di librerie che nel mondo COM (e quindi con Visual Basic 6 o ASP) vieneutilizzatoper l’accessoaidatabase. Inquesticasi, ilproblemaderivaspessodal fattodiaver sovrascritto fisicamente un file, chiamato Dynamic Link Library (DLL).SostituendounaDLL,cheattraversoilregistrodiWindowsèassociataalsuoProgrID,leapplicazionismettonodiutilizzarelaprecedenteversioneecomincianoafarriferimentoaquella nuova. Se l’aggiornamento con una nuova versione, in genere, non causa graviproblemi,molto spesso la sovrascrittura con una versione precedente ne può portare in

Page 42: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

quantità.

Purtroppoquesto limitediCOMè tale enonpuòessere superato, senonutilizzandoalcunitrucchi,cheperò,difatto,fannosìcheilcomponentesia,inognicaso,diversodaquellooriginale.

L’altro grande problema di COM è il suo modello di deployment, cioè il sistemaattraverso il quale, una volta creati, i componenti vengono registrati e distribuitinell’ambiente di produzione. La registrazione di un oggetto COM richiede un accessointerattivo al computer, per poter lanciare da riga di comando regsvr32.exe. QuestostrumentosioccupadiaggiungerenelregistrodiWindowsiriferimentidicuisièappenadetto, in modo che le applicazioni possano sapere dove trovare il file fisico cheimplementalefunzionalitànecessarie.

Infine,COMcomportaproblemianchedurantelafasedisviluppo,datocheunaDLLèfisicamente bloccata finché viene utilizzata e, in tali casi, per farne l’aggiornamento, ènecessariofermareilserviziochelastautilizzando.

Il .NETFramework differiscemolto dalmondo unmanaged, perché il corrispondentedella DLL, cioè l’assembly, è un file che al proprio interno contiene il risultato dellacompilazione espresso in MSIL, i metadati, il cosiddetto manifest, che contieneinformazionisull’assembly,elerisorse,ossiaelementidivarianatura(comeimmaginioaltro) inclusedirettamentedentro lo stesso file fisicoper rendereminime ledipendenzeesterne,comemostratonellafigura1.4.

Figura1.4–Loschemasemplificatodiunassembly.

Il vantaggio di avere i metadati che descrivono i tipi è rappresentato dal fatto che, incollaborazione con le informazioni contenute nel manifest, l’assembly è in grado dicomunicareall’esternotutteleinformazioninecessarieaffinchépossaessereutilizzatoal

Page 43: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

meglio,rendendoquindisuperflualaregistrazionenelregistrodiWindows.

IL non è un linguaggio macchina e, così com’è, disponibile nel suo formatosorgente,inchiaroall’internodell’assembly,nonèpropriamenteimmediatodacapire. Ciò comporta che possiamo leggerlo direttamente (tramite un toolchiamato ILDASM, incluso in Visual Studio) o, addirittura, disassemblare ilcodice e ottenere il sorgente Visual Basic corrispondente. Ci sono tool come.NET Reflector che, sfruttando una caratteristica del .NET FrameworkchiamataReflection, consentono di navigare all’interno di un assembly permostrarne tutti i tipi e i relativi elementi costitutivi, con la possibilità didisassemblarne il contenuto. Questi strumenti possono essere utilizzati percapire come funzionano internamente alcune caratteristiche delle classi chestiamo utilizzando, per leggere il codice in formato IL o in un linguaggiodiversodaquellod’origine.Dalmomentoche,durantelafasedicompilazione,tutte le variabili interne ai membri sono rinominate, vengono rimossi tutti icommenti e vengono effettuate alcune ottimizzazioni nel codice, con il .NETReflectornonpossiamovisualizzareilcodiceinunformatoesattamenteidenticoalsorgenteoriginale.Peraltro,ilrisultatodeldisassemblaggioètaledaesseremolto simileal codicedipartenza.Esistonodei tool, chiamatiobfuscator, cherendono il codice più difficile da decifrare. Si tratta comunque di sistemi chenongarantisconoperòunasicurezzaal100%.

Gliassembly,ingenere,sonospessoutilizzatiinformaprivata,cioèsenzaessereregistratinelsistema.Secondoquestomodello,perutilizzareuncomponenteesternoèsufficientecopiare il file in un determinato percorso, insieme ai file dell’applicazione, senza lanecessitàdieffettuarnelaregistrazionenelsistema.Questovuoldirecheinuncomputerpossonocoesisterepiùcopiedellostessoassembly,anche inversionidiverse, senzacheperquestomotivosiverifichialcunainterferenzatraloro.Tuttavia,inalcunicontesti,puòesserenecessarioavereunasolacopiacentralizzatadellostessocomponente,registrataalivellodisistema,evitandocosìdireplicarelevariecopieprivateperilfilesystem.

Persoddisfarequestanecessitàil.NETFrameworksfruttaunsistemachiamatoGlobalAssembly Cache (GAC), ovvero un repository centralizzato dove vengono inseriti gliassembly visibili a livello di sistema. Gli assembly della Base Class Library del .NETFramework, su cui si basano tutte le applicazioni .NET, rappresentano l’esempio piùevidenteescontatodiassemblycherisiedonoinGAC.

NellaGACpuòesserepresenteuna solacopiaper ciascunaversionediunassembly,doveperdeterminareunivocamentelostessosiusaunacombinazionedinome,versione,cultureepublickey.Questalimitazionenonrappresenta,difatto,unproblema,perchéil.NET Framework implementa il concetto di versioning e non quello di compatibilitàbinaria, propria delmondoCOM. IlCommonLanguageRuntime è, infatti, in grado dicaricare più versioni dello stesso assembly nello stesso istante, eliminando in un colposoloidueproblemimaggioridiCOM.

L’esecuzione side-by-side di più versioni è supportata anche dall’intero .NETFramework,nelsensochesullostessosistemaèpossibileavereversionidiversedel.NET

Page 44: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Framework installate contemporaneamente. Questa caratteristica contempla anche lapossibilitàdiaveretutteleversionidel.NETFrameworkdalla1.0alla4.6installatesullostessocomputer,senzacheesseinterferiscanominimamentefraloro.

Per leapplicazioniwebl’usodellaGACè ingenere limitatoacasiparticolari,valeadire in quelle situazioni in cui un gruppo di applicazioni sul server abbia bisogno dicondividere uno o più assembly. In tutti gli altri casi possiamo limitarci a usare gliassemblyinformaprivata.Comunque,questapraticasistadiffondendosemprepiù,ancheperlosviluppodiapplicazioniclient,atalpuntocheperfinoil.NETCorevienedistribuitoinsiemeall’applicativostesso,invececherichiedernel’installazionesullamacchina.

All’interno del manifest di un assembly, la versione ha il formatoMajor.Minor.Build.Revision.UnassemblyvieneconsideratodifferenterispettoaunaltroquandoavariaretraiduesonoivaloridiMajoroMinor.

Coloro che provengono dal mondo COM, in particolare gli sviluppatori ASP o VB6,hanno da sempre utilizzato il late-binding nel loro codice. Nel caso del motore discripting di ASP, questo approccio consente di demandare alla fase di esecuzione laverificadell’esistenzadiunmembroall’internodiuncomponente,convantaggidalpuntodi vista della scrittura del codice e altrettanti svantaggi dal punto di vista delleperformance, dato che questo controllo deve essere eseguito ogni volta a Runtime. Percapire il significato di quanto detto, basti pensare di nuovo al caso di ADO citato inprecedenza: aggiornando MDAC dalla versione 2.0 a una differente, il codice di unapaginaASPrimanecomunqueinvariato,proprioperchéglioggettiCOMsonoreferenziatinelcodicetramitel’utilizzodellate-binding.

Il Common Language Runtime offre un servizio simile a quello descritto, con ladifferenza peraltro che l’associazione viene fatta sin dalla fase di caricamentodell’assembly (e non almomento dell’esecuzione), secondo unmeccanismo noto comeearly-binding.Sfruttandoimetadati,infatti,ilCLRèingradodiconoscereaprioriqualisonoglielementiespostidaognitipopresenteinunassembly.

Esiste un meccanismo mediante il quale un assembly può essere firmatoattraverso una chiave, chiamata Public Key Token, riportata all’interno delmanifest insieme all’autore o al numero di versione. In questo modo, unassemblypuòessere identificato tramiteuno strongname, cioèun riferimentounivocodatodalnomedell’assembly,lasuaversione,unhashequestachiavepubblica.Lostrongnameserveal.NETFrameworkquandovogliamoutilizzareun tipo referenziato da una specifica versione di un assembly. Gli assemblypossonoancheesserefirmatiattraversouncertificatodigitale,peridentificarechihacreatol’assembly,unpo’comegiàavvienepergliActiveX.GliassemblyregistratinellaGACdevonoessereprovvistidistrongname.Questoargomentoèapprofonditoconmaggiordettaglionell’appendiceC.

Se nel mondo COM spesso viene utilizzato il trucco di sfruttare le interfacce permantenerelacompatibilitàtralediverseversioni,conil.NETFrameworktuttoquestononrisulta necessario, dal momento che il Common Language Runtime è in grado diindirizzarelachiamataall’assemblypiùidoneofinoaquandouncertomembromantiene

Page 45: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

lastessafirma(ovverononcambianomenétipo,siadiritornosiadeiparametriutilizzati).

Questa caratteristica fa sì che un’applicazione compilata, per esempio, per il .NETFramework 4.0, possa girare perfettamente con la versione 4.6 senza che debba esserenecessarioricompilarla.

Interoperabilitàtra.NETFrameworkeCOMSbarazzarsidituttal’esperienzaeilcodicegiàscrittononèmaiunapraticaconsigliabile.Per fortunaCOMpuòessere sfruttatonelCLRattraversounmeccanismocheprende ilnome di interop (interoperabilità). Affinché gli oggetti COM siano visibili al CLR,occorrechevenganocreatideitipi,chiamatiproxy,chefungonodatramitetralechiamateunmanagedequellemanaged,permettendoilpassaggiodidatisecondolediverseregoledirappresentazionepropriedeiduecontestidiesecuzione.D’altraparteWindowsstessoèin pratica tutto unmanaged, per cui talemeccanismo consente, ad esempio, di invocarefunzionalitànativeimplementatepropriocomeoggettiCOM.

L’interoperabilità offre comunque il vantaggio di consentire una meno brusca etraumaticamigrazionedelcodiceunmanged,graziealfattocheessopotràessereancorautilizzatoall’internodelleapplicazionimanaged.

Nel caso fosse necessario sfruttare l’interop all’interno delle proprie applicazioni,esistono strumenti, documenti ewhitepaper che facilitano il lavoro.A questo propositopossiamo trovare maggiori informazioni (in inglese) su MSDN, all’indirizzo:http://aspit.co/a6r.

ConclusioniIl .NETFrameworkrappresenta labasesucuiVisualBasic2015poggia tutta lapropriainfrastruttura, pertanto la conoscenza degli argomenti affrontati in questo capitolo siriveleràpreziosanelcorsodellibropercomprendereiconcettichetratteremoinseguito.

Il Common Language Runtime, insieme al Common Type System, alla CommonLanguage Specification, alla Cross-Library Interoperability e al modello di sicurezza,consentedisfruttareuninsiemedifunzionalitàdecisamentecomodedautilizzareinseritein una piattaforma applicativa completa,matura e pensata tanto per le applicazioni piùsempliciquantoperquellepiùcomplesse.

Inpiù, lagaranziadipoterscriverecomponenti in linguaggidifferentie fare inmodoche possano comunque scambiarsi informazioni è essenziale, poiché consente diaggiungere alle proprie applicazioni anche componenti di terze parti che, una voltacompilate,diventanoILesonodunqueconvertiteinunlinguaggiocomune.

Seppure molto vasta, la Base Class Library non copre tutte le necessità possibili,dunqueètutt’altrocherarochesianecessarioricorrereafunzionalitàaggiuntive.

D’altraparte,nelcasoincuisiabbiaancoramoltocodiceunmanagedinclusoneipropri

Page 46: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

progettidisviluppo,il.NETFrameworkriesceagarantireunatransizionemenodolorosa,grazieallapossibilitàdisfruttarel’interoperabilità(interop).

Infine, ilfattodipotercrearecomponentiedistribuirli insiemeall’applicazione,senzadoverliobbligatoriamenteregistrarealivellodisistemaall’internodellaGAC,consentedirenderelamessainproduzionedelleapplicazionidavverosempliceedimmediata.

È su queste solide fondamenta cheVisualBasic consente di creare le applicazioni diognitipo.Laconoscenzadellebasi,cosìcomedellasintassidellinguaggio,rappresentaunprerequisito essenziale, da cui non si può prescindere. Per questomotivo, nel prossimocapitolocisoffermeremosuquellechesonolepeculiaritàdibasedellinguaggiostesso.

Page 47: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

2

VisualStudio2015

Il .NETFramework è l’ambiente all’internodel quale le applicazioni vengono eseguite.Persvilupparle,tendenzialmentesiutilizzaVisualStudio,giuntoormaiallaversione2015.

VisualStudioèun’IDE(IntegratedDevelopmentEditor),cioèunambienteall’internodelqualeèpossibilegestirel’interociclodisviluppodiun’applicazione.Èdisponibileindiverse versioni, che racchiudono funzionalità specifiche per ambiti ben definiti. Laversione Express, per esempio, è indicata qualora volessimo iniziare a sperimentare lecaratteristichediVB,senzanecessitàdiacquistareunaversionecommerciale.LeversioniExpressdiVBsonodisponibiliall’indirizzohttp://www.microsoft.com/express/.

AllaversioneExpresssiaffiancaancheunanuovanata, laCommunityEdition,cheègratuitaperprogettiopensource,edentrocerti limiti,ancheper iprodotticommerciali.Tutteleinformazionisonodisponibilisulsitoufficialehttp://www.visualstudio.com/.

All’internodiquestocapitolovedremocomel’IDEelesuefunzionalitàpossonoessereutilizzate per creare applicazioni inVBdi qualsiasi tipoVedremopoi come sfruttare lefunzionalitàdell’Intellisense,comefunzionanolesolution,iprogetti,lacompilazioneeildebugger.

L’IDEdiVisualStudioVisual Studio è un ambiente di sviluppo che consente di gestire lo sviluppo diapplicazioni, di qualsiasi tipo esse siano, grazie a un meccanismo di estendibilità.Possiamo creare applicazioni basate su ASP.NET, suWinRT (perWindows 10),WPF,WCF, Entity Framework, LINQ, oppure console, mantenendo lo stesso ambiente esfruttandolostessolinguaggio.VisualStudioèun’applicazioneMDI(MultipleDocumentInterface),ingradodiconsentirel’aperturacontemporaneadipiùdocumenti,all’internoditab.

Questocapitolo,cosìcome l’intero libro,èbasatosullaversione in inglesediVisualStudio.Questo fattononrappresentaunveroproblema,datoche tra ledueversioniciòchecambiaèsoloilnomedellevocineimenu,nonlaposizionedeglistessi,nélerelativefunzionalità.

L’IDE di Visual Studio si presenta con una pagina iniziale come quella illustrata nellafigura2.1.

Page 48: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.1–LapaginainizialediVisualStudio.

Comesipuònotarenellafiguraprecedente,l’areadilavoroèsuddivisainzone,dovenellapartecentralespiccaquelladenominata“TextEditor”.Esistetuttaunaseriedizonecheèopportuno approfondire, per comprenderne al meglio l’utilizzo all’interno di VisualStudio.

Continuandoconl’ultimotrendintrodottoapartiredallaversione2012,VisualStudioha un nuovo tipo di design,mutuato dalMicrosoft Design Language (lo stesso che haportatoallaUIdelleultimeversionidiWindows),cheprivilegialasemplicità(neicolorienellostile),eliminandotral’altroletrasparenze,chenonsonopiùpresentinellefinestre.

TextEditor,designereIntellisenseApartiredaVisualStudio2010,ilTextEditorè liberamenteposizionabile,ancheinuneventuale secondo monitor. Non è più necessario che sia ancorato alla schermataprincipale: in questa modalità, chiamata docked, la finestra segue il normalecomportamento di un ambiente MDI. All’interno di questo editor, come il nomesuggerisce,vienescritto ilcodice, siaessoVisualBasic,markupHTML,codiceXAML(perWPF)oaltro codice.Questa funzionalità è stataulteriormente rifinita emigliorata,cosìdaoffrireunsupportoancoramiglioreinscenarimulti-monitor.

All’internodel texteditorèfornitaunafunzionalitàdicompletamentodelcodice,cheaiutanelloscriverelediversevariantipossibili:sitrattadell’Intellisense.

InVisual Studio 2015, comeda tradizione, l’Intellisense è stato ulteriormentepotenziatorispettoalleversioniprecedenti:lafunzionalitàcheconsentedifarsirestituireunmembroancheperoccorrenzeparzialiall’internodelnome,oltrechesemplicemente inserendo lemaiuscoleall’internodelnomedelmembro,è

Page 49: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

stataulteriormentemigliorata.

Si può sempre riportare in primo piano l’Intellisense, semplicemente premendo lasequenza Ctrl+Spazio, mentre ci si trova nel Text Editor. La figura 2.2 mostral’Intellisenseall’opera.

Figura2.2–L’Intellisenseall’opera.

Inalcuniscenari,comeper lewebformdiASP.NEToper leapplicazioniWPF, ilTextEditorpuòoccuparemetàdellospazioinaltezza,utilizzandounamodalitàchiamata“SplitView”.Inquestocaso,l’altrametàdellospazioèoccupatadaldesigner,cheèilsistemaattraversoilqualeèpossibileavereunarappresentazionevisualedell’interfacciasucuisistalavorando.La“SplitView”èvisibilenellafigura2.3.

Page 50: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.3–LaSplitViewdiVisualStudio.

Ildesigner èunamodalitàgiànota se inpassatoabbiamoutilizzatounambienteRAD,comeVisualBasic6,econsentedisvilupparetrascinandoglioggettiall’internodell’area,posizionandoliegestendoneleproprietà.Inquestocaso,sonodisponibiliduenuovitipiditoolbar,cheprendonoilnomeditoolboxepropertyeditor.

ToolboxLatoolboxèlazonaall’internodellaqualesonocontenutiicontrolli,dapotertrascinareneldesigner.GeneralmenteèpossibilecompierelastessaoperazioneancheversoilTextEditor,conl’effettocheinquestocaso,quandopossibile,vienegeneratoilcorrispondentecodice(omarkup).Latoolboxèvisibileindettaglionellafigura2.4.

Page 51: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.4–LatoolboxdiVisualStudio.

Eventualioggettiditerzepartivengonoregistratiinautomaticoeraggruppatiinmanieraopportuna,cosache,tral’altro,avvienecomunqueancheperglioggettigiàinclusi.

PropertyEditorIl Property Editor è l’area all’interno della quale possono essere definite le proprietà.Generalmentevieneutilizzato incombinazionecon ildesigner,maèpossibile sfruttarloanchequandosiutilizzailTextEditor.Èvisibileindettaglionellafigura2.5.

Page 52: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.5–IlPropertyEditordiVisualStudio.

Si tratta di un editor vero e proprio, che di default ordina le proprietà degli oggettiraggruppandoli per tipologia, ma che può mostrare anche il classico ordinamentoalfabetico. Le proprietà di tipo complesso possono, a loro volta, apriremenu o finestreaggiuntive,piuttostocheoffrirecomportamentichevannooltrelasempliceimmissioneditesto. Questi comportamenti sono definiti in fase di creazione dei controlli stessi esfruttano l’estendibilità di Visual Studio per fornirci un ambiente più semplice dautilizzare.

Altreareedell’IDEChiudiamoquestarapidacarrellatasulleareediVisualStudioparlandodellatoolbar. Inquest’ultimavengonoaggiunteunaseriedibarrechesemplificanol’utilizzodeitaskpiùcomuni.Sefacciamousodialtrilinguaggiduranteilnostrosviluppo,oltreaVisualBasic,è consigliabile, quando Visual Studio parte per la prima volta, scegliere come profilo“Generaldevelopment”,cheaggiungeintalsensolefunzionalitàpiùdiffuse.

La nostra prima analisi dell’IDE finisce qui: non ci dilungheremomolto riguardo lesingolevocideimenu,nonessendoquestounlibrosuVisualStudio,ilcuiusocomunqueèintuitivoeimpareremoapadroneggiarenelcorsodeiprossimicapitoli.

Continuiamoadareun’occhiataall’ambiente,passandoalprimopassodacompiereperlanostranuovaapplicazione:creareilrelativoprogetto.

Page 53: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

CreareunprogettoIlprogettorappresentailpuntodacuiiniziarepercreareun’applicazione.Possiamocreareun nuovo progetto dall’apposita voce, sotto il menu File. Visual Studio contiene unnumeromoltoelevatoditemplate,alcunideiqualisonovisibilinellafigura2.6.

Figura2.6–Ilwizardpercreareunnuovoprogetto.

A seconda della versione, questi template di progetto potrebbero essere in numerodifferente.LaversioneExpress,peresempio,necontieneunnumerolimitato.

Inlineadimassimaitemplatediprogettinonsonoaltrocheuninsiemegiàprontodifileconfiguratipersviluppareunospecificotipodiprogetto,percuiperimplementareunadata funzionalità è necessaria meno fatica. Visual Studio raggruppa questi templateall’interno di aree, così che sia più facile individuare quelli di nostro interesse. Peresempio,nellasezione“web”sonopresentiuninsiemeditemplatespecificiperASP.NET,mentrequelladenominata“Windows”racchiudeunaserieditemplatespecificiperquestotipodiapplicazione.

Ilmulti-targetingdel.NETFrameworkinVisualStudioDando un’occhiata più da vicino alla figura 2.6, non può sfuggirci la possibilità diselezionaredaunmenuappositoqualeversionedel.NETFrameworkvogliamoutilizzareperilnostroprogetto.VisualStudio2015offre–cosìcomeaccadeormaidallaversione

Page 54: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

2010–ilsupportoapiùversionidel.NETFramework,onorandoperciascunalerelativecaratteristiche. Questo vuol dire che scegliendo una versione, Visual Studio adatteràl’IDE, i compilatori, l’Intellisense e, in certi casi, anche le opzioni disponibili in alcunimenu.Conlaversione2015possiamocreareapplicazioniper:

.NETFramework2.0;

.NETFramework3.0;

.NETFramework3.5;

.NETFramework4.0;

.NETFramework4.5;

.NETFramework4.5.1;

.NETFramework4.5.2

.NETFramework4.6

.NETFramework4.6.1

Questo permette di avere una sola versione diVisual Studio installata per lavorare conapplicazionibasatesuversioniprecedenti.

VisualStudioèingradodigestireiprogettipensatiperleversioniprecedenti:inaltreparole, anziché migrare il file di progetto, come avveniva in passato, lo stesso vienelasciato com’è, garantendo la possibilità di essere sfruttato in team nei quali glisviluppatorifannousodiversionidiversediVisualStudio.

IlconcettodiprogettoesoluzioneAquestopuntoènecessariofarechiarezzasuiconcettidiprogettoesoluzione,menzionatigiàdiversivolte.

Il progetto è l’insieme dei file (sorgenti o risorse), che generalmente concorrono allacreazione dell’applicazione, mentre la soluzione è l’insieme dei progetti, cioèl’applicazionestessa.Moltospesso,specieinapplicazionisemplici,lasoluzionecontieneunsoloprogetto.Viceversa, inscenaripiùcomplessi,èmoltodiffusa lapresenzadipiùprogettiall’internodellasoluzione.

I progetti saranno compilati e creeranno il risultato della compilazione, che, loricordiamo,nelgergodel.NETFrameworksichiamaassembly.

DatalanaturadiVisualStudio,all’internodiunasoluzionepossonoconviveretranquillamente progetti scritti in linguaggi diversi. Possiamo quindi avere, afiancodiunprogettoinC#,unoinVisualBasicoC++managed.

Facendo un paragone conVisual Basic 6, la soluzione corrisponde ai vecchi file .vbg,mentre ilprogettoal file.vbp.Unavoltacreato ilprogetto, ilpassosuccessivoconsistenelgestirelostesso.

Page 55: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Èpossibilecambiare inqualsiasimomentoilnomedellasoluzioneedeiprogetti.Nelcaso di questi ultimi, occorre prestare attenzione al fatto che per cambiare il nome delnamespaceutilizzatodalleclassiènecessarioaccederealleproprietàdelprogettoedagiresulla schermata che apparirà. Cambiare il nome degli elementi all’interno del solutionexplorer rappresenta la scelta migliore, perché ha effetto sul nome fisico del file e,comunque,consentedimantenereintattaevalidalastrutturadellasoluzione.

GestiresoluzioneeprogettoLa parte di creazione del progetto è quella tutto sommato più semplice. Durante losviluppocicapiterà,invece,didovergestirelasoluzioneediprogettichecontiene.

Daunpuntodivistapratico,è importantenotarecome,nelcasodi soluzioniconpiùprogetti, si possa specificare quello predefinito (che viene lanciato in fase di debug)attraversolavoce“Setasstart-upproject”chevienevisualizzataquandosiaccede,coniltasto destro del mouse, al menu contestuale del progetto stesso. Non c’è limite allatipologiadiprogettichepossonoesserecontenuti,anziinapplicazionicomplesseèspessopossibiletrovare,nellastessasoluzione,tipologiediprogettidiversi:applicazioniconsole,WPF,ASP.NETeclasslibrary.Questeultimesonomoltocomode,inquantoconsentonodiraggruppareall’internodiunsoloassemblyunaseriedifunzionalitàchepossonoesserecondivisetrapiùprogettiall’internodellastessasoluzione.

AggiungereunprogettoallasoluzioneAbbiamo visto cheVisual Studio consente di avere più progetti all’interno della stessasoluzione. Per dimostrarlo, procediamo creando una applicazione di tipo Console.Successivamente,per fare inmodochealcune funzionalitàpossanoessere condivise trapiù progetti, proviamo ad aggiungerne un altro, questa volta di tipo class library. Percompiere questa operazione è sufficiente premere con il tasto destro del mouse sullasoluzioneeselezionarelavoce“Add”equindi“NewProject”,comesivedenellafigura2.7.

Page 56: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.7–L’aggiuntadiunnuovoprogettoallasoluzione.

È possibile aggiungere anche un progetto esistente, che può ritornare comodo quandoabbiamounprogettoesistenteevogliamogestirlodaunasolasolution.Inquestocaso,lavocedaselezionareè“ExistingProject”,utilizzandosemprelastessaidenticasequenzadipassaggiappenavista.

Perchéilprogettoconl’applicazioneconsolevedaquelloconlaclasslibrary,dobbiamoimparareagestirelereferenze.

GestionedellereferenzeLe referenze servono al compilatore (e quindi anche all’ambiente) per capire dove sitrovano le risorse esterne. All’interno del solution explorer sono visibili sotto il ramoReferences. Questa voce, a seconda del tipo di progetto, potrebbe non essere semprevisibile. Ad ogni modo, per poter aggiungere una reference, Visual Studio offre unappositomenu, raggiungibilepremendo il tastodestro sulprogetto stessoall’internodelSolutionExplorer, oppure dall’appositomenu. In entrambi i casi si apre una schermatacomequellavisibilenellafigura2.8.

Nelnostrocaso,dovremoselezionare il tab“Projects”,dacuipoi indicheremo l’altroprogetto. È anche possibile aggiungere referenze ad assembly presenti in GAC (comequellidellaBCL),aoggettiCOM,oadassemblycompilati,seguendolostessoapproccio.

Completataquestaoperazione, siamo ingrado, inuncolposolo,dicompilare tutta lasoluzione.

Page 57: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.8–Ilmenuperl’aggiuntadellereferenzealprogettocorrente.

GestionedidirectorynellasolutionÈpossibiletenerenellasoluzionedelledirectorychenonsianoeffettivamenteprogetti,mapossanoservireperraggrupparelogicamenteglistessi,oppureperincluderealtrerisorse,come file di testo, o documentazione.Questo è possibile dalla voce “Addnew solutionfolder”,raggiungibiledalmenucontestualesullasolution,comevisibilenellafigura2.9.

Page 58: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.9–Aggiuntadiunadirectoryallasoluzione.

I file contenuti in queste directory, se non sono all’interno di un progetto, non sarannocompilateinsiemeallasoluzione.

GestionedelcodicesorgenteÈbuonanormagestirelemodifichealcodicesorgenteappoggiandosiauntoolapposito,chenegestiscalevarieversioni.Intalsenso,siparladisourcecontrolrepository,ovverodi un sistema in gradodi garantire che noi possiamo effettuare il versioning del codicesorgente,potendotornareindietronelcasounadatamodificanonfossequalitativamenteadeguata.Questoapprocciodovrebbeessereperseguitotantodachilavorainteam,dovesarebbeimpensabilegestirelemodifichescambiandosifile,tantodalsingolosviluppatore,checosìpuòavereunacopiadibackupdelpropriosorgente.

Storicamente, gli sviluppatoriWindows sono stati abituati a utilizzare Visual SourceSafe,ma quest’ultimo è stato ormai del tutto soppiantato daTeamFoundation Server(TFS),cheperònonèsoltantolimitatoalversioningdelcodicesorgente,maèingradodigestire l’intero ciclo di vita di un’applicazione, godendo anche, tra le altre cose, difunzionalità di team management, gestione dei task e delle build. All’internodell’immagine2.10èvisibilelaschermatacheconsentedigestireilcodicesorgente.

Page 59: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.10–GestionedelcodicesorgenteconTFS.

TFSèintegratoall’internodell’IDEedèdiventatopiùsemplicedainstallareemanuteneredallaversione2010:èsufficienteseguireunwizard,chesioccuperàdiverificaretutteleoperazioninecessarieedinstallare,senonsonopresenti,iprerequisiti.TFSesisteancheinuna versione in cloud, chiamata Visual Studio Team Services, che non necessita diinstallazioni in locale ed è completamente gestita da Microsoft, come servizio inabbonamento.MaggioriinformazionisuVisualStudioTeamServicessonodisponibilisuhttp://www.visualstudio.com.

VisualStudiopoisupportainmanieracompletaancheGIT,consentendodiaccederearepositorybasatisuquestosourcecontrolserverditipodistribuito,chevamoltoinvogainquestoperiodoespessoèutilizzatocomepreferitodaiprogettiopensource,ancheperviadelsuosupportocross-platform.

TFSèdisponibileinsiemeagliabbonamentiMSDN,oppureinversionepacchettizzata.Maggioriinformazionisonodisponibilisuhttp://www.microsoft.it/visualstudio/.

CompilareunprogettoLacompilazionepuòessereeffettuatadalmenu“Build”,oppureeseguendol’applicazione,ancheconildebugger.Sepreferiamoutilizzareunasequenzadi tasti, lacompilazionesipuò scatenare premendoCtrl+Shift+B,mentre l’applicazione si può avviare premendoCtrl+F5,osemplicementeF5permandarlaindebug.

Inquestafasevengonotenuteincontolereferenzetraiprogetti,quindiVisualStudioprovvedeacompilareiprogettinell’ordinenecessario,affinchéquellichehannoreferenze

Page 60: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

trovinol’assemblygiàpronto.

PossiamoreferenziareinunprogettoAunprogettoB,manonèpossibile fareancheilcontrario.Il.NETFrameworknonsupportalereferenzecircolari.

Comedefault,ilrisultatoècontenutonelladirectory“bin\”,postasottoilprogettoindicatocome principale. All’interno di questo ci sono due directory, che si riferiscono a dueprofilichesonodisponibilididefaultesucuitorneremonellaprossimasezione.

GestireleconfigurazioniVisualStudiosupportailconcettodiconfigurazione:all’attopratico,quandocreeremounanuova soluzione, troveremo già pronte due configurazioni, denominate “Release” e“Debug”.Laprimaèindicatapercompilare(egestire)lasoluzioneperladistribuzione,mentrelasecondaèspecificaperildebug,comeilnomestessosuggerisce.

La modalità di debug andrebbe usata solo per lo sviluppo, perché non èottimizzata per la produzione. Resta possibile utilizzare i simboli (che dannomaggiori informazioni in caso di eccezioni) anche in release. In questo caso,dobbiamogenerareglistessiinfasedicompilazione,agendosulleproprietàdicompilazionedelprogetto.

Queste modalità, in genere, sono attivabili da un apposito menu a tendina, disponibilesullatoolbardiVisualStudioevisibilenellafigura2.11.

Figura2.11–Laconfigurazionepuòesseresceltadirettamentedallatoolbar.

Agendosulvalorediquestoelenco,cambiailmodoincuivienecompilatalasoluzione.Per esempio, lamodalitàDebug non ha nessuna ottimizzazione,mentre quella Releaseevita che vengano generate istruzioni utili al debug e che tutto sia ottimizzato perl’esecuzione.

Possiamoanchescriverecodiceche ilcompilatore, inbaseallaconfigurazionescelta,interpreta(ecompila)solosenecessario.Questociconsentedipotergestireilcaricamentodiinformazioniparticolarisoloinfasedidebug,piuttostochedifferenziarelaverbositàdiunafunzionedilogging.Unadimostrazioneintalsensoèvisibilenell’esempio2.1.

Esempio2.1#IfDEBUGThen'l'alternativaèRELEASE

Page 61: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'codicedaeseguiresoloindebug

#Else

'altrocodice

#EndIf

Rispetto a una soluzione di tipo differente, questa lavora a stretto contatto con ilcompilatore, quindi garantisce la certezza che, se la configurazione selezionata èdifferente, il codice non sarà nemmeno processato, come si può intuire guardando lacolorazionecheVisualStudiodàallostesso,visibilenellafigura2.12.

Figura2.12–Ledirettivedicompilazioneconsentonodigenerareilcodiceinbaseallaconfigurazionescelta.

Possiamo anche creare nostre impostazioni custom, per esempio per supportare unambientedistaging,doveleapplicazionisarannotestateprimadellamessainproduzione.

DebugdiunprogettoQuandol’applicazionediventamediamentecomplessa,ildebugèingradodigarantircilapossibilità di intervenire in maniera più proficua nell’analizzare e correggere eventualiproblematiche.SeabbiamogiàutilizzatoVisualBasic, ilconcettoègiànoto:si trattadiunaparticolaretecnicacheconsentedientrarenell’esecuzionedelcodice,consentendocidianalizzarelostatodellavariabiliediintervenireinmanieraproficua.

UsareildebuggerVisualStudioincludeundebugger:sitrattadiuncomponentecheconsentediagganciarsialprocessocheesegueilcodicee,grazieallapresenzadeisimboli,dimostrareilflussoall’internodiVisualStudio.Questociconsentedipoter interveniredurantel’esecuzione

Page 62: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

dell’applicazione,peresempioper individuare lecausecheportanoaun’anomaliadellastessa.

A prescindere dalla configurazione corrente, è sempre possibile mandareun’applicazioneindebugpremendoiltastoF5.

Ancheseèmoltopotente,usareildebuggernonsostituiscetecnichedianalisidelcodice,o di test dello stesso. Si tratta di un’arma in più, quando abbiamo necessità di poterverificareilflussodiunparticolarebloccodicodice,cosìdavederecomelostessovieneeseguito.Nellafigura2.13èvisibilelaschermatadiselezionedelprocesso,raggiungibileattraversoilmenu“Debug”,allavoce“Attachtoprocess”.

Figura2.13–Selezionedelprocessosucuieffettuareildebug.

Èpossibilefarpartirel’applicazioneindebug,oppureagganciarsiaun’applicazionegiàinesecuzione.Sipuòcontrollarealmeglioilflussosfruttandoduecaratteristiche,noteconilnomedibreakpointewatch.Inoltre,lechiamatechehannoportatoalcodicecorrentesonovisibiliinun’appositafinestra,dinormaancorainbasso,cheprendeilnomediCallStackWindow.All’internodiquest’ultimatroveremolechiamatechehannooriginatoilflussoattuale:questaèunafunzionalitàmoltocomodaquandoundatometodoèrichiamatodapiùpuntidell’applicazioneevogliamocapirecomesiamoarrivatiaundeterminatopuntodellastessa.

Breakpointewatch

Page 63: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Comecomportamentopredefinitoildebuggernonsiblocca,senonincasodieccezioni.Ibreakpointconsentonodifissareunpuntospecifico,alcuiraggiungimentoildebuggersiferma,inattesachel’utentepossaverificarelostatodiunaparticolarevariabileall’internodelcodice.Perimpostareunbreakpointèsufficientecliccareconilmouseafiancodellariga, fino a che un pallino di colore rosso non compare, come è possibile notare nellafigura 2.14. Si può anche impostare un breakpoint premendo sul tasto F9, dopo che cisiamoposizionatisullarigainteressata.

Figura2.14–Aggiungereunbreakpoint.

Possiamoancheimpostareunbreakpointselettivo,percui ildebuggersifermeràsoloalverificarsi di una determinata situazione. Possiamo visualizzare in ogni momento ibreakpointattivi,agendoattraversoilmenu“Debug”.

Sepassiamosopraaunavariabile,vienevisualizzato inautomatico il relativovalore,attraversoquellochevienechiamatoquickwatch.ApartiredaquestaversionediVisualStudio,èanchepossibiletenereinprimopianoilwatch,utilizzandol’appositafunzionedipin,comepossiamonotarenellafigura2.15.

Page 64: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura2.15–Unquickwatchconpin.

Nelcaso incuidecidessimo,dall’appositomenuchecompare facendoclickcon il tastodestro sulla variabile, di scegliere la voce “Add Watch”, il valore dell’oggetto verràmostrato, per tutto il suo ciclo di vita, dentro un’apposita finestra, denominataWatchWindow. Questo è utile quando è necessario tenere sott’occhio il valore di una datavariabiledurantetuttoilciclodivitadell’applicazioneoinvocaredellefunzioni,compresele interrogazioni con LINQ. Nella maggior parte dei casi, comunque, finiremo perutilizzaremoltodipiùlafunzionediquickwatch,checonsentediinterrogareimembridiunoggettoecontrollarelerelativeproprietàinmanieramoltosemplice.InVisualStudiosonoancheinclusideiviewerspecializzati,pervisualizzaregrandiquantitàditesto,fileinformatoXMLoJSON.

Alcunioggettisonomostratiinautomatico,attraversol’AutosWindow.Sitrattadiunafinestracheappareinautomaticoindebugemostraleultimevariabiliutilizzatedurantel’esecuzione.Neesisteancheun’altra,denominataLocalWindow,cheinvecemostralevariabiliutilizzatenelcontestocorrente(peresempio,all’internodiunaroutine).

IntellitraceehistoricaldebugVisual Studio 2010 ha introdotto l’Intellitrace, che, come avviene ormai da diverseversioni anche in Visual Studio 2015, è stato ulteriormentemigliorato. Si tratta di unatecnologiacheconsentedicreareuna funzionedel tutto identicaaquelladiunascatolanera,generalmentepostaall’internodiunaereo:consentediregistraretuttoquellocheèaccaduto,rendendopossibilel’historicaldebug,cioèildebugaposteriori.

Page 65: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Attraversolaregistrazionediinformazioniimportanti,durantelanormaleesecuzionediun’applicazionediventapossibilemandareinesecuzioneilcodiceecapirecosaèsuccessoinquelparticolaremomento.Questoconsente,per esempio,di ricevereun reportdauntester e riprodurre in locale il bug, piuttosto che comprendere meglio le cause di unproblema, che a volte analizzando il call stack o il log di un bug non possono essereimmediatamenteriprodotte.

QuestafunzionalitàèspecificadiVisualStudioUltimate,lapacchettizzazionedipunta.

RefactoringPuòcapitareche,durantelascritturadicodice,siprestipocaattenzioneadalcunidettagliesidecidadieffettuareuncontrollosuccessivoperinterveniresuglistessi,peresempio,permodificareilnomediunaclasseodiunmembro.

In questi casi si effettua quello che viene chiamato refactoring, che consiste nelsistemareilcodiceaposteriori.Conilrefactoringcambiamoilfunzionamentointernodelnostrocodice,migliorandolo,senzachelostessosubiscauncambiamentoesterno,chegliimpediscadicontinuareafunzionarecomeinprecedenza.

InVisualBasicc’èunampiosupportoaquestefunzionalità,chesiattivanoinbasealtestoselezionatonell’editor,attraversoilpulsantedestro,allavoce“QuickActions”:

Rename: rinominaunmembroounavariabile, cercando i riferimenti all’internodelcodice,perassicurarechelostessononsmettadifunzionare;

ExtractMethod:estraeunmetodo,datouncodiceselezionato.Èutilequandoènecessario estrarre una parte di codice, che prima invece era contenutoesclusivamente all’interno di un metodo, per creare un metodo a sé stante, chepossaessereriutilizzatoinaltricontesti;

ExtractInterface:consentedicreareun’interfacciaapartiredaimembripubblicidiunaclasse;

Encapsulate Field: trasforma un campo privato in una proprietà pubblica,all’internodellaqualevieneincapsulatoilcampooriginale;

RemoveParameters:rimuoveiparametridiunafunzione,alterandonelafirma;

ReorderParameters:riordinaiparametridiunafunzione,modificandonelafirma.

Tutte queste azioni non comportano soltanto la modifica del codice, ma anche unadeguamentodiquellepartichefannoriferimentoaciòchevienemodificatodallanostraazione,assicurandocheilnostrocodicenonsmettadifunzionare.

Molto interessante (e raggiungibile nello stesso modo) è anche il menu “OrganizeUsing”,checonsentediorganizzarealmeglioiblocchiusing:

RemoveUnnecessaryUsings: rimuove i riferimenti ai namespace chenon sonosfruttatinellaclasse;

Page 66: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

SortUsings:ordinainamespacereferenziatinellaclasseinordinealfabetico;

RemoveAndSortUsings:applicaentrambeleazioniriportate.

Altre funzionalità di refactoring, come “Generate Method Stub”, sono invecedirettamenteaccessibiliincontestiparticolari:questo,peresempio,èunaiutochecivieneofferto quando aggiungiamo un riferimento a un tipo (o a un membro) che non vienericonosciuto,consentendocidicrearneunaimplementazionevuota,checonsentaalcodicedi compilare correttamente e a noi di continuare a completarlo. Basta posizionarsi sulcodice per avere un pulsante, alla cui pressione appare unmenu come quellomostratonellafigura2.16.

Figura2.15–Lafunzionedigenerazioneautomaticadiunmetodochenonesiste.

Seppurenonparagonabileaquellodiadd-incommercialinatiappositamenteperquestoscopo(comeReSharperdiJetBrains), il supportoal refactoring incluso inVisualStudio2015,quandosiutilizzaVisualBasiccomelinguaggio,puòaiutareasvolgeremeglio lenormalioperazioniquotidianedirifinituradelcodice.

Grazie all’introduzione di Roslyn, il nuovo compilatore offerto come servizio, lefunzionalitàdirefactoringsonostateulteriormentemigliorate,inquantoVisualStudiopuòoracompilarepiù facilmente il codicementre scriviamo,garantendoci, tra l’altro,ancheunaprecisionemiglioredell’Intellisenseinfasediautocompletion.

In tal senso, una nuova funzionalità è quella offerta dagli analyzer: si tratta dellapossibilità di aggiungere estensioni aVisualStudio, sotto formadi codice, chevanno acontrollare il codice (mentre lo stiamo scrivendo), di aggiungere funzionalità checonsentano di forzare stili di scrittura del codice (per esempio il case) e fornire anchesuggerimentiinfasediscritturadelcodicestesso,comeavvieneperVisualStudiostesso,tramite le funzionalità che suggeriscono di aggiungere, per esempio, una direttiva diimport.

Tuttequestefeature,comunque,sonopiùinteressantiperglisviluppatoridiplug-in,ma

Page 67: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

conoscerne l’esistenzapuòsicuramente tornareutilea tutti.Maggiori informazioni sonodisponibilinelladocumentazioneufficialesuhttp://aspit.co/a6t.

ConclusioniVisual Studio è un ambiente vero e proprio, all’interno del quale, come sviluppatori diVisualBasic,passeremogranpartedelnostrotempo.Questanuovaversionesidifferenziadalle altre grazie alle migliorie apportate un po’ ovunque, dal Text Editor finoall’Intellisense,passandoperl’introduzionedinuovefunzionalità,comel’Intellitrace.

Questo capitolo non vuole essere una guida esaustiva a Visual Studio, che è moltocomplesso e tutt’altro che semplice da spiegare in poche pagine, quanto una primaintroduzione,chemostricomepotersfruttarealmegliol’ambienteperiniziarealavorare.

Prima di addentraci maggiormente nello sviluppo di applicazioni basate su VisualBasic, è necessario che esaminiamo brevemente le caratteristiche del linguaggio. Nelprossimo capitolo inizieremo a dedicare uno sguardo più approfondito al linguaggio,cominciandodallasintassidibase.

Page 68: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

3

Sintassidibase

Visual Basic 2015 rappresenta l’evoluzione del linguaggio Visual Basic, ed è statoprogettato per lo sviluppo di applicazioni orientate a oggetti, che utilizzano il .NETFramework 4.6 come ambiente di esecuzione. Infatti, diversamente dalle releaseprecedenti,comeVisualBasic6,pensateperunapproccioorientatoaicomponenti,VisualBasic 2015 abbraccia la filosofia della programmazione orientata agli oggetti, facendopropri i concetti e molti dei costrutti appartenenti a linguaggi come C#, C++ e Java,mantenendo tuttavia immutate le caratteristiche sintattiche di base, valide già a partiredalleprimissimeversioni.

Inquestocapitolocominciamoaesaminareillinguaggiopiùdavicino,introducendoleregolesintattichedibase.

IntroduzioneallinguaggioPer iniziare a parlare di Visual Basic e della sua sintassi, facciamo riferimento a unsempliceesempio,alloscopodifissareiconcettidibase.L’esempioclassicocheingenerevieneusatoperpresentareunlinguaggioealquale,ancheinquestocaso,facciamoricorsopernontradirelaconsuetudine,èilcosiddetto“HelloWorld”.

Esempio3.1NamespaceASPItalia.Books.Chapter3

ModuleHelloWorld

SubMain()

Console.WriteLine("HelloWorld")Console.ReadLine()

EndSub

EndModule

EndNamespace

L’esempio3.1 riporta la porzionedi codice relativa a una semplice applicazione, che silimitaascrivereavideo lastringa“HelloWorld”. Ilcodicepropostosicomponediunaseriedidichiarazionieistruzioni(detteanchestatement),ciascunadellequaliinclude

Page 69: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

uno o più vocaboli speciali come Namespace, Module, Sub detti keyword o ancheparolechiave.

Alcuniconcettianticipatinell’esempio3.1vengonoaffrontatiinmodospecificoneiprossimicapitolidellibro.Inparticolare,ilconcettodiclasseverràspiegatonelcorsodelprossimocapitolo.

VisualBasiccontieneungrandenumerodikeyword.Lamaggiorpartediesseècostituitadaterminiriservatiepredefinitinell’ambitodellinguaggio,chenonsonoutilizzabilicomeidentificatori per indicare variabili e oggetti (vedi tabella 3.1). Anche se è vivamentesconsigliato, è comunque possibile eliminare la restrizione, racchiudendo una di questeparoletraparentesiquadre(peresempio:[Module]).

Tabella3.1–Parolechiaveriservatedellinguaggio.

Page 70: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Le keyword EndIf, GoSub, Variant e Wend vengono mantenute come parole chiaveriservate,sebbeneinVisualBasic2015nonsianopiùutilizzate.IlsignificatodellaparolachiaveLetcambiarispettoalpassato,dalmomentocheinVisualBasic2015essavieneimpiegata nelle queryLINQ.Altre parole chiave comeFrom,Join e Where sono stateaggiunteasupportodellasintassidiLINQ,comeavremomododiscoprireneicapitoliaseguire.

Oltre allekeyword riservate, il linguaggio includeuna seriediparole chiavechenonsono riservate e che sono quindi utilizzabili come nomi per gli elementi diprogrammazione(veditabella3.2).Consigliamotuttaviadievitarequestotipodiutilizzo,poichéilcodicepotrebberisultaredidifficileletturaesipotrebberoverificareerrorigravinonfacilmenterilevabili.

Tabella3.2–Parolechiavenonriservate.

VisualBasicnonprevedel’usodidelimitatoripercontenereunbloccodicodice(ovverouninsiemediistruzioniadiacentitralorocorrelate)mautilizzalaparolachiaveEndper indicarne la conclusione. In genere, un blocco è associato a un’istruzione o a una

Page 71: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

dichiarazione particolare; la linea di codice che indica la fine di un blocco è compostadallaparolachiaveEndseguitadallakeywordrelativaall’istruzioneoalladichiarazioneinquestione.

In Visual Basic non esiste il carattere di separazione delle istruzioni come in altrilinguaggi di programmazione; solitamente, a ogni linea di codice corrisponde sempreun’unica istruzione. In passato, questa regola poteva essere peraltro infranta solamenteinserendo al termine di una riga il carattere “_” (underscore), al fine di spezzareun’istruzione su più linee contigue per migliorare la leggibilità del codice nel caso distatementparticolarmentelunghiecomplessi.ApartiredaVisualBasic2015,ilcarattereunderscorenonèpiùobbligatorioepuòessereomessoinmolticasi,einparticolare:

dopoicaratteri“virgola”o“punto”;

dopounaparentesitondaapertaoprimadiunaparentesitondachiusa;

dopounaparentesigraffaapertaoprimadiunaparentesigraffachiusa;

dopo un operatore binario, in particolare quelli booleani (gli operatori sarannotrattatiabrevenelcorsodelcapitolo);

dopounoperatorediassegnazione;

dopol’operatorediconcatenazionedistringhe“&”;

primaedopoglioperatoriusatinellequeryLINQ;

dopolaparolachiaveIn,inunostatementForEach.

Nell’esempio3.2,letreistruzionidicodiceriportatesonoequivalenti.

Esempio3.2'Istruzionesuunarigasingola

Console.WriteLine("HelloWorld")' Prima di Visual Basic 10 l'underscore era sempre obbligatorio

Console.WriteLine(_

"Hello"&_

"World")

' Dopo VB 10 l'underscore può essere omesso in molti casi

Console.WriteLine(

"Hello"&

"World")

'EinVB14sipossonofarestringhemultilinea

Console.WriteLine("Hello

World")

Certamente è da notare l’ultimo esempio, novità di Visual Basic 14, che consente di

Page 72: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

definire una stringa su più linee senza dover interrompere la stringa e con l’aggiuntaautomaticadelritornoacapo(VbCrLf).

VisualBasicèunlinguaggiocase-insensitive.Questosignificachepossiamoutilizzarequalsiasisequenzadiletteremaiuscoleeminuscoleperriferirciallestesseparolechiaveeaglistessiidentificatori.Nomiugualicon“case”diversifannoriferimentoallemedesimevariabiliekeyword(MyVarequivaleamyVar).Nell’esempiocheabbiamovistoall’iniziodelparagrafo,leistruzioniConsole.WriteLineeconsole.writelinesonoequivalenti.

Inognicaso,èbuonanormaprestareparticolareattenzioneallanomenclatura:scegliereun“case”coerenteeuniformepermettedimigliorareinmodosignificativolaleggibilitàdelcodice,contuttiivantaggicheneconseguono.Alcontrario,un“case”disordinatopuòintrodurre parecchia confusione nel codice, compromettendone la chiarezza e laleggibilità.GlieditorperVisualBasicpiùevoluti,comequelloinclusoinVisualStudio,applicano una correzione automatica al “case” delle keyword e degli identificatori,rendendoilcodicepiùuniformeeleggibile.

CommentiIn Visual Basic esistono due modalità del tutto equivalenti per inserire commentiall’internodelcodice.Possiamo,infatti,utilizzaresial’apicesingolosialaparolachiaveREMperindicareuncommento.Tuttoiltestocheseguel’apiceolakeywordvieneignoratodalcompilatoreeconsideratouncommento(esempio3.3).

Esempio3.3'Rigadicommento

REMRigadicommento

Console.WriteLine("HelloWorld")'Commentodopoilcodice

Console.WriteLine("HelloWorld")REMCommentodopoilcodice

Entrambelenotazionipossonoessereusatesiaperdefinireunarigadicommentosiaperintrodurreuntestoesplicativodopoun’istruzionealterminedellastessalineadicodice.

Inoltre, Visual Basic 14 introduce il supporto per i commenti anche all’intero delleistruzioniLINQ,chescopriremoeaffronteremoinunodeiprossimicapitoli,rendendopiùfacilecommentareistruzionichesonoespressesupiùdiunariga.

TipidibaseAciascunavariabileinVisualBasiccorrispondeuntipodidatoche,comeabbiamovistonel primo capitolo, può essere di valore o di riferimento. Oltre ai tipi dichiarati dallosviluppatore(e,inparticolare,leclassichevedremoindettaglionelprossimocapitolo)eai tipi forniti nella Base Class Library (anche detta BCL), il linguaggio è dotato di un

Page 73: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

insieme di tipi di dato intrinseci, comunemente chiamati primitive, a cui fannoriferimentomoltedelleparolechiaveelencatenellatabella3.1.

Le primitive sono tutti tipi di valore (per esempio, Integer oppure Boolean), fattaeccezioneperObjecteStringchesonotipidiriferimentoechequindinoncontengonodirettamenteunvaloreeffettivo,mapuntanoaun’areadimemoriagestitanell’ambitodelmanagedheap.Comepossiamonotarenell’esempio3.3,perazzerareilriferimentodiunastringa o di un oggetto in genere, in Visual Basic dobbiamo usare la parola chiaveNothing.

Esempio3.4DimxAsInteger=2 'Interochecontiene2

DimyAsBoolean=True 'Valorebooleanochevaletrue

Dims1AsString="Hello" 'Puntaadun'areadimemoria

Dims2AsString=Nothing 'Nonpuntaanulla

Dimobj1AsNewObject() 'Creaunnuovooggetto

Dimobj2AsObject=Nothing 'Nonpuntaanulla

LeprimitivediVisualBasicsonoelencatenellatabella3.3.Aciascunadiessecorrispondeun tipo contenuto nel .NET Framework, del quale la parola chiave rappresentasemplicementeunalias.

Tabella3.3–PrimitivediVisualBasic.Parolachiave Tipodidato Valore/RiferimentoBoolean System.Boolean TipodivaloreByte System.Byte TipodivaloreChar System.Char TipodivaloreDate System.DateTime TipodivaloreDecimal System.Decimal Tipodivalore

Double System.Double TipodivaloreInteger System.Int32 TipodivaloreLong System.Int64 TipodivaloreObject System.Object TipodiriferimentoSByte System.SByte TipodivaloreShort System.Int16 TipodivaloreSingle System.Single TipodivaloreString System.String TipodiriferimentoUInteger System.UInt32 TipodivaloreULong System.UInt64 TipodivaloreUShort System.UInt16 Tipodivalore

Nontuttiitipiindicatinellatabella3.3sonoCLS-compliant.SByte,UShort,UIntegereUlongrappresentanotipichenonrispettanolaCommonLanguageSpecificationeadessi,ingenere,dovrebberoesserepreferitiitipicorrispondenti,compatibiliconlaCLS(Byte,Short,IntegereLong).

Page 74: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

NamespaceQuandounosviluppatoredefinisceuntipo,sitrovanellanecessitàdiassegnargliunnomeche sia non solo significativo, ma anche univoco. Questo vincolo è necessario perpermetterealcompilatorediriferirsialtiposenzaambiguità.D’altraparte,assegnarenomilunghiecomplessitalidagarantirel’univocitàrichiesta,puòrappresentareunproblemaeminarenonpocolaleggibilitàdelcodice.

Perquestomotivo,inVisualBasicèpossibiledefinireinamespace(dettianchespazidei nomi), ovvero contenitori logici che hanno il duplice scopo di raggruppare eorganizzareitipidichiaratidallosviluppatoreedifornireunmeccanismopersemplificarelanomenclatura.

Inamespacerappresentanounmeccanismodiorganizzazionegerarchicadelcodice,inquanto possono includere, a loro volta, altri namespace. I nomi dei namespace annidatisono separati tra loro da un punto. Possiamo dichiarare in file e assembly diversi tipiappartenentiallostessonamespace.

Per assegnare un tipo a un namespace, dobbiamo inserire la sua dichiarazionenell’ambitodiunbloccodicodice,contrassegnatoconlaparolachiavenamespaceseguitadaunnomeidentificativo(esempio3.4).

Esempio3.5NamespaceASPItalia.Books.Chapter3

ModuleHelloWorld

SubMyMethod()

'...

EndSub

EndModule

EndNamespace

Il nome completo del tipo dichiarato nell’esempio 3.5 è:ASPItalia.Books.Chapter3.HelloWorld. Oltre a poter dichiarare altri tipi nello stessonamespace, come per esempio: ASPItalia.Books.Chapter3.AnotherType, possiamodefinireanchetipiomonimiinaltrinamespace,comeSystem.HelloWorld.

Il nome di un tipo viene connotato dal nome del namespace al quale appartiene; diconseguenza, per riferirsi ad un tipo, dobbiamo sempre indicare l’intera gerarchia deinamespace. Peraltro, se un namespace è usato frequentemente nel codice, può risultareassai scomodo ripetere ogni volta il nome del namespace prima del nome dei tipi.Utilizzandolaparolachiaveusing,inVisualBasicèpossibileinserireunriferimentoaunnamespaceinmodotaledapoterometterel’indicazionedelsuonomedavantialnomedeitipi,comemostratonell’esempio3.6.

Page 75: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio3.6ImportsASPItalia.Books.Chapter3

' Per invocare il metodo il nome del namespace può essere omesso

HelloWorld.MyMethod()

'Inalternativailmetodoèinvocabileesplicitandoilnamespace

ASPItalia.Books.Chapter3.HelloWorld.MyMethod()

Quandountipovienedichiaratosenzaindicarealcunnamespace,essovieneaggiuntoalcosiddettonamespaceglobale.

VisualBasicsupportaancheilcosiddetto“staticusing”.Questacaratteristicaconsentedievitare l’usodiun riferimentoesplicitoaun tipodurante l’invocazionediunmetodostatico(shared).Approfondiremoquestoaspettonelprossimocapitolo,quandoparleremodiExtensionMethod.

DichiarazionedivariabiliVisualBasicèunlinguaggioper ilquale ladichiarazionedellevariabilie ladefinizionedei tipi rappresentano, senza dubbio, due aspetti fondamentali e non prescindibilinell’ambitodellaprogrammazione.

Levariabili sonoentitàchecontengonoopuntanoaidatiutilizzatinell’ambitodiunbloccodicodice.Ladichiarazioneèiltipod’istruzionechepermettedicreareunanuovavariabile.Questapuòessereinseritapraticamenteovunque,malavaliditàdellavariabilecreata, in genere, si esaurisce al termine del blocco in cui essa viene definita e usata(comunemente si dice che la variabile esce dal suo scope, ovvero dal suo ambito divalidità).

Nello sviluppo di applicazioni con Visual Basic 6, VBScript e affini, ladichiarazionedelle variabili e la definizionedei tipi sono sempre stati aspettipiuttosto trascurati.Per esempio, inVBScript, ladichiarazionedelle variabilieraunoptional,datochepotevaessereomessaacausadell’esistenzadel tipoVariant mentre la dichiarazione degli oggetti sfruttava il metodoServer.CreateObject e il late-binding, con tutti gli svantaggi e lecontroindicazionicheunsimileapprocciopotevacomportare.Diversamentedalpassato,VisualBasicnonincludepiùil tipoVariant, (rimpiazzato,entrocertilimiti, dal tipo Object) e il late-binding viene sostituito dall’early-bindingtramiteladichiarazionedivariabilieoggetti.

Le variabili relative ai tipi di valore rilasciano le informazioni contenute in mododeterministicoal terminedella sezionedicodicedi afferenza.Per levariabili relativeaitipidiriferimento,valeundiscorsodiverso:ilrilasciononèdeterministico,inquanto,inquesto caso, le informazioni vengono gestite nelmanaged heap dal Garbage Collector,che,comeabbiamovistonelprimocapitolo,decideinpienaautonomiaquandoliberarela

Page 76: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

memorianonpiùinuso.

Giànell’esempio3.3sonoriportatialcunicasididichiarazionedivariabilieoggetti.Ingenerale,alnomedeltiposegueilnomedell’identificatore,eventualmenteseguitoasuavoltadaun’assegnazioneaunvalorecostanteoaun’altravariabile.

Possiamodichiararepiùvariabiliconsecutivamentenell’ambitodellastessaistruzione,indicando solamente una volta il tipo e separando i vari identificatori con una virgola,comemostratonell’esempio3.6.

Esempio3.7Dimi,j,kAsInteger

Dimx,y,zAsString

UnavariabilechenonpuòesseremodificatainfasediesecuzionesidicecostanteevienecontrassegnataconlaparolachiaveConst.Unacostantedeveessereobbligatoriamenteinizializzata a “compile-time” e non può essere modificata, in seguito, tramiteun’operazionediassegnazione(esempio3.7).

Esempio3.8DimConstPIAsDouble=3.1416

DimConstHELLOAsString="HelloWorld"

Nel caso di variabili relative a tipi di riferimento, l’assegnazione associata alladichiarazione può riguardare un’istanza preesistente oppure una nuova istanza, generatamediante un’operazionedi costruzione specificando la parola chiavenew (esempio 3.9).Unavariabile relativaaun tipodi riferimentoacuinonvengaassegnataalcuna istanza,vieneinizializzataimplicitamenteconNothing(ovverononpuntaadalcunoggetto).

Esempio3.9DimxAsNewObject() 'Puntaadunanuovaistanza

DimyAsObject=Nothing 'PuntaaNothing

DimzAsObject 'PuntaaNothing

DimobjAsObject=x 'objsiriferisceallastessaistanzadix

Visual Basic supporta la type inference, ossia la capacità di ricavare il tipo di unavariabile dalla sua espressione di inizializzazione. La type inference può essereapplicata unicamente nella dichiarazione di variabili locali interne a una routine. In talicasi, il tipodellavariabilevienericavatodall’espressioneusataper l’inizializzazione;sel’espressionevieneomessa,otteniamounerroreinfasedicompilazione.

Latypeinferencepuòessereapplicatasianelcasodivariabiliilcuitipoèdivalore(inparticolareitipiprimitivi)sianelcasodivariabiliilcuitipoèdiriferimento(classi).Nel

Page 77: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

caso dei tipi di riferimento non è ammessa l’inizializzazione a Nothing, ma soloall’istanzadiunaclasse.

InVisualBasic2015,lacapacitàdidedurreiltipotramitetypeinferenceècontrollabilemediantel’opzionedicompilazioneOptionInfer,ilcuivalorepredefinitoèOn.

Esempio3.10//Dichiarazionediunavariabileinterasenzaecontypeinference

inti=1;//ièditipointero

varj=1;//jèditipointero(typeinference)

//Dichiarazionediunastringasenzaecontypeinference

stringx="HelloWorld";//xèditipostring

vary="HelloWorld";//yèditipostring(typeinference)

L’esempio3.10mostraalcunisemplicicasid’utilizzo.Inquestoesempiolevariabilijeysono legate alla lorodichiarazioneoriginale;nonpossonocioèvariaredi tipo. Il codiceMSIL,creatoinfasedicompilazione,èilmedesimocheotteniamonormalmentequandoindichiamoperestesoiltipodellavariabiledadichiarare(comenelcasodiiex).

EspressionieoperatoriCometuttiilinguaggi,ancheVisualBasicpermettedicostruireespressionicheutilizzanounoopiùoperatori,asecondadeicasi.Esistonovarietipologiedioperatori,infunzionedelnumeroedeltipodioperandi.

Un operatore è un elemento di codice che esegue un’operazione su uno o piùoperandi,ovveroelementichecontengonounvalorediqualchetipo(variabili,costanti,oggettiedespressioni).

Un’espressione è una sequenza di operandi, combinati con operatori allo scopo diritornare un valore finale. Gli operatori agiscono sugli operandi eseguendo calcoli,confrontioaltreoperazionidivariogenere.

Sebbenesianopresentioperatoriunarieancheunoperatoreternario, lamaggiorpartedegli operatori accettano due operandi. I principali operatori riguardano le operazioniaritmetiche, le operazioni di confronto, le espressioni booleane e le assegnazioni divariabili(esempio3.11).

Esempio3.11Dimx,yAsBoolean 'Variabilibooleane

y=True 'Assegnazione

x=Noty 'Negazionebooleana(xvaleFalse)

Page 78: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

x=(18>8) 'Axvieneassegnatoilvalorebooleano

'risultantedallavalutazione

'dell'espressionediconfronto(True)

Dimi,j,kAsInteger 'Variabiliintere

i=2 'Assegnazione

j=i+1 'Sommaeassegnazione

k=i*2 'Prodottoeassegnazione

DimnumAsInteger 'Variabileintera

num=i*j+k 'Prodotto,sommaeassegnazione

DimisOddAsBoolean 'Variabilebooleana

isOdd=(numMod2)<>0 'Espressionechevalutasenumèdispari

DimhelloAsString 'VariabileditipoString

hello="Hello"&"World" 'Concatenazionedistringhe

La tabella 3.4 elenca gli operatori predefiniti in Visual Basic in funzione della lorocategoriadiappartenenza.

Tabella3.4–CategoriedeglioperatoriinVisualBasic.Categoria OperatoriOperatoriaritmetici ^*/\Mod+-

Operatoridiassegnazione =^=*=/=\=+=-=<<=>>=&=

Operatoridiconfronto <<=>>==<>IsIsNotLike

Operatoridiconcatenazione &+

Operatorilogici/bitperbit AndNotOrXorAndAlsoOrElseIsFalseIsTrue

Operatoridispostamentobit <<>>

Operatorivari AddressOfGetTypeIfTypeOf

Quando in un’espressione vengono eseguite varie operazioni, ciascuna di esse vienevalutataapartiredasinistraevienerisoltainbaseaunordineprecisodiprecedenza.Peresempio,l’operatoredimoltiplicazioneodivisionearitmeticavienesemprevalutatoprimadi quello relativo alla somma; l’operatore di negazione logica viene valutato primadell’AND o dell’OR logico. Questo ordine può essere variato, impiegando le parentesitondeperaggregarelediversepartidiun’espressioneinmodopersonalizzato.

Nell’esempio 3.12, l’uso delle parentesi tonde fa variare in modo significativo ilrisultato dell’operazione aritmetica tramite cui viene assegnata la variabile num, dalmomentochelasommavieneeseguitaprimadellamoltiplicazione.

Esempio3.12DimnumAsInteger=0'Variabileintera

num=2*3+4*5'numvale26

Page 79: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

num=2*(3+4)*5'numvale70

Latabella3.5elencaglioperatoripredefinitiinVisualBasicinfunzionedelloroordinediprecedenza.

Elevamentoapotenza ^

Identitàenegazioneunarie +-

Moltiplicazioneedivisioneavirgolamobile */

Divisionedivaloriinteri \

Moduloaritmetico Mod

Addizione,sottrazione,concatenazione +-

Concatenazionedistringhe &

Spostamentodibitaritmetico <<>>

Operatoridiconfronto =<><<=>>=IsIsNotLikeTypeOf…Is

Negazionelogicaebitabit Not

ANDlogicoebitabit AndAndAlso

ORlogicoebitabit OrOrElse

XORlogicoebitabit Xor

Assegnazione =^=*=/=\=+=-=<<=>>=&=

Come possiamo notare, l’assegnazione è, in generale, l’operatore a più bassa priorità,precedutonell’ordinedaglioperatorilogici,daquellidiconfrontoedaquelliaritmetici.

ConversionedeitipiTraglioperatori elencatinella tabella3.3,quellodicastingmeritaunapprofondimento.Per quanto abbiamo visto finora, una volta che una variabile viene dichiarata, ad essavieneassociatountipochepuòesseredivaloreodiriferimento.Peraltro,inVisualBasicesistelapossibilitàdiconvertireiltipodiunavariabileinunaltrotipoaffine(operazioneanchenotacolnomedicasting),peresempio,unIntegerinunLong.

Quandosiparladicasting,dobbiamofareunadistinzionetraleconversionifratipidivalore, in particolare i tipi numerici, e le conversioni fra tipi di riferimento.Nel primocaso,lemodalitàdicastingsisuddividonoinconversioniimpliciteeconversioniesplicite.Le conversioni implicite sono quelle che avvengono senza il rischio di perditad’informazioni, sono del tutto trasparenti e lo sviluppatore non si deve preoccupare dinulla.Peresempio,unavariabileditipobytepuòessereconvertitaimplicitamenteinuninteroperchéilrangedeivalorivalidiperiltipobyteèinclusonelrangedeivaloridiint.Leconversioniesplicitepresuppongono,piuttosto,unaperditad’informazioni,inquantoiltipodidestinazionenonèingradodirappresentarel’interodominiodeivalorideltipoorigine. Quando l’opzione di compilazioneOption Strict è impostata al valoreOn, losviluppatore è tenuto obbligatoriamente a specificare l’intenzione di voler effettuare laconversioneditipo.

L’opzione di compilazione Option Strict permette di attivare e disattivare il

Page 80: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

controllosuitipi.Quandol’opzioneèdisattivata(comportamentopredefinitoinVisualStudio),leassegnazionitratipidiversipossonoessereeseguitesenzalanecessità di effettuare il casting inmodo esplicito. In tal caso, il compilatorenon segnala alcun errore e le eventuali anomalie vengono riscontrate solo aruntime.Quandol’opzioneèattiva,ilcompilatorecontrollalacompatibilitàtraitipiesegnalatuttelesituazionicriticheincuioccorreeffettuareilcastinginmodoesplicito.

VisualBasicnonprevedeunoperatoreper le conversioni esplicite.Comealternativa, illinguaggio includeuna seriedi parole chiave specificheper eseguire la conversionedeitipi.Questekeywordsonoriepilogatenellatabella3.6.

Tabella3.6–ParolechiaveperleoperazionidicastinginVisualBasic.

Ciascunakeyword elencata nella tabella3.6 si riferisce a una particolare primitiva, conl’eccezionediCTypeeDirectCast,chehannounavalenzapiùgenerale.

LeistruzioniCTypeeDirectCastaccettanoentrambel’oggettodaconvertireeiltipodidestinazionecomeparametridiconversione.Mentrelaprimasiapplicasiaaitipidivaloresiaaitipidiriferimento,lasecondaoperasolosuitipidiriferimento.CTypetentasempredi eseguire una conversione (per esempio, permette di trasformare una stringa in unnumero).Questo aspetto rende il suo utilizzomeno performante rispetto aDirectCast,cheèsempredapreferirequaloravogliamoeseguireun’operazionedicastingfra tipidiriferimentotralorocompatibili(vediesempio3.13).L’esempio3.13riportaanchealcunecasistichediconversioneimplicitaedesplicita,applicateaitipinumerici.

Esempio3.13DimxAsInteger=CType("12.34",Integer)'xvale12

DimyAsMyType=CType(obj,MyType)

DimzAsMyType=DirectCast(obj,MyType)

'conversioniimplicitiedesplicite

DimxAsInteger=0'Variabileintera(4byte)

DimyAsByte=100'VariabileditipoByte(1byte)

x=y'Conversioneimplicita

y=CByte(x)'Conversioneesplicita

Page 81: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

y=CByte(x*10)'Erroredioverflowaruntime

Dobbiamo tenere in buona considerazione il fatto che non sempre la conversione èpossibile,epresental’insorgenzadierroriaruntimequalorailtipodidestinazionenonsiacompatibilecolvaloredaconvertire.Nell’esempio3.14,l’ultimalineadicodiceproducearuntime un errore di overflow, dato che il tipoByte non è in grado di contenere valorisuperioria255.

ArrayUnarray(dettoanchearraymonodimensionaleovettore)èunavariabilecompostadaun gruppo di oggetti dello stesso tipo. Gli elementi che fanno parte di un array sonocontrassegnati conun indice, tramite il quale èpossibile accedere a ciascunodi essi. InVisualBasicunarrayèun’istanzadeltipoSystem.Arraycontenutonel.NETFramework(sitrattadiunaclasse)edèpertantountipodiriferimentoatuttiglieffetti.

Perrichiamareunelementodiunarray,dobbiamospecificarnel’indiceracchiusoinunacoppia di parentesi tonde. L’indice vale zero per il primo elemento dell’array e vieneincrementatodiun’unitàperognielementosuccessivo.L’elementonellaposizionei-esimaè sempre contrassegnato con l’indice i-1 (esempio 3.14). Esistono principalmente duemodiperdichiarareunarray,chesonoentrambimostratinell’esempio3.14.

Nel primo caso, viene creato un array composto da tre elementi di tipo String e ladimensionevienespecificata inmodoesplicito,utilizzando l’istruzioneReDim in seguitoalla dichiarazione. Nel secondo caso, gli elementi vengono inizializzati con altrettantinumeriinterieladimensionedell’arrayrisultanteèparialnumerodeivaloriracchiusitraleparentesigraffe.

Esempio3.14

Dimx()AsStringr 'Vettoredistringhe

Redimx(3) 'Ècompostodatreelementi

x(0)="Hello" 'Contiene"Hello"

x(1)="World" 'Contiene"World"

x(2)=x(0)&x(1) 'Contiene"HelloWorld"

Dimy()AsInteger={1,2,3} 'Vettorecompostodatreinteri

DimzAsInteger=y(1) 'Lavariabilezvale2

Come avviene per le variabili semplici, in Visual Basic possiamo dichiarare un arraysfruttando la type inference. In tal caso, l’opzione di compilazioneOption Infer deveessereimpostataalvaloreOn.

Esempio3.15

Page 82: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'Vettoredinumeriinteritipizzatoimplicitamente

Dimx()=NewInteger(){1,2,3,4,5}

Gliarraypossonoesseremultidimensionali.Lalorodichiarazioneèanalogaaquantovistopergliarraymonodimensionali(esempio3.16).

Esempio3.16Dimcoords(,,)AsInteger 'Vettoredidimensionepariatre

Redimcoords(3,3,3) 'Coordinatespaziali

coords(0,0,0)=1 'Origine

coords(1,1,1)=2 'Puntox=1,y=1,z=1

coords(2,2,2)=3 'Puntox=2,y=2,z=2

Lanotazionepersepararetraloroledimensionièrappresentatadaunavirgolaeilnumerodi virgole stabilisce l’ordine di grandezza dell’array. Per esempio, due virgole indicanochel’arrayhatredimensioni.

EnumerazioniInVisualBasicesiste il tipoEnum (enumerazione)chepermettedidefinireun insiemechiusodivalori.Questotipodidatotornacomodoperobbligareunavariabileaconteneresolounaseriefinitadivaloripre-individuati(peresempio,imesidell’anno,igiornidellasettimana,ecc.).

La parola chiave Enum permette di definire l’elenco dei valori ammissibili per unparticolaretipodivaloreche,perdefault,èIntegerapartiredazero(esempio3.17).Dalmomentochepossiamoconsiderare leenumerazionicomesottoinsiemidiunparticolaretiponumerico,essesono,atuttiglieffetti,tipidivalore.

Esempio3.17EnumGender 'Enumerazioneditipointero(default)-Sesso

Male 'Vale0(Integer)-Maschio

Female 'Vale1(Integer)-Femmina

EndEnum

PerleenumerazionipossiamospecificareuntiponumericodiversodaIntegereforzareilvalore per ogni elemento dell’insieme tramite un’espressione valida per il tipo inquestione(esempio3.18).OltreaInteger, i tipididatiutilizzabili con leenumerazionipossonoessereByte,Long,SByte,Short,UInteger,ULongeUShort.

Esempio3.18

Page 83: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EnumDayOfWeekAsByte 'Giornodellasettimana

Monday=1 'Vale1(Byte)-Lunedì

Tuesday=2 'Vale2(Byte)-Martedì

Wednesday=3 'Vale3(Byte)-Mercoledì

Thursday=4 'Vale4(Byte)-Giovedì

Friday=5 'Vale5(Byte)-Venerdì

Saturday=6 'Vale6(Byte)-Sabato

Sunday=7 'Vale7(Byte)-Domenica

EndEnum

Dato che, implicitamente, gli elementi di un’enumerazione contengono valori di tiponumerico, possiamo effettuare nei due sensi la conversione esplicita, utilizzandol’istruzioneCType.

Esempio3.19DimxAsGender=Gender.Male 'VariabileditipoGender

DimyAsInteger=1 'Variabileintera

DimzAsInteger=2 'Variabileintera

y=CType(x,Integer) 'yvale0

x=CType(1,Gender) 'xvaleFemale

L’esempio 3.19 prende in considerazione l’enumerazione Gender definita nell’esempio3.16.Comemostrato,possiamofareilcastingdiunelementodiGenderal tipo interoe,viceversa, convertire una variabile intera al tipo Gender se il valore contenuto nellavariabileèammissibileperl’enumerazione.

FunzionieprocedureUnaroutine rappresentaun insiemed’istruzioni racchiuse inununicobloccoa formareun’entità richiamabile più volte nell’ambito del codice. Scopo delle routine è quello dieseguire un qualche tipo di elaborazione, sfruttando, eventualmente, un insieme diparametri di input, e fornire, qualora previsto, un risultato sotto forma di un valore diritorno.

Comedetto,unaroutinepuòessererichiamatainpiùpuntidelcodice.L’invocazionediunaroutineinterrompel’esecuzionedelcodicechiamanteeinserisceun’entryincimaallostack delle chiamate. Al termine della sua esecuzione, la chiamata viene rimossa dallostack e l’elaborazione del codice riprende dall’istruzione successiva a quellad’invocazione. Una routine può, a sua volta, richiamare altre routine: in tal caso,l’elaborazione della routine chiamante viene interrotta fino a che non terminal’elaborazionedellaroutinechiamata.

In Visual Basic è possibile distinguere due tipologie di routine: le funzioni, cherestituiscono un valore, e le procedure, che non producono risultati e si limitano a

Page 84: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

eseguire una serie di istruzioni. Alle due tipologie di routine corrispondono altrettanteparole chiave specifiche: per dichiarare una procedura, dobbiamo utilizzare la keywordSub mentre, per definire una funzione, dobbiamo usare la keyword Function (esempio3.20). Nel caso delle funzioni, il tipo del valore di ritorno va specificato in coda alladichiarazionedellaroutine,edeveessereprecedutodallaparolachiaveAs.

Esempio3.20'Funzionechecalcolalasommadiduenumeri

FunctionSum(ByValxAsShort,ByValyAsShort)AsInteger

Returnx+y

EndFunction

'Procedurachescriveunmessaggioavideo

SubWrite(ByValtextAsString)

Console.Write(text)

EndSub

Unaroutineèpienamenteidentificatadallasuafirma.Dettaanchesignature,lafirmadiunafunzioneodiunaproceduraèrappresentatadalsuonomeidentificativo,dalnumerodei parametri e dal loro tipo; il tipo dell’eventuale valore di ritorno non fa parte dellafirma.Ilconcettodifirmaèimportanteinquanto,nell’ambitodellorocontestodivalidità,tutteleroutinedevonoavereunasignatureunivoca.Questosignificache,indeterminatesituazioni,comenelcasodelladefinizionedeitipidiriferimento,piùfunzionioprocedurepossonoavere lo stessonome identificativo,ma ilnumerodeiparametri e/o il loro tipodeveesserenecessariamentedifferente(overloading).Riprenderemoquest’argomentonelcorsodelprossimocapitolo.

Un altro aspetto importante che riguarda le routine è ilpassaggio dei parametri. InVisualBasiciparametripossonoesserepassati:

nelcasodipassaggiodiunparametropervalore (byvalue), dobbiamoutilizzare laparola chiave ByVal per indicare che alla routine viene passata una copia dellavariabile per i tipi di valore e un riferimento non riassegnabile per i tipi diriferimento;

nel caso di passaggio di un parametro per riferimento (by reference), dobbiamoutilizzarelaparolachiaveByRefperindicarecheallaroutinevienesemprepassatoun riferimento alla variabile (eventualmente riassegnabile) e che ogni modificaall’interno della funzione o della procedura si propaga anche esternamente alchiamante.

L’esempio3.21mostra le due casistiche di passaggio dei parametri per una routine chesommaduenumeri.

Esempio3.21

Page 85: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'Passaggiopervalore

FunctionSum(ByValxAsShort,ByValyAsShort)AsInteger

ReturnCInt(x+y)

EndFunction

'Passaggioperriferimento

SubSum(ByValxAsShort,ByValyAsShort,ByRefresultAsInteger)

result=CInt(x+y)

EndSub

DimnumAsInteger=0'Variabileintera

num=Sum(11,22)'numvale33

Sum(111,222,num)'numvale333

Quandoilparametroèuntipodivalore,nelcasodipassaggiobyvalue,lavariabilevienecopiataall’internodellaroutineeun’eventualeriassegnazionenoninfluenzailchiamante.Seilpassaggioèditipobyreference,ognivariazionealparametrovienepropagataanchealchiamante.

Quando il parametro è un tipo di riferimento, nel caso di passaggio by value, lavariabilenonvienecopiata,mavienesemplicementepassatoilsuoriferimentocheèunpuntatore a un’area di memoria. In questo caso, la variabile non può essere assegnatanuovamente. Se il passaggio è di tipo by reference, ancora una volta viene passatosemplicemente un riferimento, ma, diversamente dal caso precedente, la variabile puòessereriassegnataliberamente.

Visual Basic permette di usare sia parametri opzionali, sia parametri nominali. Iparametriopzionaliciconsentonodipoteromettere il lorovalorenell’invocazionedellaroutine,dalmomentocheperessivieneindicatounvaloredidefaultnelladichiarazione.Iparametrinominalicipermettonoinvecedispecificaregliargomentiinfunzionedelloronome, indipendentemente dalla loro posizione all’interno della firma. Per spiegare lasintassidausareneiduecasi,facciamoriferimentoall’esempio3.22.

Esempio3.22//Funzionechesommaditrenumericondueparametriopzionali

intSum(intx,inty=0,intz=0)

{

returnx+y+z;

}

'Numeriinteri

DimiAsInteger=18,j=8,k=5

'Invocazioneclassicailrisultatoè31

Sum(i,j,k)

Page 86: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'Usodeiparametriopzionali

Sum(i,j)'Equivalea:Sum(i,j,0)eilrisultatoè

26

Sum(i)'Equivalea:Sum(i,0,0)eilrisultatoè

18

'Usodeiparametrinominali

Sum(z:=i,y:=j,x:=k)'Equivalea:Sum(k,j,i)eilrisultatoè

31

Sum(z:=k,i)'Erroredicompilazione

'Usodiunparametronominaleperassegnareunvalorediversoda

'quellodidefaultall'ultimoparametroopzionale

Sum(i,z:=k)'Equivalea:Sum(i,0,k)eilrisultatoè

23

Sum(i,,k)'ValidoinVB

'Funzionechesommaditrenumericondueparametriopzionali

PrivateFunctionSum(ByValxAsInteger,OptionalByValyAsInteger=

0,OptionalByValzAsInteger=0)AsInteger

Return(x+(y+z))

EndFunction

Comepossiamonotare, i parametri opzionali vengonodefiniti tramiteun’espressionediassegnazioneall’internodelladichiarazionedellaroutine.Ilvaloreassegnatodeveessereobbligatoriamenteunacostante.

All’internodella firma, dobbiamo specificare i parametri opzionali in fondo alla listadegli argomenti. In caso contrario, otteniamo un errore di compilazione. Inoltre,nell’invocazione di una funzione o di una procedura, possiamo omettere un parametroopzionale,aggiungendoun’ulteriorevirgola(ultimalineadell’esempioprecedente).Ancheinquestocaso,citroviamoaottenereunerroredicompilazione,semprechenonusiamounparametronominale.

Nella chiamata di una routine, i parametri nominali devono essere riportati facendoprecedere al valore parametrico il nome dell’argomento seguito dai caratteri “:=” (due-puntieuguale). Il loroutilizzociconsentedipotervariare l’ordinediapparizionedegliargomentinellachiamatadella routineedipoterassociareaunparametroopzionaleunvalorediversodaquellodidefault,indipendentementedalnumerodiargomentispecificatiedallaposizionedelparametroopzionalenellafirma.

IstruzionicondizionaliLeistruzionidiselezionesonoutiliperdeterminarel’esecuzionediunbloccodicodiceinbaseaun’espressionebooleana. InVisualBasic le istruzionidi selezione sonodue,If…Then…ElseeSelect…Case,conl’aggiuntadell’operatoreIfedellafunzioneIIf.

Page 87: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IstruzioneIf…Then…ElseL’istruzioneifvalutaun’espressionebooleanae,infunzionedelsuovalore(TrueoppureFalse),esegueilbloccodicodiceadessaassociato.Sel’espressionevaleTrue,ilbloccovieneeseguito.Incasocontrario,l’esecuzioneriprendedallaprimaistruzionesuccessiva.Facoltativamente,puòessereaggiuntounbloccod’istruzioniprecedutodallaparolachiaveElseoElseIfchevieneeseguitoinalternativaalbloccoprincipale.Esisteanchelaformacontrattadell’istruzioneIf…Then,nelcasoincuiilbloccodicodicesiacompostodaunasingolaistruzione(esempio3.23).

Esempio3.23'VersioneridottasenzailbloccoElse

If((x>0)AndAlso(x<10))Then

'Bloccodicodiceprincipale

EndIf

'VersionecompletacomprensivadelbloccoElse

If(x>0)Then

'Bloccodicodiceprincipale

Else

'Bloccodicodicealternativo

EndIf

'Formacontrattavalidanelcasodiistruzionesingola

'Espressioneedistruzionestannosullastessarigadicodice

If(x>10)Thenx=10

Else

'Bloccoalternativo(facoltativo)

EndIf

Unblocco dell’istruzioneIf…Then…Else può contenere, a sua volta, altre istruzioniIf…Then…Else.Ingenere,questoproduceunacertaconfusionenelcodice.Intalunicasi, ilricorsoall’istruzioneSelect…Casepuòprodurreunmiglioramentodellaleggibilità.

IstruzioneSelect…CaseL’istruzioneSelect…Case permette di stimare il valore di una variabile (che può essereancheunastringa)e,infunzionediquestovalore,eseguireunparticolarebloccodicodice.Il blocco Select contiene a sua volta una serie di blocchi contrassegnati con la parolachiaveCase,seguitadaunvalorecostantedellostessotipodellavariabileinesame.

Unbloccovieneeseguitoinmodoesclusivorispettoaglialtriseilvaloredellavariabile

Page 88: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

corrispondeesattamenteconquellodiunadellecostanti.L’istruzioneCaseElsepermettedi definire il blocco finale, che viene eseguito se nessun valore costante corrisponde alvaloredellavariabile.Questobloccovapostosempreperultimoenonèobbligatorio.

Esempio3.24Selectx Case1To3 'Rangedivalori

Console.Write("Compresotra1e3") 'Istruzione/i

Case4,5 'Elencodivalori

Console.Write("Vale4oppure5") 'Istruzione/i

Case6,7,8 'Elencodivalori

Console.Write("Vale6,7oppure8") 'Istruzione/i

Case9 'Valoresingolo

Console.Write("Vale9") 'Istruzione/i

CaseElse 'Bloccodidefault

Console.Write("Nessunodeiprecedenti") 'Istruzione/i

EndSelect

InunostatementSelect…Caseesistonodiversetipologiediselezione.Unbloccodicodicepuòessere,infatti,selezionatoinfunzionediunoopiùvaloricostantioppureinbaseaunrange di valori nel caso di numeri (da x a y). L’esempio 3.25mostra alcune casisticheOperatorecondizionaleIfefunzioneIIf.

L’operatore condizionale If può essere invocato utilizzando due oppure tre operandi(esempio3.24).Nelprimocaso,ilprimoparametrorappresentaun’espressionebooleanachefungedacondizionedicontrolloperlarestituzionediunodeglialtridueargomenti.Nelsecondocaso, ilparametrochefungedacondizionedicontrollovieneomesso:seilprimo argomento restituisce Nothing, l’espressione ritorna il valore del secondoargomento.Intuttiglialtricasi,l’espressionerestituisceilvaloredelprimoargomento.

Esempio3.25'Seièdispari,isOddvaleTrue

DimisOddAsBoolean=If(iMod2=1,True,False)

'Sexènull,ritornay,altrimentiritornax

DimxAsString=Nothing'xvaleNothing

DimyAsString="HelloWorld"'yvale"HelloWorld"

DimzAsString=If(x,y)'zvale"HelloWorld"

Come alternativa all’operatore condizionale ternarioIf, possiamo utilizzare la funzioneIIf che accetta tre parametri: un’espressione booleana che funge da condizione dicontrolloedueargomentiditipoObject,cherappresentanoivalorichevengonoritornatinelcasoincuilacondizionesiarispettivamenteveraoppurefalsa(esempio3.26).

Page 89: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio3.26'Seièdispari,isOddvaleTrue

DimisOddAsBoolean=IIf(iMod2=1,True,False)

L’operatoreIf,chiamatocontreargomenti,operacomelafunzioneIIfconladifferenzache utilizza la valutazione “short-circuit”. La funzione IIf valuta sempre tutti i treargomenti,mentrel’operatoreIfcontreparametrinevalutasolamentedue.

Operatorenull-conditionalUnanovitàdiVisualBasic14èl’introduzionedell’operatorenull-conditional?.(punto-di-domanda,punto).

Si trattadiunoperatoremoltopotente,checonsentedivalutare l’espressioneallasuadestrasolosequellaallasinistraèdiversadaNothing.

Esempio3.27'codiceprecedente

Dimcustomer=If(customerIsNotNothing,customer.Country,Nothing)

'nuovasintassi

Dimname=customer?.Name'NothingseCustomerèNothing

Come per gli altri operatori condizionali, anche in questo caso vale la regola del cortocircuito: se uno dei valori specificati dovesse essere Nothing, non vengono valutate leistruzioni alla destra, evitando problemi derivanti da un accesso a una proprietà di unaclassenonistanziata(chegenererebbeunerrore).

Come si può apprezzare nell’esempio 3.27, questa nuova sintassi semplificadecisamenteilcodiceelorendepiùeleganteesemplicedacomprendere.

Istruzionid’iterazioneLe istruzioni d’iterazione servono per eseguire un blocco di istruzioni ripetutamente, inmodociclico.InVisualBasicesistonodiverseistruzionipereseguireiterazioninelcodice,ciascunacaratterizzatadaunadiversamodalitàd’uscitadalciclo.

IstruzionewhileL’istruzione while permette di definire un ciclo dove la condizione booleana di uscitaviene sempre valutata prima dell’iterazione. Il ciclo termina nel momento in cui lacondizionedi controllo risulti essere falsa.Nel caso in cui il ciclo sia compostodauna

Page 90: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

solaistruzione,leparentesigraffechedelimitanoilbloccodelleistruzionipossonoessereomesse.

Esempio3.28Dimx()AsInteger={1,2,3,4,5,6,7,8,9,10}

DimyAsInteger=0'Sommadeinumericontenutinelvettore

DimiAsInteger=0'Indicedelvettore

'Sommaidiecinumericontenutinelvettore

'Allafinedelcicloyvale55eivale10

While(i<10)

y+=x(i)

i+=1

EndWhile

L’esempio3.28mostracomeeseguireun’iterazionepersommarediecinumericontenutiin un vettore di interi. In tal caso, a ogni ciclo, l’indice dell’array deve essereesplicitamente incrementato di 1, affinché la condizione d’uscita (indiceminore di 10)risultifalsaunavoltalettituttiivalori.

IstruzioneDo…LoopL’istruzione Do…Loop consente di ripetere un blocco d’istruzioni fino a quando lacondizione booleana di controllo, a seconda dei casi, resta oppure diventa True. Lacondizione d’uscita può essere posta in cima o al termine del ciclo, precedutaopzionalmentedadueparolechiave:While,cheindicadieseguireleiterazionisolamentese la condizione booleana è vera, oppure Until, che indica di ripetere il ciclo fino almomentoincuilacondizioned’uscitadiventavera.

Esempio3.29Dimx()AsInteger={1,2,3,4,5,6,7,8,9,10}

DimyAsInteger=0'Sommadeinumericontenutinelvettore

DimiAsInteger=0'Indicedelvettore

'Sommaidiecinumericontenutinelvettore

'Allafinedelcicloyvale55eivale10

Do

y+=x(i)

i+=1

LoopUntil(i=10)

Page 91: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

L’esempio3.29mostral’usodell’iterazionecheutilizzalakeywordUntilpereseguirelasomma dei numeri contenuti in un vettore.Anche in questo caso, come in precedenza,affinché la condizione di uscita sia vera, l’indice dell’array deve essere esplicitamenteincrementatodi1.

IstruzioneFor…NextL’istruzioneFor…Next permette di definire un ciclo per un intervallo di indici numerici(esempio 3.30). Il blocco di codice associato al ciclo viene chiuso dall’istruzione Nextseguitadallavariabilecontenentel’indice.

Esempio3.30Dimx()AsInteger={1,2,3,4,5,6,7,8,9,10}

DimyAsInteger=0'Sommadeinumericontenutinelvettore

'Sommaidiecinumericontenutinelvettore

'Allafinedelcicloyvale55

ForiAsInteger=0To9

y+=x(i)

Nexti

Come possiamo notare nell’esempio 3.30, diversamente dai due casi precedenti, nondobbiamospecificare l’istruzioned’incrementodell’indice,masolamentedefinire il suorangedivalidità,ovveroilvaloredipartenzaequellodiarrivo.

IstruzioneForEachL’istruzioneForEachpermettedicompiereiterazionisuitipienumerabili,comepossonoessere gli array, e di scorrere gli elementi senza la necessità di definire e utilizzare unindice(esempio3.31).Anche inquestocaso ilbloccodicodiceassociatoalciclovienechiusodall’istruzioneNext.

Esempio3.31Dimx()AsInteger={1,2,3,4,5,6,7,8,9,10}

DimyAsInteger=0'Sommadeinumericontenutinelvettore

'Sommaidiecinumericontenutinelvettore

'Allafinedelcicloyvale55

ForEachitemAsIntegerInx

y+=item

Page 92: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Next

Èimportantesottolineareilfattocheglielementichevengonoiteratinonpossonoesseremodificatiall’internodelciclo,penailsollevamentodiun’eccezionearuntime.

IstruzionidisaltoLeistruzionidisaltopermettonodimodificareilnormaleflussodiesecuzionesequenzialedelcodice,introducendospostamentitraistruzioninoncontigue.

IstruzioneExitPostaall’internodiunciclo,diunaroutine(funzioneoprocedura),diuncicloodiunostatement come Select, l’istruzione Exit ne termina immediatamente l’esecuzione,trasferendo il controllo all’istruzione successiva. Ogni qualvolta vogliamo eseguire unsalto per uscire da un blocco di codice, dobbiamo specificare anche la parola chiaverelativa allo statement. Per esempio, per uscire da una routine, possiamo utilizzare leistruzioniExitFunctionoExitSub,asecondadeicasi.

Esempio3.32Dimx()AsInteger={1,2,3,4,5,6,7,8,9,10}

DimyAsInteger=0'Sommadeinumeriintericontenutinelvettore

'Sommaiprimiquattronumeridiversida5contenutinelvettore

'Allafinedelcicloyvale10

ForEachitemAsIntegerInx

If(item=5)ThenExitFor

y+=item

Next

Nell’esempio 3.32, gli elementi dell’array superiori al 4 non vengono considerati nelcomputodella somma,dalmomentoche il ciclo s’interrompedefinitivamentequando ilvalorediventaparia5.

IstruzionecontinuePosta all’interno di un ciclo, l’istruzione continue termina l’iterazione corrente etrasferisceilcontrolloall’iterazionesuccessiva.

Esempio3.33

Page 93: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dimx()AsInteger={1,2,3,4,5,6,7,8,9,10}

DimyAsInteger=0'Sommadeinumeriintericontenutinelvettore

'Sommaiprimiquattronumeridiversida5contenutinelvettore

'Allafinedelcicloyvale10

ForEachitemAsIntegerInx

If(item=5)ThenExitFor

y+=item

Next

Èimportantenonfareconfusionetral’istruzioneExitel’istruzioneEnd.Comeabbiamodetto, Exit consente semplicemente di eseguire un salto nell’ambito del codice, infunzionedellostatementincuil’istruzionevieneinseritaenondefinisceinalcunmodolafinediunbloccod’istruzioni.

IstruzioneContinuePosta all’interno di un ciclo, l’istruzione Continue termina l’iterazione corrente etrasferisce il controllo all’iterazione successiva. Anche in questo caso, dobbiamospecificarelaparolachiaverelativaallostatementcuil’istruzionedisaltosiriferisce.

Esempio3.34Dimx()AsInteger={1,2,3,4,5,6,7,8,9,10}

DimyAsInteger=0'Sommadeinumeriintericontenutinelvettore

'Sommainumeridiversida5contenutinelvettore

'Allafinedelcicloyvale50

ForEachitemAsIntegerInx

If(item=5)ThenContinueFor

y+=item

Next

Nell’esempio3.34,l’elementodell’arrayconvalore5nonvieneconsideratonelcomputodellasomma.Infatti,ilciclos’interrompemomentaneamente,perriprenderedall’elementosuccessivoconunaconseguentevariazionedelrisultatofinale.

IstruzioneReturnL’istruzioneReturnterminal’esecuzionediunaroutine(funzioneoprocedura).Nelcasodiunafunzione,l’istruzionedeveriportareancheilvalorediritorno(esempio3.35).

Page 94: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio3.35'Sommainumericontenutinelvettorepassatocomeparametro

'Seilvettoreènulloritornazero,altrimentieseguelasomma

FunctionSum(ByValx()AsInteger)AsInteger

If(xIsNothing)ThenReturn0

DimyAsInteger=0

ForEachitemAsIntegerInx

y+=item

Next

Returny

EndFunction

Lefunzioni,inquantoroutinecheritornanonecessariamenteunvalore,devonoconteneresemprealmenoun’istruzioneReturn. Inrealtà, ilnumerod’istruzionidi ritornodentroauna funzione è determinato dal numero di flussi d’esecuzione presenti in quest’ultima.L’omissione di un’istruzione di ritorno per un flusso in una funzione produceinevitabilmenteunerroreinfasedicompilazione.

IstruzioneGoToL’istruzione GoTo consente di trasferire il controllo in corrispondenza di un punto delcodicecontrassegnatodaun’etichetta,ovverounnomeseguitodalcarattere“:”(duepunti)cheprecede,asuavolta,unaseriediistruzioni.

Esempio3.36Dimx()AsInteger={1,2,3,4,5,6,7,8,9,10}

DimyAsInteger=0'Sommadeinumeriintericontenutinelvettore

'Sommaiprimiquattronumeridiversida5contenutinelvettore

'Allafinedelcicloyvale10elasommavienevisualizzataavideo

ForEachitemAsIntegerInx

If(item=5)ThenGoToFinish

y+=item

Next

Finish:

Console.Write("Somma:"&y)

SebbeneVisualBasicincludaquestaistruzione,nesconsigliamodecisamentel’utilizzo.Ingenere, una buona strutturazione del codice permette di evitarne l’uso, con il grande

Page 95: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

vantaggiodiaccrescerenotevolmentelaleggibilitàdelcodice.

FormattazionedistringheLe stringhe sono tra i tipi più utilizzati all’interno del codice, perché ci consentono diprodurreunouputvisualizzabileavideo.VisualBasichastoricamenteutilizzatoilmetodoFormat della classe string, per consentire di formattare le stringhe utilizzando unposizionamentobasatosusegnaposti.Nell’esempio3.37vediamounospezzonedicodicechemostraquestatecnica.

Esempio3.37DimnameAsString="Daniele"

DimcityAsString="RioneroinVulture"

DimfullNameAsString=String.Format("Tichiami{0}evienida{1}",

name,city)

Il risultato di questa istruzione sarà che al posto di{0} e{1} verranno inseriti i valoriprelevati dalla variabile specifica successivamente. Non c’è limite alle variabilispecificabili, e il loro identificativo sarà determinato in base alla posizione didichiarazione.

Questo approcciovabenequando il numerodi variabili èminimo, altrimenti diventacomplesso da gestire. Per questo motivo, Visual Basic 14 introduce una nuovafunzionalità, chiamata interpolazione di stringhe, che consente di avere una sintassi piùsemplice.Ilcodicedell’esempioprecedentesitrasformainquellocontenutonell’esempio3.38.

Esempio3.38DimnameAsString="Daniele"

DimcityAsString="RioneroinVulture"

DimfullNameAsString=$"Tichiami{name}evienida{city}"

Ilcarattere$(dollaro)èutilizzatoperfarcomprenderealcompilatorechesiamodifronteaun’interpolazionedistringhe. Isegnaposti interni,anzichéutilizzare ilposizionamentobasatosuindice,sarannoequivalentialnomedellavariabile,chesaràpoiinseritoalpostogiusto. Questo approccio rende molto più semplice variare il formato del testo peradattarloallenostrenecessità.

ConclusioniVisualBasicsiènotevolmenteevolutonegliultimianni.VisualBasic2015rappresenta

Page 96: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

l’ultimo passaggio di questa evoluzione, che ha portato il linguaggio a trasformarsiprofondamente per supportare lo sviluppo di applicazioni che utilizzano il .NETFrameworkcomeambientediesecuzione.

SeèverochemoltiaspettidellasintassidiVisualBasicsonorimastiinvariatirispettoalpassato,questonondeveassolutamentefarpensarecheledifferenzerispettoalleversioniprecedenti, in particolare Visual Basic 6, siano poche. Visual Basic è profondamentecambiato:quellocheeraun linguaggioorientatoaicomponenti,oggièdiventato,a tuttiglieffetti,unlinguaggioorientatoaglioggetti.

InquestocapitoloabbiamoaffrontatounicamentegliaspettibasedellasintassidiVisualBasic. Nel corso del prossimo capitolo, dedicato alla programmazione orientata aglioggetti, illustreremogliaspettidiVisualBasicchetestimonianol’evoluzionechequestolinguaggiohasubitoconl’avventodel.NETFramework.

Page 97: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

4

Laprogrammazioneorientataaglioggetti

La programmazione procedurale, propria di linguaggi ormai datati come il Pascal o ilLinguaggio C oppure di linguaggi di scripting più recenti come il VBScript, si basaprincipalmente sull’organizzazionee suddivisionedel codice in funzioni eprocedure.Aciascuna operazione corrisponde una routine, che accetta un insieme di parametri e, infunzione di questi, produce eventualmente un risultato. Con un simile approccio, laseparazione tra idatie la logicaapplicativa risultaesserenetta:unaprocedura riceve leinformazioni utili all’esecuzione dell’operazione richiesta solamente sotto forma diparametri e il suo stato interno in genere viene del tutto perduto una volta terminatal’elaborazione. In molti casi questa netta separazione tra dati e codice rappresenta unvincoloimportantetaledarenderequestoparadigmadiprogrammazionepocoefficace.

Laprogrammazioneorientataaglioggetti (inmodoabbreviatoOOP,che in inglesecorrispondeaObjectOrientedProgramming)introduceunmododiversoo,sevogliamo,piùefficienteperstrutturareilcodiceelalogicaapplicativa.OOPè,infatti,unparadigmadiprogrammazione che si basa sulladefinizione e sull’utilizzodi una seriedi entità traloro collegate e interagenti, ciascuna delle quali è caratterizzata da un insieme diinformazionidistatoedicomportamentispecifici.Questeentitàsonodenominateoggettie ciascuna di esse può contenere contemporaneamente dati, funzioni e procedure. Inquestomodo,unaroutineassociataaunoggettopuòsfruttarelostatointernodell’oggettodi appartenenza per ricavare le informazioni utili all’esecuzione dell’elaborazioneprevista.

Nel corso di questo capitolo vedremo come l’OOP si applichi al linguaggio VisualBasicequalivantaggicomporti.

Vantaggidell’ObjectOrientedProgrammingIl grande vantaggio dell’approccio object-oriented rispetto agli altri paradigmi diprogrammazioneconsistenel fattoche,per strutturare leapplicazioni, lo sviluppatore sitrovaadutilizzareunalogicacheèmoltovicinaaquellacheportaallapercezionecomunedel mondo reale. Pensare a oggetti significa, infatti, saper riconoscere gli aspetti checaratterizzanounaparticolarerealtàesaperfornire,diconseguenza,unarappresentazioneastrattainun’otticaOOP.

Perfareunesempio,consideriamolacontabilitàdiun’azienda.Inquantolefattureole

Page 98: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

bolle sono sicuramente elementi del mondo reale che riguardano l’amministrazioneaziendale, un sistema gestionale realizzato secondo l’approccio OOP devenecessariamente includere una rappresentazione di queste entità sotto forma di oggetti.L’idea essenziale di OOP consiste, infatti, nell’individuare l’insieme degli oggetti checostituisconoecaratterizzano la realtà inesamee, al tempostesso,neldefinire ilmodocon cui essi interagiscono tra loro ed evolvono nel tempo.Ciascun oggetto individuatonondevenecessariamentecorrispondereaunelementodelmondoreale;intalunicasiessopuò consistere in una pura invenzione introdotta dallo sviluppatore per uno specificoscopo.

Visual Basic 2015 è un linguaggio orientato agli oggetti che permette di realizzareapplicazioni,chesfruttanoil.NETFrameworkcomeambientediesecuzione.Essosfruttai principi base della programmazione orientata agli oggetti e utilizza come elementifondamentaliperl’organizzazioneelastrutturazionedelcodiceleclassi,dicuiglioggettisonoistanzeparticolari.

PrincipifondamentalidiOOPComeabbiamoavutomododidirenelcorsodelprimocapitolo,itipi(siaquellidivalorechediriferimento)sonoglielementiportantidiogniapplicazionechegiranell’ambitodelCommonLanguageRuntime.Oltre ai tipi built-in, inclusi nellaBaseClass Library del.NETFramework,possiamoperaltrodefinireinostritipipersonalizzati.

Le classi rappresentano i tipi di riferimento definiti dallo sviluppatore, mentre lestrutture sono i tipidivalore. I loroelementicostitutivi (detti anchemembri)possonoesseresiadati,chefunzionieprocedure.

Iprincipifondamentalisucuisi fondalaprogrammazioneorientataaglioggettiecheriguardano leclassi (e inparteanche le strutture) sonoprincipalmente tre:ereditarietà,polimorfismo e incapsulamento. Avere dimestichezza con questi concetti è difondamentale importanza per poter capire e, al tempo stesso, sfruttare al meglio imeccanismicheregolanolaprogrammazioneorientataaglioggetti.

EreditarietàIlprincipiodi ereditarietà sibasa sul fattodipoterdefinireun legamedidipendenzaditipo gerarchico tra classi diverse.Una classe deriva da un’altra se da essa ne eredita ilcomportamentoelecaratteristiche.Laclassefigliasidiceclassederivata,mentrelaclassepadreprendeilnomediclassebase(oppuresuperclasse).Laclassebasecontieneilcodicecomune a tutte le classi da essa derivate. Ogni classe derivata rappresenta invece unaspecializzazione della superclasse, ma eredita in ogni caso dalla classe base icomportamentiinessadefiniti.

Tutteleclassicontenutenel.NETFramework(compresequellecreateex-novodallo sviluppatore) derivano implicitamente dal tipo System.Object. Questa

Page 99: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

caratteristica permette di poter utilizzare variabili di tipoSystem.Object perreferenziareleistanzediunaqualsiasiclasse,tramiteun’operazionenotacomeup-casting(castingdaunaclassederivataversounasuperclasse).L’operazioneinversaprendeilnomedidown-casting.

Per fareunesempiochiarificatore, supponiamodivoler rappresentare il genere animaledefinendounastrutturadiclassiequivalente (vedi figura4.1).Possiamoindividuareunaprimaclassebase,Animale,dacuituttelealtredevonoderivare.Aquestopuntoleclassiderivate possono essere:Mammifero, Rettile, Insetto, Anfibio, Pesce, Uccello,ecc. La classe Uomo deriva direttamente da Mammifero e indirettamente da Animale. LaclasseRana deriva da Anfibio,mentre la classe Rondine deriva da Uccello; entrambediscendonoindirettamentedaAnimale.Possiamonotarecheintuttiicasivalelarelazione“èuntipodi”(l’uomoèuntipodimammifero,laranaèuntipodianfibio,larondineèuntipodiuccello;l’uomo,laranaelarondinesonountipodianimale).

Figura4.1:LaclassebaseAnimaleelesueclassiderivate.

PolimorfismoIl polimorfismo rappresenta il principio in funzione del quale diverse classi derivatepossono implementare uno stesso comportamento definito nella classe base in mododifferente.

Datochenel.NETFrameworkogniclassederivadirettamenteoindirettamenteda System.Object, ogni oggetto presenta un certo numero di comportamenticomuni,alcunideiqualipossonoesserespecializzatisfruttandoilpolimorfismo.Tra questi comportamenti figurano le funzioni ToString, GetHashCode eEquals, la cui implementazione predefinita è inclusa nella classe baseSystem.Object. Avremo modo di riprendere il discorso sul polimorfismo nelcorsodelcapitolo.

Page 100: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Riprendendo l’esempio proposto nel caso dell’ereditarietà, consideriamo duecomportamenticomunia tuttiglianimali:RespiraeMangia.Nelmondoanimalequesticomportamentivengonomessiinattosecondomodalitàpeculiariasecondadellespecie:uncarnivoromangiainmododifferenterispettoaunerbivoro,unpescerespirainmododiversorispettoaunuccello.Sullabasediquesteconsiderazioni,icomportamentiMangiaeRespira,definitinellediverseclassiderivatedaAnimale,possonoessereimplementatiinmodo specifico e del tutto indipendente dalle altre implementazioni (e, in particolarmodo,daquellodellaclassebaseAnimale).

IncapsulamentoL’incapsulamento rappresenta il principio inbasealqualeunaclassepuòmascherare lasuastruttura internaeproibireadaltrioggettidiaccedereaisuoidatiodirichiamare lesuefunzionichenonsianodirettamenteaccessibilidall’esterno.

Nei linguaggidel .NETFramework l’incapsulamentoèottenutograzieall’usodeimodificatori di accessibilità, di cui avremomododi parlare nel corso delprossimoparagrafo.

Loscopoprincipaledell’incapsulamentoèdidareaccessoallostatoeaicomportamentidiun oggetto solo attraverso un sottoinsieme di elementi pubblici. L’incapsulamentopermettequindidiconsiderareunaclassecomeunasortadiblack-box,inaltreparoleunascatolanerachepermettedimostraresolociòcheènecessario,mascherandociòchenondevetrasparireversol’esterno.

ClassiUnavolta introdotti i principidellaprogrammazioneorientata agli oggetti, siamoprontiper vedere nel dettaglio come il linguaggio permetta di sfruttare il paradigma a oggettitramiteladefinizioneel’usodelleclassi.

Comegiàdettonell’introduzionedelcapitolo,leclassisonoitipidiriferimentodefinitidallo sviluppatore. In Visual Basic, esse vengono dichiarate tramite la parola chiaveClass, seguita dal nome identificativo. L’esempio 4.1 mostra la sintassi valida per ladichiarazionediunaclassecherappresentaunapersona.

Esempio4.1ClassPerson

'...

EndClass

Unaclasseèuncontenitorechepuòincludereunaseriedimembrisottoformasiadidati,siadicomportamenti.Traimembridiunaclassepossiamodistinguereicampi,glieventi,

Page 101: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

imetodieleproprietà.

MembridiunaclasseI campi rappresentano le variabili interne alla classe (i dati), mentre imetodi sono lefunzioni e le procedure (i comportamenti). Per i campi e i metodi valgono le stessenotazioni sintattiche viste nel corso del capitolo precedente per la dichiarazione dellevariabililocaliedelleroutine(esempio4.2).

Esempio4.2ClassPerson

Dim_fullNameAsString

Dim_ageAsInteger

FunctionGetFirstName()AsString

'...

EndFunction

EndClass

Gli eventi sono elementi che permettono di inviare notifiche verso l’esterno incorrispondenzadicertiavvenimentichetendonoavariarelostatointernodiunaclasse.Aciascun evento possono essere associate una o più azioni (dettehandler), che vengonoeseguite in corrispondenza della notifica dell’evento stesso. Nel .NET Framework glieventisfruttanountipodidatoparticolareperagganciareirispettivihandler.Sitrattadeidelegate,chenonsonoaltrochel’equivalente.NETdeipuntatoriafunzionepresentineilinguaggicomeilC++.Aglieventieaidelegateèdedicatol’interocapitolo6.

Leproprietàsonomembrichepermettonodiaccedereinletturaescritturaaicampidiunaclasse.Ingenere,unaproprietàdefinisceunacoppiadimetodi(unoperlaletturadiuncampoeunoperlasuascrittura)eadessiassociaunnomeidentificativo.InVisualBasic,per la dichiarazione di una proprietà, dobbiamo utilizzare la parola chiave Property(esempio 4.3). La dichiarazione di una proprietà avviene specificando due blocchi dicodice contrassegnati dalle parole chiave Get e Set, corrispondenti rispettivamente alleoperazioni di lettura e di scrittura. Questi due blocchi sono detti anche accessor (ofunzioni di accesso). Per una proprietà non è obbligatorio definire sempre entrambi gliaccessor.

Esempio4.3PublicClassPerson

'Campoprivatochecontieneilnomecompleto(nomeecognome)

'Ilcampoèinizializzatoconilvalore"Sconosciuto"

Page 102: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Private_fullNameAsString="Sconosciuto"

'Campoprivatochecontienel'età

'Ilcampoèimplicitamenteinizializzatoconilvalore0

Private_ageAsInteger

'Proprietàpubblicacheesponeilcampocontenenteilnome

PublicPropertyFullName()AsString

Get

Return_fullName

EndGet

Set(ByValvalueAsString)'Vaspecificatoilparametro

_fullName=value

EndSet

EndProperty

'Proprietàpubblicacheesponeilcampocontenentel'età

PublicPropertyAge()AsInteger

Get

Return_age

EndGet

Set(ByValvalueAsInteger)_age=value

EndSet

EndProperty

EndClass

Generalmente le proprietà vengono associate a un campo privato, che è detto anchebacking field, e che contiene effettivamente il valore. In questomodo diventa possibileapplicarelogicaaiduemetodilegatialcaricamentoesalvataggiodeidati,chiamatianchegetteresetter.

InVisualBasic2015possiamodefinire leproprietàdiunaclasse inmodoalternativorispetto a quantomostrato nell’esempio 4.3 attraverso le proprietà automatiche. Esserappresentano una modalità di dichiarazione molto compatta che ci evita di doverdichiarareilcampoprivato,resoaccessibiletramitelaproprietà,edidoverimplementaregliaccessorperlascritturaelaletturainmodoesplicito.Inquestotipodidichiarazioneèil compilatore che crea inmodo totalmente trasparente per lo sviluppatore sia il campoprivatosiailcontenutodegliaccessordellaproprietà.

L’esempio 4.4 mostra un semplice caso di utilizzo della sintassi per le proprietàautomatichenelladefinizionedellaclassePerson,vistainprecedenza.Ilcodiceèintuttoepertuttoequivalenteaquelloriportatonell’esempio4.3.Possiamoperaltronotarecomeinquesto secondocaso la compattezzae l’essenzialitàdel codice sianomoltomaggiori,conunconseguentemiglioramentodellaleggibilità.

Page 103: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio4.4PublicClassPerson

PublicPropertyFullNameAsString="Sconosciuto"

PublicPropertyAgeAsInteger

EndClass

VisualBasic,afiancodelleproprietàautomatiche,supportaunafeaturenotacomeauto-propertyinitializers(inizializzatoriperleproprietàautomatiche),checonsentediscrivereun codice ancora più compatto e di inizializzare, in un colpo solo, le proprietà, comepossiamovederenell’esempio4.4.

LivellidiaccessibilitàNegli esempi precedenti, le parole chiave come Private e Public rappresentano icosiddettiaccessmodifieromodificatoridiaccessibilità,chehannoloscopodidefinireilgradodivisibilitàdiundeterminatoelemento.

Inbaseaquantodettorelativamenteall’incapsulamento,all’iniziodelcapitolo,leclassie i loro membri (campi, proprietà e metodi) possono avere un diverso grado diaccessibilità.Questosignificacheimembridiunaclassepossonoesseremascheratieresiinvisibili agli altri oggetti. L’insieme degli elementi accessibili è detto interfaccia dellaclasse.Esistonodiversilivellidiaccessibilità,aciascunodeiqualicorrispondeunaparolachiavespecifica,comemostratonellatabella4.1.

Tabella4.1–ModificatoridiaccessibilitàinVisualBasic.Parolachiave VisibilitàPublic DatutteleclassiProtected SolodalleclassiderivatePrivate NonaccessibileFriend All’internodell’assemblyProtectedFriend Combinazionedelledue

Ilmodificatore di accessibilità per una classe si riferisce alla sua visibilità in relazioneall’assembly di appartenenza. Una classe pubblica può essere richiamata anche daglioggetti presenti in altri assembly; una classe definita come Friend è accessibileunicamenteall’internodell’assemblydiappartenenza.

Gli access modifier sono facoltativi. In caso di omissione, i membri di una classevengono considerati di tipo privato, mentre le classi diventano visibili unicamenteall’interno dell’assembly di appartenenza. L’omissione del modificatore di accessibilitànelladichiarazionediuncampo(vediesempio4.2)implical’utilizzodellakeywordDim,comenelcasodelladefinizionedellevariabililocali(quindiDimequivaleaPrivate).

Èbuonanormadefinire sempre i campidi una classe comeprivati e renderlieventualmente accessibili dall’esterno tramite una proprietà corrispondente.

Page 104: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Del resto, la presenza all’interno del linguaggio delle proprietà automatichefacilitaquestoapproccio.

Comecomportamentopredefinito,gliaccessordiunaproprietàhannolostessolivellodiaccessibilità indicato per il membro di classe cui si riferiscono. Possiamo peraltrodifferenziare i livelli di accessibilità dei due blocchiGet eSet, inmodo tale che sianodiversi. Nell’esempio 4.5, l’operazione di lettura è pubblica, mentre l’operazione discritturahaunlivellodiaccessolimitato.

Esempio4.5PublicPropertyFullName()AsString

Get

Return_fullName

EndGet

PrivateSet(ByValvalueAsString)

_fullName=value

EndSet

EndProperty

CreazionedelleistanzediclasseLe istanze delle classi sono gli oggetti definiti nell’introduzione del capitolo. DalmomentocheperognioggettoilCommonLanguageRuntimeallocaun’areadimemoriadistintanelmanagedheap,ciascunodiessiècaratterizzatodaun’identitàunivoca,daunostatoparticolare(memorizzatoneicampi)edacomportamentispecifici(metodi).Questosignificacheoggettidiversidiunastessaclassemantengonoinmemoriacopiedifferentideidati(quindipresentanounostatodistintodatuttiglialtrioggettisimili),anchese,ingenerale,condividonoglistessicomportamenti.

Un oggetto viene istanziato invocando unmetodo particolare, che prende il nome dicostruttore.Ilcostruttoredidefaultnonpresentaparametri,maperunaclasseèpossibiledefinirepiùcostruttori,ciascunocaratterizzatodaunafirmadifferente.Questoèpossibileinquanto,all’internodelleclassi,imetodipossonoesseresoggettiaoverloading,ovveropossonoesisterepiùmetodiconlostessonome,maconparametridiversi.Comeabbiamogiàanticipatonelcorsodelcapitolo3,lacondizionedioverloadingèapplicabileatuttiimetodidiunaclasseinbaseallafirma.L’esempio4.6mostrauncasodioverloadingdelcostruttore. Il costruttore è un tipo particolare di procedura (non presenta un valore diritorno) con nome identificativo New. Come abbiamo visto nel capitolo precedente,parlando della dichiarazione di variabili e oggetti, esso viene richiamato durante lacreazionediun’istanzadiclasse,utilizzandolaparolachiaveNew(esempio4.6).

Page 105: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio4.6PublicClassPerson

Private_fullNameAsString

PrivateReadOnly_ageAsInteger

'Costruttoredidefault

PublicSubNew()

_fullName="Sconosciuto"

_age=18

EndSub

'Costruttoreconparametri

PublicSubNew(ByValnameAsString,ByValageasInteger)

_fullName=name

_age=age

EndSub

EndClass

DimxAsNewPerson()

DimyAsNewPerson("DanieleBochicchio",36)

In una classe possiamo utilizzare una o più costanti secondo le regole sintattiche cheabbiamo già esposto nel capitolo 3. In aggiunta possiamo definire un campo comereadonly(laparolachiaveèReadOnly),chepuòessereinizializzatoconunvalorenonnecessariamentecostanteunicamenteall’internodiuncostruttore(esempio4.6).Unavoltacheunaclassevieneistanziata,isuoicampireadonlynonsonopiùmodificabili.

Un altro tipo particolare di metodo è il distruttore. Questo metodo vienerichiamatoogniqualvoltaunoggettodeveesserefinalizzato.Peraltro,essendola distruzione di un’istanza non deterministica, in quanto gli oggetti obsoleticontenuti nel managed heap vengono rimossi in modo autonomo e nonprevedibile dalGarbageCollector, il distruttore è unmetodo che solitamentenonènecessariodefinire.D’altrapartequestaregolavienemenonelmomentoincuiunaclasseutilizzarisorsenongestite,comeadesempiohandleWin32.Inquesticasilerisorseunmanageddevonoesserefinalizzateinmodoesplicito,dalmomentocheillororilasciononpuòessereeffettuatodalGarbageCollectorinmodoautomatico.

Internamenteaimetodiealleproprietàdiunaclasse,possiamoutilizzare lakeywordMecomeriferimentoall’istanzacorrentecreatatramitel’invocazionediuncostruttore.L’usodiquestaparolachiavepermette,inmolticasi,dimigliorarelaleggibilitàdelcodicee,altempo stesso, di eliminare qualsiasi possibile ambiguità, in caso di omonimia degliidentificatori.

Nell’esempio 4.7 la keyword Me viene utilizzata sia nel costruttore, sia nel metodo

Page 106: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

d’istanzaperrichiamarelaproprietàFullName.

Esempio4.7PublicClassPerson

PublicPropertyFullNameAsString="Sconosciuto"

PublicSubNew(ByValnameAsString)

Me.FullName=name

EndSub

PublicFunctionGetFirstName()AsString

ReturnMe.FullName.Split('')(0)

EndFunction

EndClass

DimxAsNewPerson("DanieleBochicchio")'Creazionedell'istanza

DimyAsString=x.GetFirstName()'yvale"Daniele"

Inun’otticadiriduzionedellaverbositàdelcodice,VisualBasic2015prevedeunasintassimoltocompattaperl’inizializzazionedioggetti,arrayecollezioni(quest’ultimeverrannotrattate in modo specifico nel prossimo capitolo). Per l’inizializzazione degli oggettidobbiamoutilizzarelaparolachiaveNewseguitadalnomedeltipoedallakeywordWithseguitadaunelencodicoppieproprietà/valoreseparatedaunavirgolaeracchiuseinunacoppiadiparentesigraffe.

L’esempio4.8riportalacreazionediun’istanzadellaclassePersonconinizializzazionedelle proprietà.Questa forma sintattica compatta è del tutto equivalente all’invocazionedelcostruttoredellaclassePerson,seguitadall’inizializzazionediciascunaproprietàconilvalorecorrispondente.

Esempio4.8'Sintassidicreazioneconinizializzazionedelleproprietà

DimxAsNewPersonWith{.FullName="DanieleBochicchio",.Age=36}

'Sintassiequivalente:costruttoredidefaultedinizializzazione

DimyAsNewPerson()

y.FullName="DanieleBochicchio"

y.Age=36

Ancheperglioggettienumerabili,comegliarrayelecollezioni,possiamoutilizzareunasintassidiinizializzazionecompatta.Inquestocasoessasiriferiscealladefinizionedeglielementicostituenti.

InVisualBasic l’inizializzazione di un oggetto enumerabile è composta dall’insiemedegli inizializzatori di ciascun elemento, separati da una virgola. La sequenza degli

Page 107: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

elementièracchiusainunacoppiadiparentesigraffeedèprecedutadalladichiarazionedel tipo enumerabile. L’esempio 4.9 mostra la sintassi per inizializzare un array dielementiditipoPerson.

Esempio4.9DimpersonsAsPerson()=

{

NewPersonWith{.FullName="CristianCivera",.Age=34},

NewPersonWith{.FullName="DanieleBochicchio",.Age=36}

}

Visual Basic 2015 permette di usare la keyword New anche nella definizione di tipianonimi (detti pure anonymous type), caratterizzati dal fatto di non avere un nomeidentificativo dichiarato esplicitamente (il nome viene comunque generatoautomaticamente,infasedicompilazione).Unanonymoustypederivadirettamentedallaclasse System.Object ed è composto semplicemente da un insieme di proprietàaccessibili.

Per definire un anonymous type, dobbiamoutilizzare la stessa sintassi già vista pocosopranel casodegli inizializzatori di oggetti (esempio4.10).La sintassi di creazione è,infatti,caratterizzatadalladichiarazionediunaseriediproprietà,ilcuitipovienericavatotramitetypeinferenceinbaseall’espressionediinizializzazione.

Esempio4.10'Definizionediunacoordinataspaziale

Dimpoint=NewWith{.X=1,.Y=2,.Z=3}

All’internodiunprogrammapossonoesisterepiùvariabiliassegnateaunanonymoustypeecorrispondenti allo stesso tipo (esempio4.11). Infatti,duedichiarazionidianonymoustype producono lo stesso risultato se nelle due definizioni il nome e il tipo di ciascunaproprietà corrispondono rispettando l’ordine di apparizione. In tal caso è possibileeseguirel’assegnazionetraleduevariabilidichiaratecomeanonime.

Esempio4.11Dimpoint1=NewWith{.X=21,.Y=10,.Z=71}

Dimpoint2=NewWith{.X=18,.Y=8,.Z=5}

'Lasecondaproprietàdipoint3èditipoString

Dimpoint3=NewWith{.X=20,.Y="1",.Z=67}

point1=point2'Assegnazionevalida(stessotipoanonimo)

point1=point3'Errore(typemismatch)

Nell’esempio4.11iduetipianonimirelativiallevariabilipoint1epoint3differisconotra

Page 108: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

loroinquantononesisteun’esattacorrispondenzatraitipideglielementicostituenti.Untentativodiassegnazionetradueistanzerelativeatipianonimidiversi,produceunerroreinfasedicompilazione.

ClassistaticheeparzialiFinoraabbiamoparlatosolamentedeglielementiassociatiaunaparticolareistanzadiunaclasse (dettimembrid’istanza). Oltre a questi ultimi, in una classe, possiamo definireanche un insieme di elementi associati direttamente al tipo e condivisi da tutte le sueistanze(dettimembristatici).

Imetodi,icampieleproprietàstatichepossonoessereutilizzatisenzadoverinvocareilcostruttoreperiltipoacuisiriferiscono.EssisonocontrassegnaticonlakeywordShared,cheliidentificacomestaticielidifferenziadaimembrid’istanza(esempio4.12).

Esempio4.12PublicClassPerson

PublicPropertyFullNameAsString="Sconosciuto"

PublicSubNew(ByValnameAsString)

Me.FullName=name

EndSub

'Metodod'istanza

PublicFunctionGetFirstName()AsString

ReturnMe.FullName.Split(""c)(0)

EndFunction

'Metodostatico

PublicSharedFunctionGetFirstName(ByValnameAsString)AsString

Returnname.Split(""c)(0)

EndFunction

EndClass

DimxAsString=Person.GetFirstName("StefanoMostarda")

Imembristaticipossonoesserecontenutiinunaclasseindipendentementedalfattocheinessasianopresentianchemembrid’istanza.Unaclassechecontieneunicamentemembristaticiprendeilnomedimodulo.EssovienedichiaratoutilizzandolakeywordModuleinsostituzionedellaparolachiaveClass,senzalanecessitàdidoverdefinireimembricomestatici(esempio4.13).

Esempio4.13

Page 109: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

PublicModuleCalculator

PublicFunctionSum(

ByValxAsInteger,

ByValyAsInteger)AsInteger

'Ritornalasommadeiduenumeri

Returnx+y

EndFunction

PublicFunctionDivide(

ByValxAsInteger,

ByValyAsInteger)AsInteger

'Ritornaladivisioneinteradeiduenumeri

Returnx\y

EndFunction

EndModule

DimiAsInteger=Calculator.Sum(18,8)

DimjAsInteger=Calculator.Divide(18,8)

Comepossiamonotarenegliesempiprecedenti,peraccedereaimembristaticidiuntipooagli elementi di un’istanza, si utilizza il carattere “.” (punto), seguito dal nomeidentificativodelmembroe,nelcasodeimetodi,dall’elencodeiparametriinclusiinunacoppiadiparentesitonde.

Un tipoparticolaredimetodostaticoè ilcosiddettoextensionmethod.Gliextensionmethodpossiedonolaparticolaritàdipoteressereinvocatiperunparticolaretipocomesefossero metodi di istanza e permettono di estendere classi pre-esistenti con metodiaggiuntivi,siacheitipiacuiessisiriferisconosianodirettamenteinclusinellaBaseClassLibrarydel.NETFramework,siachesianotipipersonalizzaticreatidallosviluppatore.

Per dichiarare un extensionmethod inVisualBasic, dobbiamo utilizzare una sintassiparticolare,marcandoilmetodostaticocontenutoinunmoduloappositoconunattributoditipoExtensionAttribute.Iltipodelprimoargomentodelmetodorappresentalaclassechevieneestesa.Ilmetodostaticodiventaparteintegrantedell’interfacciadeltipoestesoepuòessereinvocatocomeunnormalemetodod’istanza.

Un attributo rappresenta un tipo particolare di oggetto che permette diassociare in modo dichiarativo un comportamento o una descrizione a unaclasse e/o a un suo membro. Gli attributi sono trattati in modo specificoall’internodelcapitolo7.

L’esempio 4.14mostra l’estensione del tipo String con l’aggiunta delmetodo IsNull.L’istruzione x.IsNull() equivale alla chiamata del metodo staticoExtensions.IsNull(x).

Page 110: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio4.14ImportsSystem.Runtime.CompilerServices

PublicModuleExtensions

<Extension()>

PublicFunctionIsNull(ByValvalueAsString)AsBoolean

ReturnvalueIsNothing

EndFunction

EndModule

DimxAsString=Nothing'Stringanulla

DimyAsBoolean=x.IsNull()'yvaletrue

Perpoterutilizzareleestensioniperunparticolaretipo,dobbiamofareinmodocheessesiano accessibili nel codice. A tale scopo, è necessario usare la direttiva Imports perreferenziareilnamespace,incuisonoincluseledefinizionidegliextensionmethod.

PartialclassUn aspetto interessante delle classi è rappresentato dal fatto che esse possono esseredefinitecomeparziali.Ladichiarazionediunaclassepuòessere,infatti,distribuitainpiùfileseparati,ciascunodeiqualipuòincludereunsottoinsiemedeimembri.Laclassedeveessere contrassegnata con la parola chiave Partial per indicare che si tratta di unadichiarazioneparzialeenoncompleta(esempio4.15).

L’omissionedellaparolachiavecomportaunerroreinfasedicompilazione,inquanto,in questo caso, al compilatore risultano essere presenti due tipi aventi lo stesso nomeidentificativo. Durante la fase di compilazione, infatti, le varie dichiarazioni parzialivengonouniteaformareun’unicaentitàfinale.

Esempio4.15PartialPublicClass

PersonPublicSubWrite()

'...

OnWrite()

'...

EndSub

'Dichiarazionedelmetodoparzialeprivato

PartialPrivateSubOnWrite()

EndSub

EndClass

Page 111: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

PartialPublicClassPerson

PrivateSubOnWrite()

'Implementazione

EndFunction

EndClass

Ancheunmetodoprivatodiunaclasseparzialepuòesseredichiaratocomeparziale,masoloseèunaprocedurachenonritornaunvalore.Inquestocaso,unapartedellaclassecontiene solamente la definizione mentre l’altra può contenere, facoltativamente,l’implementazione (esempio 4.15). Nel caso in cui un metodo parziale non vengaimplementato, il metodo stesso e tutte le sue chiamate vengono rimosse in fase dicompilazione.

VisualBasic14 introduce lapossibilitàdicrearecomeparzialianche le interfaccee imoduli.

EreditarietàepolimorfismoInVisualBasic, l’ereditarietàmultiplanonècontemplata.Perquestomotivounaclassepuòderivareunicamentedaunasolaclassebase.Questoaspettononrappresentatuttaviaun vincolo di particolare rilievo: l’ereditarietà singola risulta essere decisamentesufficientenellamaggiorpartedeicasi.

InVisualBasic il legamediereditarietà tradueclassisiesprimecon laparolachiaveInherits. Ilnomedel tipobasevapostonella lineadi codice successivaaquelladelladichiarazione della classe derivata. L’esempio 4.16mostra la dichiarazione della classeEmployee,cheereditadallaclassebasePerson.

Esempio4.16PublicClassEmployee

InheritsPerson'Employee(impiegato)derivadaPerson(persona)

'...

EndClass

I membri pubblici e protetti del tipo base sono accessibili anche nelle classi derivate.Inoltre, tutte le forme di visibilità, ovvero gli accessmodifier di ognimembro del tipobase,vengonoereditate,amenocheessenonsianoreimpostatediversamentenellaclassederivata.

I membri statici, in quanto associati al tipo e non alle istanze, non vengonoderivati,indipendentementedallorolivellodiaccessibilità.Unmodulononpuòesserederivato.

OltreallakeywordMe,cheidentifical’istanzacorrente,inVisualBasicpossiamousarela

Page 112: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

parola chiaveMyBase come riferimento al tipo base nelle classi derivate.Questa parolachiavetornamoltoutileperrichiamareinmodoesplicitoimetodie,ingenerale,imembripubblicioprotettidel tipobaseneimetodienegliaccessordelleproprietàdiunaclassederivata(esempio4.17).

Esempio4.17PublicClassEmployee

InheritsPerson

Private_firstNameAsString

PublicSubNew(ByValnameAsString,ByValageAsInteger)

MyBase.FullName=name

MyBase.Age=age

_firstName=MyBase.GetFirstName()

EndSub

EndClass

In base a come viene dichiarata, una classe può non essere derivabile oppure può nonessere istanziabile direttamente. Una classe che non può essere derivata deve esserecontrassegnataconlakeywordNotInheritable(esempio4.18).

Esempio4.18'Customer(cliente)derivadaPersonenonpuòavereclassiderivate

PublicNotInheritableClassCustomer

InheritsPerson

'...

EndClass

Una classe che non può essere direttamente istanziata e che, quindi, deve essereobbligatoriamentederivata,sidiceastratta.Perdichiarareunaclasseastratta,dobbiamospecificarelaparolachiaveMustInherit.Leclassiastrattepossonoavereopzionalmentetuttiimetodieleproprietàounlorosottoinsiemedefinitianch’essicomeastratti.

Un membro astratto è un elemento della classe per il quale viene riportatasemplicementeladichiarazioneinsiemeallaparolachiaveMustOverride(esempio4.19).Per esso, infatti, non viene specificata l’implementazione, che deve essereobbligatoriamentefornitanelleclassiderivate.

Esempio4.19'Personèunaclasseastrattaedeveesserederivata

PublicMustInheritClassPerson

Page 113: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'Metodoastratto

PublicMustOverrideFunctionGetFirstName()AsString

'Proprietàastratta

PublicMustOverridePropertyFullName()AsString

Get

Set(ByValvalueAsString)

EndProperty

EndClass

Come abbiamo avuto modo di dire nella prima parte del capitolo, il polimorfismorappresentalapossibilitàdiridefinireleproprietàeimetodinelleclassiderivaterispettoaquellidichiaratineltipobase(overriding).Affinchépossaesserepolimorfico,unmembrodeveesseremarcatocomeastrattooppurecomevirtuale.

Datochenel tipobaseunmembroastratto riportaunicamente la suadichiarazione, èchiaro che esso debba essere implementato ogni volta in ciascuna delle classi derivate.Questo implica che ogni classe derivata è caratterizzata da comportamenti simili, chedevonoperaltroadottarenecessariamentediversestrategieimplementative.

Adifferenzadiquantosuccedeperimembriastratti,nelcasodeimembrivirtuali,esistesemprenella superclasseun’implementazionedibase.Peraltro,unmembrovirtualepuòessere ridefinito inmodopersonalizzatonelleclassiderivate.Questosignificache,oltreall’implementazione di base, possono esistere implementazioni diverse dello stessomembro,ciascunadellequaliafferenteaunadiversaclassederivata.

Se per proprietà emetodi astratti è sempre obbligatorio definire un’implementazionenellaclassederivata,questononèveroperimembrivirtuali:nelcasoincuiunmembrovirtuale non venga ridefinito nel tipo derivato, rimane valida la versione presente nellasuperclasse.

Icampidiunaclassenonpossonoesseresoggettiaoverridingnédefiniticomeastratti(delrestocontengonosolamentedati,nondefinisconocomportamenti).Gliunicimembrichepossonoesserepolimorficisonoimetodieleproprietà.

La keyword che permette di contrassegnare un membro come virtuale è Overridable(esempio4.20).Pereseguirel’overridingdiunmembroinunaclassederivata,dobbiamoinvecespecificarelaparolachiaveOverrides(esempio4.20).

Per indicarecheunmembrononpuòessereulteriormente soggettoaoverridingnelleclassiderivate,dobbiamoinfinespecificarelakeywordNotOverridable.

LaparolachiaveShadowspermettedinascondereinmodoesplicitounmembroereditato da una classe base. Questo significa che la versione derivata delmembro sostituisce la versione della classe base. Lo scopo principale delloshadowing è, infatti, quello di proteggere la definizione dei membri di unaclasse.Seneltipobasevieneaggiuntounnuovoelementoconilnomeugualeaquello del membro già definito nella classe derivata, la keyword Shadowsimpone che i riferimenti attraverso la classe vengano comunque risolti nel

Page 114: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

membrodellaclassederivataanzichénelnuovoelementodellasuperclasse.

Èsemprebenericordarecheunmembrovirtualevienerisoltoinbasealtipodell’istanzasucuivienerichiamato,noninfunzionedeltipodelriferimento.L’esempio4.20 illustraquesto importante concetto, illustrando una casistica significativa di invocazione di unmetodovirtuale.

Esempio4.20PublicClassPerson

'Metodovirtuale

PublicOverridableFunctionGetFirstName()AsString

'Implementazionedibasedelmetodo

EndFunction

EndClass

PublicClassEmployee

InheritsPerson

PublicSubNew(ByValnameAsString,ByValageAsInteger)

'...

EndSub

PublicOverridesFunctionGetFirstName()AsString

'NuovaimplementazionedelmetodoEndFunction

EndClass

DimxAsNewEmployee("MarcoLeoncini",41)

DimyAsPerson=x

'VienecomunqueeseguitoilmetododiEmployee

'ancheseilriferimentoèditipoPerson

DimzAsString=y.GetFirstName()

Nell’esempio4.20 la variabiley di tipoPerson punta a un’istanza della classe derivataEmployee. L’invocazione del metodo virtuale GetFirstName produce l’esecuzionedell’implementazione presente in Employee indipendentemente dal tipo del riferimento(ovverolavariabiley).

InterfacceUn’interfaccia èun tipo simile aunaclasseastrattapura,ossia composta solamentedametodiedaproprietàastratte.Essaè,infatti,privadiqualsiasiimplementazione,datocheil suo scopo è semplicemente quello di definire un contratto valido per le classi che lavannoaimplementare.

Page 115: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Ilgrossovantaggionell’utilizzodelleinterfacceèrappresentatodalfattocheunaclassepuò implementare più di un’interfaccia contemporaneamente. Questo aspetto va acompensare,almenoparzialmente,lamancanzadell’ereditarietàmultiplaperleclassi.

Perdefinireun’interfaccia,dobbiamospecificarelaparolachiaveInterfaceseguitadalnome identificativo, evitando di riportare gli access modifier per i suoi elementi. Perognuno di essi è, infatti, sufficiente inserire unicamente la dichiarazione, omettendoqualsiasi forma d’implementazione (esempio 4.21). In un’interfaccia possono essereinclusedichiarazionidimetodi,proprietàedeventi.

Esempio4.21'Interfacciachedefinisceunmetodoperlascrittura

PublicInterfaceIWritable

SubWrite()

EndClass

Per implementare un’interfaccia, dobbiamo ricorrere alla keywordImplements. Essa vautilizzata sia nella dichiarazione del tipo (su una linea di codice dedicata), sia per ognielemento dell’interfaccia che viene implementato nella classe (sulla stessa linea delladichiarazionedelmembro).Nelcasodi implementazionemultipla,siusa ilcarattere“,”(virgola),persepararetralorolediverseinterfaccechesonoassociateallaclasse.

Oltre all’implementazione, l’esempio 4.22 riporta anche una semplice casistica diutilizzo. Come possiamo notare, ogni istanza relativa a una classe che implementaun’interfacciapuòessereassegnataaunavariabiledell’interfacciastessa.Inquestocaso,imembrichepossonoessererichiamatisonosolamentequelliassociatiall’interfacciaenonquelliespostidallaclassecheimplemental’interfacciastessa.Perpoterinvocareimembridella classe aggiuntivi rispetto a quelli dell’interfaccia, dobbiamo necessariamenteeffettuareun’operazionedicastingaltipodellaclasseconcreta.

Esempio4.22PublicClassEmployee

InheritsPerson'DerivadallaclassebasePerson

ImplementsIWritable'Implemental'interfacciaIWritable

PublicSubWrite()ImplementsIWritable.Write

Console.Write(MyBase.FullName)

EndSub

EndClass

'IlriferimentoèditipoIWritable,mal'istanzaèditipoEmployee

DimxasIWritable=NewEmployee("AlessioLeoncini",41)

'Scrivesullaconsoleilnomecompleto

x.Write()

Page 116: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'Ènecessarioeffettuareilcastingperinvocareilmetodo

DimyAsString=DirectCast(x,Employee).GetFirstName()

Aquestopuntopuò sorgereunadomanda:quandousare le interfacceequando, invece,utilizzareleclassiastrattepureoparzialmenteimplementate?

Abbiamo detto che entrambe definiscono un contratto per le classi alle quali sonoassociate, dato che, internamente, non contengono implementazioni, ma solodichiarazioni.Peraltroleclassiastrattepurefornisconountipodicontratto“piùforte”,inquanto,oltreadefinireicomportamentiperleclassiassociate,nerappresentanoancheiltipobase.

Diversamente, le interfacce permettono unamaggiore flessibilità, in quanto sono tipiindipendenti e trasversali rispetto alla gerarchia delle classi definita tramite i legami diereditarietà.L’usodelleinterfacceèquindidapreferirenelcasoincuivogliamodefinirecontratti di natura generale, che possano essere usati indipendentemente dai legami diereditarietàechenonimponganocomportamentispecificiedesclusivi.

I tipi come le interfacce e le classi astratte, che hanno una valenza soprattuttodichiarativa, vengono genericamente identificati come tipi astratti, in contrapposizionealleclassichecontengonoleimplementazionivereeproprie,chevengonodenotatecometipiconcreti.

StruttureOltrealleenumerazioniealleclassi,losviluppatorepuòdefinireinmodopersonalizzatoancheitipidivalore,attraversolestruttureostruct.

Unastrutturaèunaggregatodidatisimileaunaclasse,dalmomentochepuòcontenerecampi, metodi, proprietà ed eventi. La differenza rispetto a una classe risiedeprincipalmentenelmodoincuiunastrutturavienemantenutainmemoria:essendountipodivalore,essanonvieneinseritanelmanagedheap,comeavvieneperleclassi,mavieneallocatadirettamentesullostack.

Tuttiitipiprimitividivalorechesonostatitrattatisonostrutture.Peresempio,System.Int32, System.DateTime, System.Boolean oppure System.Decimalsonostruct.

Quanto abbiamo detto finora per le classi rimane generalmente valido anche per ladefinizionedistrutture.Peraltrolestructpresentanoalcunelimitazionirispettoalleclassi.Latabella4.2riassumeleprincipalidifferenzeesistentitraclassiestrutture.

Tabella4.2–Differenzetraclassiestrutture.Classi StrutturePossono definire campi, proprietà, metodi edeventi. Possonodefinirecampi,proprietà,metodiedeventi.

Supportano tutti i tipi di costruttori el’inizializzazionedeimembri.

Supportano tutti i tipi di costruttori (novità di Visual Basic 14) el’inizializzazionedeimembri.

Supportano il metodo Finalize, ovvero il

Page 117: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

distruttore. NonsupportanoilmetodoFinalize.

Supportanol’ereditarietà. Nonsupportanol’ereditarietà.Sonotipidiriferimento. Sonotipidivalore.Vengonoallocatinelmanagedheap. Vengonoallocatisullostack.

Come possiamo notare nella tabella riepilogativa, le strutture non possono derivare daaltrestrutture,néessereuntipobaseperaltritipi.DaVisualBasic14,lestructsupportanoanche il costruttore di default. Come in precedenza, possiamo dichiarare, in modopersonalizzato,costruttoriconparametriinoverloadaquellodidefault.

Per definire una struttura, dobbiamo specificare la parola chiave Structure. Ladichiarazione segue le stesse regole sintattiche viste per le classi nel corso del capitolo(esempio4.23).

Esempio4.23'Definizionediunastrutturaperinumericomplessi

PublicStructureComplex

PublicPropertyRealAsSingle'Partereale

PublicPropertyImaginaryAsSingle'Parteimmaginaria

'Costruttoreconparametri

PublicSubNew(ByValrAsSingle,ByValiAsSingle)

Me.Real=r

Me.Imaginary=i

EndSub

'Metodostaticoperlasommadiduenumericomplessi

PublicSharedFunctionSum(ByValxAsComplex,

ByValyAsComplex)AsComplex

ReturnNewComplex(x.Real+y.Real,x.Imaginary+y.Imaginary)

EndFunction

EndStructure

DimuAsNewComplex()'Ilnumerocomplessovale0.0+0.0i

DimvAsNewComplex(1.0,2.0)'Ilnumerocomplessovale1.0+2.0i

L’esempio4.23si riferiscealladichiarazionediunastrutturaper inumericomplessi. Inessa è presente un costruttore con due parametri per la parte reale e per la parteimmaginariadelnumero.Questocostruttorepuòessereinvocatoperinizializzareinmodomirato le due proprietà della struct. In alternativa, è comunque possibile invocare ilcostruttoredidefault;intalcasoivaloriassegnatiallaparterealeeallaparteimmaginariadelnumerocomplessosonopariazero(ovveroilvaloredidefaultperiltipoSingle).

Aldi làdelledifferenze riportatenella tabella4.2, quandoèopportunoutilizzareunastrutturaalpostodiunaclasse?Lestrutturenasconocome tipiorientati agestirepoche

Page 118: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

informazioni di breve durata, per lo più contenute, a loro volta, in altri oggetti. Essedevono rappresentare principalmente valori singoli o tipi primitivi (per esempio, valorinumericipiùomenostrutturati,coordinatespaziali,ecc.),caratterizzatidaunadimensioneridotta(ingenere16byte)eimmutabili.Intuttiglialtricasivannousateleclassi.

RegoledinomenclaturaUn aspetto importante, che non dobbiamo sottovalutare quando creiamo e definiamo inostri tipi personalizzati, è rappresentato dalle scelte di nomenclatura che riguardano inparticolare la selezione degli identificatori per le classi, le strutture, i namespace, levariabili locali e i parametri dei metodi. I nomi assegnati agli identificatori nel codicedevonoiniziarenecessariamenteconuncaratterealfabeticooilcaratteredisottolineatura(underscore)enonpossonocontenerecaratterispecialicomeglielementidipunteggiaturaoaltro.

Possiamoidentificaretrenotazionifondamentaliperilnamingdellevariabili:

notazioneungherese: al nomedell’identificatore viene aggiunto un prefisso cheneindicailtipo(esempio:intNumberidentificaunavariabileintera);

notazionePascal:l’inizialediogniparolachecomponeilnomedell’identificatoreèmaiuscola,mentretuttelealtreletteresonominuscole(esempio:FullName);

notazioneCamel: come la notazione Pascal, a differenza del fatto che la primainizialedeveessereminuscola(esempio:fullName).

Sebbene sia una pratica ancora diffusa tra gli sviluppatori, la notazione ungherese èconsideratasuperata,inquantosiaddicepocoallelogicheetecnichediprogettazioneesviluppo object-oriented, Per questo motivo ne sconsigliamo vivamente l’utilizzo. Delresto il nomedi tutti i tipi nel .NETFrameworkedei loromembripubblici seguono lanotazionePascal,mentre,ingenerale,lanotazioneCamelvieneusatapervariabililocali,campi privati e parametri. La tabella 4.3 riassume le notazioni da applicare perl’assegnazionedeinomiagliidentificatori.

Tabella4.3–Notazionidaapplicareperilnamingdellevariabiliedeitipi.Elemento/i NotazioneNamespace NotazionePascalClassi NotazionePascalInterfacce NotazionePascalStrutture NotazionePascalEnumerazioni NotazionePascal

Campiprivati Notazione Camel, eventualmente preceduti dal carattere di sottolineatura(esempio:_fullName)

Proprietà,metodiedeventi NotazionePascalParametri dei metodi e delle funzioni ingenerale NotazioneCamel

Variabililocali NotazioneCamel

Page 119: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Laconvenzioneprevedediutilizzareilprefisso“I”(imaiuscola)perilnomeidentificativodelleinterfacce,inmodotaledapoterlesempredistingueresenzaambiguitàdaglialtritipie,inparticolare,dalleclassi.

ConclusioniLaprogrammazioneorientataaglioggettièunparadigmadiprogrammazionechesibasasulladefinizioneesull’utilizzodiunaseriedientitàcollegatetraloro,ciascunadellequaliè caratterizzata da un insieme di informazioni di stato e di comportamenti specifici.Queste entità sono denominate oggetti e ciascuna di esse può contenerecontemporaneamentedati,funzionieprocedure.

Le classi, di cui gli oggetti sono istanze particolari, rappresentano gli elementifondamentaliperl’organizzazioneelastrutturazionedelcodiceinVisualBasic.Essesonoi tipi di riferimento definiti dallo sviluppatore, contenenti campi, proprietà, metodi edeventi.

Per le classi valgono i principi fondamentali della programmazione orientata aglioggetti,cioèereditarietà,polimorfismoeincapsulamento.InVisualBasicunaclassepuòderivare solamente da un’altra classe (ereditarietà singola), può ridefinire in modopersonalizzatoleimplementazionideisuoimembri,ancheseereditatidaltipobase,epuòmascherarelasuastrutturainterna,utilizzandoinmodoappropriatogliaccessmodifier.

Leinterfaccesonotipiastrattiprividiqualsiasiimplementazione,datocheilloroscopoèsemplicementequellodidefinireuncontrattovalidoperleclassicheleimplementano.Ilgrossovantaggionell’utilizzodelleinterfacceèrappresentatodalfattocheciascunaclassepuò implementare più interfacce contemporaneamente. Questo aspetto compensa lamancanzadell’ereditarietàmultipla.

Oltrealleclassiealleinterfacce,VisualBasicincludeanchelestrutture.Questeultimerappresentano i tipi di valore definiti dallo sviluppatore e servono per definire tipiprimitivi personalizzati. Anche se non supportano l’ereditarietà, le struct sono elementiche, da un punto di vista sintattico, presentano molte similitudini con le classi, dalmomentochepossonocontenerecampi,metodi,proprietàedeventi.

Tipiparticolaridiclassisonoitipienumerabili,comegliarrayelecollezioni.Giànelcorsodiquestocapitoloedelprecedente,abbiamoavutooccasionedimenzionarequestatipologiadioggetti.Oraèarrivato ilmomentodiaffrontare l’argomentonellospecifico.Lofaremoall’internodelprossimocapitolo.

Page 120: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

5

CollectionseGenerics

Neicapitoliprecedenti abbiamo introdotto i concetti fondamentalidel linguaggioVisualBasic e abbiamovisto come siapossibileutilizzarloper rappresentare classi o strutture.Una delle necessità più comuni nello sviluppo di applicazioni è quella di raggruppareoggetti omogenei e, fin dai tempi dei linguaggi procedurali, la soluzione a questoproblemaèstatoilricorsoagliarray.Inquestocapitolocispingeremounpassopiùavanti,mostrandocome il paradigmaaoggetti abbiapermessodi sviluppare contenitori di altolivello, chiamati collection, e comesiapossibile sfruttarne laversatilità all’internodellenostreapplicazioni.

Apartiredallaversione2.0, il .NETFramework si è arricchitograzie al concettodeigenericsche,sebbenemoltoutilizzatiproprionell’ambitodellarealizzazionedicollezionidi oggetti, offrono in realtà tutta una serie di vantaggi e di prerogative grazie allasemplicitàconcuièpossibilescriverecodice fortemente tipizzato.Lasecondapartedelcapitoloèdedicataadessi.

IntroduzioneallecollectionRaggruppareinformazioniall’internodicontenitori,sianoessenumeri,caratteriooggetticomplessi, è, da sempre, una delle necessità più comuni nell’ambito dello sviluppo diapplicazioni.Storicamentepresentifindaitempideilinguaggiprocedurali,gliarraysonosopravvissuti finoaigiorninostri, tantoche il .NETFrameworkprevedeaddiritturaunaclassead-hoc,chiamataSystem.Array,dacuituttiglioggetti(ancheunarray,infatti,èatuttiglieffettiunoggetto)diquestotipoereditano.

InVisualBasic,unarraypuòesseredefinitoesuccessivamenteutilizzatoconicostruttimostratinell’esempio5.1.System.Arraycontieneunaseriedimetodieproprietà,siaditiposiadiistanza,chepossonoessereutilizzatiperinteragirvi:

Esempio5.1DimmyIntArray()AsInteger={1,5,2,3,6}

DimanotherArray(5)AsInteger

anotherArray(3)=2

Dimlength=myIntArray.Length'Recuperailnumerodielementi

Page 121: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dimindex=

Array.IndexOf(myIntArray,2)'Indicediunelemento

Dimitem=myIntArray(3)'Ritornailquartoelemento

Array.Sort(myIntArray)'Ordinaglielementi

Array.Resize(myIntArray,7)'Modificailnumerodielementi

myIntArray(6)=11

Il numero di elementi che lo compongono è statico e deciso all’atto della suainizializzazione,utilizzandolanotazioneesplicitaoquellaimplicitamostratenell’esempioprecedente; nel caso questo debba essere modificato in un momento successivo, ènecessario invocare il metodo Resize, passando la nuova dimensione. Proprio questacaratteristica rende l’array particolarmente scomodo da utilizzare quando il numero dielementinonènotoapriori,oppurevaria conunacerta frequenza. In tutti i casi in cuiabbiamo necessità di un contenitore più snello, al quale sia possibile aggiungere orimuovereelementiconfacilità,èmoltopiùcomodoutilizzareunacollection.

Il .NETFramework supporta le collection fin dalla suaprimissimaversione, grazie auna serie di classi e interfacce presenti all’interno del namespaceSystem.Collections.Queste rappresentano insiemi del tipo più generico possibile, ossia System.Object e,pertanto, possono essere utilizzate con qualsiasi oggetto. In realtà, dall’avvento deiGenerics, avvenuto con la versione 2.0 del .NET Framework, sono cadute un po’ indisuso,ma vale comunque la pena di studiarne il funzionamento perché, comunque, lalogicacheleregolaècondivisaconlelorocontropartigeneriche.

LaclasseArraylistTra le varie tipologie di collection disponibili, quella che più si avvicina al concetto diarrayèlaclasseArrayList.Quest’ultima,infatti,rappresentaunacollezionedielementiacui possiamo accedere tramite un indice numerico, ma la cui numerosità può variaredinamicamente,comemostratonell’esempio5.2.

Esempio5.2DimsampleAsNewArrayList() 'Creazionediunarraylist

sample.Add(2) 'Aggiuntadielementi

sample.AddRange({1,4}) Dimvalue=sample(1) 'Ritornailsecondoelemento

DimcountAsInteger=

sample.Count 'Recuperailnumerodielementi

Page 122: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

sample.Remove(2) 'Rimuovel'intero2

sample.Clear() 'Rimuovetuttiglielementi

IlprimopassoperpoterutilizzareunArrayListèquellodicrearneun’istanzatramiteilsuocostruttore.Aquestopunto,ciòcheabbiamoadisposizioneèuncontenitorevuoto,acui possono essere aggiunti oggetti e che può essere popolatomediante imetodiAdd oAddRange,cheaccettanorispettivamenteunsingolooggettoounacollezione(adesempioun array, o un altro ArrayList) di oggetti. Un elemento di un ArrayList può essererecuperato tramite il suo indice oppure rimosso tramite il metodo Remove, mentre ilcontenutodituttalalistapuòesserescorsoutilizzandoicostruttiForoForEach,comemostratodall’esempio5.3.

Esempio5.3Forindex=0TosampleList.Count-1

Console.WriteLine(sampleList(index))

Next

ForEachelementInsampleList

Console.WriteLine(element)

Next

Oltre a quelli indicati, l’oggetto ArrayList contiene diversi metodi e proprietà, chepossonoessereutilizzatipermanipolarne ilcontenuto.Latabella5.1contieneunelencodelleproprietàedeimetodipiùutilizzati.

Tabella5.1–MembridellaclasseArrayList.Metodo/Proprietà Descrizione Esempio

Add(item) Aggiungeunelementoallalista myList.Add("Astring")

AddRange(items) Aggiungeuninsiemedielementiallalista myList.AddRange({1,5,9})

Clear() Svuotalalista myList.Clear()

Contains(item) Verificaseunelementoappartieneallalista IfmyList.Contains("item")Then…

Count Ritornailnumerodielementi Dimitems=myList.Count

IndexOf(item)Ritornal’indicedellaprimaoccorrenzadiunelemento,o-1nelcasoincuiquestononsiapresente

Dim index =

myList.IndexOf("item")

Item(index)Ritorna l’elemento corrispondente all’indice fornito. LaproprietàItempuòessereeventualmenteomessa.

Dimitem=myList.Item(2)oppureDimitem=myList(2)

LastIndexOf(item)Ritornal’indicedell’ultimaoccorrenzadiunelemento,o-1nelcasoincuiquestononsiapresente

Dim index =

myList.LastIndexOf(5)

Insert(index,

item)InserisceunnuovoelementoallaposizionespecificatadaIndex myList.Insert(0, "First

Element")

InsertRange(index,

items)

Inserisce un insieme di elementi, a partire dalla posizionespecificatadaIndex

myList.InsertRange(0,{1,2,3})

Remove(item) Rimuovelaprimaoccorrenzadiundeterminatoelemento myList.Remove("Astring")

RemoveAt(index) Rimuovel’elementoilcuiindiceèpariaquellofornito myList.RemoveAt(0)

ToArray() Generaunarrayapartiredalcontenutodell’ArrayList DimmyArray=myList.ToArray()

Page 123: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Non sempre però accedere a un particolare oggetto tramite il suo indice è sufficiente;spesso,infatti,abbiamolanecessitàdigestiredellecollezionidicoppiechiave-valore,cheinletteraturavengonocomunementechiamatedizionariesarannol’oggettodelprossimoparagrafo.

Dizionariin.NETtramitelaclasseHashtableEsistonomolteplicicasineiqualièutilegestirecollezionidielementilacuidiscriminante,invececheunindicenumerico,èrappresentatadaunaqualsiasialtratipologiadioggetto:pensiamo,adesempio,aunaseriediimpostazionidiconfigurazionedell’applicazione,incui vogliamo associare a una determinata chiave, ad esempio “UserFontSize”, ilcorrispettivovalore“15px”.Èovviamentepossibilecreareunaclassecondueproprietà,Key e Value, per poi raggrupparne le istanze in un ArrayList,ma recuperare il valoreassociato a una data chiave vorrebbe dire, ogni volta, scorrere tutta la lista fino aidentificarel’elementodesiderato.

All’interno del .NET Framework e, in particolare, sempre nel namespaceSystem.Collections, trova posto la classe HashTable che, invece, rappresenta lasoluzioneottimaleperquestotipodiproblematiche,com’èpossibilenotaredall’esempio5.4.

Esempio5.4DimmyDictionaryAsNewHashtable() 'Creazionedell'HashTable

myDictionary.Add("someIntValue",5) 'Aggiuntadielementi

myDictionary.Add("someClass",NewStringWriter())

myDictionary.Add(DateTime.Today,"Today'sstring")

Dimvalue=myDictionary("someClass") 'Recuperaelementodallachiave

myDictionary.Remove("someClass") 'Rimuoveunelemento

Dimcount=myDictionary.Count 'Recuperailnumerodielementi

myDictionary.Clear() 'Rimuovetuttiglielementi

A un’istanza di HashTable possono essere aggiunte coppie Chiave-Valore tramite ilmetodo Add. Come possiamo notare, non è definita una particolare tipizzazione e,pertanto,essepossonoesserecompostedaunaqualsiasi tipologiadioggetto.Dobbiamofare attenzione però al fatto che, mentre nessun vincolo è posto sui valori, è invecerichiestochelechiavisianounivoche,penailsollevamentodiunerrorearuntime.

Una volta inserito un valore all’interno di HashTable, esso può essere direttamenterecuperato,utilizzandolarelativachiave.L’istruzione

Page 124: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dimvalue=myDictionary(key)

ritorna Nothing nel caso in cui la chiave specificata non sia presente all’interno deldizionarioe,pertanto,ènecessariogestirenelcodicequestaeventualità.

La classe HashTable è così chiamata perché tutte le chiavi sono sonointernamente memorizzate in una struttura basata su hash numerici; ognioggetto.NET,infatti,èingradodigenerareunpropriohashtramiteilmetodoGetHashCode.

Tuttociòrendel’operazionediricercadiunelementoestremamentevelocema,allostessotempo,richiedeuncertooverheadperlagenerazionedell’hasheperlamanutenzionedellatabellainterna.Perquesteragioni,nelcasodidizionaricon un numero limitato di elementi (inferiore a 10), è preferibile utilizzare laclasseListDictionary,cheimplementalemedesimefunzionalità,maconunastrategia differente. Una terza classe, chiamata HybridDictionary, ha lacapacitàdiconfigurarsiinternamenteprimacomeunListDictionary,perpoiconvertirsi a HashTable nel momento in cui questa soglia viene superata.Entrambe queste classi appartengono alla namespaceSystem.Collection.Specialized.

Quando invece abbiamo la necessità di scorrere il contenuto di un dizionario nella suainterezza,possiamoutilizzareletremodalitàdifferenti,mostratenell’esempio5.5.

Esempio5.5'Enumerazionedituttelecoppiechiave-valore

ForEachitemAsDictionaryEntryInmyDictionary

Console.WriteLine(item.Key+""+item.Value)

Next

'Enumerazionedituttelechiavi

ForEachkeyInmyDictionary.Keys

Console.WriteLine(key)

Next

'Enumerazionedituttiivalori

ForEachvalueInmyDictionary.Values

Console.WriteLine(value)

Next

In particolare, se applichiamo l’istruzione For Each a HashTable, l’oggetto restituito aogni iterazione è un DictionaryEntry, che consente di accedere sia alla chiave sia alvalore vero e proprio. In altre occasioni, invece, può essere necessario scorrere tutte lechiaviotuttiivaloriseparatamentee,inquesticasi,possiamoutilizzareleproprietàKeyseValues.

Page 125: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Queste, insieme con altri importantimembri della classeHashTable, sono sintetizzatinellatabella5.2.

Tabella5.2–MembridellaclasseHashTable.Metodo/Proprietà Descrizione EsempioAdd(key,value) AggiungeunelementoallaHashTable myDict.Add("someKey",5)

Clear() SvuotailcontenutodellaHashTable myDict.Clear()

Contains(key)RitornaTrue nel caso in cui la chiave specificata siapresenteneldizionario

If

myDict.Contains("someKey")

Then…

ContainsValue(value)RicercaundeterminatovaloreneldizionarioerestituisceTrue nelcasoincuiquestosiapresente

IfmyDict.ContainsValue(5)

Then…

Item(key)Recuperaunvalore tramite la corrispondentechiave.LaproprietàItempuòeventualmenteessereomessa

Dim value =

myDict.Item("somekey")

oppureDim value =myDict(“someKey”)Keys

Restituisceunacollectiondituttelechiavipresenti For Each key In

myDict.Keys…Next

Remove(key) Eliminaunelementodatalacorrispondentechiave myDict.Remove("SomeKey")

Values Restituisceunacollectiondituttiivaloripresenti For Each val InmyDict.Values…Next

Nonostante la loroversatilità,utilizzando leclassidel .NETFrameworkèpiuttosto raroimbattersi in metodi che accettino o restituiscano HashTable o ArrayList. Molto piùcomune, invece, è trovare riferimenti ad alcune interfacce, come IEnumerator,

ICollectionoIDictionary.Questodipendedallaparticolarearchitetturacheèstatadataall’infrastrutturadellecollection,chesaràoggettodellaprossimasezione.

LeinterfacceinSystem.CollectionsComeabbiamoavutomododicomprenderenelcapitoloprecedente,nelparadigmadellaprogrammazioneaoggettisiusarappresentareconun’interfaccialacapacità,dapartediundeterminatooggetto,disvolgereunaparticolarefunzione.Inquestomodo,èpossibilescrivere codice senza legarsi a una particolare implementazione concretama basandosiesclusivamente sui requisiti che l’oggetto deve presentare affinché siamo in grado diutilizzarlo. Si tratta di concetti avanzati, che appariranno più chiari proseguendo nellaletturadellibro,machetrovanounanettaapplicazioneproprioall’internodelnamespaceSystem.Collections. Quest’ultimo, infatti, oltre a contenere le definizioni di diversetipologiedicollection,dichiaraunaseriediinterfacceognunadellequalièrappresentativadi un certo insieme di funzionalità di una collezione; interfacce e classi concretecostituisconolagerarchiaditipimostratainfigura5.1.

Tra queste, l’interfaccia maggiormente utilizzata è sicuramente IEnumerable, cherappresenta lapossibilitàdiscorrereunoggetto tramiteunenumeratore (cheasuavoltaimplementa l’interfacciaIEnumerator).Questo, inpratica, si traducenellapossibilitàdiutilizzareilcostruttoForEachperesplorareilcontenutodellacollezione.Pertanto,questainterfaccia è implementata un po’ da tutte le tipologie di collection che abbiamo avutomododiincontrarefinora,daisempliciarrayfinoadarrivareall’hashtable.

Page 126: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura5.1–InterfacceeclassiinSystem.Collections.

A queste interfacce si affiancano ICollection, IList e IDictionary, che via viaaggiungonofunzionalitàpiùavanzate;intabella5.3possiamotrovareunpiccoloriepilogodi ognuna di esse, in ordine di complessità, unitamente alle carattaristiche che lecontraddistinguono.

Tabella5.3–InterfacceinSystem.Collections.Interfaccia Descrizione

IEnumerable

Espone il metodo GetEnumerator che ritorna un oggetto di tipo IEnumerator tramite il quale èpossibile scorrere l’intera collection. Si traduce nella possibilità di navigarne il contenuto tramitel’istruzioneForEach.

IEnumeratorEspone la proprietà Current e i metodi Reset e MoveNext. Un IEnumerator è automaticamentecreatoeutilizzatodalcostruttoForEachperesplorareilcontenutodiunacollection.

IDictionaryEnumerator EreditadaIEnumerator,sitrattadiunenumeratorespecificoperidictionary.

ICollectionEreditadaIEnumerableeaggiunge,tralealtre,laproprietàCountperconoscerelanumerositàdellacollezione.

IList

Eredita da ICollection e contiene le funzionalità di aggiunta e rimozione dinamica di elementi,esponendometodicomeAdd,Clear,Contains,InsertoRemove,oltreallaproprietàItemtramitelaqualerecuperareunelementoinbasealsuoindice.

IDictionaryEreditadaICollectionedesponemetodieproprietàsimiliaquellidiIList,marelativiaidizionariequindibasatisullachiavepiuttostochesull’indice.

UlterioritipologiedicollectionIlsupportodapartedel.NETFrameworkallarappresentazionedicollezioninonsifermacertamenteallapresenzadiArrayListeHashTable.Oltrealisteedizionari,all’internodiSystem.Collections trovano posto ulteriori classi, che vale comunque la pena citare,pensatepersoddisfareesigenzespecifiche.

Concetticomepileocodesono,adesempio,implementatirispettivamentedalleclassiStack e Queue. Si tratta di collezioni che non implementano l’interfaccia IList e che,

Page 127: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

quindi,nonpossonoesserepopolateconimetodistandardAddoRemove.

In particolare,Stack rappresenta un contenitore di oggetti che può essere riempito esvuotato secondo una logicaLIFO (Last In First Out): l’aggiunta di elementi avvienetramite il metodo Push, mentre per la rimozione bisogna utilizzare Pop, che ritornal’ultimoelementoinseritoinordineditempo,rimuovendoloalcontempodallacollezione.

Queue,invece,operainmododifferente,implementandounalogicaditipoFIFO(FirstInFirstOut):lacollezionevieneriempitatramiteilmetodoEnqueuementre,conDequeue,èpossibile svuotarla, recuperandodivolta involta l’elementopiùantico al suo interno.Perchiariremeglioiconcettisinquiespressi,consideriamoilcodicedell’esempio5.6.

Esempio5.6Console.WriteLine("---Stack---")

DimmyStackAsNewStack()

myStack.Push("Marco")

myStack.Push(5)

myStack.Push(NewObject())

Console.WriteLine(myStack.Pop)

Console.WriteLine(myStack.Pop)

Console.WriteLine("---Queue---")

DimmyQueueAsNewQueue

myQueue.Enqueue("Marco")

myQueue.Enqueue(5)myQueue.Enqueue(NewObject())

Console.WriteLine(myQueue.Dequeue)

Console.WriteLine(myQueue.Dequeue)

In questo esempio, una Queue e uno Stack vengono riempiti con i medesimi valori esuccessivamente svuotati,mostrandogli elementi recuperati sulla console.Eseguendo ilcodice,otteniamol’outputmostratoinfigura5.2,incuièpossibileapprezzareildiversoordinesecondocuivienerestituitoilcontenuto.

Ulteriori tipologie di collezioni quali, ad esempio, StringCollection oStringDictionary, presenti inSystem.Collections.Specialized, sono attualmente daconsiderarsi superate e non più utilizzate, grazie all’avvento dei generics, che sonol’argomentodescrittonellapartefinaledelcapitolo.

Page 128: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura5.2–EsempiodiutilizzodiStackeQueue.

IGenericselatipizzazioneforteLe varie tipologie di collezioni presentate possiedono ovviamente il requisito di poteressere utilizzabili con qualsiasi tipo di oggetto, tant’è che ilmetodo Add o la proprietàItemdiArrayList,adesempio, lavoranoconil tipoObject;questaversatilità,però,hauncosto.Immaginiamodiavere,adesempio,unalistadioggettiDateTimeedidoverpoirecuperareunelemento.Ilcodicedascrivereèsimileaquellodell’esempio5.7.

Esempio5.7DimdateListAsNewArrayList

dateList.Add(DateTime.Now)

dateList.Add(NewDateTime(2000,1,10))

dateList.Add(DateTime.Today.AddYears(-1))

DimfirstItem=

DirectCast(dateList(0),DateTime)

Comepossiamonotare, avere a che fare conuna listadiObject implica la necessità didovereffettuareognivolta il castingal tipodesiderato(DataTime inquestocaso),vistoche il datonon è direttamentedisponibile come tale.Questo fatto, oltre che scomodo eripetitivo,èanchepotenzialmentemoltopericolosoperché,difatto,nonèpossibileattuarenessuntipodicontrollosull’effettivocontenutodiunalista.Seesaminiamol’esempio5.8,infatti, possiamo notare come il suo contenuto possa essere quanto di più eterogeneopossibile.

Esempio5.8

Page 129: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DimlistAsNewArrayList

list.Add(10)

list.Add("Somestring")

list.Add(DateTime.Now)

list.Add(NewArrayList())

list.Add(NewSystem.Globalization.CultureInfo("en-US"))

DimsecondItemAsDateTime=

DirectCast(list(1),DateTime)

Il codice precedente viene ritenuto come perfettamente valido dal compilatore ma, seeseguito, genera un errore (viene sollevata una InvalidCastException) in quantonell’ultimostatementsistaprovandoaconvertireundatoditipoStringinunDateTime.Il grosso problema è che, purtroppo, finché il tutto non è in esecuzione, non abbiamoalcunostrumentoperaccorgercene;ingergo,sidicecheunaclassecomeArrayList(eingeneralepraticamentetuttelecollectioneleinterfaccediSystem.Collections)supportasololatipizzazionedebole.

Il.NETFrameworkutilizzaunsistemadinotificadeglierroriaruntimetramitel’utilizzo di Exception: quando l’esecuzione di un metodo non terminacorrettamente, ilchiamantericeveunasegnalazionenella formadiunoggettochederivadallaclasseSystem.Exceptioneilcuitipoidentificalaparticolaretipologiadierrorechesièverificata.Affronteremoquestoargomentoinmodomaggiormentedettagliatoduranteilcapitolo7.

Noivogliamoinvececodiceconrigidivincoliditipo,omegliofortementetipizzate,cosìcheinunalistadiDateTimesiaeffettivamenteconsentitoaggiungeresolodatiomogenei,pena errori già in fase di compilazione, quindi facilmente identificabili e tracciabili.Proprioquestoèilvantaggiointrodottodaigenerics.

LecollezionigenericheDalla versione 2.0 del .NET Framework, è stato introdotto il nuovo namespaceSystem.Collections.Generic,checontieneunaseriedicollezioniche,adifferenzadelleprecedenti,nonfannopiùriferimentoaObjectmaconsentono,divoltainvolta,quandoutilizzate,dispecificareconesattezzailtipochedovrannocontenere.Ilmodomiglioreperrendere più chiaro questo concetto è sicuramente quello di esplorare, nel dettaglio, ilfunzionamentodiquellacheprobabilmenteèlacollectiongenericaaoggipiùutilizzata:List(OfT).

Lalistanelmondodeigenerics:List(OfT)List(OfT) rappresental’alter-egogenericodiArrayListedè,pertanto,adattaacrearedelle strutture simili ad array, ma in grado di supportare l’aggiunta e la rimozione di

Page 130: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

elementi,adattandodinamicamentelalorodimensione.L’esempio5.9mostracomedebbaessereutilizzataperrealizzareunalistadistringhe.

Esempio5.9DimstringsAsNewList(OfString)'InizializzazionediList(OfT)

strings.Add("MarcoDeSanctis")'PossiamoaggiungeresoloString

strings.Add("VisualBasic10.0")

strings.Insert(0,"Primoelemento")

Dimindex=

strings.IndexOf("MarcoDeSanctis")'Ritorna1

DimmySubstring=

strings(0).Substring(5)'GiàString:castnonnecessario

IlparametrogenericoT,presentenelnomediquestacollection,staaindicareiltipodeglielementi contenuti al suo interno.Puòesserepensatocomeuna sortadi segnapostochedevepoiessereobbligatoriamente specificatoall’attodelladichiarazionedellavariabile.Nelcodiceinalto,adesempio,dovendorealizzareunalistadistringhe,èstatadichiarataeistanziataunavariabileditipoList(OfString).

Il primo vantaggio consiste nel fatto che, recuperando un elemento dalla collection,mentreArrayListrestituivaunObjecte,quindi,eranecessarioscrivere:

dimmyString=

DirectCast(arrayList(0),String)

nelcasodiList(OfT)ciònonèpiùnecessario,inquantol’oggettorestituitoègiàditipoString.Questofattooffreilvantaggiodiscriveremenocodiceedievitareun’istruzionecomeDirectCast che, comunque, potenzialmente potrebbe fallire e generare un errore.Ciòèpossibileperchél’infrastrutturadeigenericsassicuracheilcontenutodellalistasiacompostoesclusivamentedaoggettiditipostringaecheunarigadicodicesimilea:

strings.Add(DateTime.Now)

provochiunerroregiàinfasedicompilazione.Questaè,inassoluto,lacaratteristicapiùimportantedeitipigenerici,grazieallaqualesiamoingradodiscriverecodicefortementetipizzato,incuisiailcompilatoresial’IntellisensediVisualStudio,comemostralafigura5.3, sono in grado di intercettare eventuali errori già nella fase di scritturadell’applicazione.

Figura5.3–Supportodell’IntellisenseaiGenerics.

Solitamente il primodubbiocheaffiora,unavoltamessidi fronteai vantaggi

Page 131: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

deitipigenerici,riguardaeventualipenalità,alivellodiprestazioni,chequestipossono presentare rispetto ai corrispettivi non generici. La realtà dei fattidimostra invece esattamente il contrario: il parametro generico, infatti, fungeesclusivamente da segnaposto e viene rimpiazzato con il tipo reale in fase dicompilazione, senza pertanto comportare alcuna perdita nelle performance.Quandopoiilparametrogenericovienevalorizzatoconunvaluetype,siottieneaddiritturaunnotevolemiglioramentodelleprestazioni:senzaspingersitropponeidettagli,basti saperecheList(OfInteger),ad esempio, è estremamentepiùvelocediArrayListpergestirelistediinteri,inquantoconsentedievitareilricorsoaoperazionidispendiose,comeBoxingeUnboxing,per trasformareuntipovaloreinuntiporiferimentoeviceversa.

LeinterfaccenellecollezionigenericheDaunpuntodivistaarchitetturale, lastrutturadellecollectiongenerichenonsidiscostapiù di tanto da quanto già visto in precedenza e consta, innanzitutto, di un insiemed’interfacce,perlopiùomonimedellecontropartinongeneriche.Ildiagrammapresenteinfigura5.4mostraivincolidiereditarietàchesussistonotraquesteinterfacce:

Figura5.4–Interfaccedellecollectiongeneriche.

Comesipuònotare,icapisaldisonocostituitidaIEnumerable(OfT)eICollection(OfT),cheespongonoalcunefunzionalitàbase,einparticolare:

IEnumerable(OfT)-eIEnumerator(OfT)-consentonodiscorrere ilcontenutodiunacollectioneabilitanoilsupportoall’istruzioneForEach;possiamonotareche, al fine di mantenere la compatibilità anche con i tipi non generici,IEnumerable(OfT)ereditadaIEnumerable;

ICollection(OfT)esponelefunzionalitàdibasediunacollezionee,adifferenzadelcasonongenerico,oltreaCount,annoveraanchemetodiqualiAdd,RemoveoContains;

Page 132: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Questedueinterfaccevengonoutilizzatecomebasedipartenzaperlefunzionalitàrelativealletretipologieprincipalidicollectionprevistedal.NETFramework:

IList(OfT)rappresentalelogichetipichedelleliste,introducendoilconcettodiindice in una collezione: fanno la loro comparsa pertanto i membri basati sulconcetto di posizione all’interno della lista, quali la proprietà Item e metodiIndexOf,InserteRemoveAt;

IDictionary(Of TKey, TValue) espone le logiche tipiche dei dizionari,analogamenteaIDictionary, consentendoperòdi specificare i tipidautilizzareperlachiaveeperivalori;

ISet(OfT)èutilizzataperrappresentareinsiemidioggettiunivoci.

In precedenza abbiamo introdotto List(Of T), che implementa la prima di queste treinterfacce,leprossimesezioniinvecesarannocompletamentededicateallerestantiduee,inparticolare,alleclassiDictionary(OfTKey,TValue)eHashSet(OfT).

Undizionariofortementetipizzato:Dictionary(OfTKey,TValue)Le funzionalità tipiche di un dizionario sono implementate, nelle collection generiche,dallaclasseDictionary(OfTKey,TValue).Permoltiversihauncomportamentosimilea quello visto in precedenza per HashTable ma espone due parametri generici perspecificareitipiammissibiliperchiavievalori,comemostratonell’esempio5.10.

Esempio5.10DimfesteAsNewDictionary(OfString,DateTime)

feste.Add("Natale",NewDateTime(2015,12,25))

feste.Add("Capodanno",NewDateTime(2015,1,1))

feste.Add("Compleanno",NewDateTime(2015,7,10))

DimvigiliaCompleanno=feste("Compleanno").AddDays(-1)

Anche in questo caso, com’è corretto attendersi, il codice è fortemente tipizzato e untentativodiusareuntipodiversodaStringperlachiaveoDateTimeperilvalore,causaunerroreincompilazione;ovviamente,lostessovaleancheinfasedirecuperodeldato,comemostrainmodoefficacelafigura5.5:

Figura5.5–Typesafetydeldictionary.

Page 133: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dictionary(Of TKey, TValue) utilizza internamente il medesimo sistema dimemorizzazione basato su un hash utilizzato da HashTable, con il risultato di rendereestremamentevelocilericerchebasatesullachiave.Adifferenzadiquest’ultima,però,iltentativo di recupero di un elemento tramite una chiave inesistente, non restituisceNothing, ma risulta in un errore a runtime (viene sollevata un’eccezione di tipoKeyNotFoundException). Pertanto, prima di utilizzare la proprietàItem, è consigliabileinvocareilmetodoContainsKeyperverificarnepreventivamentelapresenza:

DimdataAsDateTime

Iffeste.ContainsKey("chiave")Then

data=feste("chiave")

Else

Console.WriteLine("Ladatacercatanonesiste")

EndIf

In alternativa, tramite TryGetValue è possibile scrivere del codice funzionalmenteidentico,inmanieraunpo’piùconcisa:

DimdataAsDateTime

IfNotfeste.TryGetValue("chiave",data)Then

Console.WriteLine("Ladatacercatanonesiste")

EndIf

Questometodo,infatti,oltrealvaloredellachiave,accettaunsecondoargomentopassatoper riferimento e restituisce un Boolean che indica il successo o l’insuccessodell’operazione.

Unacollectionconelementiunivoci:HashSet(OfT)Untipodicollezionechenonhauncorrispondentenongenericoèl’HashSet.Sitrattadiuna collezione simile alla lista, in quanto consente l’inserimento di valori ma con unoscopocompletamentediverso,quellodirappresentareuninsiemenonordinatodielementiunivoci.Consideriamol’esempio5.11:

Esempio5.11DimholidaysAsNewHashSet(OfDateTime)

holidays.Add(NewDateTime(2015,12,25))

holidays.Add(NewDateTime(2015,1,1))

holidays.Add(NewDateTime(2015,5,1))holidays.UnionWith(ferieEstive)

DimsomeDate=NewDateTime(2015,11,1)

Page 134: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DimwillWork=

holidays.Contains(someDate)

Ilcodiceinaltomostraquellocheèil tipicoutilizzodiunHashSet,ossianonquellodifungere da contenitore di elementi con lo scopo di recuperarli, bensì di utilizzarlo perverificarel’appartenenzaomenodiundatoall’insieme.Questaclasse,infatti,utilizzaunsistemabasato sui codicihashper rendereoperazionidiquesto tipo (come l’esecuzionedelmetodoContains) estremamenteveloceedefficiente.Unesempio tipicopuòesserequellomostratoinprecedenza,incui,tramiteunHashSetdifestività,sideterminaseunacertadataèlavorativaomeno.

Proprio per questo scopo, HashSet non espone membri tramite i quali recuperare ilcontenuto(sesiescludeilfattochecomunqueèammessol’usodelcostruttoForEachperscorrerlo),bensìpresentaunaseriedimetodi tipicidella teoriadegli insiemi,sintetizzatinellatabella5.4.

Tabella5.4–MetodidiHashSet(OfT).Metodo/Proprietà Descrizione

Add(value)Aggiungeunelementoall’HashSet,senonègiàpresente,eritornaunbooleanperindicaresel’aggiuntaèstataeffettuataomeno

Clear() Cancellatuttiglielementi

Contains(value)EffettuaunaricercatramitecodicehasheritornaTruesel’elementoappartieneallacollezione

ExceptWith(collection)Elimina dal set tutti gli elementi presenti nella collezione in input, realizzandoun’operazionedidifferenza

IntersectWith(collection)Eliminadalsettuttiglielementinonpresentinellacollezioneininput,realizzandoun’operazionediintersezione

IsSubsetOf(collection)

IsProperSubsetOf(collection)

Verifica se l’HashSet è un sottoinsieme (eventualmente in senso stretto) dellacollezioneininput

IsSuperSetOf(collection)

IsProperSupersetOf(collection)

Verificaselacollezioneininputèunsottoinsieme(eventualmenteinsensostretto)dell’HashSet

Overlaps(collection) RitornaTrueseilsetelacollectionininputhannoalmenounelementoincomuneRemove(value) Elimina,sepresente,unelementodalsetUnionWith(collection) Realizzaun’operazionediunioneconlacollectionininput

AltretipologiedicollezionigenericheOltre a quelle presentate finora, il .NET Framework e, in particolare, il namespaceSystem.Collections.Generic,contengonounaseriediulterioritipologiedicollection,diusopiùspecifico,chevaleperòcomunquelapenacitare:

Stack(OfT)eQueue(OfT) sono leversionigenerichedelleanaloghecollectiongiàvisteinprecedenzainquestocapitolo;

SortedList(Of TKey, TValue) e SortedDictionary(Of TKey, TValue) sonoduedifferentiimplementazionidiundizionarioicuielementisonoordinatiinbaseal valore della chiave. Differiscono nella loro implementazione interna, con laprimaingeneralemenoaffamatadimemoria,mentrelasecondaèpiùvelocenelleoperazionidiinserimentoerimozionedeldato;

Page 135: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

LinkedList(Of T) è una lista di elementi ognuno dei quali ha un puntatoreall’elementosuccessivoeunoalprecedente.L’usodiquesto tipodicollezioneèestremamente vantaggioso quando si presenta spesso la necessità di inserire erimuovereelementi,inquantoquesteoperazionirisultanoestremamenteveloci;

BindingList(Of T) e ObservableCollection(Of T) non appartengono alnamespace System.Collections.Generic, ma rispettivamente aSystem.ComponentModel e System.Collections.ObjectModel. A livellofunzionale si comportano come List(Of T), e implementano alcune interfacceaggiuntive, indispensabili per l’utilizzo come sorgente dati in un’applicazioneWindowsForms,WPFoSilverlight.Sitrattadiconcetticheesulanodallamateriatrattatainquestocapitoloechesarannotrattatinelprosieguodellibro.

Lepotenzialitàdeitipigenericinonsiesaurisconoconlecollectionesonomolteplicigliesempi all’interno del .NET Framework di tipi che ne fanno uso. Ovviamente essepossono essere sfruttate anche per la creazione di classi personalizzate. Nelle prossimepaginevedremocome.

CreazioneditipigenericiCostruireunaclassechesfruttiigenericsèestremamentesemplicee,inpratica,richiedeesclusivamente di specificare, all’atto della dichiarazione, il numero e il nome dei tipigenerici da utilizzare. Supponiamo, ad esempio, di avere la necessità di realizzare unasequenza di elementi, in cui ognimembro sia in grado dimemorizzare un valore e unriferimentoall’elementosuccessivo,comemostratoinfigura5.5.

Figura5.6–Sequenzadielementi.

Si tratta di quella che, in letteratura informatica, è comunemente chiamata“lista”; questo termine ha però un’accezione differente all’interno del .NETFrameworke,pertanto,laindicheremogenericamentecome“sequenza”.Ancheseabbiamogiàintrodottoinprecedenzaunastrutturadatisimileaquesta,ossiaLinkedList(Of T), da un punto vista didattico riteniamo comunque correttoprovare a costruire un esempio personalizzato, per illustrare come sfruttare igenericsancheinquestocaso.

OgnielementodellasequenzapuòessereimplementatotramiteunaclasseedeveesporreunaproprietàValuecontenenteilvalorememorizzato.Senzaigenerics,saremmocostrettiarealizzareun’implementazionespecificaperognitipodasupportare,oppureautilizzareunaproprietà il tipoObject, perdendo così i vantaggi della tipizzazione forte.Grazie aloro, invece, il codice da scrivere è estremamente semplice e comprensibile, comepossiamonotarenell’esempio5.12.

Page 136: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio5.12PublicClassListNode(OfT)

PublicPropertyValueAsT

PublicPropertyNextNodeAsListNode(OfT)

EndClass

Ladichiarazionedellaclassepresenta lastessasintassivistaormaidiversevoltedurantequesto capitolo; una volta indicato, tramite il segnaposto T, il tipo indeterminato, essodiviene a tutti gli effetti utilizzabile nel codice, comeogni altro, comepossiamonotaredalladichiarazionedelleproprietàValueeNextNode.

Iparametrigenericipossonoesseredichiaratieutilizzatianchesuunsingolometodo,senzadovernecessariamentecostruireunaclassegenericachelocontenga,comemostratonelcodicequisotto:

Esempio5.13PublicClassUtils

PublicSharedSubSwap(OfT)(ByReffirstAsT,ByRefsecondAsT)

DimtempAsT=first

first=second

second=Temp

EndSub

EndClass

L’esempio 5.13 mostra un metodo in grado di scambiare due oggetti passati comeargomenti. Come possiamo notare, esso è contenuto in una classe Utils che non èdichiaratacomegenerica,mentreilparametrogenericoèdefinitodirettamentesulmetodoSwap. Un aspetto interessante è che il compilatore, in alcune situazioni, è in grado dideterminareautonomamente ilvaloredaassegnareal tipoT, senzachesiamocostrettiaspecificarloesplicitamente:

DimaAsInteger=5

DimbAsInteger=8

Utils.Swap(a,b)'invecediUtils.Swap(OfInteger)(a,b)

Questacaratteristicaèdenominatatypeinferenceeconsentediscriverecodiceinmanieraestremamenteconcisaeleggibile.

ImpostaredeivincolisultipogenericoAvolte,definireunparametrogenericoTnonèsufficiente,maènecessariospecificarneanchealcunirequisiti,comeilfattochesiaunaclassepiuttostocheunastrutturaoppure

Page 137: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

cheimplementiunadeterminatainterfaccia.Supponiamo,adesempio,divolerrealizzareunmetodopercalcolareilmassimovaloreall’internodiunalista,similea:

PublicSharedFunctionMax(OfT)(ByVallistAsIEnumerable(OfT))AsT

...

EndFunction

Inquestocasononèpossibileaccettarequalsiasi tipoper ilparametroT:nelcodicedelmetodoMax,infatti,saremosicuramentecostrettiaeffettuareoperazionidiconfronto,chenon è detto siano applicabili a un tipo qualisiasi, come System.IO.File oSystem.Exception. Pertanto, è necessario specificare come vincolo che T implementil’interfaccia IComparable, in modo che siamo in grado di confrontare due valori dellacollection in input e di determinare qual è il maggiore. La sintassi è quella mostrata,unitamenteall’implementazione,nell’esempio5.14.

Esemptio5.14Public Shared Function Max(Of T As IComparable)(ByVal list As

IEnumerable(OfT))AsT

DimisFirstAsBoolean=True

DimresAsT

ForEachitemAsTInlist

IfisFirstThen

res=item

isFirst=False

EndIf

Ifres.CompareTo(item)<0Thenres=item

Next

Returnres

EndFunction

IlrisultatoèchesaràpossibileutilizzareMaxconunalistadiinterioconarraydistringhe,inquantoentrambiimplementanoIComparable,masolleveràunerrore incompilazione,seinvocataconunalistadiObject.

La tabella 5.5mostra le possibili tipologie di vincoli che possono essere imposti suiparametridiuntipogenerico.

Tabella5.5–Vincolisuitipigenerici.OfTAsClass IltipoTdeveessereunaclasse(tiporiferimento)

OfTAsStructure IltipoTdeveessereunastructure(tipovalore)

OfTAsNew IltipoTdeveavereuncostruttoresenzaparametri

OfTAsInterface IltipoTdeveimplementarel’interfacciaspecificata

OfTAsBaseClass IltipoTdeveereditaredallaclassebasespecificata

Page 138: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Unparticolaretipogenerico:Nullable(OfT)Nei capitoli precedenti abbiamo visto come nel .NET Framwork esistano sia tipiriferimento sia tipivalore.All’internodel secondogruppo ricadono tipi comeInteger,DateTimeoBoolean,percitarnealcuni,chepresentanotuttilacaratteristicadinonpoterassumereunvalorenullo.InVisualBasic,infatti,assegnareNothingauntipoInteger,adesempio, equivale a valorizzarlo a 0. Spesso, invece, soprattutto nell’ambito diapplicazioni che si interfaccianoconbasididati, abbiamo lanecessitàdi rappresentare,anchecondeitipivalore,ildato“indeterminato”.

A questo scopo, il .NET Framework mette a disposizione oggetti chiamatiNullableValue Types, realizzati tramite il tipo generico Nullable(Of T), che consentono diaggiungere anche tale stato a un tipo di valore. Un aspetto interessante è che essi,internamente, ridefinisconogli operatori di uguaglianza e casting, inmodo chepossanoessere utilizzati al posto delle controparti non nullabili, in maniera quasi del tuttotrasparente. L’esempio 5.15 mostra alcune tipiche modalità di utilizzo e contribuisce achiarirequestoconcetto.

Esempio5.15

DimintAsInteger=NothingDim nullableInt As Nullable(Of

Integer)=Nothing

Console.WriteLine(int) 'Stampa0

Console.WriteLine(nullableInt) 'Stampaunarigavuota

int=5 nullableInt=7 'Assegnazionediunvaloreintero

Dimres=int+nullableInt 'resèditipoNullable(OfInteger)

IfnullableInt.HasValueThen

'Verificapresenzadiunvalore

Dimvalue=nullableInt.Value 'ContieneilvaloreInteger

EndIf

In particolare, tramite le proprietà HasValue e Value è possibile, rispettivamente,verificare la presenza di un valore all’interno del tipo nullabile ed eventualmenterecuperarlo.PerdichiarareunNullableValueType,possiamoutilizzareanchelanotazionecontrattamostratainbasso.

DimnullableIntasInteger?

Assegnazionitratipigenerici:covarianzaecontrovarianzaUn aspetto che, sulle prime, lascia piuttosto perplessi utilizzando i generics, è la

Page 139: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

complessità nel gestire le assegnazioni tra tipi diversi quando, tra i relativi parametri,sussistono comunque relazioni di ereditarietà. Ad esempio, non è lecito (e provoca unerroredicompilazione)ilcodicedell’esempio5.16

Esempio5.16PublicSubSomeMethod(ByVallistAsList(OfObject))

ForEachitemInlist

Console.WriteLine(item)

Next

EndSub

SubMain()

DimstringsAsNewList(OfString)

SomeMethod(strings)

EndSub

Inquestocodice,infatti,siprovaainvocareunmetodocheaccettaunaList(OfObject),passandounaList(OfString),alfinedistamparneilcontenutosullaconsole.Inrealtà,sebbenesulleprimepossasembrarestrano,ilcompilatoreVisualBasichatutteleragioniperrifiutarequestocodice:apriori,infatti,nonvièalcunagaranziacheSomeMethodnontentidimodificare il contenutodella lista, aggiungendoelementi leciti perunaList(OfObject)manonperunaList(OfString).

Questo limite può essere superato se si riscrive SomeMethod utilizzando, in luogo diList(OfObject),l’interfacciaIEnumerable(OfObject):quest’ultima,infatti,possiedela caratteristica di esporre il tipo T solo in uscita, come risultato cioè di funzioni oproprietàinsolalettura,emaiiningresso,superando,difatto,ilproblemacheaffliggevainveceilcodiceprecedente:

PublicSubSomeMethod(ByVallistAsIEnumerable(OfObject))

ForEachitemInlist

Console.WriteLine(item)

Next

EndSub

QuestaversionediSomeMethodconsentealcodicedell’esempio5.16dicompilare;sidiceche,inIEnumerable(OfT),ilTècovariante,ossiacheadessopuòessereassegnatounIEnumerable(OfTDerivato)conuntipogenericopiùspecificodiquellooriginale.

D’altrocanto,esistonocasiincuiilparametrogenericoTvieneutilizzatoall’internodiun’interfaccia come un argomento per i metodi da essa esposti. Una List(Of T), adesempio, può essere ordinata tramite il metodo Sort e un opportuno oggettoIComparer(OfT).

L’interfacciaIComparer(OfT)servearappresentareunaparticolarestrategia

Page 140: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

per confrontare due istanze del tipo T; essa espone il metodo Compare cheaccetta le due istanze su cui effettuare il confronto e restituisce un intero,negativo nel caso in cui la prima sia minore della seconda, positivo in casocontrario. Utilizzare un IComparer(Of T) nel metodo Sort di una lista,consente di cambiare criteri di ordinamento in maniera veramente versatile,semplicemente fornendo come argomento, di volta in volta, dei comparerdifferenti,secondolanecessità.

Supponiamo allora di avere una List(Of Car), dove Car eredita dalla classe baseVehicle,edivolerlaordinareinbaseallavelocitàmassimatramiteunoSpeedComparer;itreoggettisonomostratinell’esempio5.17.

Esempio5.17PublicClassVehicle

PublicPropertySpeedAsInteger

EndClass

PublicClassCar

InheritsVehicle

EndClass

PublicClassSpeedComparer

ImplementsIComparer(OfVehicle)

PublicFunctionCompare(ByValxAsVehicle,ByValyAsVehicle)_

AsIntegerImplementsIComparer(OfVehicle).Compare

Returnx.Speed-y.Speed

EndFunction

EndClass

Comepossiamonotare,essendolaproprietàSpeeddefinita inVehicle,SpeedComparerimplementa l’interfacciaIComparer(Of Vehicle); esso può essere comunque utilizzatoper ordinare una List(Of Car), nonostante il metodo Sort di quest’ultima accetti unoggettoditipoIComparer(OfCar).

DimcarsAsNewList(OfCar)

'...sipopolalalista

cars.Sort(NewSpeedComparer())

Ciò è possibile perché IComparer(Of T) utilizza il tipo T esclusivamente in ingresso,ossiacomeargomentodeisuoimetodi,mamaicomerisultatodiunafunzione.Pertanto,sidicecheinIComparer(OfT),Tècontrovariante,cioècheadessopuòessereassegnatounoggettocheimplementiIComparer(OfTBase),conTcheereditadaTBase.

In base a quanto detto in questo paragrafo, possiamo facilmente dedurre cheinterfacce come IList(Of T) o ICollection(Of T) non possono essere né

Page 141: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

covarianti,nécontrovarianti.Laprima,infatti,esponemetodichecoinvolgonoTsiacomeargomentosiacomerisultato,mentrelasecondapresentametodicheaccettanoTsoloiningresso,manonpuòesserecontrovarianteinquantoereditadaIEnumerable(OfT),cheèasuavoltacovariante,datocheesponeiltipoTinuscita.

CreazionediinterfaccecovariantiecontrovariantiOvviamentecovarianzaecontrovarianzanonsonoconcetticherimangonocircoscrittiallesole interfaccedel .NETFramework,edèpossibile realizzarnedinuoveconsupportoaquesteparticolarimodalitàdiassegnazione.CiòèpossibileassociandoleparolechiaviIneOutalladefinizionedelinterfacciagenererica,comemostratodall’esempio5.18:

Esempio5.18PublicInterfaceICovariant(OfOutT)

FunctionSomeCovariantMethod()AsT

EndInterface

PublicInterfaceIContravariant(OfInT)

SubSomeContravariantMethod(ByValargAsT)

EndInterface

Anteponendo la parola chiave Out al tipo generico T, ci impegniamo a definireesclusivamente metodi che utilizzino il tipo T come risultato e mai come argomento.Viceversa,dichiarandol’interfacciacome(OfInT),siamoobbligatiausareTsempreesolocomeargomento,penaunerroreincompilazione.

ConclusioniIn questo capitolo abbiamo illustrato alcuni concetti chiave per la realizzazione diapplicazioniobjectorientedtramiteVisualBasic.

Innanzitutto, abbiamo visto come l’infrastruttura delle collection e il gran numero divarianti presenti nel .NET Framework consentono di rappresentare diverse tipologie distrutture dati: ArrayList e HashTable garantiscono una flessibilità estremamente piùelevata rispetto ai semplici array, mentre Stack e Queue possono essere utilizzate pergestireproblematichepiùspecifiche.

Lasecondapartedelcapitolo, invece,èstatadedicatacompletamenteai tipigenerici,mettendoinluceglienormibeneficichelascritturadicodicefortementetipizzatohadalpuntodivistadell’affidabilitàdel codice.Lecollezionigeneriche, infatti,permettonodievitare il ricorso alle conversioni di tipo edi intercettare eventuali errori, già in fasedicompilazione, ma abbiamo mostrato come le potenzialità dei generics possano essere

Page 142: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

sfruttateanchenellastesuradicodicepersonalizzato.

Nel capitolo che segue, utilizzeremonuovamente questi concetti, nell’esplorazionediunaltro importanteconcettonellaprogrammazioneorientataaglioggetti: idelegatee losviluppodicodicebasatosueventi.

Page 143: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

6

DelegateedEventi

Finora abbiamo imparato a utilizzare Visual Basic per costruire oggetti, ossia entitàautonomeingradodimantenereunostatointernotramiteicampiediesporreproprietàemetodi inmodo che essi possano interagire con altri oggetti, effettuando elaborazioni escambiandodati.Spesso siamoabituati apensare aquestiultimi semprecome stringhe,numeri,allimiteancheulteriorioggetti,matuttiilinguaggievoluti,inrealtà,consentonodi considerare come “dato” anche una funzione o una procedura. Visual Basic (o piùprecisamente il .NET Framework) non fanno eccezione e, grazie all’infrastruttura deidelegate,permettonodimemorizzaredeiriferimentiafunzionietrattarlecomesefosserocomunivariabili,chepossonoquindiessereassegnateopassateametodisotto formadiargomenti,oltreche,ovviamente,eseguite.

Proprioidelegatecostituisconol’argomentoprincipalediquestocapitolo:nellaprimaparte impareremo a conoscerli e a sfruttarne le potenzialità, mostrando come spessocostituisconounasoluzioneeleganteedefficaceaproblematichericorrenti.Introdurremoancheunasintassiparticolareperdefinireidelegateinmanieraestremamenteconcisaedelegante-lelambdaexpression-cherappresentanounconcettodiestremaimportanzacherisulteràindispensabileneicapitolisuccessivi,vistocheèallabasedellalogicafunzionalediLINQ.

Nella seconda parte del capitolo, invece, riusciremo finalmente a superare un limiteproprio degli oggetti che siamo in grado di costruire fino ad ora: basandoci sulleconoscenzedeidelegatefinquiapprese,infatti,introdurremoilconcettodievento,tramiteilqualepotremofareinmodocheinostrioggettiabbianolacapacitàdiinviarenotificheailoroutilizzatori,instaurandoquindiunaveraepropriacomunicazionebidirezionale.

IDelegatenel.NETFrameworkQuando nel capitolo precedente abbiamo parlato delle collection, non abbiamo citatoalcunmetodopereseguiredellericercheall’internodellestesse.SicuramenteabbiamolapossibilitàdiscorrerletramiteilcostruttoForEachedirecuperareglielementidesideratima,inrealtà,sonodisponibilisistemipiùavanzatiedeleganti:unaList(OfString),adesempio,contieneunmetodoFind,cheaccettacomeunicoargomentounoggettoditipoPredicate(OfString),comemostralafigura6.1.

Page 144: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura6.1–IntellisensedelmetodoFind.

Per il momento non addentriamoci nei dettagli su come utilizzare questometodo, saràtuttopiùchiarotrapoco,macerchiamodicapiremeglioilsignificatodiquestadefinizionee,inparticolare,ilruolodiPredicate(OfT).Questooggetto,contrariamenteatuttiquellicheabbiamo incontrato finora,nonèundato intesocomeunnumeroounastringa,marappresenta, invece,unafunzione,cheperòpossiamogestirecomesefosseunanormalevariabile,tant’èchesiamoingradodipassarlaaunmetodocomeargomento.Adesempio,possiamo ricercare la prima stringa che inizia per la lettera “a”, scrivendo un metodoFindStringsWithAeutilizzandolocomeargomentoperFind,comenell’esempio6.1.

Esempio6.1FunctionFindStringsWithA(ByValitemAsString)AsBoolean

Returnitem.StartsWith("a")

EndFunction

SubMain()

DimstringsAsNewList(OfString)

strings.Add("Thisisatest")

strings.Add("abcdefgh")

strings.Add("a1234567")

'UtilizzodelpredicatecomeargomentodiFind

DimfoundString=strings.Find(AddressOfFindStringsWithA)

'Stampaabcdefghsullaconsole

Console.WriteLine(foundString)

EndSub

Il fatto che FindStringsWithA sia utilizzabile come criterio di ricerca, dipendeunicamente dalla sua firma. In genere, infatti, un Predicate(Of T) è un metodo cheaccettainingressounoggettoditipoTerestituisceunBoolean;nelcasoquestocontrattononvengarispettato,ilrisultatochesiottieneèunerroreinfasedicompilazione.

Al di là del risultato finale del codicemostrato, che comunque può rivelarsi utile inmolteplici occasioni, ciò che è importante comprendere è che, in Visual Basic, siamoeffettivamente in grado di definire e istanziare puntatori a funzioni fortemente tipizzati,cheall’internodel.NETFrameworksonochiamatidelegate.

Page 145: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DefinizioneeutilizzodiundelegateUndelegateèunivocamenteidentificatodaunnomeerecaconséleinformazionirelativeai requisiti di forma, in termini di signature e tipo del risultato, che una funzione deverispettare affinché possa essergli assegnata. Predicate(Of T), che abbiamo visto nelparagrafoprecedente,nonèaltrocheunodellecentinaiaditipididelegateall’internodel.NET Framework. Ovviamente, in Visual Basic c’è la possibilità di definirne dipersonalizzati,tramitel’utilizzodellaparolachiaveDelegate.

Cerchiamo di capire, allora, come realizzarli e poterli sfruttare nel nostro codice perimplementare un logger, cioè una classe in grado di memorizzare delle informazionicronologiche, scrivendole su diversi supporti, quali file, e-mail o la stessa consoledell’applicazione. Invece di essere costretti a realizzare diverse versioni della classeLogger per ognuno di essi, o magari a utilizzare molteplici blocchi If al suo interno,possiamopensaredi definireundelegate apposito, dichiarandolo come se si trattassediunaqualsiasiclasse:

PublicDelegateSubStringLogWriter(

ByValtimestampAsDateTime,ByValmessageAsString)

Si tratta di una soluzione estremamente versatile perché, in questo modo, può esserel’utilizzatore stesso a decidere su quale supporto scrivere i messaggi di log. Il codicecompletodellaclasseLoggerèindicatonell’esempio6.2.

Esempio6.2PublicDelegateSubStringLogWriter(

ByValtimestampAsDateTime,ByValmessageAsString)

PublicClassLogger

PrivatewriterAsStringLogWriter

PublicSubNew(ByValwriterAsStringLogWriter)

Me.writer=writer

EndSub

PublicSubLog(ByValmessageAsString)

IfNotMe.writerIsNothingThen

Me.writer(DateTime.Now,message)

EndIf

EndSub

EndClass

Come possiamo notare, essa accetta uno StringLogWriter come argomento delcostruttore, per poi utilizzarlo all’interno del metodo Log, allo stesso modo di comefaremmoconunanormaleprocedura.Inrealtà,dietrolequinte,lostatement

Me.writer(DateTime.Now,message)

Page 146: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

vienesostituitoconlachiamataalmetodoInvokedeldelegatecheabbiamodefinito:Me.writer.Invoke(DateTime.Now,message)

Per utilizzare la classe Logger, a questo punto, è sufficiente creare una procedura cherispetti la firma stabilita da StringLogWriter e utilizzarla per crearne un’istanza,referenziandolatramitelaparolachiaveAddressOf,allostessomododell’esempio6.3.

Esempio6.3ModuleSampleModule

SubMain()

DimmyLoggerAsNewLogger(AddressOfConsoleWriter)

'Stampasullaconsoleilmessaggioinbasso

myLogger.Log("Messaggiodiesempio")

EndSub

PrivateSubConsoleWriter(

ByValtimestampAsDateTime,ByValmessageAsString)

Console.WriteLine(

String.Format("{0}-{1}",timestamp,message))

EndSub

EndModule

Fino a questo punto abbiamo appreso come come definire, istanziare e utilizzare undelegateeabbiamoancheaccennatoalfattocheesso,comeognialtraentitàall’internodel.NET Framework, è rappresentato da un vero e proprio modello a oggetti: proprioquest’ultimosaràl’argomentodelprossimoparagrafo.

ModelloaoggettideidelegateQuandodichiariamoundelegateinVisualBasic,ciòcheaccadedietrolequinteècheilcompilatore genera per noi un particolare tipo di classe, come possiamo facilmenteverificare conunqualsiasi tool ingradodi esplorare il contenutodiunassembly, comeILDASM o Reflector. Ad esempio, il progetto del paragrafo precedente contiene ladefinizionediunoggettoditipoStringLogWriter,simileaquellonellafigura6.2:

Page 147: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura6.2–GerarchiadiStringLogWriter.

Al suo interno troviamo il metodo Invoke, già citato in precedenza, che corrispondeesattamente alla firma del delegate stesso e che consente l’esecuzione della proceduraassegnata.Accanto a quest’ultimo, BeginInvoke ed EndInvoke realizzano il supporto aquelloche si chiamaAsynchronousProgrammingModel (APM), ossia la capacità dapartediundelegatediessereeseguitoinunthreadseparatorispettoalchiamante;sitrattadi un concetto avanzato, che verrà comunque trattato in un prossimo paragrafo e,successivamente, esteso in un capitolo interamente dedicato alle tecniche diprogrammazionemultithreading.

Scorrendo la gerarchia di classi, possiamo notare che, in ultima analisi,StringLogWriterereditadallaclasseSystem.Delegate.Quest’ultima,oltreacontenerelalogica implementativa necessaria al funzionamento dei delegate, espone una coppia diproprietàcheconsentonodi recuperare informazioni relativealmetodoacui ildelegatepunta.Inparticolare:

Methodcontieneinformazionirelativealmetodoeallasuasignature,comeiltipochelodefinisce,itipidegliargomentiiningressoequellodell’eventualerisultato;

Target contiene un riferimento alla specifica istanza a cui appartiene il metodoassegnatoaldelegate.

Percapiremeglioquestoconcettoprendiamoinesameilcodicedell’esempio6.4.

Esempio6.4PublicClassFileLogWriter

PublicPropertyFileNameAsString

PublicSubNew(ByValfilenameAsString)

Me.FileName=filename

EndSub

Page 148: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

PublicSubWrite(ByValtimestampAsDateTime,

ByValmessageAsString)

'Scritturamessaggiosufile…

EndSub

EndClass

SubMain()

DimwriterAsNewFileLogWriter("c:\somefile.txt")

DimwriterDelegateAsStringLogWriter=AddressOfwriter.Write

Console.WriteLine(writerDelegate.Method)

Console.WriteLine(

DirectCast(writerDelegate.Target,FileLogWriter).FileName)

EndSub

Essocontieneladefinizionediunaclasseingradodiscrivereimessaggidilogsufile,lacui procedura Write viene poi utilizzata per creare un’istanza di StringLogWriter. Sitrattadiunanovità,rispettoaquantoabbiamovistonelparagrafoprecedente,incuiinveceabbiamocostruitodelegateassociatiaprocedurestatiche.Inquestocaso,ildelegatepuntaaunmetododiistanzae,pertanto,laproprietàTargetcontieneilriferimentoall’istanzadiFileLogWriteracuiessoappartiene.Ilrisultatoditalecodiceèquellomostratoinfigura6.3.

Figura6.3–Outputdell’Esempio6.4.

Valelapenarimarcare,ancoraunavolta,chequandosicostruisceundelegatetramite un metodo di istanza, come nel caso dell’esempio precedente, essomantieneunriferimentoall’oggettoacuitalemetodoappartiene.CiòsignificachetaleoggettononpotràesseredistruttodalGarbageCollectorfinoachenonverrà rimosso dal delegate stesso. Questo concetto avrà un’implicazioneimportantenellasecondapartedelcapitolo,quandoparleremodeglieventi.

Negliesempicheabbiamovistofinoraabbiamosemprecostruitodelegatechepuntasseroa una singola procedura. Nel prossimo paragrafo cercheremo di capire quali sono glistrumentichecipermettonodisuperarequestolimite.

Page 149: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Combinazionedidelegate:laclasseMulticastDelegateUnacaratteristicache rende idelegateestremamentepotentieversatili ècostituitadallacapacità di mantenere al loro interno una invocation list e quindi, di fatto, puntarecontemporaneamente più metodi, da eseguire poi in sequenza. Questa componibilità èimplementata internamente dalla classe MulticastDelegate, anch’essa, comeSystem.Delegate, classe base per tutti i delegate, e può essere sfruttata utilizzando ilmetodostaticoCombine,comemostratonell’esempio6.5.

Esempio6.5'Definizionedelprimodelegate

DimwriterAsNewFileLogWriter("c:\somefile.txt")

DimfileDelegateAsNewStringLogWriter(AddressOfwriter.Write)

'Definizionedelsecondodelegate

DimconsoleDelegateAsNewStringLogWriter(AddressOfConsoleWriter)

'Combinazionedeidelegate

DimcombinedDelegateAsStringLogWriter=DirectCast(

[Delegate].Combine(consoleDelegate,fileDelegate),StringLogWriter)

DimmyLoggerAsNewLogger(combinedDelegate)

'Scrivesullaconsoleesufileilmessaggioinbasso

myLogger.Log("Messaggiodiesempio")

Nel codice esposto qui sopra, vengono utilizzate due differenti istanze diStringLogWriter per crearne una terza, combinedDelegate, con cui poi inizializzareeffettivamente la classe Logger. Il risultato che otteniamo consiste nel fatto che ognichiamataalmetodoLogprovocal’esecuzionedientrambiidelegateeil tuttoavvieneinmaniera trasparente per la nostra classe Logger, tant’è che non siamo stati costretti adapportarealcunamodificaalcodicescrittoneiparagrafiprecedenti.Quandosiutilizzailmetodo Delegate.Combine, è comunque opportuno fare attenzione ad alcuni aspetti:innanzitutto,idelegatedacombinaredevonoesseretuttidellostessotipo,altrimentivienesollevatounerrorearuntime;insecondoluogo,comesipuònotaredalcodiceprecedente,questo metodo restituisce un oggetto di tipo Delegate e pertanto, prima di poterloeffettivamenteutilizzare,ènecessarioeffettuareun’operazionedicasting.

Come è facile comprendere, i multicast delegate risultano estremamente utiliquando si vogliono concatenare più invocazioni a procedure in manieratrasparente per l’utilizzatore. Quando, però, sono applicati a funzioni, èimportante avere cognizione del fatto che il valore di ritorno restituito dallachiamataèsemprepariaquellodell’ultimafunzioneinvocata.

Altri due metodi della classe Delegate, che risultano utili nella gestione dei multicastdelegate, sono GetInvocationList, tramite il quale è possibile recuperare l’elenco deidelegate che compongono la sua lista, e Remove, che consente di creare un multicast

Page 150: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

delegate a partire da uno esistente, rimuovendo unmembro dalla sua invocation list. Illoroutilizzoèmostratonell’esempio6.6.

Esempio6.6DimcombinedDelegateAsStringLogWriter=DirectCast(

[Delegate].Combine(consoleDelegate,fileDelegate),StringLogWriter)

ForEachitemAs[Delegate]IncombinedDelegate.GetInvocationList()

Console.WriteLine(item.Method)

Next

combinedDelegate=DirectCast(

[Delegate].Remove(combinedDelegate,fileDelegate),StringLogWriter)

Console.WriteLine(vbCrLf+"Dopolarimozione:")

ForEachitemAs[Delegate]IncombinedDelegate.GetInvocationList()

Console.WriteLine(item.Method)

Next

Il codice precedente utilizza questi due metodi per visualizzare e manipolare lo stessocombinedDelegate che abbiamo introdotto all’inizio di questo paragrafo, in particolare,creandounnuovodelegatedopoaverrimossounodeisuoimembridallainvocationlist.L’outputdiquestosnippetdicodiceèquellomostratoinfigura6.4.

Figura6.4–Outputdell’Esempio6.6.

Cennisull’esecuzioneasincronadiundelegateLe applicazioni che abbiamo utilizzato negli esempi visti finora presentano tutte lacaratteristicadiessereeseguiteinunsingolothread:sitrattadiunconcettoavanzato,chesarà spiegato in maniera estesa nel corso del capitolo 9 ma che, sostanzialmente, puòtradursi nel fatto che i vari statement sono processati in sequenza, facendo sì che, alterminediognunodiessi,siavviil’esecuzionedelsuccessivo.

Quando un metodo coinvolge risorse tipicamente lente, quali la rete o dispositivi diinput/output,ilflussodell’applicazionerestabloccatofintantochequestaoperazionenon

Page 151: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

venga completata. In situazioni simili, il modo migliore per aumentare le prestazionidell’applicazione,èquellodisfruttarelefunzionalitàdiesecuzioneasincronadeidelegate,tramite la coppia dimetodiBeginInvoke edEndInvoke. Per capiremeglio quali sono ivantaggi,guardiamoilcodicedell’esempio6.7.

Esempio6.7DelegateFunctionSampleDelegate(ByValinputAsString)AsString

PublicFunctionVeryLongEchoFunction(ByValinputAsString)AsString

'Bloccal'esecuzionedelthreadcorrentepertresecondi

Thread.Sleep(3000)

Return"Hello"+input

EndFunction

SubMain()

DimmyEchoAsNewSampleDelegate(AddressOfVeryLongEchoFunction)

Console.WriteLine(myEcho("Marco"))

Console.WriteLine(myEcho("Daniele"))

Console.WriteLine(myEcho("Riccardo"))

EndSub

In esso abbiamo reso la funzione VeryLongEchoFunction artificiosamente lenta,utilizzando l’istruzione Thread.Sleep, che ne blocca l’esecuzione per tre secondi, inmododasimularelalatenzatipica,adesempio,dell’interazioneconundispositivodirete.Il risultato è che l’applicazione impiega circa nove secondi per essere completata, pariquindiallasommadeltemponecessariopercompletareletreinvocazionialdelegate.

Inrealtà,durantetuttoquestotempo,l’applicazionerestaquasisempreinattesa,senzafarnulla,epertantocitroviamoinunodeicasitipicineiqualil’esecuzioneasincronapuòeffettivamentefareladifferenza.ProviamoalloraariscrivereilmetodoMain,persfruttarequestafunzionalitàdeidelegate.

Esempio6.8SubMain()

DimmyEchoAsNewSampleDelegate(AddressOfVeryLongEchoFunction)

'esecuzioneparalleladelletreVeryLongEchoFunction

DimresultsAsNewList(OfIAsyncResult)

results.Add(myEcho.BeginInvoke("Marco",Nothing,Nothing))

results.Add(myEcho.BeginInvoke("Daniele",Nothing,Nothing))

results.Add(myEcho.BeginInvoke("Riccardo",Nothing,Nothing))

'Recuperodeirisultatiestampasullaconsole

Page 152: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ForEachresultAsIAsyncResultInresults

Console.WriteLine(myEcho.EndInvoke(result))

Next

EndSub

In questa versione, invece di utilizzare Invoke come in precedenza, l’esecuzione deldelegate viene scatenata tramite il metodo BeginInvoke, anch’esso generatoautomaticamentedalcompilatore,inbasealladichiarazionediSampleDelegateeallasuasignature.Inquestafase,nonciinteressaentrareneldettagliodegliulterioriargomenticheesso implica (saranno approfonditi nel capitolo 19), bensì è importante comprendere lasostanziale differenza rispetto all’esempio precedente: ognuno deimetodiBeginInvoke,infatti, presenta la caratteristicadi avviare l’esecuzionediVeryLongEchoFunction inunthread parallelo e di ritornare immediatamente il controllo al thread principale, che,quindi, può passare subito a processare la chiamata successiva. Il risultato consiste nelfatto che le tre invocazioni vengono scatenate parallelamente, come schematizzato infigura6.5.

Figura6.5–Schemadiesecuzionemultithreaded.

PerrecuperareilvalorediritornodiVeryLongEchoFunctionestamparlofinalmentesullaconsole,èinvecenecessarioutilizzareilmetodoEndInvoke,cheaccettacomeargomentol’oggetto di tipo IAsyncResult restituito da ognuna delle invocazioni precedenti.EndInvoke, ovviamente, blocca l’esecuzione del thread principale fino al termine diVeryLongEchoFunction, ma il fatto che le tre elaborazioni vengano eseguite quasicontemporaneamente, consente comunque all’applicazione di essere decisamente piùvelocerispettoallaversionedell’esempio6.7.

Page 153: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IdelegateeigenericsEssendoidelegatedelleclassi,èovviamentepossibilesfruttareigenericspercrearedellestrutture facilmente riutilizzabili e versatili e, pertanto, sono supportate tutte lefunzionalitàcheabbiamoimparatoaconoscerenelcapitolo5.

Esempio6.9PublicDelegateFunctionMyDelegate(OfTAsStructure)(

ByValinputAsT)AsString

PrivateFunctionDateTimeWriter(ByValinputAsDateTime)AsString

Returninput.ToShortDateString()

EndFunction

SubMain()

DimsampleAsNewMyDelegate(OfDateTime)(AddressOfDateTimeWriter)

EndSub

Nell’esempio6.9,abbiamodefinitoundelegate,impostandounvincolosultipogenerico,chedeveessereuntipodivalore.All’internodel.NETFrameworksonogiàdisponibiliungrannumerodidelegategenericiutilizzabilie,inparticolare:

Action(OfT1,...,T8): si trattadiunaseriedidelegate iquali rappresentanounaproceduracheaccettafinoaottodifferentiargomentiiningresso;

Func(OfT1,...,TResult):consisteinottodifferentidelegateperrappresentarefunzioni che accettano fino a otto differenti argomenti, per restituire un tipoTResult.

Usando queste ultime, ad esempio, possiamo riscrivere il codice precedente comenell’esempio6.10.

Esempio6.10PrivateFunctionDateTimeWriter(ByValinputAsDateTime)AsString

Returninput.ToShortDateString()

EndFunction

SubMain()

DimfuncSampleAsNewFunc(OfDateTime,String)(

AddressOfDateTimeWriter)

EndSub

Comevedremopiùavantinellibro,ActioneFuncrivestonoun’importanzafondamentaleall’interno della tecnologia LINQ, dato che gran parte dei metodi che ne costituisconol’infrastrutturautilizzano, seppur indirettamente,proprioqueste tipologiedidelegateper

Page 154: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

costruire espressioni complesse. In generale, però, non è comodo utilizzare in manieraintensivaidelegatese,perognunodiessi,siamocostrettiarealizzareunafunzioneounaprocedura da qualche altra parte nel nostro codice. Per ovviare a questo inconveniente,Visual Basic supporta una sintassi contratta per rappresentarli. Quest’ultima saràargomentodelprossimoparagrafo.

Delegateinunarigadicodice:lelambdaexpressionQuando, all’inizio del capitolo, abbiamo mostrato come, tramite il metodo Find el’utilizzo di un Predicate, sia possibile ricercare elementi all’interno di una lista dioggetti, siamo stato costretti a scrivere parecchio codice per dichiarare la funzione diricercaeutilizzarlaperinizializzareildelegate.

FunctionFindStringsWithA(ByValitemAsString)AsBoolean

Returnitem.StartsWith("a")

EndFunction

SubMain()

DimstringsAsNewList(OfString)

'..

DimfoundString=strings.Find(AddressOfFindStringsWithA)

EndSub

La medesima funzionalità può essere ottenuta tramite una sintassi più breve, che ciconsente di definire la funzione in-line, ovvero direttamente nel momento in cuiinvochiamoilmetodoFind.

Esempio6.11SubMain()

DimstringsAsNewList(OfString)

'..

DimfoundString=strings.Find(Function(s)s.StartsWith("a"))

EndSub

La formasintattica,utilizzatanell’esempio6.11,prende il nomedi lambdaexpression.Cerchiamodicomprendernel’anatomia:

la prima parte è costituita dalla dichiarazione dell’espressione e inizia con unaparola chiave che, a secondadel fatto che l’espressione restituiscaun risultatoomeno,puòessereFunctionoSub;

successivamente, devono essere dichiarati gli argomenti della routine; in questafaseèpossibilesolodeciderneilnome,inquantoilnumeroeiltipodiognunoèdeterminato automaticamente dal compilatore, in base al contesto in cui ci

Page 155: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

troviamo. Nel nostro caso, ad esempio, essendo l’argomento di Find unPredicate(OfString),lafunzionepuòavereunsoloargomento,ditipoString,acui,nell’esempio6.11,abbiamodatoilnomes;

l’ultimoelementocostitutivodiunalambdaexpressionèilveroepropriocodice,in cui risiede la logica dell’espressione stessa; per utilizzare la sintassi vista inprecedenza, dev’essere composta da un unico statement, pertanto, ad esempio,invece del costrutto If..Then..Else.. End If, siamo costretti a utilizzare lefunzioniIfoIIfvistenelcapitolo3.Un’ultimaosservazioneriguardailfattoche,nel caso di unaFunction, la parola chiave Return è implicita e non dev’essereindicata.

Nelcaso incuivogliamoutilizzarequestanotazionesintatticaperesprimere logichepiùcomplesse, è possibile scriveremetodimulti-riga, utilizzando i costruttiFunction..EndFunctionoSub..EndSubseguenti:

DimfoundString=strings.Find(

Function(s)

statement1()

statement2()

Returns.StartsWith("a")

EndFunction)

myClass.ExecuteSomeCode(

Sub(a,b)

statement1(a)

statement2(b)

EndSub)

Attenzioneche,inquestocaso,l’usodellaparolachiaveReturninunafunzionetornaadesserenecessario.

Una funzionalità estremamente comoda e interessante delle lambda expression ècostituita dalla cosiddetta closure, ossia dalla possibilità di accedere, dal corpodell’espressione, a eventuali altre variabili definite nel metodo in cui la lambda èdichiarata;l’esempio6.12mostracomepossiamosfruttaretalecaratteristicaperricercarestringhecheinizinoperunqualsiasicarattere.

Esempio6.12DimstringsAsNewList(OfString)

'..

DimsearchString="B"

DimfoundString=strings.Find(Function(s)s.StartsWith(searchString))

Implementareuna tale logica tramite i solidelegate, richiederebbe lacostruzionediuna

Page 156: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

classe ausiliaria, detta per l’appunto closure, che in questo caso, invece, èautomaticamentegeneratadalcompilatore.

Idelegatenel.NETFramework,insomma,nonsonosolosemplicipuntatoriafunzione,maverieproprioggettidotatidifunzionalitàavanzateediunottimosupportodapartedelcompilatore. Essi sono alla base dell’infrastruttura degli eventi, che esamineremo neisuccessiviparagrafidiquestocapitolo.

Idelegatecomestrumentodinotifica:glieventiOltre a quello visto nelle pagine precedenti, l’ulteriore campo di utilizzo tipico deidelegatesitrovaintuttequelleoccasioniincuivogliamofareinmodocheunaclassesiaingradodiforniredellenotificheaisuoiutilizzatori.Supponiamo,adesempio,didoverleggereundatodaunaportadelPCedi realizzare, quindi, una classe che si occupidiincapsularetuttalalogicadicomunicazione,comequelladell’esempio6.13.

Esempio6.13PublicClassPortReceiver

DelegateSubDataReceivedCallback()

Private_callbackAsDataReceivedCallback

PublicSubSubscribe(ByValcallbackAsDataReceivedCallback)

Me._callback=callback

EndSub

PropertyDataAsString

PublicSubReceiveData()

Data="Datareceived"

IfNotMe._callbackIsNothingThen

Me._callback()

EndIf

EndSub

'..codicediinterfacciamentoconlaporta..

EndClass

LaclassePortReceiverdefiniscealsuointernounparticolaretipodidelegate,chiamatoDataReceivedCallback,chevieneinvocatoognivoltachevengonoricevutideidati.Unoggettochevogliaricevereunanotificadell’avvenutaricezionedeldato,deveutilizzareilmetodo Subscribe, per fornire a PortReceiver una propria procedura da eseguire alverificarsidiquestoevento,comeaccadenell’esempio6.14.

Esempio6.14

Page 157: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

PublicClassSomeClass

Private_receiverAsPortReceiver

PublicSubNew(ByValreceiverasPortReceiver)

Me._receiver=receiver

Me._receiver.Subscribe(AddressOfMe.dataReceived)

EndSub

PrivateSubdataReceived()

Console.WriteLine(_receiver.Data)

EndSub

EndClass

In questo modo, siamo riusciti effettivamente a instaurare una comunicazionebidirezionale tra i due oggetti senza, tra l’altro, introdurre dipendenze all’interno diPortReceiver, il quale, effettivamente, non ha cognizione alcuna di chi sia il propriosottoscrittore,aparte il fattochecontieneunaproceduraconunasignaturebendefinita.Siamostatiperòcostrettiascrivereunadiscretaquantitàdicodice,cheandrebbereplicatoperogninuova tipologiadinotifica, introducendodivolta involtaun’ulterioreversionedelmetodoSubscribe.

Fortunatamente, tutto questo sforzo non è necessario, poiché il .NET Frameworkcontienegiàglistrumentiadattiasopperireaquestotipodinecessità:glieventi.

DefinizioneeusodiuneventoinunoggettoGli eventi, in Visual Basic, rappresentano il modo più efficace e semplice per renderepossibilel’inviodinotifichedapartediunoggettoaunnumeroarbitrariodisottoscrittori.L’esempio6.15mostra comepossiamo riscriverePortReceiver, per dotarlo dell’eventoPortDataReceived,utilizzandolaparolachiaveEvent.

Esempio6.15PublicClassPortReceiver

PublicEventPortDataReceived(ByValreceiverasPortReceiver)

PropertyDataAsString

PublicSubReceiveData()

Data="Datareceived"

RaiseEventPortDataReceived(me)

EndSub

'..codicediinterfacciamentoconlaporta..

EndClass

Page 158: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Come possiamo notare, nella classe PortReceiver non abbiamo più bisogno né delmetodoSubscribe, nédeldelegatedi callback (anche se, comevedremopiùavanti,glieventisonointernamentegestitipropriotramiteidelegate),macisiamolimitatiadefinireun nuovo evento, specificandone la signature desiderata. In maniera del tutto analogarispettoaquantoaccadeva inprecedenza,all’internodelmetodoReceiveDatapossiamoinviare una notifica ai sottoscrittori, utilizzando la parola chiave RaiseEvent evalorizzandoopportunamentegliargomentirichiesti.

Nell’accezione propria del .NET Framework, il metodo che viene invocato incorrispondenza del sollevamento di un evento è chiamato handler. Per agganciare unhandleraunevento,possiamoutilizzarelasintassidell’esempio6.16e, inparticolare, laparola chiave AddHandler, specificando un metodo la cui signature corrispondaesattamenteaquelladell’eventostesso,penaunerroreincompilazione.

Esempio6.16PublicClassSomeClass

PublicSubNew(ByValreceiverAsPortReceiver)

AddHandlerreceiver.PortDataReceived,AddressOfdataReceived

EndSub

PrivateSubdataReceived(ByValreceiverAsPortReceiver)

Console.WriteLine(receiver.Data)

EndSub

EndClass

Nel caso in cui l’oggetto del quale vogliamo gestire gli eventi sia memorizzato in uncampo all’interno della classe, una modalità alternativa di gestione è rappresentatanell’esempio 6.17; questamodalità consiste nell’utilizzare la clausola WithEvents nelladichiarazione,indicandopoiilrelativogestoretramitelaparolachiaveHandles.

Esempio6.17PublicClassSomeClass

PrivateWithEvents_receiverAsPortReceiver

PublicSubNew(ByValreceiverAsPortReceiver)

Me._receiver=receiver

EndSub

PrivateSubDataReceived(ByValreceiverAsPortReceiver)_

Handles_receiver.PortDataReceived

Console.WriteLine(receiver.Data)

EndSub

EndClass

Page 159: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dato che, come abbiamo già accennato, gli eventi, nel .NET Framework, sono gestititramite l’utilizzo dei delegate, è ovviamente ancora valida la peculiarità dei multicastdelegateovverolapossibilitàdiconcatenarepiùchiamate;pertanto,adifferenzadiciòcheaccadeva inVisualBasic6, aogni eventopossonoessere associatipiùgestori e il tuttoavvieneinmanieratrasparente,aprescinderedaqualedelleduemodalitàdisottoscrizionevogliamoutilizzare.

Come visto in precedenza, delegate legati ametodi di istanzamantengonounriferimento a quest’ultima, impedendo quindi che il GarbageCollector possarimuoverla dalla memoria. Ciò è ovviamente valido anche nel caso deglihandler a eventi; nel caso si utilizzi AddHandler, è possibile cancellare lasottoscrizione grazie alla parola chiave RemoveHandler mentre, nel caso diWithEvents,ènecessarioimpostarelarelativavariabileaNothing.

OracheconosciamolenozionidibasedellagestionedeglieventiinVisualBasic,ètempodi capire quali sono le possibilità di personalizzazione di questi strumenti e le bestpracticeconsigliate.

CreareeventipersonalizzatiNel paragrafo precedente, abbiamo accennato al fatto che la gestione degli eventi, nel.NET Framework, è totalmente basata sull’utilizzo dei delegate sebbene, in realtà, nelcodice che abbiamo visto finora non sia presente ilminimo accenno a questi ultimi. Inrealtà, se utilizziamo nuovamente Reflector per esplorare il contenuto dell’assemblyprodottodalcompilatore,otteniamoilrisultatodifigura6.6,nellaqualepossiamonotarecomePortReceivercontenga ladefinizionediundelegate, ilcuinomerichiamaquellodell’eventoPortDataReceived.

Figura6.6–MembridiPortReceiver.

Page 160: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Nonostante il fatto che, per ogni evento, il compilatore si preoccupi di generare ilrispettivodelegate,generalmenteècomunquepreferibiledichiararloinmanieraesplicita,inmodocheeventiconlamedesimasignaturepossanoriutilizzaretuttilostessodelegate.Perconvenzione,ilsuonomedeveterminareconilsuffisso“EventHandler”epuòessereindicatoincorrispondenzadelladichiarazionediPortDataReceived.

PublicDelegateSubPortDataReceivedEventHandler(

ByValreceiverAsPortReceiver)

PublicEventPortDataReceivedAsPortDataReceivedEventHandler

Unaltroaspettomigliorabiledelcodicescrittonelparagrafoprecedente,riguardailmodocon cui solleviamo l’evento, ossia utilizzando RaiseEvent direttamente all’interno delmetodo ReceiveData. Infatti, sebbene tutto funzioni correttamente, la nostra attualeimplementazionenonconsenteaun’eventualeclassederivata,dimodificarelelogichechedeterminanosesollevareomenol’eventostesso.Perquestaragione,unabestpracticeèquelladiutilizzare allo scopounmetododefinito comeProtectedOverridable, il cuinomeconvenzionalmenteè“On”,seguitodalnomedell’evento,ediinvocareilcomandoRaiseEvent solo mediante quest’ultimo. A valle di queste considerazioni, allora,l’implementazionediPortReceiverdivienequelladell’esempio6.18.

Esempio6.18PublicClassPortReceiver

PublicDelegateSubPortDataReceivedEventHandler(

ByValreceiverAsPortReceiver)

PublicEventPortDataReceivedAsPortDataReceivedEventHandler

ProtectedOverridableSubOnPortDataReceived()

RaiseEventPortDataReceived(Me)

EndSub

PropertyDataAsString

PublicSubReceiveData()

Data="Datareceived"

OnPortDataReceived()

EndSub

'..codicediinterfacciamentoconlaporta..

EndClass

Finoraabbiamoillustratoqualisonoimetodimiglioriperstrutturareunoggettochesiaingrado di sollevare eventi ma ci resta ancora da capire come utilizzarli per scambiareinformazioniconisottoscrittori.

Scambiaredatitramiteeventi:laclasseEventArgselesue

Page 161: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

derivateQuandoabbiamorealizzatoPortDataReceivednonabbiamopostopiùditantol’accentosulla particolare signature che esso deve avere; nel corso degli esempi che abbiamomostrato,siamoarrivatiaun’implementazione incui,quasipercaso,abbiamodecisodiincludere l’istanza di PortReceiver responsabile di aver sollevato l’evento. Si tratta,invece,diundatochedovrebbeesseresempreobbligatoriamenteinviato:unabestpracticediMicrosoftconsigliadiutilizzare,perglieventipiùsemplici,lasignature

SubEventName(ByBalsenderAsObject,ByValeAsEventArgs)

tantoche il .NETFrameworkcontieneundelegateapposito, chiamatoEventHandler. Ilsecondo argomento è un’istanza della classe EventArgs; si tratta di un tipo che noncontienealcunainformazione,malacuiadozioneècomunqueconsigliataperunrequisitodiformachesaràresopiùchiarofrapoco.IlmodopiùcorrettoesemplicepervalorizzarloètramiteilsuocampostaticoEmpty:

RaiseEventPortDataReceived(Me,EventArgs.Empty)

Nelcasoincui,invece,sianecessarioinviareinformazionidistato,ilconsiglioèquellodirealizzare una classe personalizzata che derivi da EventArgs e il cui nome,convenzionalmente,terminicontalesuffisso.Pertantose,adesempio,volessimopassaretramitePortDataReceived anche il dato appena ricevuto, dovremmo definire un nuovooggetto PortDataReceivedEventArgs e modificare il relativo delegate. L’esempio 6.19mostral’implementazionediPortReceiver,comprensivadiquesteulteriorimigliorie.

Esempio6.19PublicClassPortDataReceivedEventArgs

InheritsEventArgs

PropertyDataAsString

EndClass

PublicClassPortReceiver

PublicDelegateSubPortDataReceivedEventHandler(

ByValsenderAsObject,ByValeAsPortDataReceivedEventArgs)

PublicEventPortDataReceivedAsPortDataReceivedEventHandler

ProtectedOverridableSubOnPortDataReceived(ByValdataAsString)

DimeAsNewPortDataReceivedEventArgs()

e.Data=data

RaiseEventPortDataReceived(Me,e)

EndSub

PropertyDataAsString

PublicSubReceiveData()

Me.Data="Datareceived"

Page 162: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Me.OnPortDataReceived(Data)

EndSub

'..codicediinterfacciamentoconlaporta..

EndClass

Comepossiamonotare,l’introduzionediPortDataReceivedEventArgscomportaanchelamodificadiOnPortDataReceived,chepossiamosfruttareperincapsularetuttalalogicadicreazionedegliargomentidell’evento.

Ancheitipidel.NETFrameworkseguonoleregolecheabbiamoenunciato,perdotaregli eventi di informazioni di stato e, pertanto, esistono un gran numero di classi chederivano da EventArgs (insieme, ovviamente, ai relativi delegate) che possiamoeventualmente sfruttare nel nostro codice. CancelEventArgs, ad esempio, contiene unaproprietà booleana chiamata Cancel ed è tipicamente utilizzata come argomento deicosiddetti eventi di preview, vale a dire quegli eventi sollevati prima di una certaoperazione,perdare lapossibilità all’utilizzatoredi cancellarne l’esecuzione.L’esempio6.20mostracomesfruttarequestafunzionalitàall’internodiPortReceiver.

Esempio6.20PublicClassPortReceiver

'..altrocodicequi..

PublicEventPortDataReceivingAsCancelEventHandler

ProtectedOverridableSubOnPortDataReceiving(

ByValeAsCancelEventArgs)

RaiseEventPortDataReceiving(Me,e)

EndSub

PublicSubReceiveData()

DimeAsNewCancelEventArgs(False)

OnPortDataReceiving(e)

'Quiverifichiamoseunsottoscrittore

'hacancellatolaricezionedati

IfNote.CancelThen

Me.Data="Datareceived"

Me.OnPortDataReceived(Data)

EndIf

EndSub

'..codicediinterfacciamentoconlaporta..

EndClass

Ingenerale,perognitipologiadiclassederivantedaEventArgs,èdisponibileildelegate

Page 163: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

generico EventHandler(Of T), che possiamo utilizzare se non riteniamo necessariodefinirneunopersonalizzato.

Inquest’ultimoesempio, è lampante che l’utilizzodeidelegate comebaseperl’infrastrutturadeglieventinel.NETFrameworkcomportiundifferentemododiragionare rispetto al passato; dato che un evento può avere sottoscrittorimultipli,ilmodomiglioreperfarsìcheanchequestiultimipossanocondividereinformazionidistatoèproprioquellodiutilizzareunaclasseEventArgs,ossiauntipodiriferimento,efarsìchelamedesimaistanzavengainviataaognunodiessi.UnafunzioneconunrisultatoditipoBoolean,invece,avrebbedatosoloall’ultimo metodo della invocation list il privilegio di impostare o meno lacancellazionedell’evento.

Un ulteriore aspetto riguarda la ragione per cui è consigliato l’uso dellasignaturestandard,compostadaidueargomentiditipoObjecteEventArgs (ounasuaclassederivata)perdefinireunevento,anchenelcasoincuiessonondebba tramandare informazioni di stato. Il vantaggio risiede nel fatto che,grazieallacontrovarianzadeidelegate,possiamopensaredicrearedeigestoriuniversali,ingradocioèdiessereassegnatiaqualsiasievento.Ciònonsarebbepossibileseognunoesponesseunnumerodiversodiargomentioppuresequestinonappartenesseroallamedesimagerarchia.

DefinizioneesplicitadieventiInalcunicasipuòesserenecessarioeseguiredelcodicepersonalizzatoincorrispondenzadell’aggiuntao rimozionediunhandlerauneventooppure incorrispondenzadella suaesecuzione. Quelle che abbiamo utilizzato sinora, per definire PortDataReceiving ePortDataReceived, sono le forme contratte (ma allo stesso tempo più utilizzate) per ladefinizione di eventi. Alla stessa stregua di ciò che accade per le proprietà, infatti,possiamoutilizzarelaformaestesadell’esempio6.21.

Esempio6.21PublicCustomEventClickAsEventHandler

AddHandler(ByValvalueAsEventHandler)

EventHandlerList.Add(value)

EndAddHandler

RemoveHandler(ByValvalueAsEventHandler)

EventHandlerList.Remove(value)

EndRemoveHandler

RaiseEvent(ByValsenderAsObject,ByValeAsEventArgs)

ForEachhandlerAsEventHandlerInEventHandlerList

Page 164: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IfhandlerIsNotNothingThen

handler(sender,e)

EndIf

Next

EndRaiseEvent

EndEvent

Conquestosistema,sipossonoottenereeffettiparticolarmenteinteressanti,comefareinmodocheuneventosiasempregestitoalmassimodaunsolohandlero,adesempio,chetutti gli handler siano eseguiti inmaniera asincrona, utilizzando ilmetodoBeginInvokedelrelativodelegate,comenell’esempio6.22.

Esempio6.22RaiseEvent(ByValsenderAsObject,ByValeAsEventArgs)

ForEachhandlerAsEventHandlerInEventHandlerList

IfhandlerIsNotNothingThen

handler.BeginInvoke(sender,e,Nothing,Nothing)

EndIf

Next

EndRaiseEvent

ConclusioniInquestocapitoloabbiamointrodottounaseriediconcettidifondamentaleimportanzapercostruire applicazioni complesse in Visual Basic. I delegate rappresentano per il .NETFrameworkquellochesonoipuntatoriafunzioneperilinguaggimenoevolutie,oltreallefunzionalità di base, incapsulano logiche complesse come multicasting o esecuzioneasincrona.Unacertacomplessità,perquantoriguardailcodicenecessarioadutilizzarli,ècompensata dall’introduzione delle lambda expression, che consentono di scriveredelegatesempliciinunasolarigadicodice.

Nellasecondapartedelcapitoloabbiamovistocomepossiamodotareinostritipidellacapacitàdiinviarenotificheall’esterno:neabbiamomostratolecaratteristicheprincipali,indicandolebestpracticedaadottareinfasedidefinizione,eabbiamospiegatocomesiapossibilepersonalizzarli a tutti i livelli, intervenendopersinonelle fasi in cuiuneventovienesottoscrittoosollevato.

Nel prossimo capitolo continueremo a esplorare le peculiarità di Visual Basic e del.NETFramework,occupandocidiunaspettocrucialenello sviluppodiun’applicazione,come la gestione degli errori, per poi spingerci fino a trattare una tecnologia, chiamataReflection, tramite la quale ispezionare a runtime i membri degli oggetti e invocarne

Page 165: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

dinamicamentel’esecuzione.

Page 166: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

7

Approfondimentodellinguaggio

Grazieaquantoabbiamo illustratonegliultimicapitoli, lanostravisionedel linguaggioVisual Basic inizia oramai a essere abbastanza completa da consentirci di iniziare ascrivere le prime applicazioni. Prima di questo passo, però, c’è un ultimo aspettoinfrastrutturaledel.NETFrameworkcheèindispensabileconoscereedalqualequalsiasiprogrammatorenonpuòprescindere:glierroriaruntime.Essirappresentanol’argomentoalqualeèdedicatalaprimapartediquestocapitolo,nellaqualeimpareremoqualisonoleazionichepossiamointraprenderenelmomentoincuiabbiamolanecessitàdigestiredellesituazioninonprevisteeanchelemodalitàsecondolequalipossiamousareleeccezionipersegnalaresituazionianomaleachihainvocatounnostrometodo.

Lasecondapartedelcapitolosaràinvecededicataaconcettiavanzati, inparticolareareflection, ossia un set di classi di cui possiamo avvalerci sia per esplorare i metadaticontenuti negli assembly, sia per istanziare e interagire dinamicamente con imembri inessidefiniti.Vedremoinoltrequalisonoglistrumentidel.NETFrameworktramiteiqualirealizzareoggettiingradodimutarelalorostrutturainmanieradinamicaecomeinvecesfruttareicustomattributesperscriverecodicedichiarativo.

InfinedaremounbrevissimocennosuRoslyn,lalibreriadiMicrosoftchepermettediaccedereallefunzionalitàdelcompilatoredirettamenteda.NET.

GestionedelleeccezioniIl fatto che l’esecuzione di un determinato programma possa generare un errore èun’eventualitàchevapresainconsiderazionenelmomentoincuisidecidedisviluppareun’applicazione;ilcodice,potenzialmente,fallisceaprescinderedallabravuradichil’hascritto,semplicementeperchéleragionipercuiciòavvienenonsonosempreprevedibiliogestibili:unmetodopuòsollevareunerroreacausadiunasvistadellosviluppatore,maanche in risposta a un problema hardware o al tentativo di accedere a una risorsa nondisponibile.

Ecco perché qualsiasi linguaggio e tecnologia di sviluppo sono dotati di sistemi pergestireglierrori.Il.NETFramework,inparticolare,chiamaquestieventiimprevisticonilnome di eccezioni, ed essendo completamente orientato agli oggetti, sfrutta proprio ilparadigma della programmazione a oggetti per realizzare un’infrastruttura di gestioneaffidabile e facilmente espandibile. Per apprezzarne appieno le caratteristiche, però, è

Page 167: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

necessarioprimacomprenderecosaaccadeinCOMeWin32.

Glierroriprimadel.NETFrameworkQuando un metodo genera un errore, la prima azione che tipicamente è necessariointraprendereèquelladiinterromperel’esecuzionedelcodice,cercarediidentificarnelanaturaedeventualmentemettereinattodellecontromisure,perevitarechel’applicazionesi comporti in maniera imprevista; nel caso in cui ciò non sia possibile, l’errore deveesserenotificatoalchiamantedelmetodoche,asuavolta,deveprovarea ripercorrere imedesimipassi.

InambitoCOMeWin32,inassenzadiun’infrastrutturadedicataallagestionediquestotipo di situazioni, solitamente ci si limita a esporremetodi che restituiscono un valoreinteromedianteilqualeindicaresel’esecuzionesiaandataabuonfineomeno.LeAPIdiWindows, per citare un caso, non appartengono alla categoria del codice managed econtinuano,pertanto,aseguirequestosistema,comepossiamonotare,adesempio,dallasignaturedellafunzioneGetDateFormat.

intGetDateFormat(

__inLCIDLocale,

__inDWORDdwFlags,

__inconstSYSTEMTIME*lpDate,

__inLPCTSTRlpFormat,

__outLPTSTRlpDateStr,

__inintcchDate

);

Quest’ultima restituisce un valore intero che, nel caso sia pari a 0, indica che si èverificato un errore durante la sua esecuzione. In generale, poi, una volta appurato chel’esecuzione non si è conclusa con successo, è necessario invocare ulteriori funzioni disistemaperrecuperareinformazionicircalanaturadell’errorestesso.

Si tratta, insomma, di una gestione non proprio elementare e assolutamente nonstandardizzata,chetral’altrohailgravedifettodidemandaretotalmenteall’utilizzatoreilcompito di determinare il successo o meno dell’invocazione. Quest’ultimo aspetto èparticolarmente pericoloso, in quanto dimenticarsi di verificare il valore di ritorno ocontrollarlo in maniera non corretta equivale in genere a perdere la notifica di uneventualeerrore,generandoquindipericolosibugdisicurezzaeminando,ingenerale,lastabilitàel’affidabilitàdell’applicazionestessa.

VisualBasic,d’altrocanto,finoallaversione6.0hautilizzatounapprocciodifferente,chesibasavasull’utilizzoall’internodiunaclausolaOnError,tramitelaquale,incasodierrore,erapossibilerimandareaunaporzionedicodice.Leinformazionisull’erroreeranodisponibili all’interno di un particolare oggetto, chiamato Err, che venivaautomaticamente valorizzato dal runtime quando necessario e comunque codificate

Page 168: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

numericamente.

Si tratta, in buona sostanza, di due modalità decisamente differenti, ognuna con leproprie peculiarità e difetti ma comunque non standardizzate. Nel .NET Framework,invece, la gestione delle eccezioni diviene infrastrutturale e comune a tutti i linguaggi,consentendoci di liberarci dal concetto di “errore identificatodaun codicenumerico” erisolvendopraticamentetutteleproblematicheevidenziateinWin32.Cerchiamodicapirecome.

GestionestrutturatadeglierroritramiteleexceptionPer iniziareacomprenderequalisianoivantaggidiunagestionestrutturatadeglierrori,come quella che possiede il .NET Framework, vediamo cosa accade nel codicedell’esempio7.1.

Esempio7.1SubMain()

Dimresult=Division(5,0)

'Questocodicenonvienemaieseguito

Console.WriteLine("Ilrisultatoè"+result.ToString())

EndSub

PublicFunctionDivision(ByValaAsInteger,ByValbAsInteger)

AsInteger

DimresultasInteger=a\b

'Incasodierrorequestocodicenonvienemaieseguito

Console.WriteLine("Risultatocalcolatoconsuccesso")

Returnresult

EndFunction

Quandovieneeseguitoilcalcoloall’internodellafunzioneDivisionutilizzandoilvalore0 come quoziente, la sua esecuzione viene immediatamente interrotta e, al contesto diruntime, viene associato un particolare oggetto di tipo DivideByZeroException,rappresentativo della tipologia di errore che si è verificata. Successivamente, lo stessocomportamento si ripete all’interno del metodo Main, che viene anch’esso terminato,provocandoquindilachiusuradell’applicazionestessa,comemostratoinfigura7.1.

Page 169: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura7.1–Applicazioneterminatapereccezionenongestita.

Ilcomportamentogeneraledellagestioneeccezioninel.NETFrameworkèschematizzatoinfigura7.2.

Figura7.2–Flussodiunaexception.

In generale, ciò che accade quando un metodo solleva un’eccezione è che il CLRinterrompeilflussologicoinesecuzione,perpassareallaricercadiuneventualegestore,ossiadiunbloccodicodiceopportunamentemarcatocomeingradodiprenderlaincarico.Nel caso in cui questo non venga trovato, l’eccezione viene propagata al metodochiamante dove si ripete il medesimo pattern, via via risalendo tutto lo stack. Se talericerca si conclude con successo, il gestore viene eseguito e questo flusso di notifica èinterrotto,amenocheessonondecidadirisollevarlaasuavolta.

In caso contrario, invece, una volta giunti all’origine dello stack, l’eccezione vienemarcata come non gestita e provoca la chiusura dell’applicazione, come nel casodell’esempio7.1.

Come possiamo notare, si tratta di un approccio strutturato molto differente separagonatoallatecnologiaWin32cheabbiamovistonelparagrafoprecedente.Nel.NETFramework, i valori di ritorno delle funzioni adempiono al ruolo per cui sono pensati,ossia quello di rappresentare il risultato logico dell’operazione, mentre la gestione dieventualierroriècompletamenteacaricodelCLR,cheprovvededasoloainterromperel’esecuzionedelcodiceeafarsicaricodipropagarlilungolostack.

Abbiamo più volte accennato al fatto che le eccezioni nel .NET Framework sonorappresentate come oggetti. Nel prossimo paragrafo cercheremo di capire meglio le

Page 170: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

caratteristichediquestomodello.

LaclasseSystem.ExceptionIl.NETFrameworkèunatecnologiacompletamenteorientataversolaprogrammazioneaoggettiesfruttaquestoparadigmaancheperrappresentareglierrorichevengonosollevatiaruntime.Abbiamoaccennatoalfattoche,alverificarsidiun’eccezione,ilCLRassociaal contestodi esecuzioneun’istanzadiunparticolareoggetto il cui tipo è (oderivada)Exception.

Proprioiltipoutilizzatoèlaprimadiscriminanteutilizzabileperdeterminarelanaturadell’eccezionechesièverificata,comeabbiamopotutoverificarenell’esempio7.1:unadivisioneperzerosollevainfattiunaDivisionByZeroException,mentre,invece,accederein lettura a un file inesistente genera un errore FileNotFoundException. La classeException,inparticolare,ècapostipitediunanumerosagerarchiaditipi,ognunodeiqualièassociatoaunaparticolarecasisticadierrore.Essaesponealcunimembriche,pertanto,sonocomuni a tutte le eccezionidefinitenel .NETFramework, e sono sintetizzati nellatabella7.1

Tabella7.1–MembridellaclasseSystem.Exception.Nome Significato

Message Contieneunmessaggiodierroredescrittivodell’eccezione.

Source Senonimpostatodiversamente,contieneilnomedell’assemblychehasollevatol’eccezione.

StackTrace Lostackdichiamatealmomentoincuisiverifical’eccezione.

Data Unadictionarycheconsentedispecificareulterioriinformazionisull’erroreverificatosi.

HelpLink E’unaproprietàincuièpossibilememorizzareunURLperrimandareaunapaginadihelp.

InnerExceptionUnoggettoExceptionpuòfungeredacontenitoreperun’ulterioreeccezionepiùspecifica,chevieneespostatramitequestaproprietà.Questoconcettosaràspiegatomeglionelcorsodelcapitolo.

TargetSite Ladefinizionedelmetodochehasollevatol’eccezione.

ToString()Questo metodo è ridefinito nella classe System.Exception e produce una stringa contenente la naturadell’eccezione,ilmessaggioelostacktrace.

A questi membri se ne possono aggiungere altri, propri della particolare tipologiad’eccezione che è stata sollevata e dell’errore che essa deve rappresentare: la classeSqlException, ad esempio, viene sollevata in risposta a un errore segnalato da SQLServer e contiene, fra le altre, le proprietà LineNumber o Procedure, che indicanorispettivamentelarigadiT-SQLelastoredprocedurechehannocausatoilproblema.

RealizzarecustomexceptionEssendoleeccezioninient’altrocheoggetti,nullavietadicostruiredelleproprieeccezionipersonalizzate permodellare errori applicativi particolari, che non trovano riscontro traquelligiàprevistinel .NETFramework.LagerarchiadiereditarietàchehaoriginedallaclasseSystem.Exceptiontrova,alsecondolivello,dueclassiche,almenonelleintenzioni,

Page 171: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

hannoloscopodisuddividereleeccezioniinaltrettantecategorie:

SystemException rappresenta la classe base per tutte le eccezioni sollevate dalCLR;

ApplicationException è invece da intendersi come la classe base per tutte leeccezioni applicativee,pertanto, è consigliabileutilizzarlacome taleper tutte leeccezionipersonalizzatecheabbiamobisognodirealizzare.

Per realizzare una custom exception, quindi, non dobbiamo far altro che ereditare daquest’ultima classe base per creare una classe il cui nome, per convenzione, dovrebbeterminareconilsuffisso–Exception.

Lo scopo di una tale suddivisione è quello di dare la possibilità allosviluppatoredidistinguere facilmente lanaturadiun’eccezione, inmodoche,adesempio,sipossanogestireinmanieracentralizzatatuttequellegeneratedalCLR e, in maniera puntuale, quelle applicative. In realtà, nello sviluppo del.NETFrameworkquestaregolanonèstataseguitafinoinfondoeoggiesistonoeccezioni CLR che derivano direttamente da Exception o addirittura daApplicationException.Ciò nonostante, è comunque consigliabile seguire lalineaguidageneraleedereditarequindidaquest’ultima.

L’esempio 7.2 mostra il codice necessario a definire un’eccezione personalizzata perrappresentareunerroredimancatavalidazionediunoggettoCustomer.

Esempio7.2<Serializable()>

PublicClassInvalidCustomerException

InheritsApplicationException

PublicPropertyCustomerAsCustomer

PublicSubNew(ByValcustomerAsCustomer)

Me.New(customer,"Customerisinvalid")

EndSub

PublicSubNew(ByValcustomerAsCustomer,ByValmessageAsString)

MyBase.New(message)

Me.Customer=customer

EndSub

PublicSubNew(ByValcustomerAsCustomer,ByValmessageAsString,

ByValinnerExceptionAsException)

MyBase.New(message,innerException)

Me.Customer=customer

EndSub

Page 172: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

PublicSubNew(ByValinfoAsSerializationInfo,

ByValcontextAsStreamingContext)

MyBase.New(info,context)

EndSub

EndClass

SebbenerealizzareunaclassechederividaExceptionequivalgaacostruireunaeccezionepersonalizzataperfettamentevalida,ilcodicemostratosispingeunpo’oltreperadottarealcune best practice consigliate nella realizzazione di queste particolari tipologie dioggetti.Inparticolare:

L’eccezione deve essere marcata con l’attributo Serializable. Il concetto diattributo sarà presentato più avanti in questo capitolo; per il momento ci bastisapere che quella particolare notazione consente al .NET Framework dirappresentare l’eccezione con uno stream binario, in modo che possa essereeventualmenteinviataattraversolareteopersistitasuunamemoriadurevole;

La nostra custom exception può, a tutti gli effetti, contenere delle proprietàaggiuntive, nel nostro caso la particolare istanza di Customer che non è stataritenutavalida;

Devonoesserepresentiduecostruttoricheconsentanodispecificareunmessaggiopersonalizzato e una InnerException, ossia un’eccezione di cui si vuole tenertraccia (solitamente perché è stata la causa prima dell’errore) e che si vuolememorizzareall’internodellanostraclassepersonalizzata;

Deve essere presente un costruttore che accetti i due tipi SerializationInfo eStreamingContext;sitrattadiuncostruttore“diservizio”,chevieneutilizzatonelmomentoincuisivuolericostruireunaeccezionedadatiserializzati.

Ora che abbiamo appreso nel dettaglio ilmodello a oggetti che nel .NETFramework èutilizzatoperrappresentareglierroriaruntime,èfinalmentearrivatoilmomentodicapirecome, all’interno del codice, è possibile interagire con essi, sia per quanto riguarda lagestionedi eventuali eccezioni, sianell’otticadi sollevarlepernotificare altrimetodidieventuali situazioni anomale. Le prossime pagine saranno dedicate proprio a questoargomento.

LavorareconleeccezioninelcodiceLacapacitàdiintercettareleeccezioniall’internodelcodiceèinteramentebasatasultipodiExceptionchevienesollevatache,comeabbiamovisto inprecedenza, rappresenta lanaturadell’errorechesièverificato.

Intercettareegestiresituazionidierroresignificascrivereparticolariblocchidicodicechevengonoeseguitiinquestesituazionispecifiche.IlprimofraquellicheanalizzeremoèilcostruttoTry..Catch..EndTry,ingradodiattivarsialverificarsidiunparticolaretipodieccezione.

Page 173: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IntercettareleeccezioniIl codice visto nell’esempio 7.1 sollevava un errore a causa della divisione per zero e,trattandosidiun’eccezionenongestita,portavaalcrasheallachiusuradell’applicazionestessa. Per evitare queste conseguenze, lo possiamo modificare come mostratonell’esempio7.3.

Esempio7.3SubMain()

Try

Dimresult=Division(5,0)

'Questocodicenonvienemaieseguito

Console.WriteLine("Ilrisultatoè"+result.ToString())

CatchexAsException

Console.WriteLine("Sièverificatounerrore")

EndTry

Console.WriteLine("Esecuzioneterminata")EndSub

Tuttelevolteincuiabbiamoachefarecondelcodicechepotenzialmentepuòsollevareun’eccezioneevogliamoessereingradodigestirequestaeventualità,possiamoavvalercidel costrutto Try..Catch..End Try appenamostrato, grazie al quale, quando il codiceall’interno del blocco Try genera un’eccezione, ne viene interrotta l’esecuzione e ilcontrollovienepassatoalbloccoCatchchecorrispondealtipodell’eccezionesollevata.

Nelnostroesempio,inparticolare,allaclausolaCatchèassociatoiltipoExceptionedessendo quest’ultimo il tipo base per qualsiasi eccezione del .NET Framework, èconsideratoungestorevalidoperlaDivideByZeroExceptionsollevatadallostatement

Dimresult=Division(5,0)

Ilrisultatofinale,quindi,èchel’eccezionerisultagestitael’applicazionenonterminapiùin maniera anomala come accadeva in precedenza, come si può notare dall’outputmostratodallafigura7.3.

Page 174: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura7.3–Eccezionegestita.

Il risultato sarebbe il medesimo se si indicasse come eccezione da gestire la stessaDivideByZeroException o ArithmeticException, da cui essa deriva, mentrel’applicazione tornerebbeachiudersi conunerrore se ilgestore fosse relativoaun tipodifferentecome,adesempio,OutOfMemoryException.

Ingenerale,unbloccoTry..Catch..EndTrypuòconteneremoltepliciclausoleCatch,inmododaprevederediversigestoriperspecifiche tipologiedieccezione,comemostral’esempio7.4.

Esempio7.4Try

Dimresult=Division(5,0)

'Questocodicenonvienemaieseguito

Console.WriteLine("Ilrisultatoè"+result.ToString())

CatchexAsDivideByZeroException

Console.WriteLine("Errore:nonsipuòdividereperzero")

CatchexAsOutOfMemoryException

Console.WriteLine("Memoriaterminata")

CatchexAsException

Console.WriteLine("Sièverificatounerroregenerico")

EndTry

Quando si utilizza questo particolare approccio, bisogna prestare attenzione all’ordinesecondocuivengonodispostiiblocchiCatch,datochevengonovalutatiinsequenzadalCLRfinchénonneviene trovatounoadatto;pertanto, senel codicedell’esempio7.4 ilblocco

CatchexAsException

si trovasse in prima posizione, essendo in grado di gestire qualsiasi tipo di eccezione,impedirebbedifattol’esecuzionediquellipiùspecifici.

Page 175: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Un altro concetto piuttosto importante nella gestione delle eccezioni, è quello degliexceptionfilter,ossialapossibilitàdiattivareundeterminatobloccocatchinbaseaunacondizionespecifica.

Esempio7.5Try

ExecuteSqlQuery()

CatcheAsSqlExceptionWhen(e.Class>19)

Console.WriteLine("Errorefatale")

CatcheAsSqlException

Console.WriteLine("Erroredurantelaquery")

EndTry

Ilcodicedell’esempio7.5intercettaun’eccezionedi tipoSqlException induedifferentiblocchi Catch. Il primo, in particolare, grazie alla keyword When, viene attivato soloquando il livello di severity dell’errore è superiore a 19, ossia in presenza di un errorefatale,mentretuttiglialtricasisarannogestitidalsecondobloccoCatch.

IlbloccoFinallyAllevoltelanecessitàcheabbiamononèquelladiintercettareunaparticolaretipologiadieccezione, ma di assicurarci che una determinata porzione di codice venga eseguitacomunque,siainpresenzasiainassenzadiunerrore.Tipicamentesitrattadicodicedettodicleanup, ossia utilizzato per liberare risorse. Consideriamo il caso dell’esempio 7.6,cheutilizzaunoggettoditipoStreamReaderperleggereilcontenutodiunfile.

Esempio7.6DimsrAsNewStreamReader("c:\test.txt")

Try

DimcontentAsString=

sr.ReadToEnd()

Finally

sr.Close()

EndTry

In casi simili abbiamo bisogno di essere certi che il metodo Close venga comunqueinvocato, inquantonecessarioper liberarel’handlediWindowsassociatoalfileacuisistaaccedendo; ilbloccoFinally garantisce l’esecuzionedel codice in esso contenuto aprescinderedalfattocheleistruzioniall’internodelcorrispondentebloccoTry sollevinoeccezioni o meno. Try, Catch e Finally possono essere utilizzati anche

Page 176: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

contemporaneamente,comemostral’esempio7.7.

Esempio7.7DimsrAsNewStreamReader("c:\test.txt")

Try

DimcontentAsString=

sr.ReadToEnd()

CatchexAsIOException

Console.WriteLine("ErrorediI/O:")

Console.WriteLine(ex.Message)

Finally

sr.Close()

EndTry

Solitamente gli oggetti che, come StreamReader, allocano risorse di sistema,implementano anche una particolare interfaccia per consentirne il rilascio in manieradeterministica,adesempio,all’internodiunbloccoFinally.Sitrattadiunargomentodiestrema importanza, dato che una gestione errata delle risorse spesso si accompagna aleak, blocchi dell’applicazione e a sovraccarichi del sistema, ai quali è interamentededicatoilparagrafosuccessivo.

L’interfacciaIDisposableeilbloccoUsingQuando, nel corsodel primo capitolo, abbiamoparlatodella gestionedellamemoria daparte del CLR, abbiamo visto come il processo di disallocare oggetti non più utilizzatiavvenga inmanieradel tutto trasparente allo sviluppatore, grazie aungestore chiamatoGarbageCollector e, in particolare, abbiamo visto come questo operi inmaniera nondeterministica,inbaseallerichiestedirisorsedapartedell’applicazioneeallecondizionidelsistema.

Esistono però casi in cui un comportamento del genere non è accettabile: si pensi alprecedenteesempio7.6, nel quale sfruttiamo unoStreamReader per accedere a un file,impegnandoquindiunarisorsanongestitaqualeunhandlediWindows.Quandoquestooggettovienecoinvoltoinunagarbagecollection,nevieneinvocatoildistruttore,inmodochetalirisorsevenganoeffettivamenteliberate.

Si tratta però di una sorta di “ultima spiaggia”, in quanto non è assolutamenteaccettabile che lasciamo il file impegnato dall’applicazione, anche quando abbiamoeffettivamente terminato di utilizzarlo, attendendo l’intervento del Garbage Collector,sullacuicadenzatemporalenonabbiamoalcuncontrollo.

In tutti i casi in cui vogliamo invece liberare una risorsa in maniera deterministica,possiamo utilizzare il pattern Disposable, che consiste nell’implementare l’interfaccia

Page 177: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IDisposable.VisualStudio2015utilizzaun templatedi codice conungrannumerodicommentiperguidarcinellarealizzazioneditalepatternche,grossomodo,ricalcaquellovisibilenell’esempio7.8.

Esempio7.8PublicClassDisposableObject

ImplementsIDisposable

ProtectedOverridableSubDispose(ByValdisposingAsBoolean)

IfdisposingThen

'quisiliberanolerisorsegestite

EndIf

'quisiliberanolerisorsenongestite

EndSub

PublicSubDispose()ImplementsIDisposable.Dispose

Me.Dispose(True)

GC.SuppressFinalize(Me)

EndSub

ProtectedOverridesSubFinalize()

Me.Dispose(False)

MyBase.Finalize()

EndSub

EndClass

Cerchiamodicapireindettaglioilsignificatoeilfunzionamentodiquestitremetodi:

Il primometodo Dispose accetta un parametro in ingresso che indica se è statoinvocatodeterministicamentedall’utente(valoreTrue)odal finalizzatore (valoreFalse)acausadiunagarbagecollection.Nelprimocaso,devonoessereliberatetuttelerisorse,siagestitechenon,nelsecondocasosoloquesteultime,inquantoilgarbagecollectorpotrebbeavergiàdistruttoleprime;

IlsecondooverloaddiDispose,senzaparametri,èquelloprevistodall’interfacciaIDisposable e, dopo aver opportunamente invocato il metodo descritto inprecedenza, comunica alGarbageCollector che non è più necessario eseguire ilfinalizzatore per quella particolare istanza, visto che le risorse sono state giàliberate;

Il terzometodo Finalize è il distruttore dell’oggetto e si occupa di invocare ilmetodoDisposeforzandolaliberazionedellesolerisorsenongestite.

L’implementazionedell’interfacciaIDisposable,comesipuòcapiredaquantoabbiamo detto finora, consente di liberare in maniera deterministica,

Page 178: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

invocandone il metodo Dispose, eventuali risorse non gestite, utilizzatedirettamente o indirettamente. Essa va pertanto implementata, assieme alfinalizzatore, quando utilizziamo direttamente risorse non gestite (ad esempiounhandleounoggettoCOM)oppureneicasiincuiilnostrooggettomantengariferimenti ad altri oggetti che implementano a loro volta IDisposable. Inquest’ultimo caso, però, non è necessario dotare la nostra classe di undistruttore. In ogni modo, è importante sottolineare che IDisposablenon hanulla a che vedere con il concetto di liberare memoria, che resta invecetotalmenteunaprerogativadelGarbageCollector.

QuandoistanziamounoggettoIDisposablenelcodicediunmetodo,dovremmosempreutilizzarlo all’interno di un blocco Try..Finally per essere sicuri di invocarecorrettamente il metodo Dispose anche in eventuali casi di errore, come mostratodall’esempio7.9.

Esempio7.9SubMain()

DimmyObjectAsNewDisposableObject

Try

myObject.SomeMethod()

Finally

myObject.Dispose()

EndTry

EndSub

Visual Basicmette a disposizione una sintassi particolare, di fatto equivalente a quellaprecedente,utilizzandoilbloccoUsingcomenell’esempio7.10.

Esempio7.10UsingmyObjectAsNewDisposableObject

myObject.SomeMethod()

EndUsing

Essoèriconosciutocomevalidodalcompilatoresolonelcasoincuil’oggettoistanziatonel primo statement implementi l’interfaccia IDisposable e ha la caratteristica diinvocarneautomaticamenteilmetodoDisposealterminedelblocco,siainpresenzasiainassenzadieventualieccezioniaruntime.

Dopo questo breve excursus su come gestire oggetti che allocano risorse nel .NETFrameworkanche incasodieccezioni,dalprossimoparagrafo torneremoall’argomentoprincipaledellaprimapartediquestocapitolo,ossialagestionedeglierroriaruntime,conparticolare attenzione alle best practice consigliate per l’utilizzo di questo strumento

Page 179: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

all’internodelnostrocodice.

SollevareeccezioninelcodiceebestpracticeOvviamente,durantel’esecuzionediun’applicazione,nonèdettochecitroviamosempredallapartedicoloroche“subiscono”ilverificarsidiunerrore,bensìpuòcapitarechesianecessarioedoverososollevareun’eccezioneperrispondereaunasituazioneanomala.Aquesto scopo possiamo utilizzare la parola chiave Throw, che accetta come argomentoun’istanzadiunoggettochederividallaclasseSystem.Exception.L’esempio7.11mostrauntipicoutilizzodiquestaparolachiaveperrispondereaunadellelineeguidafornitedaMicrosoft in merito al design delle nostre classi, ossia il verificare preventivamente,all’interno di ogni metodo, che i parametri obbligatori siano correttamente valorizzati,sollevandounaArgumentNullExceptionincasocontrario.

Esempio7.11PublicSubSomeMethod(ByValitemsAsList(OfInteger))

IfitemsIsNothingThen

'Sisolleval'eccezioneindicandoilnomedell'argomentonon

'correttamentevalorizzato

ThrowNewArgumentNullException("items")

EndIf

'Codicedelmetodoqui

EndSub

Unpossibileproblemadell’esempioprecedenteècostituitodall’utilizzodiunastringaperindicare il nome del parametro errato items. Il codice funziona perfettamente,ma nonsupporta le funzionalità di refactoring esposte da Visual Studio 2015. Per esempio, serinominiamo il parametro, l’ambiente di sviluppo non è in grado di individuare questastringaeaggiornarla.

L’alternativapiùcorrettaèquelladiutilizzarelaparolachiaveNameOf,cheaccettaunqualsiasi membro e restituisce una stringa con il suo nome. L’esempio 7.12 mostra ladifferenza:

Esempio7.12PublicSubSomeMethod(ByValitemsAsList(OfInteger))

IfitemsIsNothingThen

'Sisolleval'eccezioneindicandoilnomedell'argomentonon

'correttamentevalorizzato

ThrowNewArgumentNullException(NameOf(items))

Page 180: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndIf

'Codicedelmetodoqui

EndSub

L’istruzioneThrownonvautilizzatasolonelcasoincuiabbiamolanecessitàdigenerareunanuovaeccezionemaanchequando,dopoaverneintercettataunainunbloccoCatch,vogliamorilanciarlapernotificarecomunqueilchiamante.

GestioneerilanciodelleeccezioniQuandoun’eccezionevienesollevataeintercettataall’internodiunbloccoCatch,amenochenonsiapossibileporvirimedioeaggirareilproblema,solitamenteledueazionipiùconsonedaintraprenderesono:

eseguire del codice per gestire almeno parzialmente l’errore, ad esempio,limitando i danni che una stored procedure possa aver provocato eseguendo unrollbackdi una transazione, oppure registrando l’eccezioneottenuta inun file dilog,cosìchepossaessereinvestigatainfuturo;

rilanciarel’eccezionealchiamante,pernotificarlodell’anomalia,ecosìviafinoa raggiungere la root dell’applicazione, dove un gestore centralizzato possavalutare la gravità della situazione, mostrare un messaggio d’errore o,eventualmente,terminarel’esecuzione.

Il concetto di rilanciare un’eccezione non completamente gestita, quindi, è difondamentale importanza all’interno del bloccoCatch, per far sì che gli altri chiamantinello stack siano anch’essi notificati, e si esplicita utilizzando la parola chiave Throw,comenell’esempio7.13.

Esempio7.13Try

DimmyObjectAsNewSomeClass

myObject.SomeProblematicMethod()

CatchexAsException

logger.Log(ex.ToString)

Throw

EndTry

Quandol’istruzioneThrowvieneutilizzatasenzaspecificarealcunargomento,l’eccezionesollevata è quella dell’attuale contesto di runtime; quello dell’esempio7.13 è sempre ilmodopiùcorrettoperrilanciareun’eccezione,inquantoconsentedipreservarnelostacktraceoriginale,graziealqualeèpossibileavereevidenzadelmetodoche,inultimaanalisi,hageneratoilproblema.Questainformazioneverrebbeinvecepersautilizzandolasintassi

Page 181: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

CatchexAsException

..

Throwex

EndTry

UtilizzodelleInnerExceptionInalcunesituazioni,invece,puòesserenecessarioinglobarel’eccezioneottenutainunadipiù alto livello. Immaginiamo, ad esempio, che l’esecuzione di una query SQL pervalidare le credenziali dell’utente fallisca, generando una SqlException. Visto che, inultima analisi, ciò comporta anche la mancata validazione delle credenziali utente,rilanciare un’eccezionedi tipoSecurityException può rappresentare forse la decisionepiù corretta, facendo però in modo che quest’ultima contenga anche le informazionirelativeallaveranaturadell’errorechesièverificato.

Esempio7.14Public Function ValidateCredentials(ByVal username As String, ByVal

passwordAsString)asBoolean

Try

'codicepervalidareusernameepasswordsudatabase

CatchexAsSqlException

ThrowNewSecurityException(

"Nonèstatopossibilevalidarelecredenziali",ex)

EndTry

EndFunction

Il codice dell’esempio 7.14, come possiamo notare, rilancia una SecurityExceptionfornendocomeargomentodelcostruttorel’istanzadell’eccezioneoriginale, inmodochesiaaccessibiletramitelaproprietàInnerException.

Considerazioniprestazionalisull’usodelleExceptionUn’ultima riflessione deve essere invece fatta dal punto di vista delle performance. Lagestionedelleeccezioniè,infatti,moltoonerosaperilCLResovraccaricamoltolaCPU,rendendo estremamente lenta la nostra applicazione. Per questa ragione, esse vannoutilizzate per gestire eventi, per l’appunto, eccezionali. Pertanto non è corretto, adesempio,segnalareconunaSecurityException lamancatavalidazionedellecredenzialiutentequandousernameepasswordsemplicementenoncorrispondono:sitrattadiuncasoprevedibilee,pergestirlo,èmoltopiùopportunoutilizzareunafunzionecherestituiscaunvalore Boolean, come quella dell’esempio precedente, mentre l’eccezione deve essere

Page 182: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

utilizzata soloperun eventononprevedibile apriori, comeun erroredi connessione aldatabaseodiesecuzionedellaquery.

Conquesteconsiderazionisiconcludelaprimapartedelcapitolo,dedicataallagestionedelleeccezioniaruntimenelleapplicazionibasatesul .NETFramework.Nelleprossimepagine introdurremo invece un’altra peculiarità di questa tecnologia, grazie alla quale èpossibileispezionareeinvocaredinamicamenteimembrideinostrioggetti:reflection.

EsplorareitipiaruntimeconReflectionNelcorsodelprimocapitolo,abbiamovistocomeilrisultatodellacompilazionedicodicesorgente nel .NET Framework sia un assembly, ossia un contenitore di alto livello, ingrado di immagazzinare non solo codice MSIL ma anche informazioni aggiuntiverelativamente al suo contenuto, catalogate tramite i metadati; il meccanismo grazie alquale è possibile interrogare questi metadati ed eventualmente utilizzare nel codice leinformazioniinessicontenute,èdenominatoReflectionedèimplementatomedianteunaseriediclassi,appartenentialnamespaceSystem.Reflection.Grazieaquesteultime,adesempio,possiamoesplorarearuntimeilcontenutodiunassemblyerecuperarel’elencodeitipiinessodefiniti.

Esempio7.15'Recuperaunareferenceall'assemblycorrente

DimcurrentAssemblyasAssembly=Assembly.GetExecutingAssembly()

'Ricercadeitipidefinitinell'assemblyinesecuzione

ForEachtypeAsTypeIncurrentAssembly.GetTypes()

'Stampailnomedeltiposuconsole

Console.WriteLine(type.Name)

Next

La classeAssembly, utilizzata nell’esempio7.15, espone una serie dimetodi statici perottenerearuntimel’accessoaunparticolareassembly.NelnostrocasoabbiamoutilizzatoilmetodoGetExecutingAssembly, che ritorna un riferimento a quello correntemente inesecuzione,ma è possibile caricare una libreria inmemoria a partire da un tipo in essadefinito,dalnomelogico,dalnomedelfilechelacontiene,oaddiritturadaunostreamdibyte che ne rappresenta il contenuto. Ad esempio, tramite il tipo Integer, possiamorecuperareunriferimentoamscorlib,cuiessoappartiene.

Esempio7.16DimMsCoreLibAsAssembly=

Assembly.GetAssembly(GetType(Integer))

Page 183: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Console.WriteLine(MsCoreLib.FullName)

Console.WriteLine(MsCoreLib.Location)

Console.WriteLine(MsCoreLib.GetName().Version)

Comepossiamonotarenell’esempio7.16,un’istanzadiAssemblypuòessereutilizzatapermolteplici scopi, ad esempio, per reperire informazioni quali il fully qualified name, ilpath fisicoo il numerodiversione.La figura7.4mostra il risultato dell’esecuzione delcodiceprecedente.

Figura7.4–RecuperoinformazionitramitelaclasseAssembly.

Torniamoora,perunmomento,all’esempio7.15,incuisiamostatiingradodirecuperareunelencoditipidefinitiinunassembly,tramiteilmetodoGetTypes.

ForEachtypeAsTypeIncurrentAssembly.GetTypes()

..

Next

Il risultato di questometodo è un array di oggetti di tipoSystem.Type, una classe che,nonostante non appartenga al namespace System.Reflection, costituisce il cardine diquestosetdiAPI,comeavremomododivederenelprossimoparagrafo.

LaclasseSystem.TypeLaclasseTyperappresentailmodelloaoggettidiunqualsiasitipodelCLResvolgeunaduplicefunzione:

espone contenuto informativo sulla natura del tipo stesso, permettendoci, adesempio,dicapiresesitrattadiuntipodiriferimentoodivalore,seèastratto,seèun’interfaccia,ecc.

consentel’accessoatuttiimembriinessodefiniti,quindicampi,proprietà,metodiedeventiaffinché,dataunaparticolareistanzadiun’oggetto,siamopoiingradodiinvocarlidinamicamente.

Latabella7.2mostraimembridiquestaclassepiùcomunementeutilizzati.

Page 184: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Tabella7.2–MembridellaclasseSystem.Type.

Nome Significato

AssemblyRestituisceunriferimentoall’assemblyincuiiltipoèdefinito.

NameFullNameNamespace-AssemblyQualifiedName

Restituiscono rispettivamente il nome del tipo, ilnomecompletodinamespace,ilsolonamespaceeilnome completo di namespace e assembly didefinizione.

IsAbstractIsClassIs-

ValueTypeIsEnumIsInterfaceIsArrayIsGenericTypeIsPublicIsSealed

Si tratta di una serie di proprietà tramite le qualipossiamoidentificarelanaturadeltipoinquestioneeillivellodiaccessibilità.

GetProperty()GetProperties()GetField()Get-Fields()GetMethod()

GetMethods()GetConstructor()GetConstructors()GetEvent()

GetEvents()

Restituiscono oggetti che derivano dalla classeMemberInfo, rappresentativi rispettivamente diproprietà, campi, metodi, costruttori ed eventi. E’possibile recuperare tutti questi elementi oricercarne uno in particolare in base al nome e, inseguito,utilizzarel’oggettoottenutopermanipolareocreareun’istanzadeltipostesso.

FindInterfaces()Restituisceunelencodelle interfacce implementatedaltipo.

IsInstanceOfType(oasObject)RestituisceTrue se l’argomentoèun’istanzavalidaperiltipo.

IsAssignableFrom(tasType)RestituisceTrue nel caso in cui un’istanza del tipofornitocomeargomentosiaassegnabilealtipo.

System.Type è una classe astratta, quindi non è possibile istanziarla direttamente;l’esempio 7.17, tuttavia, mostra le diverse modalità grazie alle quali è possibilerecuperarneun’istanzavalida.

Esempio7.17DimintegerTypeAsType

'Utilizzodell'istruzioneGetType

integerType=GetType(Integer)

'UtilizzodelmetodoObject.GetType()apartire

'daun'istanzadell'oggetto

DimvalueAsInteger=5

integerType=value.GetType()

'UtilizzodelmetodoType.GetTypeapartire

'dalnomeinformatostringadeltipo

integerType=Type.GetType("System.Int32")

L’ultimarigadicodice,inparticolare,èunpiccoloesempiodicomesiapossibilesfruttarereflection per dotare le nostre applicazioni di codice dinamico: come vedremo nelleprossimepagine,apartiredalsemplicenomediuntipo,siaessoinseritodall’utenteinunafinestradidialogoolettodaunfilediconfigurazione,siamoinfattiingradodirecuperarelarelativadefinizioneesuccessivamenteinteragireconesso.

Page 185: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ScritturadicodicedinamicoQuando si parla di codice dinamico, s’intende comunemente indicare la possibilità dieseguire istruzioni che in fase di compilazione non siano ancora note: si tratta di unacaratteristica che non appartiene a nessuno degli esempi che abbiamo avuto modo dianalizzare finoaquestopuntodel libro, tutticaratterizzatidal fattochecodicescritto inVisualBasicvenivacompilatoinMSILememorizzatoall’internodiunassemblyinformastatica. Nei prossimi paragrafi vedremo le differenti modalità messe a disposizione daVisualBasicperscriverecodicedinamico.

RealizzazionedicodicedinamicoconreflectionAbbiamo già visto, nel precedente esempio 7.17, come possiamo utilizzare il metodoType.GetType() per ottenere il riferimento a un particolare tipo, dato il suo nome informato stringa. Supponiamo allora di aver realizzato una libreria di classi chiamataClassLibrary,all’internodellaqualesiapresentel’oggettoPersondell’esempio7.18.

Esempio7.18PublicClassPerson

PublicPropertyNameAsString

PublicPropertyAgeAsInteger

PublicOverridesFunctionToString()AsString

ReturnString.Format("{0}ha{1}anni",Name,Age)

EndFunction

EndClass

Perutilizzarequest’oggettodaun’applicazioneconsole,unavoltaarrivatiaquestopunto,è sufficienteutilizzare ivarimetodipresentati in tabella7.2 per costruirne, ad esempio,un’istanza e interagire con i suoi membri, e il tutto funziona anche se la nostraapplicazionenonpossiedeunareferenceversol’assemblyincuiPersonèdefinito.

Esempio7.19'Recuperiamounriferimentoaltipo

DimpersonTypeAsType=

Type.GetType("ClassLibrary.Person,ClassLibrary")

'Tramiteilcostruttoredidefault(senzaparametri)

'necostruiamoun'istanza

DimconstructorAsConstructorInfo=

personType.GetConstructor(Type.EmptyTypes)

Page 186: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DimpersonAsObject=constructor.Invoke(Nothing)

'TramitePropertyInfovalorizziamoNameeAge

DimnamePropertyAsPropertyInfo=

personType.GetProperty("Name")

nameProperty.SetValue(person,"MarcoDeSanctis",Nothing)

DimagePropertyAsPropertyInfo=

personType.GetProperty("Age")

ageProperty.SetValue(person,33,Nothing)

'VisualizziamosuConsoleilrisultatodiPerson.ToString()

Console.WriteLine(person.ToString())

Come possiamo notare nel’esempio 7.19, a partire da un Type siamo in grado direcuperare oggetti quali PropertyInfo, ConstructorInfo (e, oltre a questi, anche icorrispettividimetodi,campiedeventi)semplicemente inbaseal loronomee,di fatto,utilizzarli per costruire un’istanza di Person, valorizzarla e visualizzare l’output delmetodoToStringsullaconsole,realizzandoquindialgoritmichenonsarebberopossibiliconcodicestatico.

In alternativa all’utilizzo esplicito di ConstructorInfo, nel caso di costruttori senzaparametri può essere utilizzata la classe Activator, per ottenere un’istanza del tipodesiderato:

'Creazionediun'istanzadiperson

DimpersonTypeAsType=

Type.GetType("ClassLibrary.Person,ClassLibrary")DimpersonAsObject=Activator.CreateInstance(personType)

Una tale versatilità si paga tuttavia in termini di performance, essendo l’utilizzo direflectionpiuttostoonerosoesoprattuttoperchéilcodicescrittoinquestomodononèpiùfortemente tipizzato: assegnare un valore stringa alla proprietà Age, ad esempio, risultaperfettamentelecitoinfasedicompilazione,datocheilmetodoPropertyInfo.SetValueaccettaungenericotipoObject,maprovocheràunerrorearuntime.

CodicedinamicoconilLateBindingdiVisualBasicUno dei consigli in assoluto più comuni, quando si sviluppa un’applicazione in VisualBasic,èquellodiattivarel’opzioneStrictdelcompilatoretramiteladirettiva

OptionStrictOn

inmododaforzarelascritturadicodicefortementetipizzato,facendosìcheassegnazionie invocazioni di metodi possano essere risolte direttamente in fase di compilazione.Questotipodiapproccioèchiamatoearlybinding.

In alcuni (rari) casi, soprattutto quando si fa uso di codice dinamico simile a quello

Page 187: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

visto in precedenza, può risultare comodo disattivare questa opzione, in modo che ilcompilatore dilazioni fino al runtime la risoluzione dei metodi e dei campi utilizzati,usandolatecnicachiamata latebinding. Inquestomodo,quindi, ilcodicedell’esempioprecedentepuòessereriscrittoinunaformanotevolmentepiùconcisa.

Esempio7.20'Creazionediun'istanzadiperson

DimpersonTypeAsType=

Type.GetType("ClassLibrary.Person,ClassLibrary")DimpersonAsObject=Activator.CreateInstance(personType)

'Utilizzodell'oggetto

person.Name="MarcoDeSanctis"

person.Age=33

Console.WriteLine(person.ToString())

Nell’esempio7.20,comeavvenivainprecedenza,abbiamocreatoun’istanzadell’oggettoPerson tramite reflection, definendola come Object a causa del fatto che la nostraapplicazione non possiede un riferimento all’assembly dove Person è definito.Successivamenteperò,grazieal fattodiaverattivato il latebinding,possiamoutilizzaredirettamenteleproprietàNameeAge.

Se avessimo lasciato Option Strict On, infatti, questo codice non compilerebbe,poichéquestedueproprietànonappartengonoaltipoObject.Pertanto,ancheseaprimavista può non sembrare così, anche quello dell’esempio 7.20 è, a tutti gli effetti, daconsiderarsi codice dinamico, visto che fa uso di proprietà la cui effettiva esistenzadipendedalparticolarerisultatodelmetodoCreateInstancee,pertanto,sarànotasoloaruntime.

LeclassiDynamicObjecteExpandoObjectIllatebindingdiVisualBasic,inultimaanalisiutilizzareflectionperassociarearuntimeil nome di un membro alla relativa definizione all’interno della classe; il risultato,tornando al precedente esempio 7.18, è che Name e Age devono essere effettivamenteproprietàdefiniteall’internodeltipoPerson,penaunerrorearuntime.

In alcuni casi, invece, può essere comodovolermodificare questo comportamento didefault, intervenendo sulle logiche secondo le quali il meccanismo di late binding diVisualBasicfunzionapercreareoggettidinamici,incuipossiamoavereiltotalecontrollosulle modalità di risoluzione di questi riferimenti. Un risultato di questo tipo si puòottenerecreandounaclassecheereditidaltipoDynamicObject,comeaccadeperlaclassenell’esempio7.21.

Page 188: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio7.21PublicClassMyDynamicObject

InheritsDynamicObject

PublicOverridesFunctionTryGetMember(

ByValbinderAsGetMemberBinder,

ByRefresultAsObject)AsBoolean

result="Property"+binder.Name

ReturnTrue

EndFunction

PublicOverridesFunctionTryInvokeMember(

ByValbinderAsInvokeMemberBinder,ByValargs()AsObject,

ByRefresultAsObject)AsBoolean

result="Method"+binder.Name

ReturnTrue

EndFunction

EndClass

ModuleModule1

SubMain()

DimmyObjectAsObject=NewMyDynamicObject()

Console.WriteLine(myObject.Property1)

Console.WriteLine(myObject.SomeMethod("Test"))

EndSub

EndModule

DynamicObjectesponealcunimetodichevengonoeseguitiinconseguenzadiuntentativodilatebinding,chepossiamoridefinireperplasmarneilfunzionamentosecondolenostrenecessità. MyDynamicObject, ad esempio, effettua l’override di TryGetMember eTryInvokeMember, utilizzati rispettivamente in fase di lettura di una proprietà edesecuzionediunmetodo, ritornando,come risultato,unastringacontenente ilnomedelmembrostesso.Ilrisultatodell’esecuzionedell’esempio7.21èmostratoinfigura7.5.

Page 189: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura7.5–UtilizzodiDynamicObject.

La classe DynamicObject può, in fin dei conti, essere utilizzata per realizzare classidinamiche,privecioédiunastrutturafissa,madiutilizzogeneraleechepossiamoquindiplasmare a runtime secondo le nostre necessità. Per contro, però, si tratta di una classeastratta e, come tale, è possibile sfruttarla solo come classe base di un nostro tipopersonalizzato,costringendociquindi,difatto,ascriveredelcodice.

UnoggettosimilenegliscopiaDynamicObject,mapercontrogiàdotatodiunalogicaingradodirenderlodirettamenteutilizzabilenelcodice,èExpandoObject,unaclasseicuimembri, sianoessimetodi,proprietàoeventi,possonoesseredinamicamenteaggiunti erimossiaruntime,comemostral’esempio7.22.

Esempio7.22DimmyObjectAsObject=NewExpandoObject()

myObject.ToText=Function()_

String.Format("{0}ha{1}anni",myObject.Name,myObject.Age)

myObject.Name="MarcoDeSanctis"

myObject.Age=30

Console.WriteLine(myObject.ToText.Invoke)

SiaDynamicObjectsiaExpandoObject,comeabbiamopiùvolteavutomododiaccennare,sfruttanoimeccanismidilatebindingdiVisualBasice,pertanto,richiedonochel’opzioneStrictsiaimpostataaOff.

Le funzionalità sin qui mostrate consentono di limitare al massimo le informazionifornite al compilatore e di scrivere codice anche quando le definizioni degli oggettiutilizzatisonoincompleteo,addirittura,assenti.Ilprossimoparagrafoinvecetratteràdiunargomento che, in un certo senso, si muove in una direzione opposta, garantendoci lapossibilità di integrare ulteriormente imetadati dei nostri tipi, grazie all’uso di specialistrumenti:gliattributi.

Page 190: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

CodicedichiarativotramitegliattributiNelle prime pagine di questo capitolo, quando abbiamo visto come costruire eccezionipersonalizzate,abbiamo incontratounaparticolarenotazione tramite laquale indicarealCLRchelaclasserealizzatapotevaessereserializzata:

<Serializable()>

PublicClassInvalidCustomerException

InheritsApplicationException

...

EndClass

Taledichiarazioneèrealizzataconl’ausiliodiunoggettoparticolare,dettoattributo,cheviene utilizzato per integrare i metadati associati alla definizione diInvalidCustomerException; la classe SerializableAttribute non implementa alcuntipo di funzionalità particolare ed è totalmente estranea alla logica del tipo a cui èassociata. Svolge, in pratica, semplicemente la funzione di marcatore, in modo che unoggetto interessato a determinare se InvalidCustomerException sia serializzabile omeno,possascoprirlovisionandogliattributiaessoassociati.

I nomi delle classi che rappresentano attributi terminano convenzionalmentecon il suffisso Attribute. Quando vengono utilizzate, questo suffisso puòfacoltativamente essere omesso e questa è la ragione per cui nel codiceprecedente si è potuto scrivere Serializable invece cheSerializableAttribute.E’indifferenteutilizzarel’unool’altroidentificativo.

Gliattributipossonoessereassociatiadiversielementidicodice;l’esempio7.23mostraalcunitipicicasidiutilizzo.

Esempio7.23'Alivellodiassembly

<Assembly:AssemblyVersion("1.0.0.0")>

'Alivellodiclasse

<Serializable()>

PublicClassSomeClass

'Alivellodiproprietà

<XmlIgnore()>

PublicPropertyMyPropertyAsString

'Alivellodifield

<NonSerialized()>

PrivatemyFieldAsString

'Alivellodiargomentodiunmetodo

PublicSubSomeMethod(

<MarshalAs(UnmanagedType.LPWStr)>ByValvalueAsString)

Page 191: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'...

EndSub

EndClass

Gliargomentichepossiamospecificaresonoquellicorrispondentiaidiversioverloaddelcostruttore;nonènecessarioperòcheneesistaunoperognipossibilecombinazionedelleproprietà da valorizzare, dato che è eventualmente possibile utilizzare la sintassidell’esempio7.24perspecificarequellenonesplicitamentepreviste.

Esempio7.24<WebMethod(BufferResponse:=True)>

PublicSubSomeMethod()

'...

EndSub

Quandoutilizziamogliattributi,comunque,nondobbiamomaidimenticare la lororealenatura,ossiaquelladimetadati aggiuntivi aquelligiàprevistidalCLR.Come tali,nonvengonovalutatiaruntime:essendostrutturestatiche,quindi,èpossibilevalorizzarlesolocondaticostantiocondeitipi.Èquindilecitoscriverequalcosacome

<MyAttribute("Test",SomeType:=GetType(Integer))>

mentre non è invece possibile scrivere espressioni che necessitino una valutazione aruntime:

<MyAttribute("Test",newDateTime(2000,1,1))>'NONcompila

L’uso degli attributi può essere un’ottima scelta in tutte le casistiche in cui stiamorealizzando delle API e vogliamo fornire all’utilizzatore la possibilità di utilizzare deimarcatori all’interno del codice, in modo che possiamo poi valutarli a runtime, dandoquindil’illusionediscriverecodicedichiarativo.Unesempiopraticodiquestatecnicahacomeprerequisito l’argomentodelprossimoparagrafo,ossia lacreazionediunattributopersonalizzato.

Costruireeusareattributicustom:laclasseSystem.AttributeImmaginiamo,adesempio,divolerrealizzareunsistemaingradodiprodurreunatabelladauna listadioggettieche,perogniproprietà,vogliamoessere ingradodi specificarel’intestazionedellarelativacolonna.

L’ideaèdirealizzareuncustomattributeingradodimemorizzarequesteinformazioni,cosìchel’utilizzatorechevogliafarusodellanostrafunzionalitàsilimitiaindicarlesulleproprietà dell’oggetto da rappresentare. Per costruire un oggetto di questo tipo nondobbiamo far altro che realizzare una classe che erediti da System.Attribute, come

Page 192: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

quelladell’esempio7.25.

Esempio7.25<AttributeUsage(AttributeTargets.Property, AllowMultiple:=False)> Public

ClassReportPropertyAttribute

InheritsAttribute

PublicPropertyHeaderAsString

PublicSubNew(ByValheaderAsString)

Me.Header=header

EndSub

EndClass

Oltre a rispettare la convenzione sul naming del tipo, che richiede l’uso del suffissoAttribute,abbiamospecificato tramite l’attributoAttributeUsage imembriper iqualivogliamo dare la possibilità di utilizzare il nostro ReportPropertyAttribute, pena unerrore in fase di compilazione: nel nostro caso sarà possibile utilizzarlo per decorareproprietà,indicandolo,alpiù,unasolavolta.L’esempio7.26nemostrauntipicoutilizzo.

Esempio7.26PublicClassPerson

<ReportProperty("Nome")>

PublicPropertyFirstNameAsString

<ReportProperty("Cognome")>

PublicPropertyLastNameAsString

<ReportProperty("Età")>

PublicPropertyAgeAsInteger

EndClass

Aquestopunto,affinchélanostralibreriadireportingsiaeffettivamenterealizzabile,restasolodacapirecomeleggerequestimetadatiaruntime,ossiautilizzandoreflection.

Esempio7.27PublicFunctionBuildReport(OfT)(

ByValitemsAsIEnumerable(OfT))AsString

DimheadersAsNewDictionary(OfPropertyInfo,String)

ForEachpropAsPropertyInfoInGetType(T).GetProperties()

Dimattributes()AsObject=

prop.GetCustomAttributes(GetType(ReportPropertyAttribute),True)

Page 193: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

If(attributes.Length>0)Then

DimreportAttributeAsReportPropertyAttribute=

DirectCast(attributes(0),ReportPropertyAttribute)

headers.Add(prop,reportAttribute.Header)

EndIf

Next

'...Quilogicaperprodurreilreportinbase

'alcontenutodeldictionaryheaders…

EndFunction

L’esempio7.27mostra ladefinizionediunmetodogenericoBuildReport che riceve iningressounalistadioggettiperprodurreunelencoinformatoString.Tramitereflection,esso scorre tutte le proprietà del tipo in ingresso e, per ognuna di esse, usa il metodoGetCustomAttributes per ricercare attributi di tipo ReportPropertyAttribute in unoqualsiasideglioggettidellagerarchiadiTe, incasoaffermativo,neutilizza laproprietàHeaderperpopolareundictionary,chepotremopoiutilizzareperlaveraeproprialogicadigenerazionedelreport,quiomessapersemplicità.

Si trattadiunsempliceesempio,che tuttaviamette in luce lepotenzialitàdeicustomattributes:grazieadessi, infatti, siamostati ingradodi realizzareunmetododiutilizzogenerale, che uno sviluppatore può sfruttare semplicemente indicando, in manieradichiarativa,leproprietàdaincluderenelreportelarelativaintestazione.

Grazie alle potenzialità di Visual Studio 2015, in realtà, possiamo spingerci ancoraoltre, arrivando a controllare persino il processo di interpretazione e compilazione delcodice: accenneremo a queste funzioni avanzate nella prossima sezione, dedicata aRoslyn.

Ilcompilatorecomeservizio:RoslynL’introduzionediRoslynnel.NETFrameworkrappresentaunaveraepropriarivoluzionecopernicananell’ambitodellosvilupposoftware.Perlaprimavolta,infatti,siamoingradodiinterfacciarciesfruttare,all’internodelnostrocodice,uncomponentedell’ambientedisviluppo che abbiamo utilizzato migliaia di volte come se fosse una scatola nera: ilcompilatore.

Roslynèunaseriedi librerie,rigorosamenteopensourceescaricabilidaGitHub,chemappano levarie fasidelprocessodi compilazionedel codice, apartiredalparsingdeltestofinoallagenerazionedegliassembly.

Lepossibilitàchesiapronosonoinfinite,bastipensarechegranpartedellefunzionalitàdi Visual Studio, dal refactoring all’intellisense, sono basate su questa libreria. Almomentodellascritturadiquestotesto,ètuttoancorainfasedipreview,equindinontuttele featuresonodisponibili. Inparticolare,sonoesposteesclusivamente le funzionalitàdiparsing e tokenizzazione del codice, mentre, per esempio, per la generazione diMSIL

Page 194: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

compilatodovremoattendereunaversionesuccessiva.

Tuttavia, nonostante queste limitazioni, possiamo comunque fare qualche piccoloesperimentoperprendereconfidenzaconRoslyn.

InstallazioneeprimipassiconRoslynLaprimaoperazioneèquelladieffettuareildownloadel’installazionedeitoolinVisualStudio. Come detto, Roslyn è completamente open source, e pertanto codice edocumentazione sono disponibili in hosting su GitHub, all’indirizzohttp://aspit.co/a6l.

PerpoteriniziareautilizzarloconVisualStudio2015,però,dobbiamoscaricareil.NETCompiler SDK, disponibile all’indirizzo http://aspit.co/a6q: esso installa tutte lelibrerie necessarie, alcuni nuovi template di progetto e il SyntaxVisualizer, tramite cuipossiamovederelefunzionalitàdiparsingall’operaconilnostrocodice,inrealtime.

Una volta completate le procedure di installazione, proviamo ad aprire un progettoqualsiasi e a visualizzare il Syntax Visualizer tramite il menù View, Other Windows,SyntaxVisualizer.Siapriràunafinestrasimileaquelladellafigura7.6,suddivisaindueporzioni:quella inaltomostra l’alberaturadeglioggetti individuatidaRoslyn,quella inbasso,unavoltaevidenziatounelemento,indicalevarieproprietà,peresempio,sec’èunerroredisintassiolaposizionedeicaratteriall’internodeltesto.

Figura7.6–SyntaxVisualizerinVisualStudio2015.

IlSyntaxVisualizerè interattivo:manmanochecispostiamonelcodice, infatti,essosiaggiornapervisualizzareilnodocorrispondenteallaposizionedelcursore.Inmanieradeltuttoanaloga,possiamoanchecliccaresuunnodopervedereiltestorelativoevidenziatonell’editordicodice.

Page 195: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Se ora proviamo a modificare il testo, introducendo un errore, il visualizzatore siaggiorneràdiconseguenza,mostrandoinmanieraevidenziataalcunedellerighechesonostateimpattatedaesso.Peresempio,seeliminiamolaparolachiaveAsprimadiIntegernelladichiarazionediAge,ilrisultatosaràquellochepossiamovederenellafigura7.7.

Figura7.7–ErroredisintassinelSyntaxVisualizer.

Come possiamo notare, Roslyn è ancora in grado di interpretare la totalità del nostrocodice,edigenerareilSyntaxTree.Alcunielementi,tuttavia,sonosegnalaticomeerrati,acausadell’erroredisintassicheabbiamointrodotto.

Questeinformazionipossonoesseremoltoutilisevogliamo,peresempio,realizzareunadd-on per Visual Studio che, sfruttando Roslyn, fornisca funzionalità di generazioneautomaticadelcodiceodirefactoring.

AnalisidellasintassiOvviamentepossiamo invocarequesteAPIanchedacodiceVisualBasic,per effettuareanalisi sintattica, semantica e anche riscrittura emodifica del codice. Questi argomentisonoparecchioavanzatiefuoridagliobiettividiquestolibro,tuttaviapossiamocapirelepotenzialitàdiRoslynancheconunsempliceesempio.CreiamoquindiunnuovoprogettoditipoCodeAnalysisTool(all’internodelgruppoExtensibility)eproviamoascrivereilcodicedell’esempio7.28:

Esempio7.28ModuleModule1

SubMain()

Page 196: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DimSyntaxTree=VisualBasicSyntaxTree.ParseText(">

PublicClassTest

PublicPropertyMyPropertyAsString

EndClass")

Dimroot=SyntaxTree.GetRoot()

DimNodes=root.DescendantNodes()

EndSub

EndModule

Questoesempiocostruisceunsyntax treeapartiredaunveroepropriobloccodi testo:grazie al metodo ParseText di VisualBasicSyntaxTree, infatti, possiamo chiedere alcompilatorediinterpretareilcontenutodiunastringaeanalizzarlo,generandounalberodeltuttoanalogoaquellocheabbiamovistonellasezioneprecedente.

Possiamo verificarlo semplicemente eseguendo l’esempio e mettendo un breakpointnell’ultimariga.Almomentolefunzionalitàsonoancorainfasedisviluppo(lalibreriaèancora in preview), ma in un rilascio successivo sarà anche possibile emettere codiceMSIL,apartiredatesto,edeseguirlo.

ConclusioniNella prima parte del capitolo abbiamo illustrato come le applicazioni basate sul .NETFrameworkpossano avvalersi di un sistema strutturatoper la gestionedelle eccezioni aruntime: non siamo più costretti a controllare manualmente il corretto esitodell’esecuzione di unmetodo,ma è ilCommonLanguageRuntime stesso a notificarci,tramiteunsistemainteramentebasatosullamodellazioneaoggettidelconcettodierrore,eventualianomaliechesisonoverificate.

Ilnormaleflusso logicodell’applicazioneviene interrottoe, tramiteopportuniblocchidi codice, possiamo intercettare particolari eccezioni per porre in atto opportunecontromisure,oppurepossiamodecideresemplicementedilimitarcialiberarerisorseperpoiinoltrarenuovamentel’errorelungotuttolostackdichiamate.

La seconda parte del capitolo è stata invece incentrata su concetti avanzati dellosviluppodiapplicazionitramiteVisualBasiceil.NETFrameworkingenerale.Abbiamomostratocome,tramitel’usodireflection,possiamorecuperarearuntimeinformazionisuitipi definiti all’interno di un assembly o come sfruttare il medesimo set di classi perinteragiredinamicamenteconoggetti.Èstatoquestoilprimoesempiodiprogrammazionedinamica, una tecnica avanzata di sviluppo che è implementabile anche trmite il latebinding di Visual Basic. Infine, abbiamo introdotto due classi, DynamicObject edExpandObject,chepossiamosfruttareperrealizzaretipiingradodimodificarelapropriastrutturaaruntime.

Successivamenteabbiamotrattatogliattributi,grazieaiqualicièpossibileintegrareimetadatideglioggetticondelleulterioriinformazioni,chepossonopoiessererecuperate

Page 197: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

tramite reflection. Questa infrastruttura consente di realizzare codice dichiarativo congrandefacilità,comeabbiamoavutomododiapprezzarerealizzandounmetodoingradodiprodurrereportgenericibasandosisull’usodiattributipersonalizzati.

Nell’ultimaparte,abbiamoaccennatoaRoslyn,unalibreriachepuòesseredescrittaconlafrase“CompilerasaService”:sitrattainfattidiunaseriediAPI,tramitecuipossiamoaccedereallefunzionalitàdelcompilatore,comeparseretokenizer.SitrattadiunprogettoOpenSourcemoltobendocumentato,mediante il qualepossiamo realizzare add-onperVisualStudio, comenuovi refactoringogeneratoridi codice.Abbiamovisto come,unavolta installato l’SDK, abbiamo a disposizione un Syntax Visualizer che ci aiuta nellacomprensionedell’objectmodeledelfunzionamentodelparser.

Il prossimo capitolo servirà invece a presentare una delle peculiarità in assoluto piùinteressantieutilizzatedel.NETFramework,chetrovaapplicazioneinunampiospettrodisituazioni,dallagestionedeglioggetti inmemoriafinoall’interrogazionedellebasididati:LINQ.

Page 198: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

8

EseguirequerynelcodiceconLINQ

FinoaquestopuntoabbiamoanalizzatolastrutturaelepotenzialitàdellinguaggioVisualBasic. Da questo capitolo cominciamo a mettere in pratica quanto abbiamo imparato,sfruttandounodegliautenticigioiellidel.NETFramework:LINQ.

Una delle più grandi feature del .NET Framework è senza dubbio LINQ (LanguageINtegratedQuery),ovverounatecnologiarealizzataperpermetterelaricercaall’internodiqualunquestrutturadati,sfruttandodirettamenteillinguaggio.Grazieaquestatecnologia,possiamo scrivere query tipizzate per ricercare dati in una lista di oggetti, nodi in unastrutturaXMLotabelleinundatabaseSQL.

Inoltre,grazieallatipizzazione,VisualStudiopuòfornirel’intellisenseeilcompilatorepuò eseguire il controllo immediatamente, individuando gli errori senza la necessità dieseguire l’applicazione. Queste caratteristiche incrementano notevolmente la nostraproduttivitàecipermettonodiscriverecodicevicinoallostilefunzionale.

Nel corso del capitolo vedremo come LINQ permetta di risparmiare una enormequantitàdicodice, rendendoloanchepiù leggibile (qualoranonneabusiamo).Grazieaivarimetodimessi a disposizione, possiamo svolgere inmanieramolto più semplice edelegantenonsololericerchemaanchemoltealtreoperazioni.

LINQ si basa su caratteristiche del .NET Framework quali lambda expression,extensionmethod,anonymoustypeeobject,collectioninitializerearrayinitializer, tuttefunzionalitàchesonostateampiamentetrattateneiprecedenticapitoli.Èimportantedireche molte di queste funzionalità sono state create proprio per rendere il più semplicepossibilel’utilizzodiLINQ.

IperchédiLINQQualunqueapplicazionedevemanipolaredati.Perloronatura,questidatipossonoesserememorizzatiindiversiformatieindiversitipidistorage.Molteapplicazionisalvanoidatisu un database, altre utilizzano file XML, mentre altre ancora sono astratte dallapersistenza dei dati tramite web service. In più, tutte queste tipologie di applicazionespessotrattanoancheidatiinmemoriaehannobisognodicompiereoperazionisuquestiultimi.

Ilveroproblema,inquesteapplicazioni,èchedobbiamousareAPIdifferentiperognitipodi dato da trattare. Alla fine però quello che dobbiamo eseguire è semplicemente un

Page 199: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

accessoaidati.Partendodaquestopresupposto,Microsofthalavoratoaunapiattaformache permettesse di effettuare query allo stessomodo, qualunque fosse il tipo di storagesottostante:XML,database,webservice,oggettiinmemoria.QuestapiattaformaèLINQ.

Un’altra idea che ha guidatoMicrosoft nella creazione di LINQ è l’integrazione neilinguaggidiprogrammazione.Inquestomodoilcompilatoreèingradodicontrollarelequeryscritteedirestituireeventualierrorigiàinfasedicompilazione.

Ilrisultatoècheilcodicediinterrogazionediventaunivocoecipermettediignorarelediversitàdellostoragedeidati.Lafigura8.1mostracomeLINQottengaquestorisultato.

Figura8.1–LastrutturadiLINQ.

LINQ ha diversi flavor. LINQ to Objects permette di eseguire query su oggetti inmemoria. LINQ to Dataset abilita query su oggetti DataSet. LINQ to SQL e LINQ toEntitiesabilitanoqueryversoundatabasee, infine,LINQtoXMLpermettedieseguirequeryversostruttureXML.

IflavourdiLINQsonotrasparentiperilprogrammatore.Anchesealcuniaggiungonoulteriorifunzionalità,labaseècomuneatutti.NelcorsodiquestocapitoloanalizzeremosoloLINQtoObjects,vistocheglialtriflavorverrannoanalizzatineicapitolisuccessivi.

PrimadivedereLINQ inazione,diamouno sguardoall’internodiquesta tecnologia,percapirecomefunziona.

ComefunzionaLINQAllabasediLINQvièlaclasseEnumerable,situatanelnamespaceSystem.Linq.Questaclassecontieneunaseriediextensionmethodcheestendonol’interfacciaIEnumerable(OfT),aggiungendoimetodichevengonoutilizzatinellequery.Poichénel.NETFrameworkogni lista generica implementa, direttamente o indirettamente, l’interfaccia

Page 200: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IEnumerable(Of T), automaticamente ogni lista generica è interrogabile via LINQ.Inoltre, la classe Enumerable contiene anche i metodi che estendono l’interfacciaIEnumerablenongenerica,consentendodiotteneredaquest’ultimaunaversionegenericapronta per essere interrogata.Grazie a questo designdelle classi e senza alcuno sforzo,abbiamoadisposizioneilmotorediinterrogazione,integratodirettamentenellinguaggio.

Inoltre, molti dei metodi presenti nella classe Enumerable sono funzioni che, a lorovolta, restituiscono un oggetto IEnumerable(Of T) e quindi rendono possibile laconcatenazionedipiùmetodinellastessaquery.IlfunzionamentobasediLINQstatuttoqui;noncisonoaltrecosedacapire.

SepoivogliamoentrarenelmeritodialcunespecializzazionidiLINQ,comeLINQtoSQLeLINQ toEntities, cominciamoad avere a che fare conExpressionTree eLINQProvider.Inpocheparole,primalaqueryvieneconvertitainunalberodifunzioniepoiilLINQ Provider si preoccupa di trasformare questa struttura ad albero in un’entità chepossainterrogarelasorgentedatipercuiilproviderèrealizzato.NelcasodiLINQtoSQLl’albero viene trasformato in un comando SQL mentre, nel caso di LINQ to Entities,l’albero viene trasformato in un linguaggio di interrogazione dello schema logico (vedicapitolo11).

Potenzialmente,grazieaquestastruttura,possiamointerrogaresorgentidatidiognitipocomewebservice,motoridiricerca,ActiveDirectory,NHibernate,JSON,Excelemoltoaltro ancora. Molti di questi provider sono stati già realizzati da terze parti e sonofacilmenterintracciabilisulweb.

Sul sito di LINQItalia.com è disponibile un ottimo articolo che spiega comecreareunLINQproviderpersonalizzatopereffettuarequeryversoilmotorediricercaLiveSearch.Lotrovateall’URL:http://aspit.co/aei.

Ora che abbiamo compreso il funzionamento interno di LINQ, possiamo cominciare ascrivere query. Prima però, diamo un veloce sguardo alla struttura degli oggetti su cuiandremoaeseguireleinterrogazioni.

Introduzioneall’esempiodelcapitoloNelcorsodelcapitolo,ilmodelloaoggettisucuieseguiamolequeryprevedeunaclasseOrdine,checontieneunaproprietàDettagliconlalistadeidettaglidell’ordine.Lalistadegliordinièvalorizzatacomenell’esempio8.1.

Esempio8.1Dimdettaglil()AsDettaglioOrdine={

NewDettaglioOrdineWith{.Id=1,.Prezzo=50,.Quantita=10,

.Prodotto=NewProdottoWith{.Id=1,.Nome="Scarpe"}},

NewDettaglioOrdineWith{.Id=2,.Prezzo=30,.Quantita=1,

Page 201: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

.Prodotto=NewProdottoWith{.Id=2,.Nome="Calzini"}},

NewDettaglioOrdineWith{.Id=3,.Prezzo=12,.Quantita=13,

.Prodotto=NewProdottoWith{.Id=3,.Nome="Cappelli"}}

}

Dimdettagli2()AsDettaglioOrdine={

NewDettaglioOrdineWith{.Id=4,.Prezzo=32,.Quantita=18,

.Prodotto=NewProdottoWith{.Id=1,.Nome="Scarpe"}},

NewDettaglioOrdineWith{.Id=5,.Prezzo=15,.Quantita=4,

.Prodotto=NewProdottoWith{.Id=3,.Nome="Cappelli"}}

}

Dimdettagli3()AsDettaglioOrdine={

NewDettaglioOrdineWith{.Id=6,.Prezzo=2,.Quantita=9,

.Prodotto=NewProdottoWith{.Id=2,.Nome="Calzini"}},

NewDettaglioOrdineWith{.Id=7,.Prezzo=15,.Quantita=4,

.Prodotto=NewProdottoWith{.Id=4,.Nome="Magliette"}},

NewDettaglioOrdineWith{.Id=8,.Prezzo=21,.Quantita=150,

.Prodotto=NewProdottoWith{.Id=5,.Nome="Occhiali"}},

NewDettaglioOrdineWith{.Id=9,.Prezzo=1,.Quantita=400,

.Prodotto=NewProdottoWith{.Id=6,.Nome="Polsini"}},

NewDettaglioOrdineWith{.Id=10,.Prezzo=3,.Quantita=84,

.Prodotto=NewProdottoWith{.Id=7,.Nome="Pantaloncini"}}

}

Dimdettagli4()AsDettaglioOrdine={

NewDettaglioOrdineWith{.Id=11,.Prezzo=2,.Quantita=30,

.Prodotto=NewProdottoWith{.Id=2,.Nome="Calzini"}},

NewDettaglioOrdineWith{.Id=12,.Prezzo=2,.Quantita=2,

.Prodotto=NewProdottoWith{.Id=7,.Nome="Pantaloncini"}}

}

ordini.Add(NewOrdineWith{

.Id=1,.Data=DateTime.Now,.Dettagli=dettagli1

})

ordini.Add(NewOrdineWith{

.Id=2,.Data=DateTime.Now.AddDays(-10),.Dettagli=dettagli2

})

ordini.Add(NewOrdineWith{

.Id=3,.Data=DateTime.Now.AddDays(-5),.Dettagli=dettagli3

})

Page 202: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ordini.Add(NewOrdineExWith{

.Id = 4, .IsInternational = True, .Data = DateTime.Now.AddDays(-5),

.Dettagli=dettagli4

})

Oltreallalistadeglioggettidainterrogare,primadieseguireunaquerydobbiamoanchesapere quali sono i metodi di LINQ. Nella prossima sezione ci occuperemo di questoproblema.

GliextensionmethoddiLINQGliextensionmethodmessi adisposizionedaLINQsono tantissimie sonosuddivisi incategorieasecondadelloroscopo.Questimetodisonoriportatinellatabella8.1.

Tabella8.1–GliextensionmethoddiLINQ(inordinedicategoria).

Tipologia Operatori

Aggregazione Aggregate,Average,Count,LongCount,Max,Min,Sum

Concatenamento Concat,Zip

Conversione Cast,ToArray,ToDictionary,ToList,ToLookup

Elemento DefaultIfEmpty, ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault,

Single,SingleOrDefault

Generazione Empty,Range,Repeat,

Intersezione GroupJoin,Join

Ordinamento OrderBy,ThenBy,OrderByDescending,ThenByDescending,Reverse

Partizionamento Skip,SkipWhile,Take,TakeWhile

Proiezione Select,SelectMany

Quantificazione All,Any,Contains

Uguaglianza SequenceEqual

Raggruppamento GroupBy

Restrizione OfType,Where

Insieme Distinct,Except,Union,Intersect

Dalla tabella possiamo desumere tutte le informazioni per eseguire query nel codice:quindi,dallaprossimasezione,potremofinalmenteiniziareautilizzareLINQ.

LafilosofiaallabaseLINQPer capire la filosofia che sta alla base di LINQ, è meglio partire direttamente da unesempio,inmododarendereiltuttopiùsemplicedacomprendere.Prendiamolaseguentequery.

Esempio8.2

Page 203: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dimo=Ordini.

Where(Function(w)w.Id=1).

Select(Function(s)NewWith{s.Data,s.Id})

QuestaqueryLINQprendelalistadegliordini,ricercal’ordineconlaproprietàIdugualea1eritornaunanonymoustypeconlesoleproprietàDataeId.Senzaentraretroppoindettaglio,visonoalcunecosechedobbiamoapprofondire.

Innanzitutto l’intellisense. Come detto nell’introduzione del capitolo, Visual Studiooffre il pieno supporto a LINQ. Questo vale sia per gli extension method sia per leproprietàdelleclassiinterrogate.

Perabilitaregliextensionmethodnelcodice,bisogna importare ilnamespaceSystem.LinqtramiteImports.

Figura8.2–IntellisenseinVisualStudioconVisualBasic.

IlsecondoconcettosulqualedobbiamosoffermarcièlacompletainnovazionediLINQinterminidimodalitàdiricerca.Nellaquerydell’esempio8.2,nonabbiamoscrittocomeilcodicedebbaeffettuare la ricerca,bensìabbiamoscrittocosadev’esserecercato; ilverolavorodiricercavienefattodalcodicedegliextensionmethod.Ilfattodiscriverecodicefunzionale e non imperativo rappresenta una novità per il mondo .NET al momentodell’uscitadiLINQerimanetutt’oraunagrandecaratteristica.

Laconcatenazionedipiùoperatorielapossibilitàdicrearnedipersonalizzatipermettediottenere, inuna solaqueryun risultatochealtrimenti richiederebbedi scriveremolterighedicodice.

OracheabbiamocapitocomescrivereunasemplicequeryconLINQ,possiamopassareallafasesuccessivaeapprofondireilfunzionamentodegliextensionmethod.

AnatomiadiunaqueryNell’esempio8.2èstatointrodottounprimoesempiodiricercadeidati.Laricercaèstataeffettuata tramite l’operatore Where, che permette di filtrare i dati. La firma di questometodo è, in effetti, molto più verbosa di quanto possa sembrare dal codice, comepossiamovederenell’esempio8.3.

Page 204: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio8.3PublicSharedFunctionWhere(OfTSource)(

ByValsourceAsIEnumerable(OfTSource),

ByValpredicateAsFunc(OfTSource,Boolean))

AsIEnumerable(OfTSource)

Innanzitutto, Where è un metodo generico ma nell’esempio 8.2 non vi è traccia delparametro. Questo è possibile grazie alla type inference in quanto, essendo la listainterrogatagenerica,ilcompilatoreutilizzaautomaticamenteiltipodellalista,evitandocididoverloscrivereesplicitamente.

IlmetodoWhere accettaun soloparametro in input.Questoparametroèunpredicatoche rappresenta lacondizione inbaseallaqualeeseguire il filtroedè formulato tramiteunalambdaexpression.IlpredicatochepassiamoininputalmetodoWherepossiedeunafirmaincuiilparametroininputèl’oggettocorrentedellalistaeilrisultatoinoutputèunBoolean,chespecificaselacondizionediricercaèsoddisfattaono.

La classe Func rappresenta un delegato che accetta da uno a diciassetteparametritipizzatitramitegenerics.L’ultimoparametrogenericorappresentailtipodiritornodeldelegato.

Ovviamente, i concetti appena visti sono applicabili non solo al metodo Where ma, ingenerale,atuttigliextensionmethod.

Finalmente abbiamo acquisito tutte le conoscenze di base indispensabili per scriverequalunquetipodiqueryequindi,daquiinavanti,esamineremoindettagliotuttiimetodidiLINQ.

GlioperatoridirestrizioneNel paragrafo precedente abbiamo già illustrato, in maniera abbastanza dettagliata,l’operatore Where, che è il più importante fra quelli che fanno parte della categoria inesame.Nelprossimoparagrafoutilizzeremoquestometodoconuntagliopiùpratico.

La lambda expression con cui esprimiamo il filtro è scritta in codice managed e,pertanto,possiamoinserirepiùcondizionidiricerca,comenelseguenteesempio.

Esempio8.4Dimresult=ordini.Where(Function(o)o.Id=1_

AndAlsoo.Data.Date=DateTime.Now.Date)

Molto spesso le query di ricerca sono dinamiche, nel senso che, in base a determinatecondizioni,dobbiamoapplicarealcunifiltrienonaltri.PoichéilmetodoWhereritornaunIEnumerable(OfT), il risultato della chiamata è nuovamente interrogabile con un’altra

Page 205: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

chiamataaunsecondometodoWhere,comemostral’esempio8.5.

Esempio8.5Dimresult=ordini.Where(Function(o)o.Id=1)

result=result.Where(Function(o)o.Data.Date=DateTime.Now.Date)

IlmetodoWherehaunsecondooverloadchesidifferenziadalprimoinquantocambialafirma del predicato. Infatti, il delegato, oltre che accettare in input l’oggetto della lista,accetta anche il suo indice. Questo può tornare pratico in scenari dove, per esempio,vogliamoprendere sologlioggetti con indicepariodispario, comunque,dove l’indicepuòessereunadiscriminante.Nelladefinizionedellalambda,ilsecondoparametrovieneseparatodalprimotramiteuncarattere“,”(virgola)enonnecessitadelladefinizionedeltipo, così come avviene già per il primo parametro, grazie sempre alla type inference.L’esempio8.6mostrailcodicechesfruttaquestooverload.

Esempio8.6Dimresult=ordini.Where(Function(o,i)iMod2=0)

L’altrooperatorechefapartediquellidirestrizioneèOfType,ilqualefiltraglioggettiinbaseadaltricriteri.

OfTypeIlsecondometododellacategoriadeglioperatoridirestrizioneèOfType.Questometodoserveperfiltrareglioggettiinunalistainbaseallorotipo.Ilmodoincuiquestometodocomparailtipodeglioggettièidenticoall’operatoreTypeOf..Is.Questosignificache,secerchiamo il tipo Ordine, ci vengono restituiti tutti gli oggetti Ordine e quelli che,direttamenteoindirettamente,ereditanodaquestaclasse.Seinvececerchiamoglioggettidi tipo OrdineEx allora viene restituito solo l’ordine con Id pari a 4. Se volessimorecuperareleistanzedeisolioggettiditipoOrdine,dovremmousareilmetodoWhereedeffettuare manualmente il controllo sul tipo. L’esempio 8.7 mostra l’utilizzo di questometodo.

Esempio8.7Dimres1=ordini.OfType(OfOrdine)()'Tornatuttiglioggetti

Dimres2=ordini.OfType(OfOrdineEx)()'Tornasolol'ordine4

La particolarità di questo metodo è che il tipo di oggetto che stiamo cercando non èspecificatotramiteunparametro,bensìtramitegenerics.

Ora che sappiamo come filtrare, passiamo a vedere come formattare l’output dellenostrequery.

Page 206: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

GlioperatoridiproiezioneGli operatori di proiezione permettono dimodificare il risultato di output di una query.Quandoeseguiamounaquerysuunalistagenerica,ilrisultatoèunanuovalistagenericanella quale il tipo è lo stesso della lista di input.A volte, dobbiamomodificare questocomportamentoalfinediavere, inoutput,unoggettopiùsnelloperché,peresempio, lodobbiamocollegareaunagrigliaoppureperchédobbiamorestituirel’oggettoall’esternoenonvogliamoesporretutteleproprietà.

SelectIlprimooperatorediproiezioneèSelect.Questometodopermettedieffettuarediversetrasformazionidelrisultatodiunaquery.

SupponiamodiavereunmetodochedeverestituiregliIDdegliordini.Tornarel’interooggettononha senso,né in termini logiciné in terminiprestazionali.LaviamiglioreèrestituireunalistacongliID,comesipuòvederenell’esempio8.8.

Esempio8.8Dimresult=ordini.Select(Function(o)o.Id)

Inaltricasi,unmetodopotrebbedovertornaredeglioggettidiversidaquelli interrogati,perscopidiottimizzazioneoppureperchéalcunidatisonosensibilienondevonoessereespostiall’esterno.Inquestiscenaripossiamoriversareilcontenutodellaclassediinputinun’altra,cheèquellachevienepoirestituitaalchiamante.GrazieagliObjectInitializers,questopuòesserefattoinunasolarigadicodice,comepossiamonotarenell’esempio8.9.

Esempio8.9Dimresult=ordini.Select(Function(o)_

NewOrdineDTOWith{.Id=o.Id,.Data=o.Data})

Unaltroscenariochepuòtrarrebeneficiodallamodificadelrisultatoèlavisualizzazionedei dati. Se abbiamo una griglia dove vogliamo presentare una serie di fatture senzamostrarne i dettagli, ci basta creareunoggetto inoutput checontenga tutte leproprietàtranne Dettagli. Il caso è identico a quello che abbiamo appena visto ma con ladifferenza che OrdineDTO è una classe che deve essere creata e mantenuta mentre, inquesto caso, grazie agli anonymous type, possiamo creare la classe al volo e collegarlasubitoallagriglia.L’esempio8.10dimostraquestatecnicainpratica.

Esempio8.10Dimresult=ordini.Select(Function(o)_

Page 207: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

NewWith{o.Id,o.Data})

Il nome delle proprietà dell’oggetto anonimo viene automaticamente ricavato dalleproprietàdell’oggettooriginale.Sedobbiamocambiareilnomedelleproprietà,dobbiamoanteporre il nuovo nome preceduto dal carattere “.” e seguito dal carattere “=”.Nell’esempio8.11mostriamocomeottenerequestorisultato.

Esempio8.11Dimresult=ordini.Select(Function(o)_

NewWith{.IdOrdine=o.Id,.DataOrdine=o.Data})

Il metodo Select è tutto qui e pensiamo non necessiti di ulteriori spiegazioni, quindipossiamopassarealprossimooperatorediproiezione.

SelectManyL’operatoreSelectManyserveperappiattirequeglioggettiche,altrimenti,avrebberounastruttura ad albero. Sebbene la definizione possa sembrare complicata, in realtàSelectMany svolge una funzione molto semplice e facile da capire, una volta vista inazione.Prendiamolaquerydell’esempio8.12,chetornaidettaglidiunordine.

Esempio8.12Dimordine=Ordini.

Where(Function(o)o.Id=1).

Select(Function(o)o.Dettagli)

Ciòcheotteniamodaquestaqueryèunalistaconunsoloelemento,contenenteunelencocon i dettagli dell’ordine; in pratica la query ritorna una lista di liste. Sebbene scorrerequesti dati sia semplice, avere a disposizione direttamente la lista èmolto più comodo.Questoèancorapiùveroquandovogliamoritornareidettaglidituttigliordini.

AquestopuntoentraincampoilmetodoSelectManycheappiattiscetutti idettagliinunalistaunica,piùsemplicedascorrere.Ilsuoutilizzoèmostratonell’esempio8.13.

Esempio8.13Dimordine=Ordini.SelectMany(Function(o)o.Dettagli)

Glioperatoridi selezionesonomolto importantie il loroutilizzoè frequentedurante lascrittura delle query. Fortunatamente la loro estrema semplicità ci permette dicomprenderneconfacilitàilfunzionamento.Orapassiamoaglioperatorichepermettonodiordinareleliste.

Page 208: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

GlioperatoridiordinamentoGlioperatoridiordinamentohannoilsemplicescopodiordinareunalistainbaseaunaopiù proprietà.Grazie a questimetodi, non dobbiamo più creare una classe ad hoc, cheimplementiIComparableperordinareleliste,equindiotteniamounnotevolerisparmiodicodice.Vediamooraiprimimetodidiquestacategoria.

OrderBy,OrderByDescending,ThenByeThenByDescendingImetodiOrderByeOrderByDescendingpermettonodiordinarelalista,rispettivamenteinmaniera ascendente e discendente, in base a una proprietà degli oggetti contenuti.L’esempio8.14mostraunprimoutilizzodiquestimetodi.

Esempio8.14Dimresult=ordini.OrderBy(Function(o)o.Data)

LacaratteristicapeculiarediquestiduemetodiècheilrisultatononèunoggettoditipoIEnumerable(Of T), bensì un oggetto IOrderedEnumerable(Of T) (che eredita daIEnumerable(OfT)).Ilmotivodell’esistenzadiquestainterfacciaèdovutoalfattochelapossibilità di ordinare per più campi non è rappresentabile in una lambda expression.Infatti, quando usiamo il metodo Where, è facile unire due condizioni, in quanto illinguaggio già lo permette, ma nel caso dell’ordinamento non esiste nulla che possaesprimere due o più proprietà in base a cui ordinare. Per questo motivo, sono statiintrodotti due ulteriori operatori tramite l’interfaccia IOrderedEnumerable(Of T):

ThenByeThenByDescending.Questimetodipermettonodispecificareulterioricampipereffettuare l’ordinamento dopo una prima chiamata aOrderBy o OrderByDescending. Inquesto modo siamo sicuri di aver già fatto un ordinamento prima di invocare questimetodi.Illoroutilizzoèmostratonell’esempio8.15.

Esempio8.15Dimresult=ordini.

OrderBy(Function(o)o.Data).

ThenBy(Function(o)o.Id)

In questo esempio viene effettuato l’ordinamento degli ordini prima in base alla data eall’ID.

In una query può esserci un solo metodo OrderBy o OrderByDescending. Lapresenzadidueopiùchiamateaquestimetodicomportachel’ultimachiamataèquellachevince.Questodiscorsononsiapplica,invece,perglialtrioperatoriThenByoThenByDescending.

Oltre agli operatori che ordinano in base a uno o più campi, abbiamo a disposizione

Page 209: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Reverse,unoperatorecheeffettuaunaltrotipodiordinamento.

ReverseL’ultimo operatore della categoria dell’ordinamento è Reverse. Già il nome esprime inmodochiaroloscopodiquestometodo.Infatti,chiamandoilmetodoReverse,otteniamounalista,conglioggettiinordinecompletamenteinvertito.

Vi sono un paio di osservazioni da fare su questo metodo. Innanzitutto, se ci sonooggetti di tipo differente nella lista di partenza, il metodo va in errore. Inoltre, poichéesistegiàunmetodoReverseperalcunioggettichegestisconoliste(vediList(OfT)),intali casi dobbiamo specificare, via generic, il tipo dell’oggetto della lista, altrimenti ilcompilatore cerca di utilizzare il metodo non generico e scatena un errore. Se invecestiamofacendolaquerydirettamentesuunoggettoIEnumerable(OfT),nonc’èbisognodispecificareiltipo.L’esempio8.16mostral’utilizzodiquestometodo.

Esempio8.16Dimresult=ordini

.Where(Function(o)NotTypeOfoIsOrdineEx)

.Reverse()'Filtraeinverte

Oltrechepermetteredifiltrare,tornaredatiinformatidiversieordinare,LINQpermetteanchedieffettuareraggruppamenti.Nellaprossimasezioneanalizzeremoquestacapacità.

GlioperatoridiraggruppamentoNella categoria oggetto di questo paragrafo, esiste un solo operatore: GroupBy. Questometodopermettediraggruppareidatiinbaseaunachiavechepuòessereunaproprietàol’unionedipiùproprietàinunasola.Peresempio,sevogliamoraggrupparelefatturepergiorno,ilcodicedautilizzareèquellomostratonell’esempio8.17.

Esempio8.17ordini.GroupBy(Function(o)o.Data.Date)

Ciòcheotteniamodaquestaqueryèunoggettodi tipoIEnumerable(OfIGrouping(OfT, Of K)), dove T è di tipo DateTime e K di tipo IEnumerable(Of J) con J di tipoOrdine.Aprimavista,questastrutturapuòsembraremoltocomplessama,inrealtà,èpiùsemplice di quel che possiamo immaginare. Basta pensare a una struttura ad albero,contenente gli ordini classificati in base alla loro data di emissione. A ogni datacorrispondeunnododell’albero e, per ognunodi questi nodi, esistono tanti figli quantisonogliordiniperquelladata.Dettoquesto,èchiarocheilmodoincuiscorriamolalista

Page 210: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

nonèlostessocheabbiamousatoinprecedenza,macambiainvirtùdelfattochelalistaèaduelivelli.L’esempio8.18mostracomecambia ilmododiciclare traglielementidelrisultato.

Esempio8.18DimsbAsNewStringBuilder

ForEachitemInresult

sb.Append("<h3>"&item.Key&"</h3>")

ForEachobjInitem

sb.Append("<div>ordinenumero"&obj.Id.ToString()&"</div>")

Next

Next

ltl.Text=sb.ToString()

Ilprimocicloscorretutti inodidiprimolivellodellastruttura(ledate)eperognunodiessi va a esaminare i figli (gli ordini). Il valore della chiave di raggruppamento ècontenuto nella proprietà Key del tipo IGrouping(Of T, Of K) (l’oggetto di primolivello).

GroupByhadiversioverload,fraiqualiunomoltoimportanteèquellochepermettedisceglierequaleoggettoinserirenellalistalegataallachiave.Didefault,quandopassiamoalmetodoGroupBysolo lachiavedi raggruppamento, l’oggettodella listadi inputvieneinserito in quella di output. Tuttavia, se vogliamo modificare questo comportamento,possiamopassareunsecondoparametrochespecifichicosainserireinoutput.Cosìcomeper il metodo Select, possiamo scegliere di inserire un oggetto personalizzato, comeOrdineDTOoppureunanonymoustype(soluzionemostratanell’esempio8.19).

Esempio8.19Dimresult=ordini.

GroupBy(Function(o)

o.Data.Date,

Function(o)

NewWith{o.Id,.Dettagli=o.Dettagli.Count()})

DimsbAsNewStringBuilder

ForEachitemInresult

sb.Append("<h3>"&item.Key&"</h3>")

ForEachobjInitem

sb.Append("<div>ordinenumero"&obj.Id.ToString()&

"Dettagli"&obj.Dettagli.ToString()&"</div>")

Page 211: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Next

Next

ltl.Text=sb.ToString()

Inquestocasootteniamounanonymoustypeconl’IDdell’ordineeilnumerodidettagliper ognuno. È importante sottolineare che, pur utilizzando gli anonymous type, VisualStudiorimaneingradodioffrirel’intellisenseinqualunquemomento.

Un’altracaratteristicacheLINQmetteanostradisposizione,èlapossibilitàdieseguirecalcolisuunalistadivaloritramiteglioperatoridiaggregazione.

GlioperatoridiaggregazioneGlioperatoridiaggregazionehannoloscopodicalcolareunsingolovaloredauninsiemedi dati.Questimetodi tornano utili quando vogliamo calcolare il valoremassimo di unnumero, contare gli elementi in una lista o altro ancora. Cominciamo analizzando glioperatoricheeseguonocalcolisuidati.

Average,Min,Max,SumImetodiAverage,Min,MaxeSumcalcolanorispettivamentelamedia,ilvaloreminimo,quellomassimoe lasommadiunparticolare insiemedidati. Ilmodoperspecificaresuqualedato si debbaeseguire il calcolo è sempre tramitepredicato e lambdaexpression,comepossiamovederenell’esempio8.20.

Esempio8.20Dimmaxdata=ordini.Max(Function(o)o.Data)

Dimmindata=ordini.Min(Function(o)o.Data)

Dimavgvendite=ordini.Average(Function(oAsOrdine)_

o.Dettagli.Count())

Dimfatturato=ordini.Sum(Function(o)_

o.Dettagli.Sum(Function(dAsDettaglioOrdine)d.Prezzo*d.Quantita))

La variabile maxdata contiene la data dell’ultimo ordine piazzato, mentre mindatacontieneilprimo;avgvendite indicalamediadeidettagliperordine,mentrefatturatocontieneiltotaledituttigliordini.

IlmododicalcolareilfatturatoèunadellefunzionipiùpotentidiLINQ.Infatti,nonc’èunasolaquery,mavenesonodueinnestate.Percalcolareilrisultato,LINQscorrelalistadegli ordini e per ogni ordine scorre i dettagli, sommando il prezzomoltiplicato per laquantità tramite Sum. Infine, questi valori vengono sommati nuovamente tramite Sum,arrivandocosìalrisultatofinale.

Page 212: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Ora che abbiamo visto come utilizzare questo tipo di operatori, possiamo passare aquellichecontanoglielementi.

Count,LongCountComeèfaciledesumeredailoronomi,CounteLongCountritornanoilnumerodielementichesonopresentiinunalista.LadifferenzatraiduerisiedenelfattocheCountrestituisceunInt32,mentreLongCountunInt64.Illoroutilizzoèmostratonell’esempio8.21.

Esempio8.21Dimcount=ordini.Count()

Dimlongcount=ordini.LongCount()

Ora che abbiamo trattato anche questa categoria, passiamo ad analizzare la prossima,relativaaglioperatorichefiltranoidatiinbaseallaloroposizione.

GlioperatoridielementoGlioperatorichefannopartediquestacategoriahannoloscopodifarrestituireallaqueryunsoloelementoenonunalista.Infatti,quandoeseguiamounaqueryLINQ,ilrisultatoèsempre un IEnumerable(Of T) (oppure un’interfaccia derivata). Se sappiamo già chestiamo cercando un solo elemento, possiamo utilizzare questi operatori per impostaredirettamentel’oggettocometipodiritorno.

Il primo metodo è First e serve per restituire il primo elemento della lista, comemostratonell’esempio

Esempio8.22Dimfirst=ordini.First()

Se la lista non contiene alcun elemento, questo metodo solleva un’eccezione. Perprevenirequestocomportamento,esisteilmetodoFirstOrDefaultche,nelcasoincuilalista sia vuota, torna il valore di default del tipo (“0” per interi, “false” per booleani,“null”peritipiperriferimento,comelestringheecc.).

Entrambi i metodi appena menzionati hanno anche un overload che permette dispecificareunacondizionediricerca.Inquestocaso,vienerestituitoilprimooggettochecorrisponde ai criteri di ricerca. L’impiego di questo overload permette di risparmiarecodice, inquantoevita l’utilizzodelmetodoWhere, comepossiamonotarenell’esempio8.23.

Esempio8.23

Page 213: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DimfirstAsOrdine=ordini.First(Function(o)o.Id=1)

Mentre First e FirstOrDefault tornano il primo elemento, Last e LastOrDefaultsvolgonoilcompitoesattamenteopposto,restituendol’ultimoelementodellalista.AncheperLast,valelaregoladelleeccezionivistaperFirst.Senonvogliamochesiasollevataun’eccezione,dobbiamousareLastOrDefault.

Un altro metodo importante è Single. Questo operatore ritorna sempre il primomembro di una lista, ma presenta la caratteristica di sollevare un’eccezione non soloquandononci sonoelementio se il filtrodi ricercanonhaprodotto risultati,maanchequando la lista ha più di un elemento. Questo metodo è molto comodo perché, allapresenzadisituazionianomalecondatiduplicati,questiultimivengonosubitoindividuati.

L’utilizzodiSingleOrDefault tieneal riparodaeccezionididatinonpresentima, incasodipiùoggettinellalista,l’eccezionevienecomunquesollevata.

Gli ultimi due metodi di questa tipologia sono ElementAt e ElementAtOrDefault.Questimetodi restituiscono l’elementochesi trovaaunospecifico indicenella lista.SeutilizziamoElementAte l’elementononesiste,vienesollevataun’eccezione.Se, invece,utilizziamoElementAtOrDefault,l’eccezionenonvienesollevataeotteniamoilvaloredidefaultdeltipocercato.

Sin qui questi duemetodi si comportano inmaniera del tutto analoga agli altri dellastessa famiglia.Tuttavia c’èunapiccoladiversitàdovuta al fatto chequestimetodinonhannounoverloadpereffettuareuna ricercamauna sola firma,cheaccetta in inputunInt32checontienel’indice.

DefaultIfEmpty è unmetodo completamente diverso rispetto agli altri. Il suo scoponon è quello di restituire un solo elemento,madi aggiungere un elemento vuoto a unalista, nel caso in cui questa sia vuota. Nel caso di query che fanno uso di outer join,possiamoutilizzarequestometodoperassociareunelementovuotoladdovenoncisianocorrispondenze.

Orachesappiamocomeestrarreunoggetto inbaseallasuaposizione,vediamocomeestrarregruppidioggetti,utilizzandolostessocriterio.

GlioperatoridipartizionamentoGlioperatoridipartizionamentohannoloscopodiestrarreoggettidaunalistainbaseallaloro posizione. Un esempio classico dell’utilizzo di questi metodi si verifica quandodobbiamofareunapaginazione.ImetodiprincipalidiquestacategoriasonosTakeeSkip.

TakeeSkipIlmetodoTakeserveperrestituireleprimenrighediunalista.Questometodoaccettaininputunsoloparametro,ditipoInt32,chespecificailnumerodielementidaestrarre.Il

Page 214: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

suoutilizzoèmostratonell’esempio8.24.

Esempio8.24Dimresult=ordini.Take(2)

DipersèilmetodoTakenonèdigrandeutilità,inquantopuòestrarresoloiprimirecord.Tuttavia, la vera potenza di questo metodo si svela quando ne facciamo un utilizzocombinatoconSkip.L’operatoreSkippermettedisaltarel’estrazionedelleprimenrighediunalista.Aquestopunto,possiamofacilmentecrearequeryingradodiestrarrepaginedidaticonunasola istruzione,utilizzandoadovereilmetodoSkippersaltareipriminelementieTakeperprendereipriminelementisuccessivi.L’esempio8.25dimostracomeeffettuareunapaginazione.

Esempio8.25Dimresult=ordini.Skip(2).Take(2)

Inquestaqueryrecuperiamoun’ipoteticasecondapaginacompostadidueelementipoichéiprimidueoggettivengonosaltati.

TakeWhileeSkipWhileIlmetodoTakeWhileserveperrestituireiprimielementidiunalista,chesoddisfanounadeterminata condizione tramite una lambda expression. La caratteristica principale diquesto metodo è che, appena incontra un oggetto che non soddisfa la condizione,l’iterazionesiarrestaetuttiisuccessivirecordvengonoignorati.

IlmetodoSkipWhileè,intuttoepertutto,l’oppostodiTakeWhile.Questometodosaltatuttiiprimirecordchesoddisfanolacondizioneespressatramitelalambdaexpressione,appena trova un record non corrispondente, smette di effettuare il controllo e ritornaindiscriminatamentetuttiglialtrioggettidellalista.

Ora che anche gli operatori di partizionamento sono stati trattati, possiamo passareall’ultimacategoria,chesioccupadicompiereoperazionid’insiemisticasulleliste.

OperatoridiinsiemeGlioperatoridi insiemehannoilcompitodiconfrontarelelisteeindividuareglioggettiuguali, quelli differenti e quelli doppi. Oltre a questo, tramite l’operatore di unione,possiamofondereinsiemedueopiùliste.

Per fare le comparazioni negli esempi proposti di seguito, dobbiamo introdurre unasecondalista,chepossiamovederenell’esempio8.26.

Page 215: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio8.26DimordiniSetAsNewList(OfOrdine)

ordiniSet.Add(NewOrdineWith{.Id=1,.Data=DateTime.Now})

ordiniSet.Add(NewOrdineWith{.Id=2,.Data=DateTime.Now})

ordiniSet.Add(NewOrdineWith{.Id=5,.Data=DateTime.Now})

ordiniSet.Add(NewOrdineWith{.Id=6,.Data=DateTime.Now})

ordiniSet.Add(NewOrdineWith{.Id=6,.Data=DateTime.Now})

IlprimooperatorecheandiamoadanalizzareèExcept.

ExceptIl metodo Except permette di estrarre da una lista gli oggetti che non hanno unacorrispondenzaconquellipresentiinunasecondalista.Questometodohadueoverload:unprimo,dovepassiamosololalistadaconfrontareeunsecondo,dovepossiamopassareunIEqualityComparerperdeciderequandodueoggettisonougualiononlosono.SenonvogliamocreareunaclassecheimplementaIEqualityComparer,possiamoricorrereallamodifica della classe Ordine per gestire le uguaglianze. Per fare questo, basta darel’override dei metodi GetHashCode e Equals, così come possiamo notare nell’esempio8.27.

Esempio8.27PublicOverridesFunctionEquals(ByValobjAsObject)AsBoolean

ReturnCType(obj,Ordine).Id=Id

EndFunction

PublicOverridesFunctionGetHashCode()AsInteger

ReturnId

EndFunction

Facendol’overridediquestimetodi,LINQèingradodicapiredasoloquandodueoggettisonouguali. Inquestocaso,dueordinipresenti inentrambe le liste sonougualiquandohannolostessoID.

Aquestopunto,possiamoutilizzare ilmetodoExcept senzadifficoltà,comemostratonell’esempio

8.28.

Esempio8.28Dimresult=ordini.Except(ordiniSet)

Page 216: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Questaqueryproducecomerisultatolarestituzionedegliordini3e4,inquantogliordini1e2sonopresentianchenellasecondalista.

IntersectQuestometodohaloscopodicreareunanuovalistadovesianopresentiglielementichesonoinentrambelelistecomparate.Anchequestometodohadueoverload:ilprimocheaccetta la lista da comparare e il secondo che accetta un IEqualityComparer, perspecificareaLINQcomeidentificareidoppioni(inutileinquestocaso,datochelaclasseOrdineimplementaimetodiEqualseGetHashCode).L’esempio8.29nemostral’utilizzo.

Esempio8.29Dimresult=ordini.Intersect(ordiniSet)

Il risultato di questa query è una lista con gli ordini 1 e 2, che sono quelli presenti inentrambelelisteispezionate.

DistinctL’operatoreDistinctpermettediottenereunalistaincuiglieventualidoppionivengonoeliminati.Poichéidoppionivengonocercatinellalistastessa,questometodononaccettaparametri, a meno che non usiamo l’overload che accetta un IEqualityComparer.L’utilizzovienemostratonell’esempio8.30.

Esempio8.30Dimresult=ordiniSet.Distinct()

Il risultato di questa query è una lista di quattro elementi, poiché l’ordine con ID 6 èinclusoduevoltenellalista.

UnionUnionèl’ultimometododellacategoriainesameepermettedifondereinsiemedueliste.Nel caso in cui LINQ sia in grado di determinare quando due oggetti sono uguali, idoppioni vengono eliminati tramite IEqualityComparer o override dei metodi dellaclasse.Nell’esempio8.31,diamounadimostrazionediutilizzodiquestometodo.

Esempio8.31Dimresult=ordiniSet.Union(ordiniSet)

Page 217: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Ilrisultatodiquestaqueryèunalistacongliordini1,2,3,4,5e6senzaildoppioneconIDparia6.

Aquestopuntoabbiamoillustratoiprincipalimetodichepermettonodieseguirequerycon LINQ. Ovviamente non abbiamo coperto il 100% delle possibilità ma abbiamoanalizzato solo quelli che vengono utilizzati nella maggior parte dei casi. Il passosuccessivosaràquellodiscoprireunmododiversodiscriverelequery.

LaQuerySyntaxL’utilizzo degli extension method in combinazione con le lambda expression è moltocomodo. Tuttavia, molti sviluppatori non si trovano perfettamente a loro agio usandoquesta sintassi; soprattutto quelli che possiedono un background orientato al linguaggioSQL.

Per questi sviluppatori è stata introdotta la cosiddetta Query Syntax. QuestafunzionalitàpermettediscriverequeryLINQconunasintassimoltosimileallinguaggioSQL.InquestomodopossiamoapprocciareconunamaggiorfamiliaritàlascritturadellequeryLINQ,comemostratonell’esempio8.32.

Esempio8.32Dimresult=FromoInordini

Whereo.Id=1

Selecto

Da questo esempio possiamo vedere come la sintassi siamolto simile a quella SQL, aeccezionedellaprima istruzione,cheèunaFrom enonunaSelect. Ilmotivodi questascelta risiede nel fatto che, per permettere a Visual Studio di offrire l’intellisense,dobbiamospecificaredasubitoqualioggettidevonoessereinterrogati.

Bisognateneresemprepresenteunacosa:quandoilcompilatoreincontraquestaquery,la converte in chiamate agli extensionmethod.Questo significa che, dal punto di vistadelleperformance,nonvièalcunvantaggionell’usarel’unaol’altratecnica.Lasceltaèdettataesclusivamentedainostrigustipersonali.

Sebbenesiamoltocomoda,laQuerySyntaxnonhalestessepotenzialitàoffertedagliextensionmethodassociatialle lambdaexpression.Pertanto,èutilizzabilesolo inalcuniscenarinontroppocomplessi.Difatto,sonomoltopochigliextensionmethodchehannounmappingconleclausoledellaQuerySyntax.

Tabella8.2–ParolechiaveconlaQuerySyntax.

QuerySyntaxOperator ExtensionMethod

Aggregate Aggregate

Distinct Distinct

Page 218: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

From From

GroupBy GroupBy

GroupJoin GroupJoin

Join Join

Let SubSelect

OrderBy Orderby

Select Select

Skip Skip

SkipWhile SkipWhile

Take Take

TakeWhile TakeWhile

Where Where

Questa tabellamostra che sedaun lato abbiamoadisposizionemoltimetodi, dall’altroquesti non sono sufficienti a coprire tutte le esigenze. In base alla nostra esperienza,possiamoaffermareche,nellamaggiorpartedeicasi,lasintassicongliextensionmethodèl’unicastradapercorribile.

ConclusioniLINQ introduce una serie di nuovi strumenti per lo sviluppatore, ampliandonenotevolmentelepotenzialità.Grazieaquestatecnologia,sirealizzainmanieraconcretalapossibilitàdiscriveremenocodiceedirenderlo,allostessotempo,moltopiùleggibilecheinpassato.

Inoltre,LINQhaun’espressivitàintrinsecacheavvicinaillinguaggioVisualBasicallaprogrammazionefunzionale;tuttoquesto,sommatoall’architetturaaprovider,poneLINQalcentrodellestrategiediaccessoverso lepiùsvariatesorgentidati.PerquestomotivoMicrosofthainprogrammadisupportareedespandereLINQnellesuccessiveversionidel.NETFramework.

Ora che abbiamo spiegato come scrivere query all’interno del codice, nel prossimocapitoloanalizzeremolepotenzialitàdell’esecuzioneparalleladicodice.

Page 219: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

9

Multithreadingedesecuzioneparallela

Algiornod’oggipraticamente tutti i personal computer sonodotatidiprocessorimulti-core.Realizzareapplicazioniingradodigestiresimiliarchitetturerappresentaunaveraepropriasfida,datocheènecessarioripensareeristrutturareglialgoritmifinorautilizzatiaffinchépossanoessereeseguitiinparallelo.

Il multithreading rappresenta la prima tecnica che, come sviluppatori, abbiamo adisposizione per migliorare le prestazioni della nostra applicazione. Proprio ad essa èdedicata laprimametàdi questo capitolo, in cui vedremo ledifferenti possibilità che il.NETFrameworkciforniscepereseguirediverseporzionidicodicenellostessomomento.

Maavviarepiùthreadcontemporaneamentenonbastaagarantirecheilcaricodilavorosia equamente distribuito tra le diverse CPU a disposizione. Nella seconda parte delcapitolo, introdurremo una serie di classi, denominate Parallel Extensions, tramite lequali possiamo scrivere codice parallelo, tralasciando i dettagli relativi allo scenariohardware in cui esso viene eseguito. In seguito vedremo come l’utilizzo delle keywordAsynceAwait,introdottegiàdaVisualBasic2012,semplificanonotevolmentelascritturadicodiceasincrono.

Infine, avremo modo di vedere come la vera e propria sfida in questo ambito disviluppo risieda nella facilità con cui l’accesso concorrente alle risorse, semal gestito,possacomportarebugaruntimedifficilmenteriproducibilieindividuabili.Analizzeremoancheinquestocasoglistrumentimessiadisposizionedalsitemaoperativoedal .NETFrameworkperevitarequestotipodiproblemi.

ProcessiethreadQuandorichiediamol’esecuzionediunprogramma,ilsistemaoperativocreaun’istanzadiun particolare oggetto del kernel, chiamato process (processo), a cui assegna un bendefinito(eisolato)spaziodiindirizzamentoinmemoria.Unprocesso,dipersé,nonèingradodieseguirealcuncodiceesvolgeilcompitodipuroesemplicecontenitorediquellechepotremmodefinirecomeleentitàfunzionalielementaridelsistemaoperativo:ithread.Ogni processo dispone di almeno un thread, chiamatoprimary thread, al termine delqualeessovienedistrutto,liberandolospaziodimemoriaelerisorseadessoassegnate.

Il normale ciclo di vita di un’applicazione consiste nell’esecuzione squenziale dinumerosi blocchi di codice richiamati dal thread principale, che a loro volta possono

Page 220: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

richiamareulterioriblocchidicodice.Quandoquestoavviene,ilmetodochiamanterisultaovviamentebloccatofintantochelaroutineinvocatanongiungealtermine.Sitrattadiunapproccio con diversi limiti e, per forza di cose, non sempre percorribile: se i nostriprocessifosseroingradodieseguireunsolothread,ilcontrolloortograficodiMicrosoftWord causerebbe continue interruzioni nella digitazione del testo oppure ogni richiestapervenuta a un’applicazione ASP.NET impegnerebbe il server per tutta la durata dielaborazione, fino alla generazione della risposta. Fortunatamente ogni thread ha lapossibilitàdiassegnareaunthreadsecondariol’esecuzionediunmetodo.Inquestocaso,lachiamataaquest’ultimoritornaimmediatamenteilcontrolloalthreadchiamanteeidueblocchidicodicepossonoeffettivamenteessereeseguitiinparallelo.

Il .NET Framework fornisce un gran numero di classi per gestire questo tipo disituazioniall’internodell’applicazioneerenderepossibilel’esecuzionecontemporaneadidiversi metodi. Esse sono, per lo più, contenute all’interno del namespaceSystem.Threading,alqualelaclasseThreadappartiene.

LaclasseSystem.Threading.ThreadIlcodicediunapplicazione.NETvieneeseguitodaunmanagedthread,ossiadaunthreadgestito dal Common Language Runtime. Si tratta di un’astrazione di più alto livellorispetto al thread del sistema operativo; più thread gestiti, infatti, possono essere inconcreto implementati utilizzando ilmedesimo thread di sistema, al fine di risparmiarerisorse,oppureunmanagedthreadpuòessereeseguitoparzialmentetramiteunwindowsthread per poi essere spostato su un altro. Si tratta di ottimizzazioni che, per noiutilizzatori,risultanoassolutamentetrasparenti,datocheèilCLRapreoccuparsidigestiretutte queste tipologie di operazioni, in assoluta autonomia, a seconda del particolarescenariodiesecuzione.

All’interno del .NET Framework, un thread è rappresentato dall’omonima classeThread. Il suo costruttore accetta un delegate di tipo ThreadStart (oParametrizedThreadStart, nel caso in cui dobbiamo anche passare dei parametri),tramite il quale possiamo fornire al thread il codice che esso dovrà eseguire, comemostratodall’esempio9.1.

Esempio9.1SubMain()

DimmyThreadAsNewThread(

Sub()

Console.WriteLine("MyThreadèiniziato")

Thread.Sleep(1000)

Console.WriteLine("MyThreadèterminato")EndSub)

Page 221: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'EsecuzionedimyThread

myThread.Start()

Thread.Sleep(500)

Console.WriteLine("MainThread")

EndSub

NelcodiceabbiamocreatounanuovaistanzadellaclasseThread,acuiabbiamoassegnatoun metodo, definito tramite la notazione delle lambda expression, che visualizza unmessaggioinconsoledopounsecondodiattesa.QuestodelegatevienepresoinconsegnadamyThreadedeseguitoinunthreadseparato,chiamatoworkerthread,all’invocazionedelmetodoStart.Ilrisultatodell’esecuzioneèquellomostratoinfigura9.1.

Figura9.1–Esecuzionedell’esempio9.1.

Come possiamo notare, ciò che accade è che effettivamente i due blocchi di codice,appartenenti al thread principale e a myThread, sono eseguiti in parallelo, tant’è chel’output suconsoleprodottodalprimoapparenelmezzodeiduemessaggi stampatidalsecondo,secondoloschemamostratoinfigura9.2.

Page 222: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura9.2–Parallelismodeithreaddell’esempio9.1.

Quando viene eseguita l’istruzione Console.WriteLinedel thread principale,quest’ultimo termina la sua esecuzione; in condizioni normali, ciòcomporterebbe la chiusura dell’applicazione senza visualizzare il messaggioprodotto dal worker thread “MyThread è terminato”. In realtà, nell’esempio9.1, ciò non accade perché quest’ultimo è un thread di foreground e, cometale, è in grado di mantenere in vita l’applicazione finché non sia concluso.TramitelaproprietàIsBackground,sipuòconfiguraremyThreadcome threaddi background; in questo caso l’applicazione non deve attenderne ilcompletamentoperpoterterminare.

L’esempio che abbiamo mostrato esegue codice isolato, che non accetta parametridall’esterno.Sitrattadiunalimitazionecheelimineremonelprossimoparagrafo.

PassareparametriaunworkerthreadNel caso in cui dobbiamo passare un parametro al codice eseguito nel worker thread,possiamo avvalerci di un delegate di tipo ParametrizedThreadStart, che accetta unargomentoditipoObject,comenell’esempio9.2.

Esempio9.2DimsomeVariableasString="MarcoDeSanctis"

DimworkerThreadAsNewThread(

Page 223: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Sub(argument)

Console.WriteLine("Salutida:{0}",argument)EndSub)

workerThread.Start(someVariable)

Ilparametropuòpoiesserevalorizzatotramitel’overloaddelmetodoStart,cheabbiamoutilizzato, nel nostro caso, per passare la variabile someVariable al thread secondario.Sebbene, tramite l’utilizzo delle lambda expression, possiamo referenziare direttamentequestavariabiledaldelegate,evitandoquindil’utilizzodiunParametrizedThreadStart,quello mostrato è l’unico modo corretto per passare parametri a un worker thread,evitandoracecondition, ossia comportamenti anomali dell’applicazione che dipendonodalle tempistiche di esecuzione dei vari thread. Per comprendere meglio il problema,consideriamol’esempio9.3.

Esempio9.3DimsomeVariableAsString="MarcoDeSanctis"

DimworkerThreadAsNewThread(

Sub()

Thread.Sleep(500)

Console.WriteLine("Salutida:{0}",someVariable)

EndSub)

workerThread.Start()

someVariable="DanieleBochicchio"

Nel codice precedente, abbiamo referenziato someVariable direttamente in fase dicostruzionedelthread,supponendopertantodivisualizzareilnome“MarcoDeSanctis”.Questa variabile, però, viene in realtà valutata solo al momento dell’esecuzione diConsole.WriteLine, non quando viene istanziato workerThread, né quando ne vieneinvocato il metodo Start, stampando a console “Daniele Bochicchio”. In sostanza, ilrisultatodell’esempio9.3dipendedachi,frathreadprincipaleeworkerthread,accedeperprimo asomeVariable (da qui il termine race condition). Si tratta di un problema che,sovente,èfontedibugdifficilementeindividuabilieriproducibili(come,ingenerale,tuttiquelli causati daunutilizzo impropriodelmultithreading) epertanto ènecessarioporreestremaattenzioneaquestiaspetti,passando iparametri inmanieracorretta,comevistonell’esempio9.2.

Finoracisiamogiàscontraticonleprimeproblematichedisincronizzazioneeabbiamosfruttato ilmetodo Sleep, che blocca un thread per un tempo prestabilito, per regolarel’esecuzionedellenostreapplicazionidiesempio.Unsimileapprocciononèovviamentepossibileinuncontestoreale;perquestenecessitàesisteunostrumentopiùadeguato,dicuicioccuperemonelprossimoparagrafo.

Page 224: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ControllareilflussodiesecuzionediunthreadIlvantaggiodiutilizzareunoggettodi tipoThreadnellanostraapplicazioneèquellodipoterne controllare in maniera esplicita il flusso di esecuzione. Una problematicaestremamente comune da dover gestire, ad esempio, è quella di ricevere una notificaquando un worker thread ha terminato il proprio lavoro. Questo risultato può essereraggiuntotramitel’usodelmetodoJoin.

Esempio9.4DimlistAsNewList(OfThread)

'Quicreiamoedeseguiamocinqueworkerthread

Forindex=1To5

DimmyThreadAsNewThread(

Sub(currentIndex)

Console.WriteLine("Thread{0}èiniziato",currentIndex)Thread.Sleep(500)

Console.WriteLine("Thread{0}èterminato",currentIndex)

EndSub)

myThread.Start(index)

list.Add(myThread)

Next

'Attesadelcompletamentodiognunodeiworkerthread

ForEachthreadAsThreadInlist

thread.Join()

Next

Console.WriteLine("Esecuzionedituttiithreadterminata")

L’obiettivodelcodicedell’esempio9.4èquellodivisualizzareunopportunomessaggiosuconsole solo nelmomento in cui tutti iworker thread costruiti all’interno del cicloForabbianocompletatolaloroesecuzione.InvocandoilmetodoJoindalthreadprincipale,senebloccal’esecuzionefinchél’istanzadelworkerthreadnonabbiaterminatodieseguireil relativo codice. Eventualmente, Join accetta come argomento anche un timeout, cherappresentailtempomassimodiattesaalterminedelqualerestituireilcontrollo.

'Attesadimassimounsecondo

thread.Join(1000)

Un’altranecessitàpiuttostocomuneèquelladiinterromperedeltuttounworkerthread:sipensi, ad esempio, al caso in cui si voglia dare la possibilità all’utente di annullarel’esecuzionediunalungaoperazione.Inquesticasi,ilmetododautilizzareèAbort,comemostratodall’esempio9.5.

Page 225: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio9.5DimworkerThreadAsNewThread(

Sub()

Console.WriteLine("Iniziodiunthreadmoltolungo")

Thread.Sleep(5000)

Console.WriteLine("Termineworkerthread")

EndSub)

workerThread.Start()

workerThread.Join(500)

'Seilworkerthreadèancorainesecuzione,losicancella

If(workerThread.ThreadState<>ThreadState.Stopped)Then

workerThread.Abort()

EndIf

Console.WriteLine("Termineapplicazione")

Ilcodiceprecedente,dopoaver invocato ilmetodoJoinperattendere il completamentodelworkerthread,verificatramitelaproprietàThreadStatesequest’ultimosiaancorainesecuzione e, in caso affermativo, lo cancella, invocando il metodo Abort. Quandol’esecuzione di un thread viene cancellata, il relativo codice viene interrotto da unaThreadAbortException,chepossiamoeventualmentegestireperintrodurredelcodicedicleanup.

DimworkerThreadAsNewThread(

Sub()

Try

Console.WriteLine("Iniziodiunthreadmoltolungo")Thread.Sleep(5000)

Console.WriteLine("Termineworkerthread")CatchexasThreadAbortException

'quicodicepergestirel'eccezione

EndTry

EndSub)

Finoadoraabbiamoimplementatofunzionalitàmultithreadingnellenostreapplicazioni,creandoinmanieraesplicitaistanzedellaclasseThread.Unatalepraticaèconsigliatasoloneicasiincuivogliamocontrollareinmanieradirettailciclodivitaelecaratteristichedelthread secondario, ad esempio, rendendolo o meno di background tramite la proprietàIsBackgroundoppureimpostandonelapriorità:

workerThread.IsBackground=False

workerThread.Priority=ThreadPriority.Lowest

Page 226: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Per tutte le altre casistiche, invece, questa non è una pratica consigliabile, dato che ilCommon Language Runtime mantiene già, per ogni applicazione, un certo numero dithreadinesecuzione,inmododaottimizzarel’utilizzodellerisorsedisistemainrelazionealparticolareambientediesecuzione:ilThreadPool.

IlThreadPoolperapplicazionimultithreadingIl numero ottimale di thread per eseguire codice parallelo varia secondo il particolarescenario hardware e software, in cui l’applicazione viene eseguita. In generale, però,quandorealizziamoapplicazionimultithreadingdobbiamotenerepresenteche:

ognithreadconsumarisorsedisistemaeimpegnaunacertaquantitàdimemoria;

lacreazionee ladistruzionediun threadsono, ingenerale,operazionicostose interminiprestazionali.

Per limitarequesti inconvenientieconsentireallostesso tempo l’esecuzioneparalleladicodice, l’ideaèquelladinondistruggereunthreadunavoltachequestiabbia terminatol’esecuzionemadimantenerloattivoperuncertoperiododitempoinstatoIdle,inmodoche possa essere riutilizzato in seguito. Il CLR mette pertanto a disposizione uncontenitore,chiamatoThreadPool,all’internodelqualemantieneunalistadithreadattivie tramite il quale permette di gestire le code dei task che vengono ad esso via viaassegnati.LaclassestaticaThreadPoolesponeilmetodoQueueUserWorkItem,cheaccettaundelegatedi tipoWaitCallback, tramite il qualepossiamoaccodareunnuovo taskdagestireinparallelo.

Esempio9.6ThreadPool.QueueUserWorkItem(

Sub()

Console.WriteLine("Inizioworkerthread")

Thread.Sleep(1000)

Console.WriteLine("Termineworkerthread")EndSub)

Thread.Sleep(500)

Console.WriteLine("Metodomain")Thread.Sleep(2000)

L’esempio 9.6 è molto simile concettualmente al precedente 9.1, ma non istanziadirettamenteunoggettoditipoThreadesiavvaledelthreadpooldelCLRpereseguireuntaskinparallelo.

Tutti iworker threadappartenentialpoolsonothreaddibackgroundequindil’applicazione non deve attenderne la conclusione per terminare. Pertanto,

Page 227: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

nell’esempio9.6siamostaticostrettiausareilmetodoThread.Sleepperdaretempoalpooldicompletareiltaskassegnato.

Quandountaskrichiedeunparametroiningresso,possiamospecificarlotragliargomentidiQueueUserWorkItem,comemostratonell’esempio9.7.

Esempio9.7DimsomeVariableAsString="MarcoDeSanctis"

ThreadPool.QueueUserWorkItem(

Sub(argument)

Thread.Sleep(500)

Console.WriteLine("Salutida:{0}",argument)

EndSub,someVariable)

someVariable="DanieleBochicchio"

Thread.Sleep(2000)

Perquestaparticolarenecessità,infatti,valgonotutteleconsiderazionicheabbiamofattonellepagineprecedentiapropositodelleracecondition.Pertanto,sebbenesiapossibileutilizzarevariabili esternealcodiceaccodato tramite le lambdaexpression,ècomunqueassolutamente sconsigliato procedere in questo senso. Specificando invece il valore delparametro in fase di accodamento del task, come avviene nel codice dell’esempio 9.7,siamosicurichequest’ulimovengaeseguitoconilvaloreatteso,anchenelcasoincuilavariabiledipartenzadovessecambiareperoperadiunaltrothread.

Lasincronizzazionedei taskeseguiti inquestomodorichiedealcuniaccorgimentinelcodice,datoche,nonessendodisponibileun’istanzadiThread,nonèpossibileutilizzarneilmetodo Join per poterne attendere la conclusione. Allo scopo, possiamo sfruttare laclasseManualResetEvent,comenell’esempio9.8.

Esempio9.8DimlistAsNewList(OfManualResetEvent)

Try

Forindex=1To5

'CreazionedelwaitHandleperiltaskcorrente

DimwaitHandleAsNewManualResetEvent(False)

list.Add(waitHandle)

'Oggettodapassarealtaskaccodato

DimstateAsNewTuple(OfInteger,ManualResetEvent)(

index,waitHandle)

ThreadPool.QueueUserWorkItem(

Page 228: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Sub(untypedState)

'WaitCallbackaccettaunObject,pertantoènecessariouncast

DimtaskState=DirectCast(untypedState,

Tuple(OfInteger,ManualResetEvent))

'Visualizzazionedeimessaggisuconsole

Console.WriteLine("Thread{0}èiniziato",taskState.Item1)

Thread.Sleep(500)

Console.WriteLine("Thread{0}èterminato",taskState.Item1)

'Segnalazionedelterminedell'esecuzionedeltask

'utilizzandoilSetdelManualResetEvent

taskState.Item2.Set()

EndSub,state)

Next

'AttesachetuttiiManualResetEventsianoinstatoSet

ForEachhandleAsManualResetEventInlist

handle.WaitOne()

Next

Finally

ForEachhandleAsManualResetEventInlist

handle.Dispose()

Next

EndTry

Console.WriteLine("Esecuzioneterminata")

In questo caso il codice è divenuto leggermente più complesso rispetto a quello cheistanziavaithreadinmanieraesplicita.AogniiterazionedelcicloFor,vienecostruitaunanuovaistanzadiunoggettoditipoTuple,checontieneledueinformazionichevogliamopassarealtask,ossia:

l’indicedell’iterazione,chesaràpoistampatoavideo;

l’istanza di ManualResetEvent, che il task può poi utilizzare per segnalare ilterminedellasuaesecuzione,invocandoneilmetodoSet.

Quest’ultimoèanchememorizzatoall’internodiunalista,cosìche,inseguito,possiamoinvocareperognunodeiManualResetEvent istanzianti ilmetodoWaitOne.EssoèmoltosimileaThread.Joineagiscebloccandol’esecuzionedelthreadcorrentefinchénonsiaimpostatoinstatoSet,permettendociquindidiattendere,difatto,laconclusionedituttiitaskaccodati.

OltreaManualResetEvent,il.NETFrameworkmetteadisposizioneancheunaversionemenoonerosaper il sistema, chiamataManualResetEventSlim.Essapossiede la limitazione di non poter essere condivisa tra più processi, ma

Page 229: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

assicuramiglioriprestazioniqualoraitempid’attesasianobrevi.

LaclasseManualResetEvent implementa l’interfacciaIDisposable e, pertanto, è buonanormainvocarneilmetodoDisposeall’internodiunbloccoTry..Finally.

AsynchronousprogrammingmodelNelcorsodelcapitolo6abbiamoaccennatoal fattoche idelegatenel .NETFrameworkpossono essere utilizzati per eseguire codice in modalità asincrona, tramite il metodoBeginInvoke. Come abbiamo visto, quest’ultimo presenta la caratteristica di ritornareimmediatamente il controllo al thread chiamante e di iniziare l’esecuzionedel delegate,utilizzandointernamenteil threadpooldelCLR,comemostratodalcodicedell’esempio9.9.

Esempio9.9DelegateFunctionSomeDelegate(ByValparameterAsString)asInteger

SubMain()

DimmethodAsNewSomeDelegate(

Function(parameter)

Thread.Sleep(1000)

Console.WriteLine("Ciaoda{0}",parameter)Returnparameter.Length

EndFunction)

method.BeginInvoke("MarcoDeSanctis",Nothing,Nothing)

Console.WriteLine("Esecuzioneavviata")Thread.Sleep(2000)

EndSub

Daunpuntodivistafunzionale,questotipodiimplementazionenonsidiscostamoltodaquelle viste in precedenza, salvo il fatto che, questa volta, il passaggio di parametri almetodo asincrono avviene inmaniera tipizzata,mentre sia nel caso dell’utilizzo direttodellaclasseThreadsiaavvalendosidelthreadpool,l’eventualeparametroèsempreditipoObject. Oltre che per questo importante vantaggio, l’utilizzo dei delegate per eseguireoperazioniasincronerisultaestremamentecomodoperlasuaversatilitànelintercettareilterminedell’elaborazioneparallelae, inparticolare,perrecuperarneilrisultato.Esistonotrediversemodalitàperraggiungerequestoscopo,chesarannol’argomentodeiprossimiparagrafi.

UtilizzodelmetodoEndInvoke

Page 230: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

AccantoalmetodoBeginInvokecheabbiamovisto inprecedenza,ognidelegateesponeanche un metodo EndInvoke che può essere utilizzato per attendere la conclusionedell’operazione asincrona e recuperarne il risultato. L’esempio 9.9, nel quale abbiamoancoraunavoltaimpropriamenteutilizzatoperquestoscopoilmetodoThread.Sleep,puòessereriscrittocomemostratonell’esempio9.10.

Esempio9.10DimmethodAsNewSomeDelegate(

Function(parameter)

Thread.Sleep(1000)

Console.WriteLine("Ciaoda{0}",parameter)

Returnparameter.Length

EndFunction)

'Esecuzioneasincronadeldelegate

DimasyncResultAsIAsyncResult=

method.BeginInvoke("MarcoDeSanctis",Nothing,Nothing)

Console.WriteLine("Esecuzioneavviata")

'Attesadelterminedell'operazioneerecuperorisultato

DimresultAsInteger=method.EndInvoke(asyncResult)

Console.WriteLine("Ilrisultatoè{0}",result)

IlmetodoBeginInvoke avvia l’esecuzione in parallelo del codicedel delegate e ritornaimmediatamente il controlloal chiamante,dandociquindi lapossibilitàdi eseguirealtreistruzioni nel thread principale. Esso restituisce un oggetto di tipo IAsyncResult, chedobbiamo utilizzare come argomento nella successiva chiamata a EndInvoke.Quest’ultimo ha la caratteristica di bloccare il thread in esecuzione fino al terminedell’operazioneasincrona,consentendociquindi, a tuttigli effetti,di sincronizzare iduethread;nelcasoincuiildelegatesiaunafunzione,EndInvokerestituiscecomerisultatoilvalore di ritorno della stessa che, nell’esempio precedente, abbiamo visualizzato suconsole.

SincronizzazionetramiteIAsyncResultepollingUnamodalitàalternativaperattendereilterminedell’elaborazioneinparalleloèquelladiutilizzare direttamente l’oggetto restituito dal metodo BeginInvoke. Esso implemental’interfacciaIAsyncResult,cheesponeimembrielencatiintabella9.1.

Tabella9.1–Membridell’interfacciaIAsyncResult.

Nome Descrizione

AsyncState

ProprietàditipoObjectchepuòessereutilizzataperpassareunoggettoarbitrariotralevariefasi

Page 231: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

dell’invocazioneasincrona.

AsyncWaitHandleContieneunriferimentoadunWaitHandlechepuòessereutilizzatopersincronizzarel’esecuzionedeldelegateasincrono.

CompletedSynchronously ProprietàditipoBooleancheindicaseiltaskèstatocompletatoinmanierasincrona.

IsCompleted ProprietàditipoBooleancheindicasel’esecuzionedeltaskèstatacompletata.

Inparticolare,laproprietàAsyncWaitHandlerestituisceunoggettoditipoWaitHandle,deltuttoanalogoalManualResetEvent,cheabbiamoutilizzatoneiparagrafiprecedentiechepossiamosfruttareanchenelcasodeidelegate,comenell’esempio9.11.

Esempio9.11DimmethodAsNewSomeDelegate(

Function(parameter)

Thread.Sleep(1000)

Console.WriteLine("Ciaoda{0}",parameter)

Returnparameter.Length

EndFunction)

'Esecuzioneasincronadeldelegate

DimasyncResultAsIAsyncResult=

method.BeginInvoke("MarcoDeSanctis",Nothing,Nothing)

Console.WriteLine("Esecuzioneavviata")

'PollingsulWaitHandle

WhileNotasyncResult.IsCompleted

Console.WriteLine("Esecuzioneincorso…")

asyncResult.AsyncWaitHandle.WaitOne(200)

EndWhile

DimresultAsInteger=method.EndInvoke(asyncResult)

Console.WriteLine("Ilrisultatoè{0}",result)

Comepossiamonotare,l’utilizzodirettodiIAsyncResultoffreilvantaggiodiconsentirciuna maggiore flessibilità nel gestire l’attesa per la conclusione del task. Nel codiceprecedente abbiamo implementato unalgoritmo di polling che effettua periodicamentequestaverifica, inviando,nelfrattempo,dellenotificheall’utente.Al terminedell’attesa,possiamo comunque utilizzare il metodo EndInvoke (che, a questo punto, ritornaimmediatamenteilcontrolloalthreadchiamante,vistocheildelegatehaterminatoilsuolavoro),perrecuperareilrisultatodell’invocazione.

UtilizzodiunmetododicallbackIn alcune occasioni può capitare che, una volta iniziata l’esecuzione asincrona di un

Page 232: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

delegate, vogliamo evitare di gestirne il termine dal metodo chiamante, perchéquest’ultimo dovrà successivamente occuparsi di altre funzionalità della nostraapplicazione. In casi simili, in luogo delle due tecniche viste in precedenza, possiamointercettarelaconclusionedell’invocazione,configurandoildelegateinmodocheeseguaunmetododicallback,comeavvienenelcodicedell’esempio9.12.

Esempio9.12SubMain()

DimmethodAsNewSomeDelegate(

Function(parameter)

Thread.Sleep(1000)

Console.WriteLine("Ciaoda{0}",parameter)Returnparameter.Length

EndFunction)

'Esecuzioneasincronadeldelegate

method.BeginInvoke("MarcoDeSanctis",AddressOfMyCallback,Nothing)Console.WriteLine("Esecuzioneavviata")

Console.ReadLine()

EndSub

PrivateSubMyCallback(ByValarAsIAsyncResult)

Console.WriteLine("Esecuzioneterminata")

EndSub

LasignaturediMyCallbackdeverispettarequelladeldelegateAsyncCallback,cheaccettainingressol’istanzadiIAsyncResultassociataall’esecuzionedeldelegateasincrono.

Nel caso esso produca un risultato e vogliamo recuperarlo, possiamo avvalerci dellaproprietàAsyncStatediIAsyncResult, che abbiamocitatonel paragrafoprecedente.Sitratta di un generico contenitore a cui, in corrispondenza del metodo BeginInvoke,possiamo associare un qualsiasi tipo di oggetto, e quindi anche l’istanza del delegatestesso, inmodo che possiamopoi utilizzarlo secondo i nostri scopi, come nell’esempio9.13.

Esempio9.13SubMain()

DimmethodAsNewSomeDelegate(

Function(parameter)

Thread.Sleep(1000)

Page 233: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Console.WriteLine("Ciaoda{0}",parameter)Returnparameter.Length

EndFunction)

'Esecuzioneasincronadeldelegate

method.BeginInvoke("MarcoDeSanctis",AddressOfMyCallback,method)Console.WriteLine("Esecuzioneavviata")Console.ReadLine()

EndSub

PrivateSubMyCallback(ByValarAsIAsyncResult)

Console.WriteLine("Esecuzioneterminata")

Dimmethod=DirectCast(ar.AsyncState,SomeDelegate)

DimresultAsInteger=method.EndInvoke(ar)

Console.WriteLine("Ilrisultatoè{0}",result)

EndSub

Quando ci troviamo all’interno del metodo di callback, l’esecuzione del delegateasincronoèterminataepertantopossiamoinvocarneilmetodoEndInvoke,certicheessocompletiimmediatamentel’invocazione,ritornandoilrisultatodesiderato.

Questatecnicarisultaparticolarmenteutilenell’ambitodiapplicazionidesktopoRIA,come quelle realizzate conWPF o Silverlight: in questi scenari, infatti, usare il threadprincipale per intercettare il termine di un’esecuzione asincrona equivale a bloccarel’interfaccia utente, peggiorando quindi la user experience. Possiamo pensare allora diavviareiltasktramiteBeginInvoke,diritornareimmediatamenteilcontrolloall’utenteedigestirne successivamente lachiusuraall’invocazionedelmetododicallback.Tuttaviadobbiamo prestare estrema attenzione al fatto che ilmetodo di callback viene eseguitoall’internodelworkerthreadassociatoaldelegateasincrono.Pertanto,essononpuòessereutilizzatodirettamenteperaggiornareglielementidell’interfacciautente.

Le funzionalità viste finora fanno parte del .NET Framework sin dalle primissimeversioni,quandoaverepiùdiunaCPUadisposizioneeraunapeculitaritàsolodeimiglioriserver. Anche in simili ambienti, però, il sistema operativo e in particolar modo loscheduler,rendonol’illusionediriuscireaprocessarepiùistruzionicontemporaneamente,assegnando ogni flusso di codice alla CPU per un certo periodo di tempo. Ma, comepossiamo facilmente immaginare, possiamo parlare di vero e proprio parallelismo soloquandodueo più thread siano assegnati ad altrettanti distinti coremessi a disposizionedall’hardware. Il .NET Framework dispone di una libreria specifica per l’esecuzioneparalleladicodice,chesaràargomentodelleprossimepagine.

EsecuzioneparallelaconParallelExtensionsCon l’avvento e il diffondersi dimacchinemulti-core, per poter sfruttare almassimo lepotenzialità dell’hardware è necessario strutturare le applicazioni secondo architetture

Page 234: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

innovative volte, in particolare, a favorire l’uso del parallelismo. Non si tratta diun’operazionesemplicemaavereadisposizionestrumentievolutirappresentasicuramenteun enorme vantaggio, soprattutto quando forniscono a noi sviluppatori la possibilità diconcentrarci solo sugli aspetti logici del requisito da soddisfare, come se creassimosemplice codice multithread, senza doverci preoccupare dei dettagli tecnici con cui ilparallelismovieneimplementato.

All’interno del .NET Framework trova spazio una libreria, chiamata ParallelExtensions, che è in grado di gestire threadmultipli inmaniera ottimizzata in base alnumero di CPU, così che anche le nostre applicazioni possano effettivamente eseguirecodiceinparallelo.Essasicomponedidueelementifondamentali:

TaskParallelLibrary(TPL),cioèuninsiemediclassi,tramitelequalisiamoingradodieseguireinparalleloporzionidicodicepersonalizzate;

ParallelLINQ(PLINQ),ossiaunaseriediextensionmethodcheciconsentonodisfruttareilparallelismopercalcolareilrisultatodiquerydiLINQtoObjects.

Lo scopo dei prossimi paragrafi è proprio quello di imparare a conoscere questi duestrumentipercapireneldettagliocomesfruttarlialmeglio.

LaTaskParallelLibraryLa classe Task appartiene al namespace System.Threading.Tasks e fornisceun’interfaccia evolutaper la creazione e il controllo sull’esecuzionedi codiceparallelo.Essabasa lasua interfacciasull’utilizzodeidelegateActioneFunc,asecondadel fattocheeseguiamounaproceduraounafunzione.L’esempio9.14mostraalcunicasitipicidiutilizzo.

Esempio9.14'Costruzionediunsemplicetask

DimsimpleTask=Task.Factory.StartNew(

Sub()

Thread.Sleep(1000)

Console.WriteLine("CiaodasimpleTask")

EndSub)

'Costruzionediuntaskconparametroininput

DimparameterTask=Task.Factory.StartNew(

Sub(name)

Thread.Sleep(1000)

Console.WriteLine("CiaodaparameterTask,{0}",name)

EndSub,"MarcoDeSanctis")

Page 235: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'Costruzionediuntaskcheritornaunrisultato

DimresultTask=Task.Factory.StartNew(

Function(inputValue)AsDecimal

ReturnPerformSomeLongCalculation(inputValue)

EndFunction,5000D)

La creazione di un task può essere realizzata tramite l’oggetto TaskFactory, a cuipossiamoaccederetramitelaproprietàstaticaTask.Factorye,inparticolare,sfruttandoilmetodo StartNew. Come possiamo notare nell’esempio 9.14, si tratta di un metodoestremamente versatile, grazie al quale possiamo creare istanze di Task che eseguonoprocedureofunzioni,siacon,siasenzaparametriiningresso.

I task creati in questomodo vengono automaticamente schedulati per l’esecuzione equindiavviatinonappenapossibile.Inalternativa,possiamoavvalercidelcostruttorepergenerareun’istanzadellaclasseTaske,successivamente,chiamareilmetodoStart.

Esempio9.15'Creazioneesplicitadiuntask

DimresultTask=NewTask(

Function(inputValue)AsDecimal

ReturnperformSomeLongCalculation(inputValue)

EndFunction,5000D)

'Esecuzione

resultTask.Start()

Ilcodicedell’esempio9.15risultautilequandovogliamolimitarciaistanziareunoggettoTasksenzaprocedereimmediatamenteall’esecuzione,magariperchélanostraintenzioneè quella di passarlo come parametro a una procedura. Negli altri casi, l’utilizzo diTaskFactorycomportaleprestazionimigliori.

Quando creiamo un task passando un argomento di tipo Func, ossia una funzione,l’oggettocheinrealtàvienecostruitoèditipoTask(OfResult),unaclassechederivadaTask e cheespone laproprietàResult, tramite la qualepossiamo recuperare il risultatodell’invocazione,comenell’esempio9.16.

Esempio9.16DimresultTask=Task.Factory.StartNew(

Function(inputValue)AsDecimal

ReturnperformSomeLongCalculation(inputValue)

EndFunction,5000D)

'..altrocodicequi..

'Determinazionedelrisultato

Page 236: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Console.WriteLine("Ilrisultatoè:{0}",resultTask.Result)

Utilizzandoquestaproprietà,attiviamoautomaticamentelasincronizzazionedeltaskconil thread chiamante, che rimane bloccato finché il risultato non viene reso disponibile,ossiafinoalterminedell’elaborazioneasincrona.

La proprietà Result risulta molto comoda per recuperare il risultatodell’esecuzione di un task perché ne consente anche implicitamente lasincronizzazione. Tuttavia, bisogna prestare grande attenzione al suo utilizzoperchénonci vienepermessodi specificareun timeout.Pertanto,accedere inletturaaun taskbloccatoononancoraavviato,puòcomportare ilbloccodelthreadchiamante.

Ingenerale,quandoabbiamolanecessitàdiattenderechel’esecuzionediunoopiùtasksiaconclusa,possiamoutilizzareunodeitremetodiriassuntiintabella9.2.

Tabella9.2–MetodidiattesadellaclasseTask.Nome Descrizione

Wait Metododiistanzatramiteilqualepossiamoattenderelaconclusionedeltaskcorrente.

WaitAllMetodo statico esposto dalla classe Task, che accetta in ingresso un array di task da sincronizzare e ritorna ilcontrolloalthreadchiamantequandotuttihannoterminatol’esecuzione.

WaitAnyMetodo statico esposto dalla classe Task, che accetta in ingresso un array di task da sincronizzare e ritorna ilcontrolloalthreadchiamantequandoalmenounohaterminatol’esecuzione.

Essiconsentonoanchedispecificareuneventualetimeout,oltreilqualeilcontrollovienecomunquerestituitoal threadchiamante.L’esempio9.17mostradiversiutilizzidiquestimetodi.

Esempio9.17'Attesasenzatimeout

DimmyTask=Task.Factory.StartNew(AddressOfSomeMethod)

myTask.Wait()

'Attesacontimeoutdi1secondo

myTask=Task.Factory.StartNew(AddressOfSomeMethod)

myTask.Wait(1000)

'AttesaconclusionediunotramyTaskeanotherTask

myTask=Task.Factory.StartNew(AddressOfSomeMethod)

DimanotherTask=Task.Factory.StartNew(AddressOfSomeMethod)

Task.WaitAny(myTask,anotherTask)

'AttesaconclusionediunalistadiTask,contimeoutdi2secondi

DimtaskListAsList(OfTask)=GetTaskList()

Task.WaitAll(taskList.ToArray(),2000)

Essi,ingenerale,nondevonoessereutilizzatisoloneicasiincuiabbiamolanecessitàdi

Page 237: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

attendere la conclusione di un task, ma anche quando vogliamo essere sicuri chel’esecuzione siaandataabuon fine.Quandoun task solleva internamenteun’eccezione,infatti,quest’ultimavienenotificataalchiamantesoloincasodi invocazionedeimetodiWait,WaitAlloWaitMany,odiaccessoallaproprietàResult.

Esempio9.18DimproblematicTask=Task.Factory.StartNew(

Sub()

ThrowNewApplicationException("Errore!")

EndSub)

Try

problematicTask.Wait()

CatchexAsAggregateException

Console.WriteLine("Iltaskhasollevatolaseguenteeccezione:")

Console.WriteLine(ex.InnerException)

EndTry

Nelcasodell’esempio9.18,l’eccezionesollevatadaproblematicTaskvienerilevatasolonelmomento in cui richiamiamo ilmetodoWait edè incapsulata come inner exceptionall’internodiunaAggregateException.

ComposizioneditaskUna caratteristica della classe Task, che spesso risulta estremamente comoda, è lapossibilitàdicombinarel’esecuzionedipiùdelegateutilizzandoilmetodoContinueWith.

Esempio9.19DimcompositeTask=Task.Factory.StartNew(

Sub()

Thread.Sleep(1000)

Console.WriteLine("Primotask")EndSub).ContinueWith(

Sub()

Thread.Sleep(1000)

Console.WriteLine("Secondotask")EndSub)

'Accodamentodiunafunzione

Page 238: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DimresultTask=compositeTask.ContinueWith(

Function(taskAsTask)AsString

Dimresult="Funzionedelterzotask"

Console.WriteLine(result)

Returnresult

EndFunction)

Console.WriteLine("Ilrisultatoè:{0}",resultTask.Result)

Ilcodicedell’esempio9.19utilizzaquestafunzionalitàperconcatenaretredifferentitask,iprimiduecontenentiprocedureeilterzo,invece,relativoaunafunzione,recuperandoaltermine il risultato di quest’ultima. Nel caso vogliamo attendere la conclusione dimolteplici elaborazioni prima di procedere all’esecuzione di una nuova istanza diTask,possiamo utilizzare i metodi ContinueWhenAll o ContinueWhenAny dell’oggettoTaskFactory, comenell’esempio9.20.Essi accettano in ingresso un array di istanze diTaskdamonitorareeildelegatedaavviarequando,rispettivamente,tutteoalmenounadiquesteterminaconsuccesso.

Esempio9.20DimtaskListAsList(OfTask)=getTaskList()

'TaskdaeseguirealterminedituttiquellicontenutiintaskList

DimfinalTask=Task.Factory.ContinueWhenAll(

taskList.ToArray(),

Sub()Console.WriteLine("Tuttiitaskcompletaticonsuccesso"))

NestedtaskechildtaskIldelegatefornitocomeparametroalmetodoTaskFactory.StartTaskoalcostruttorediTaskpuò,ovviamente,esserearbitrariamentecomplessoemagari istanziareeavviarealsuointernoulterioritask,comenell’esempio9.21.

Esempio9.21DimouterTask=Task.Factory.StartNew(

Sub()

DiminnerTask=Task.Factory.StartNew(

Sub()

Thread.Sleep(2000)

Console.WriteLine("NestedTask")

EndSub)

Page 239: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Console.WriteLine("Firsttask")

EndSub)

outerTask.Wait()

Console.WriteLine("outerTaskTerminato")

Un’istanzacomeinnerTasknell’esempio9.21èchiamatanestedtask (taskannidato) ehalacaratteristicadipossedereunciclodivitaproprio,del tuttoindipendentedaquellodeltaskdacuièstatagenerata.Pertanto,l’invocazionealmetodoouterTask.WaitattendeilterminedelsoloouterTask.Infasedicostruzioneperò,possiamospecificarelavolontàdi sincronizzare innerTask ed outerTask, usando il parametro opzionaleTaskCreationOptions.AttachedToParent.

Esempio9.22DimouterTask=Task.Factory.StartNew(

Sub()

DiminnerTask=Task.Factory.StartNew(

Sub()

Thread.Sleep(2000)

Console.WriteLine("ChildTask")

EndSub,TaskCreationOptions.AttachedToParent)

Console.WriteLine("Firsttask")

EndSub)

outerTask.Wait()

Console.WriteLine("outerTaskTerminato")

Nelcasodell’esempio9.22,innerTaskèdenominatochildtask(taskfiglio)epresentauncomportamentosensibilmentediversorispettoalprecedente,datocheiduetasknonsonopiù indipendenti: outerTask, infatti, riceve le eventuali notifiche delle eccezioni dainnerTaske,comunque,neattendeilcompletamentoprimadichiudersi,producendosuconsoleilrisultatomostratoinfigura9.3.

Figura9.3–Risultatodell’utilizzodeichildtask.

TramitelaclasseTask,inconclusione,siamoingradodieseguireinparalleloprocedureefunzioni, sfruttandoalmassimo i core adisposizionema senzadoverci preoccuparedei

Page 240: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

dettagli hardware.LaParallelTaskLibrary rappresenta, però, solo una parte di ParallelExtensions, che è anche in grado dimigliorare sensibilmente le prestazioni delle nostrequeryLINQtoObjects,comevedremonelprossimoparagrafo.

ParallelLINQLINQtoObjectsèsenz’altrounadellefunzionalitàpiùinteressantieutilizzatedel.NETFramework, grazie alla semplicità e all’intuitività con cui possiamo realizzareinterrogazioni,anchecomplesse,sucollezionidioggettiinmemoria.

All’interno delle Parallel Extension trova posto un’implementazione di LINQ graziealla quale possiamo facilmente fare in modo che le nostre query sfruttino al massimol’architetturamulticoreemultiprocessoremessaadisposizionedall’hardwaredioggi.Ciòè possibile grazie alla presenza dell’extension method AsParallel, tramite il qualepossiamo istruire il runtime per far sì che la query venga eseguita in parallelo.Ovviamente,affinchénepossiamoapprezzareivantaggi,itestdevonoessereeseguitisuungrannumerodidati,comenelcasodell’esempio9.23.

Esempio9.23'Creazionediunalistadinumericasuali

DimmyListAsNewList(OfInteger)

DimrndAsNewRandom

Forindex=1To10000000

myList.Add(rnd.Next(0,100000))

Next

'Queryperrecuperareinumeriprimi

Dimprimes=FromnInmyList.AsParallel()

WhereIsPrime(n)

Selectn

Dimsw=Stopwatch.StartNew()

primes.Count()

sw.Stop()

Console.WriteLine("Esecuzioneparallela:{0}",sw.Elapsed)

SemplicementeaggiungendoAsParallelequindiattivandol’enginediPLINQ,unaquerycomequelladell’esempioprecedentericevetangibilimiglioramentiprestazionali; lalistain ingresso viene infatti partizionata in diversi sottogruppi di dati, in modo che possaessereprocessatainparallelodallediverseunitàdicalcolodelsistema(coree/oCPU).Ciòsievinceanchedandoun’occhiataaltaskmanagerdiWindows,monitorandol’utilizzodeiprocessoridurantel’esecuzionedell’applicazione,comemostratoinfigura9.4.

Page 241: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura9.4–UtilizzodelleCPUsenzaeconPLINQ.

I vantaggi prestazionali derivanti dall’uso di PLINQ non sono i medesimi per tutte lequery e dipendono pesantemente dalla logica di ognuna di esse. In generale, imiglioriguadagni si avvertono quando esse coinvolgono algoritmi di calcolo potenzialmentelunghiincorrispondenzadelleclausolewhereoselecteperiqualil’ordinedeglielementinonrappresentiunfattore.

Dimquery=FromitemInlist.AsParallel()

WhereVeryLongAlgorithm(item)

Selectitem

Ingenerale, l’esecuzionediunaquerysudiverseCPUnongarantisceche l’ordinedeglielementi in ingresso venga preservato; nel caso in cui questo sia necessario, possiamoindicarlotramiteilmetodoAsOrdered.

Dimquery=FromitemInlist.AsParallel().AsOrdered

WhereVeryLongAlgorithm(item)

Selectitem

È comunque l’engine stesso a valutare, caso per caso, se il parallelismo possarappresentare un vantaggio o meno, decidendo eventualmente di eseguire la querysequenzialmente,ancheinpresenzadellaclausolaAsParallel.

Le query LINQ in generale non vengono eseguite finché non accediamo al lorocontenutoe,tipicamente,ciòavvieneutilizzandoilmetodoToListpergenerareunalistadi elementi o iterandole tramite il costrutto For Each. In quest’ultimo caso, sebbenePLINQ riesca a sfruttare il parallelismo per calcolare il risultato dell’espressione, ènecessariocomunquepopolareunacollezionetemporaneaconidatiestratti,inmodochel’iteratore possa funzionare. Si tratta, ovviamente, di una condizione penalizzante che,qualora l’ordinedeglielementinon fosse importante,potrebbeessereevitatautilizzandol’extensionmethodForAll,comenell’esempio9.24.

Esempio9.24Dimprimes=FromnInlista.AsParallel()

Page 242: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

WhereIsPrime(n)

Selectn

primes.ForAll(Sub(item)DoSomething(item))

In questo caso la Action che abbiamo specificato come argomento di ForAll verràeseguitasuisingolipartizionamenti incuiPLINQhasuddiviso la lista iniziale,godendoquindideivantaggidelparallelismoe senza l’overheaddi ricostruireunacollezione sulthreadchiamante.

Esistono molteplici casi in cui, in generale, vogliamo realizzare cicli chepotenzialmente possono essere eseguiti in parallelo, senza che questicoinvolgano necessariamente query PLINQ. Per gestire situazioni simili, il.NETFrameworkdisponedellaclasseParallel,cheesponeduemetodistatici,ForeForEach.Essi sono rappresentativi degli omonimi costruttiVisualBasicma sfruttano internamente l’infrastruttura dei task per ripartire l’onerecomputazionaletraicoredisponibili.

Task Parallel Library e PLINQ sicuramente costituiscono un validissimo aiuto nellarealizzazione di codice parallelo e asincrono. Sin da Visual Basic 2012, però, è statointrodotto un nuovo costrutto che semplifica ulteriormente il nostro lavoro. Saràl’argomentodelleprossimepagine.

ProgrammazioneasincronaconAsynceAwaitFinora abbiamo visto diversi sistemi per realizzare codicemultithread, in grado cioè diessereeseguitosupiù threadcontemporaneamente.Unparticolareeffettodellosviluppomultithreadècostituitodall’esecuzioneasincronadiunmetodo, incuicioèil threadcheeffettualachiamatanonrestabloccatoinattesadelcompletamentodelmetodoinvocato.

Ivantaggidellaprogrammazioneasincronasinotanosoprattuttonell’ambitodiapplicazioniWindowsStoreoWPF,datocheinquesticasiilthreadchiamanteèquasisemprequellodell’interfacciautente:metodicheduranoalungo,senonsono eseguiti in maniera asincrona, bloccano l’interfaccia e quindil’applicazione non è più responsiva, mentre ciò non accade nel caso diesecuzioneasincrona.Tuttavia,ancheinaltriambiti,qualiperesempioquellodelleapplicazioniweb,losviluppoasincronopresentaimmensivantaggi,perchéconsenteinognicasodi liberareunthreadchepuòesseresfruttatodalserverperservireun’altrarichiesta.

NonostanteilmodellodeiTaskvistofinorasiasicuramenteunodeisistemipiùavanzatieintuitiviperscriverecodiceasincrono,èinnegabilecheilcodicerisultantesiasicuramentepiùcomplessoemenoleggibile.

Ciòpuòrappresentareunproblemaquandolalogicadaimplementaresiacomplicatae,per certi versi, ha sempre rappresentatounadelle difficoltà principali all’adozionedellaprogrammazioneasincrona.VisualBasic2015semplificadimoltoquestoscenariograzieall’introduzione di due nuove parole chiave, Async e Await. Cerchiamo di chiarirne il

Page 243: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

funzionamentoconunesempio.

Esempio9.25PublicSubDownload()

DimclientAsWebRequest=

HttpWebRequest.Create("http://www.google.com")

Dimresponse=client.GetResponse()

UsingreaderAsNewStreamReader(response.GetResponseStream)

'esecuzionesincronadellarichiesta

Dimresult=reader.ReadToEnd()

Console.WriteLine(result)

EndUsing

EndSub

Il codice dell’esempio 9.25 sfrutta la classe WebRequest e, successivamente,StreamReader,perrecuperareilcontenutodell’URLspecificatoe,fintantocheilrisultatonon viene recuperato, il thread resta bloccato e in attesa. Sfruttando Async e Awaitpossiamorealizzarnelaversionesincronainmanieraestremamentesemplice.

Esempio9.26PublicAsyncFunctionDownloadAsync()AsTask

DimclientAsWebRequest=

HttpWebRequest.Create("http://www.google.com")

Dimresponse=client.GetResponse()

UsingreaderAsNewStreamReader(response.GetResponseStream)

'esecuzioneasincronadellarichiesta

Dimresult=Awaitreader.ReadToEndAsync()

Console.WriteLine(result)

EndUsing

EndFunction

Questa nuova versione delmetodo ha richiesto intanto di specificare la keywordAsyncnellasuadichiarazione,chedasempliceSubèdivenutaunaFunctioncherestituisceunTask. Si tratta di una direttiva che indica al compilatore la nostra intenzione di gestireall’internodiquestometododellechiamateasincrone.IlpassosuccessivoèstatoquellodiutilizzareilmetodoReadToEndAsync,cherappresentalavarianteasincronadiReadToEnd:esso, infatti, restituisce un oggetto di tipo Task(Of String) ed esegue l’operazione didownloadinunaltrothread.

Con il .NET Framework 4.5, la maggior parte dei metodi la cui durata può

Page 244: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

essere potenzialmente “lunga” possiede una variante asincrona. Anchel’aggiunta di riferimenti a web service esterni consente di generare metodiasincroni. Se, per un particolare caso, il metodo asincrono non risultadisponibile, è sufficiente eseguirlo all’interno di un Task per poter sfruttarecomunquelatecnicacheabbiamomostrato.

Incondizioninormali,dovremmo inqualchemodogestire il callback suquestooggettoperrecuperarel’informazioneprelevatadallarete;grazieallaparolachiaveAwait,invece,èilcompilatorestessoapreoccuparsidiiniettaretuttoilcodicenecessario,enoipossiamosemplicementelimitarciaprelevareilrisultatodell’esecuzioneasincronaeassegnarloallavariabileresultdi tipoString, senzacurarcidel fatto che in realtà ilmetodo invocatorestituiscaunTask.

Ilvantaggio,ovviamente,èchepur sfruttando lepotenzialitàe lecaratteristichedellaprogrammazione asincrona, il codice che siamo chiamati a scrivere è assolutamenteanalogoallaversionesincronadell’esempio9.25.

EseguireoperazioniinparalleloconAsynceAwaitL’estremacomoditàdiAsynceAwaitsinotano,inmanieraparticolare,nelmomentoincuidobbiamoeseguireoperazioniasincroneincascata,comenelcasodell’esempio9.27.

Esempio9.27PublicAsyncFunctionSequentialOperations()AsTask

DimclientAsNewHttpClient()

DimfirstResult=Awaitclient.GetStringAsync("http://www.google.com")

Console.WriteLine(firstResult)

DimsecondResult=Awaitclient.GetStringAsync("http://www.yahoo.com")

Console.WriteLine(secondResult)

DimthirdResult=Awaitclient.GetStringAsync("http://www.bing.com")

Console.WriteLine(thirdResult)

EndFunction

In questo caso, per esempio, abbiamo concatenato tre invocazioni, ognuna delle qualinecessitadelrisultatodellaprecedenteperessereeseguita.Scriveremanualmenteilcodiceanalogoporterebbesicuramenteaunrisultatomoltomenoleggibileesuscettibiledierrori.Ogni volta che utilizziamo Await in un’operazione asincrona, il flusso del metodochiamanteviene interrottoper attendere ladisponibilitàdel risultato.Ciò imponeche lechiamate asincrone siano eseguite tutte in sequenza. Quando esse sono logicamenteindipendenti le une dalle altre, invece, può aver senso ristrutturare il codice comenell’esempio9.28,inmodochevenganoavviateinparallelo.

Page 245: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio9.28PublicAsyncFunctionParallelOperations()AsTask

DimclientAsNewHttpClient()

DimtasksAsNewList(OfTask(OfString))From{

client.GetStringAsync("http://www.google.com"),

client.GetStringAsync("http://www.yahoo.com"),

client.GetStringAsync("http://www.bing.com")

}

AwaitTask.WhenAll(tasks)

ForEachtaskIntasks

Console.WriteLine(task.Result)

Next

EndFunction

In questo caso, abbiamo evitato di utilizzare Await in corrispondenza di ogni singolachiamata,memorizzando le istanzedeiTask(OfString) restituiti all’interno della listatasks.Ilrisultatoècheilflussodelcodicenonvienepiùinterrottoperattendereirisultatieleoperazionivengonoeffettivamenteavviateinparallelo.Perrecuperarepoiirisultati,dobbiamoattendereilcompletamentodituttelechiamateasincrone,effettuandounAwaitsulmetodoWhenAlldellaclasse,comemostratonelcodice.

RealizzaremetodiasincroniNegliesempiprecedenti,abbiamomostratocometrasformareunmetodosincronoinunoasincrono:questaoperazionehacomportato, tra levariemodifiche, la trasformazionediuna Sub in una Function, denominata DownloadAsync, che restituisce un Task. Ingenerale, non si tratta di un’operazione necessaria, visto che possiamo applicare Asyncanche a una Sub, ma lo è nel momento in cui vogliamo consentire a chi utilizzeràDownloadAsync di effettuare, a suavolta,unAwait.Cercandodi riassumere lemodalitàconcuidichiarareunmetodoasincrono,possiamofareriferimentoaiseguentipunti:

SedichiariamounaAsyncSub,essasaràingradodieseguiremetodiasincronialsuointerno,mailsuochiamantenonsaràingradodieffettuarnel’Await.Sidice,allora,chelasuaesecuzionesaràditipo“fireandforget”.

Unmetodo di tipoAsyncFunctionasTask è unmetodo in grado di invocareoperazioni asincroni; la differenza rispetto al casoprecedente è che il chiamantepuòeffettuare l’Await eattenderne il completamento.Nonostante si trattidiunaFunction,acontifatti,nonrestituisceperòalcunrisultato,senonilTaskutilizzatointernamenteperlasincronizzazione.

UnmetododitipoAsyncFunctionasTask(OfT)èunafunzionechepossiedetutte le caratteristiche del punto precedente, ma che è in grado di restituire un

Page 246: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

oggettoditipoT.

Un’operazionepiuttostocomunedacompiereèquelladirealizzareunaversioneasincronadi un metodo. Abbiamo visto, all’inizio di questa sezione, che se gli oggetti cheutilizziamoespongonoalorovoltadelleversioniasincrone,latrasformazioneèpiuttostosemplice.Quando invecequestimetodinonesistono,possiamo invecesfruttareunTaskcomenell’esempio9.29.

Esempio9.29PublicFunctionSomeMethod()AsString

'codicequi…

Thread.Sleep(3000)

Return"test"

EndFunction

PublicFunctionSomeMethodAsync()AsTask(OfString)

Returntask.Run(Function()SomeMethod())

EndFunction

PublicAsyncSubExecute()

Dimresult=AwaitSomeMethodAsync()

Console.WriteLine(result)

EndSub

L’esempio9.29contieneunmetodoSomeMethodcheretituisceunaStringenonèpensatoper l’utilizzo asincrono. Il successivo SomeMethodAsync ne consente l’esecuzioneasincronainvocandoloall’internodiunTask.Comepossiamonotare,nonènecessariochequesto metodo sia marcato come Async, dato che internamente non ha necessità dieffettuarel’Awaitdialcunachiamata.Nonostanteciò,vistochecomunquerestituisceunTask,essopuòessereinvocatoinmodalitàasincronaall’internodiunmetodochiamante(Execute,nelnostrocaso).

Finoadora,parlandodimultithreadingeparallelismo,abbiamo trascuratounpaiodiaspetti di estrema importanza: l’accesso alle risorse condivise e la gestione dellaconcorrenza,cherappresentanofattorichiaveinapplicazionidiquestotipo.Essisarannol’argomentodelprossimoparagrafo.

ConcorrenzaethreadsafetyNellepagineprecedenti,eprecisamentenell’ambitodell’esempio9.3,cisiamoimbattutiinunaproblematicatipicadelleapplicazionimultithread:l’accessononregolamentatodaparte di thread concorrenti a risorse condivise, puòdar luogo a comportamenti anomalidenominati race condition, in cui l’effettivo risultato dell’algoritmo dipende dallatempisticaconcuiithreadevolvono.

Page 247: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Ingenerale,ognivoltacheinvochiamometodieproprietàdiunoggettoinunoscenarioparallelo, dobbiamo interrogarci sulla sua capacità di gestire accessi contemporanei daparte di più thread o, per meglio dire, sulla sua thread safety. Il .NET Frameworkgarantisce,perognunodeglioggettidefinitiall’internodellaBaseClassLibrary,lathreadsafetydi tutti imembri statici. Imembridi istanza, invece,nonsono ingenerale threadsafe,salvodiversespecifichenelladocumentazione.

Sincronizzarel’accessoallerisorseCerchiamo ora di capire in chemodo le race condition possonominare la stabilità delnostro codice e, per farlo, consideriamo l’esempio 9.30, in cui due task accedono allamedesimacollezione,unoleggendounelemento,l’altroeffettuandonelarimozione.

Esempio9.30DimmyListAsNewList(OfString)

myList.Add("Elementoditest")DimfirstTask=Task.Factory.StartNew(

Sub()

IfmyList.Count>0Then

'racecondition!

Console.WriteLine(myList(0))

EndIf

EndSub)

DimsecondTask=Task.Factory.StartNew(

Sub()

IfmyList.Count>0Then

myList.RemoveAt(0)

EndIf

EndSub)

Task.WaitAll(firstTask,secondTask)

Il codice riportato nell’esempio 9.30 sembra formalmente corretto, dato che entrambi itask verificano che sia presente almeno un elemento all’interno della lista prima diprocedereconilpropriocompito.

Tuttaviaesisteunapossibilitàpercui,dopochefirstTaskabbiaverificatolapresenzadialmenounelementodella lista,secondTask riescaa rimuoverloprimachequestosiaeffettivamente visualizzato sulla console, generando quindi un’eccezione a runtime;inoltre,nonessendoiltipoList(OfT)threadsafe,l’accessoconcorrentediduethreadaisuoimembripotrebbegenerareerrorinellavalutazionedimyList.CountodimyList(0).

Page 248: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Cosa ancora peggiore, questi malfunzionamenti non sono deterministici, dato chedipendonodalletempistichediesecuzionedeiduetaskche,comeabbiamoavutomododiapprendere nel corso del capitolo, sono soggette a un gran numero di variabili, quali ilnumerodiCPUpresentiolecondizionidicaricodellamacchina.

Pertanto, l’unicomodo per consentire un corretto funzionamento del codice visto inprecedenza,èquellodiregolare l’accessoallarisorsacondivisamyListdapartedeiduethread,comenell’esempio9.31.

Esempio9.31DimsyncObjectAsNewObject

DimmyListAsNewList(OfString)

myList.Add("Elementoditest")

DimfirstTask=Task.Factory.StartNew(

Sub()

DimlockTakenAsBoolean=False

Monitor.Enter(syncObject,lockTaken)

Try

IfmyList.Count>0Then

Console.WriteLine(myList(0))

EndIf

Finally

IflockTakenThen

Monitor.Exit(syncObject)

EndIf

EndTry

EndSub)

DimsecondTask=Task.Factory.StartNew(

Sub()

DimlockTakenAsBoolean=False

Monitor.Enter(syncObject,lockTaken)

Try

IfmyList.Count>0Then

myList.RemoveAt(0)

EndIf

Finally

IflockTakenThen

Monitor.Exit(syncObject)

Page 249: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndIf

EndTry

EndSub)

Task.WaitAll(firstTask,secondTask)

Nel codice precedente abbiamo utilizzato la classe Monitor per far sì che ogni taskacquisiscal’accessoesclusivoaunarisorsa,nelnostrocasol’oggettosyncObject.Questapraticagarantiscel’assenzadelmalfunzionamentovistoinprecedenzaperché,inpresenzadiunlockesclusivodapartediunthread,qualsiasialtrainvocazionealmetodoEnterdapartedialtrithreadrisultabloccatafinoalrilasciodellockstessotramiteilmetodoExit.

Per evitare che una risorsa resti comunque bloccata in caso di eccezione, èsemprenecessarioinvocareilmetodoExitall’internodiunbloccoFinally. IlflaglockTakenvienepassatoperriferimentoalmetodoEntere,sevalorizzatoaTrue,indicacheillockèstatoacquisitoe,pertanto,ènecessarioprocederealsuorilascio.

Invece di usare direttamente la classe Monitor, è possibile sfruttare la parola chiaveSyncLockdiVisualBasic,cheproducerisultatideltuttoequivalenti,consentendociperòdiscrivereunaminorequantitàdicodice.

DimfirstTask=Task.Factory.StartNew(

Sub()

SyncLocksyncObject

IfmyList.Count>0Then

Console.WriteLine(myList(0))

EndIf

EndSyncLock

EndSub)

Vale la pena di notare che, ovviamente, l’uso di lock esclusivi pone un limite alparallelismoe,pertanto,risultapiuttostopenalizzantedalpuntodivistadelleprestazionicomplessivedellanostraapplicazione.

Ancheperquestaragioneèdeterminante,adesempio,lapresenzanel.NETFrameworkdi collezioni che garantiscano la thread safety limitando al massimo l’utilizzo di lock,comevedremonelleprossimepagine.

CollezioniconsupportoallaconcorrenzaUtilizzare le collezioni inuno scenarioparallelononèbanalee anche leoperazionipiùsemplici rischiano di creare non pochi problemi: immaginiamo di dover scorrere unaList(OfString)mentreunaltrothreadtentadimodificarneilcontenuto.

Esempio9.32

Page 250: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DimmyListAsList(OfString)=GetList()

'Creazionedeltaskchescorrelacollection

DimfirstTask=Task.Factory.StartNew(

Sub()

ForEachitemAsStringInlista

DoSomething(item)Next

EndSub)

'Creazionedeltaskchemodificalacollection

DimsecondTask=Task.Factory.StartNew(

Sub()

lista.Add("Taskelement")

EndSub)

Task.WaitAll(firstTask,secondTask)

Se proviamo a eseguire il codice dell’esempio 9.32, noteremo che alcune voltel’applicazione si conclude regolarmente mentre in altri casi viene sollevata unaInvalidOperationExceptionacausadelfattochelacollezioneèstatamodificataquandol’enumerazioneeraancoraincorso.

Riuscireagestirequesto tipodi situazioni implica,adesempio,didoveracquisireunlockesclusivosullacollezioneedimantenerlofinoalterminedelbloccoForEach,masitratta di una soluzione che, come abbiamo avuto modo di vedere in precedenza, minaprofonamenteivantaggiprestazionaliderivantidalparallelismo.

Il.NETFramework,einparticolareleParallelExtensions,contengonoledefinizionidiunaseriedicollezionithreadsafesiainletturasiainscrittura,profondamenterivistenellalorostrutturainternainmododaminimizzarel’usodellockegarantire,inquestomodo,prestazioni elevate. Esse fanno parte del namespace System.Collctions.Concurrent esonoelencatenellatabella9.3.

Tabella9.3–CollezionicontenuteinSystem.Collections.Concurrent.Nome Descrizione

ConcurrentBagSi tratta di un contenitore generico di oggetti, in cui l’ordine non è importante e che ammette lapresenzadiduplicati.

ConcurrentStack ImplementazionethreadsafediunacollezioneconaccessobasatosulogicaLIFO(LastInFirstOut).

ConcurrentQueue ImplementazionethreadsafediunacollezioneconaccessobasatosulogicaFIFO(FirstInFirstOut).

ConcurrentDictionary Rappresentaundizionario,ossiauninsiemenonordinatodicoppiechiave-valore.

Esse non corrispondono esattamente alle loro controparti contenute nel namespaceSystem.Collections.Generics ed espongono un set limitato di metodi e proprietà: loscopo, infatti, non è quello di replicare tutte le funzionalità tipiche, ad esempio, dellaclasseList(OfT),maquellodi fornireun insiemedi strumentibasilari chesupportinoscenariincuiagiscono,inscritturaelettura,diversithreadcontemporaneamente.

Page 251: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Semplicementeriscrivendo ilcodicemostrato inprecedenza,utilizzandoun’istanzadiConcurrentBag in luogodella listadi tipoList(OfString), l’applicazione si concludesemprecorrettamentesenzasollevarealcunerrore(esempio9.33).

Esempio9.33DimmyBagAsNewConcurrentBag(OfString)(GetList())

DimfirstTask=Task.Factory.StartNew(

Sub()

ForEachitemAsStringInmyBag

DoSomething(item)

Next

EndSub)

DimsecondTask=Task.Factory.StartNew(

Sub()

myBag.Add("Taskelement")

EndSub)

Task.WaitAll(firstTask,secondTask)

Quandoun threadutilizza il bloccoForEach per enumerare la collezione, viene infattigeneratointernamenteunosnapshotrappresentativodelsuocontenutonelmomentoincuil’enumeratore viene istanziato, così che eventuali successivi inserimenti non creinoproblemi, pur in assenza di lock esclusivi. ConcurrentBag è anche in grado di gestireinternamentecodedielementi,differenziateasecondadelthreadcheliinserisce,inmodoche,fintantocheunthreadaccedeinletturaaimedesimielementichehascritto,nonsianecessarioalcunmeccanismodisincronizzazione.

ConclusioniInquestocapitoloabbiamotrattatoargomentichepossonoessereritenutiavanzatimache,negli anni a venire, rappresenteranno un bagaglio indispensabile per ogni sviluppatore.Scrivere codice multithread, in grado cioé di eseguire contemporaneamente diverseoperazioni sfruttando l’infrastruttura di threading del sistema operativo, consente diincrementarenotevolmenteleprestazionidellenostreapplicazioni.Nellaprimapartedelcapitoloabbiamovistoquali sonoglioggettimessiadisposizionedal .NETFrameworkper lagestionedei thread,chepossonoessere istanziatiesplicitamenteoprelevatidaunpoolgestitodalCLR.

Successivamente, abbiamo introdotto il concetto di parallelismo, ossia la capacità diun’applicazione multithread di assegnare i task creati dallo sviluppatore alle unità dicalcolo(coree/oCPU)messeadisposizionedall’hardware.LeParallelExtensionssonouna porzione del .NET Framework il cui compito è proprio quello di fornire strumenti

Page 252: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

evolutiperrealizzarecodiceingradodiessereeseguitoinparallelo.TramitelaclasseTaskpossiamo facilmente eseguire delegate in maniera asincrona, ottimizzandone laschedulazioneinbasealnumerodiunitàdicalcolopresentinelsistema.GrazieaParallelLINQ,abbiamoinoltrelacapacitàdimiglioraresensibilmenteleprestazionidellenostrequery LINQ toObjects, grazie a un engine in grado di valutare se esse possono trarrebeneficidall’esecuzioneparallelae,eventualmente,utilizzarel’infrastrutturadei taskperimplementarla.

Scrivere applicazioni di questo tipo non è però semplice, dato che codice non threadsafeeraceconditionpossonominarnelastabilità.Nell’ultimapartedelcapitolocisiamooccupati proprio di queste problematiche, mostrando quando è necessario utilizzaresistemidi sincronizzazioneper evitarebug legati alla concorrenza, e come le collezioniconcorrenti possano garantire, allo stesso tempo, thread safety ed elevate prestazioni,grazieallimitatoutilizzodeilockesclusivi.

Con il prossimo capitolo cambieremo radicalmente argomento, passando a un temaassolutamentecentralenell’ambitodellosviluppodiapplicazionireali:l’accessoaidati.

Page 253: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

10

L’accessoaidaticonADO.NET

La tecnologia raccomandata daMicrosoft per l’accesso ai dati è Entity Framework: laversionediLINQpensataspecificamenteperl’accessoadatabase.Primadiesaminareinprofondità questo framework, vale la pena conoscere l’infrastruttura di oggetti su cui sipoggia.MoltideglioggettichefannopartediADO.NET,acuiilcapitoloèdedicato,sonoinfattiutilizzatidaEntityFrameworkcomecomponentiinterniperaccederealDBMSe,inparticolare,perlaletturaelamodificadeidati.

ADO.NETrappresenta il sottosistemadiaccessoaidatipresenteall’internodel .NETFramework. Ispiratosi profondamente ad ActiveX Data Objects (ADO), ADO.NETfornisceaglisviluppatoriinambito.NETfunzionalitàsimiliaquellechevengonofornitedaADOaglisviluppatoriinambitoCOMnativo(ComponentObjectModel).

Tuttavia,ADO.NETintroduceunmodellodiprogrammazionemoltodiversorispettoalpassato.L’utilizzodel.NETFrameworkcomebaseassicural’uniformitàdellatecnologiaperl’accessoaidati:unsistemaditipicomune,imodellidiprogettazioneeleconvenzionidi denominazione vengono infatti condivisi da tutti i componenti. ADO.NET è statoprogettatoper soddisfare le esigenzedi questomodellodi programmazione: architetturadeidatidisconnessa,strettaintegrazioneconXML,rappresentazionecomunedeidati,conlapossibilitàdicombinaredatiprovenientidadiversesorgenti,efunzionalitàottimizzateperl’interazioneconundatabase,tuttielementinatividel.NETFramework.

ADO.NETfornisceuniformitàdiaccessosiaaiDBMScomeSQLServereOracle,siaasorgentidatiraggiungibilitramiteproviderOLEDBedriverODBC.TramiteADO.NET,le applicazioni sono in grado di connettersi a sorgenti dati eterogenee, modificare eaggiornareidatiinessecontenuti.

ManagedDataProviderADO.NET è composto da una serie di namespace che raccolgono le diverse classi perl’accessoaidatiinfunzionedelloroscopoedellaloroimplementazione:

ilnamespaceSystem.Data racchiude le classi di usogenerale, indipendenti dallaparticolaretipologiadisorgentedati;

iManagedDataProvider implementano inmodoparticolare le classi utilizzateperaccedereasorgentidatispecifiche;

Page 254: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

i namespace System.Data.Common e System.Data.ProviderBase includono leclassi base per gli oggetti fondamentali presenti in ciascun data provider eimplementatiinmodospecificoapartiredaunastrutturacomune;

ilnamespaceSystem.Data.SqlTypescontieneleclassicherappresentanoitipididatiutilizzatiinambitoSQL.

Come abbiamo già detto, i data provider rappresentano i contenitori per leimplementazionispecifichedeglioggettiutilizzatiperl’accessoaunaparticolaresorgentedati. Il .NETFramework includediversimanagedproviderbuilt-in, relativiallesorgentidati più in uso nell’ambito dello sviluppo di applicazioni in ambiente Microsoft. Lasezione system.data del file di configurazione di sistema machine.config contienel’elencodeimanagedproviderdisponibilialivellodisistema(veditabella10.1).

IdataproviderOleDbeOdbcnonsonospecificiperunparticolareDBMSmaservonodatramiteversosorgentidatiaccessibilitramiteproviderOLEDBedriverODBC(vedifigura 10.1). Diversamente dai managed provider, che utilizzano esclusivamente classinativecontenutedirettamentenel.NETFramework,idataproviderOleDbeOdbcesconodall’ambiente managed interoperando con l’ambiente unmanaged COM sottostante. Ilcosto legato al marshalling, cioè la trasformazione da ambiente managed ad ambienteunmanaged, fa preferire, dal punto di vista della prestazione, l’utilizzo dei managedproviderspecifici,qualorasianodisponibili.

IldataproviderperSQLServersiriferiscealleversionisuperiorialla7.0mentre,perlaversione 6.5, occorre utilizzare il provider OleDb (compatibile in particolare conSQLOLEDB,MSDAORAeilJetEnginediAccess)piuttostochequelloOdbc(riferitoaidriverODBC,tracuianchequelliperSQLServer,OracleeJetEngine).

Il managed provider per Oracle incluso in ADO.NET è contenuto in un assemblyseparato (il file System.Data.Oracle.dll). Questo data provider fa parte del .NETFramework sin dalle prime versioni e ormai è diventato obsoleto. In alternativa, perriuscire a sfruttare inmodo completo la più recente versione di Oracle, è consigliabilel’uso di ODP.NET 12c (Oracle Data Provider for .NET), fornito da Oracle stessa eaggiornato al .NET Framework 4.5.2. Il provider alla versione 3, funziona pienamenteanche con la versione 4.6 del .NET Framework ed è scaricabile all’indirizzohttp://aspit.co/a6u.

Tabella10.1–Imanageddataproviderbuilt–indiADO.NET.

ManagedDataProvider Namespaceenomeinvariante

OdbcDataProvider(ODBC) System.Data.Odbc

OleDbDataProvider(OLEDB) System.Data.OleDb

SqlClientDataProvider(SQLServer) System.Data.SqlClient

SQLServerCompactEditionDataProvider System.Data.SqlServerCe

Parallelamente ai data provider built-in, sono disponibili e reperibili in Internet anche imanagedproviderperaltriDBMScomeMySQL,Firebird,PostgreSQLealtriancora.

Page 255: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura10.1–ArchitetturadiADO.NET.

I managed provider di ADO.NET implementano un insieme comune di classi astratte,contenutenelnamespaceSystem.Data.Common:

DbConnection:permettelaconnessioneaundatabase;

DbConnectionStringBuilder: è l’oggettobuilderper lacostruzionedella stringadiconnessione;

DbCommand:consentel’esecuzionedicomandiSQLedistoredprocedure;

DbDataReader: implementa un cursore forward-only (statico), read-only e clientside,perlaletturadeirisultatidiunaquery;

DbCommandBuilder:èl’oggettobuilderperlacostruzionediuncomandoSQL;

DbTransaction:permettedieseguirepiùcomandiinuncontestotransazionale;

DbDataAdapter: consente di “riempire” un container di dati disconnesso daldatabase(DataSetoppureDataTable);

DbParameter: rappresenta un parametro di input e/o output per una storedprocedureouncomandotestuale;

DbParameterCollection:rappresentaunacollezionediparametri;

DbException:fungedaclassebaseperleeccezionispecifichediundataprovider;

Page 256: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DbProviderFactory:èunaclassefactoryperlacreazionediistanzedialcunideglioggettisopraelencati(connessioni,comandi,ecc.).

La comunicazione con una sorgente dati e il relativo modello di programmazione diADO.NETprevedeuna serie di azioni chehannovalidità generale e chedevono esseresempreattuate, indipendentementedal tipodi sorgentedati.Aciascunadiquesteazionicorrisponde,perognidataprovider,unaclassederivatadaunodei tipiastratticontenutinelnamespaceSystem.Data.Commoneimplementatainbaseallecaratteristichespecifichedellasorgentedatidiriferimento.

ConnessioneaunasorgentedatiIl primo oggetto che prendiamo in considerazione è la connessione. Infatti, percomunicare con una sorgente dati al fine di eseguire comandi di lettura e diaggiornamento,èsemprenecessarioinstaurareuncertotipodicollegamento,chedipendeinevitabilmentedaltipodisorgentedati.Nelcasodeidatabaserelazionali,l’attivazionediunaconnessionefisicaalserverèpropedeuticaall’inoltrodiqualsiasicomandoSQLperlaletturaolamodificadeidaticontenutinelletabelle.

CiascundataproviderdiADO.NETimplementalaclasseastrattaDbConnectioninbaseallecaratteristichepeculiaridellasorgentedatidiriferimento.Questaclasseincludealcunimembri di utilità generale e, in particolare, il metodo di apertura Open, il metodo dichiusuraCloseelaproprietàConnectionString,cherappresentalastringacontenenteleinformazioni di configurazione della connessione. La stringa di connessione per unaparticolareistanzapuòesserespecificatasiatramitelaproprietàappenamenzionataprimadell’invocazione del metodo di apertura, sia in fase di creazione tramite un costruttoreparametrico.

L’esempio10.1mostracomeaprireechiudereunaconnessioneversoundatabaseSQLServer,definendolastringadiconnessionetramiteilcostruttoreparametricodellaclasseSqlConnection.L’utilizzodelbloccodigestionedelleeccezionipermettediintercettareinmodoappropriatoglieventualierrori,derivanti,peresempio,daun’errataconfigurazionedelle credenziali dell’utente oppure da un problemadi connessione al server.Una voltaaperta,laconnessioneaunasorgentedativasemprechiusainmodoesplicito,perevitaresprechidirisorse.

Esempio10.1'Stringadiconnessione

DimconnectionStringAsString="Server=localhost;"&

"Database=Northwind;UserID=appUser;Password=p@$$w0rd"

'Creazionedell'istanzadiSqlConnection

DimconnAsNewSqlConnection(connectionString)

Page 257: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Try

'Aperturadellaconnessione

conn.Open()

'...

CatchexAsSqlException

'Gestionedell'eccezione

Finally

'Chiusuradellaconnessione

If(conn.State=ConnectionState.Open)Thenconn.Close()

EndTry

DalmomentochelaclasseDbConnectionimplemental’interfacciaIDisposable,ilcodiceprecedentepuòesserescrittoinmodopiùcompatto,sfruttandoilcostruttoUsing(esempio10.2).

Esempio10.2DimconnectionStringAsString="..."

UsingconnectionAsNewSqlConnection(connectionString)

connection.Open()

'...

EndUsing

Ilcodiceriportatonell’esempio10.2èdeltuttoequivalenteaquellomostratonell’esempio10.1. La connessione viene chiusa in modo trasparente al termine del blocco Using,medianteunachiamataimplicitadelmetodoDisposesiaincasodisuccessosiaincasodierrore.

Una volta creata e aperta una connessione, possiamo avviare un contestotransazionale per i comandi a questa associati, tramite il metodoBeginTransaction,con la possibilità di specificare il nome identificativo e illivellodiisolamento.Perulterioridettaglieapprofondimentiinmeritoall’usodelle transazioni in ADO.NET, rimandiamo alla documentazione in linea diMSDN.

La stringa di connessione è composta da una serie di coppie nome/valore separate dalcarattere “;” (punto-e-virgola), al quale corrispondono altrettante parole chiave. Leprincipalikeywordsonoelencatequidiseguito:

DataSource(equivalenteaServer)specificailpercorsodoverisiedelasorgentedati;

Database(equivalenteaInitialCatalog)identificaildatabasepredefinito;

User ID (equivalente a Uid) identifica il nome dell’utente nel caso in cui sia

Page 258: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

necessariospecificarelecredenzialidiaccesso(peresempio,autenticazioneSQLServer);

Password(equivalenteaPwd)identificalapassworddell’utentenelcasoincuisianecessariospecificarelecredenzialidiaccesso;

IntegratedSecurity (equivalente aTrusted_Connection) permettedi abilitarel’autenticazioneWindows(autenticazioneintegrata).Inquestocaso,lecredenzialidell’utentepossonoessereomesse;

Provider(validoperilmanagedproviderOLEDB)specificailproviderOLEDBdautilizzare;

Driver (valido per il managed provider ODBC) specifica il driver ODBC dautilizzare.

Tabella10.2–Alcuniesempidistringhediconnessione.Tipologia Stringadiconnessione

SQL Server (autenticazione SQLServer)

"Data Source=localhost; User ID=appUser; Password=p@$$w0rd; Initial

Catalog=Northwind;"

SQL Server (autenticazioneintegrata)

"Data Source=localhost; Integrated Security=true; Initial

Catalog=Northwind;"

SQL Server Express (cartella/App_Data/)

"Server=.\SQLExpress; AttachDbFilename=|DataDirectory|Northwind.mdf;

Database=Northwind;Trusted_Connection=Yes;"

SQL Server Express (percorsoassoluto)

"Server=.\SQLExpress; AttachDbFilename=C:\Data\Northwind.mdf;

Database=Northwind;Trusted_Connection=Yes;"

MySQL(OLEDB) "Provider=MySQLProv; Data Source=localhost; User ID=appUser;

Password=p@$$w0rd;"

MySQL (MySQLConnector/NET)

"Server=localhost; Port=3306; Database=Northwind; Uid=appUser;

Pwd=p@$$w0rd;"

Oracle con tnsnames.ora(autenticazioneOracle)

"DataSource=DBNAME;UserId=appUser;Password=p@$$w0rd;"

Oracle con tnsnames.ora(autenticazioneintegrata)

"DataSource=DBNAME;IntegratedSecurity=SSPI;"

MicrosoftAccess(OLEDB) "Provider=Microsoft.Jet.OLEDB.4.0;DataSource=C:\Data.mdb;"

MicrosoftExcel(ODBC) "Driver={MicrosoftExcelDriver(*.xls)};DBQ=C:\Data.xls;"

Latabella10.2riportaalcuniesempidistringhediconnessioneemostradiversecasistichediformattazioneinbaseallatipologiadiprovideroditecnologiadiconnessioneutilizzata,altipodiautenticazionerichiesta(integrataomeno)einordineall’eventualepercorsosudiscodelfilecontenenteidati(SQLServerExpress).

L’autenticazioneintegratarappresentalamodalitàdiconnessionepiùsicuraedèquindida preferire ove possibile. Indipendentemente dal tipo di autenticazione scelta, in ognicaso, è buona norma utilizzare sempre utenti con permessi ristretti. L’impiego di utenticonpermessiamministrativi(come,peresempio,l’utente“sa”diSQLServer)rappresentasempreunapraticadaevitare,permotividisicurezza,anchedurantelafasedisviluppo.

Una volta scelto il tipo di autenticazione e l’utente, dobbiamo verificare che essodispongadeipermessiperpoteraccedereallasorgentedati(inletturaedeventualmentein

Page 259: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

scrittura).Incasocontrario,vienesollevataun’eccezionearuntime.

Nel file di configurazione dell’applicazione, possiamo specificare, in un’appositasezione, l’elenco delle stringhe di connessione disponibili per un’applicazione (esempio10.3).Lestringhediconnessione, specificatenel filediconfigurazione, sonoaccessibilivia codice o, in modo dichiarativo, tramite la collezioneConfigurationManager.ConnectionStringsepossonoessereprotettetramitecrittazioneRSAoppureDPAPI.

Esempio10.3<connectionStrings>

<addname="SqlServer"connectionString="..."

providerName="System.Data.SqlClient"/>

<addname="MsAccess"connectionString="..."

providerName="System.Data.OleDb"/>

</connectionStrings>

Oltreaessererecuperatadalfilediconfigurazione,unastringadiconnessionepuòesserecostruita in modo programmatico sfruttando l’implementazione della classe astrattaDbConnectionStringBuildercheognimanagedproviderfornisce.

La classe DbConnectionStringBuilder permette di assemblare la stringa diconnessione, fornendo un controllo intrinseco sul formato e sulla validità dei variparametri. L’esempio 10.4 si riferisce al caso della costruzione di una stringa diconnessioneperaccedereaundatabaseSQLServer.

Esempio10.4DimbuilderAsNewSqlConnectionStringBuilder()

builder.DataSource=serverName

builder.InitialCatalog=database

builder.IntegratedSecurity=True

DimconnAsNewSqlConnection(builder.ConnectionString)

Aciascunparametrodella stringadi connessione corrispondeunaproprietàdell’oggettobuilder,chedeveessere impostata inmodoopportuno.Unavoltavalorizzati iparametrinecessari,lastringafinaleèaccessibiletramitelaproprietàConnectionString.

Nel caso in cui le parti della stringa di connessione derivino da un input da partedell’utente,l’utilizzodell’oggettobuildermiglioradecisamentelasicurezza,riducendoinmodosignificativoilrischiodiiniezionipotenzialmentedannose.

Page 260: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EsecuzionediuncomandoUnavoltachelaconnessioneèstataattivata,possiamoinviarecomandiallasorgentedatiperlaletturaoperlascrittura.Atalescopo,ilmodelloaoggettidiADO.NETfornisceiltipo base astratto DbCommand, che include una serie di membri comuni a tutte leimplementazioni,presentineivarimanagedprovider.Latabella10.3riportaleproprietàeimetodidiusopiùfrequente.

Tabella10.3–MembriprincipalidellaclasseDbCommand.Proprietàometodo Descrizione

CommandText ProprietàcheimpostalostatementSQLoilnomedellastoredproceduredaeseguire.

CommandTypeProprietà di tipo CommandType (enumerazione) che definisce la tipologia del comando. I valoripossibilisono:Text(default),StoredProcedure,TableDirect.

Connection Proprietàcheassociaunaconnessionealcomando.

Parameters Proprietàcherappresentalacollezionedeiparametridiinputeoutpututilizzatidalcomando.

TransactionProprietà che permette di definire a quale transazione associata alla connessione il comandoappartiene.

ExecuteNonQuery

ExecuteNonQueryAsync

Metodi per l’esecuzione di un comando diverso da una query. Il primoviene eseguito inmodalitàsincrona e ritorna il numerodi righe interessate. Il secondoviene eseguito inmodalità asincrona eritornaunoggettoTaskcheesponeilnumerodirigheinteressate.

ExecuteReader

ExecuteReaderAsync

Metodi per l’esecuzione di una query. Il primo viene eseguito in modalità sincrona e ritorna uncursoreditipoforward-onlyeread-only,contenenteilrisultato.IlsecondovieneeseguitoinmodalitàasincronaeritornaunoggettoTaskcheesponeilcursore.

ExecuteScalar

ExecuteScalarAsync

Metodiperl’esecuzionediunaquery.Ilprimovieneeseguitoinmodalitàsincronaeritornailvalorepresente nella prima colonna della prima riga del risultato (di tipoobject).Gli altri dati vengonoignorati. Il secondo viene eseguito in modalità asincrona e ritorna un oggetto Task che espone ilvaloredellaprimacolonnadellaprimariga.

Comepossiamovederenellatabella10.3,imetodiperl’esecuzionediuncomandosonotre (in realtà sono sei se consideriamo che ci sono sia le versioni sincrone che quelleasincrone).Ciascuna funzione restituisceunvaloredi ritornodifferente, a testimonianzadelfattocheimetodisonostaticoncepitiperunutilizzospecifico.ExecuteNonQueryelasua versione asincrona permettono di invocare un comando di inserimento (INSERT),aggiornamento (UPDATE) o cancellazione (DELETE) e ritornano il numero di righeinteressate. ExecuteReader e la sua versione asincrona consentono di eseguireinterrogazionisuidati(SELECT),restituendounoopiùresultset.ExecuteScalarelasuaversione asincrona permettono infine di recuperare un valore singolo da una query e sirivelano particolarmente efficaci nel caso di comandi che recuperino valori aggregaticome,peresempio,SELECTCOUNT.

D’orainpoi,quandoparleremodeimetodiasincroni,nomineremosoloilnomedel metodo sincrono, ma le stesse valutazioni si applicano anche al metodoasincrono.

L’esempio10.5riportaletrecasistiched’esecuzionediuncomandosincronoeasincronoversoundatabaseSQLServer.

Page 261: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio10.5'MetodosincronoPrivateSubMethod()

'Aggiornamento

DimcmdUpdateAsNewSqlCommand("UPDATEProductsSET…")

DimaffectedRowsAsInteger=cmdUpdate.ExecuteNonQuery()

'Query

DimcmdQueryAsNewSqlCommand("SELECT*FROMProducts")

DimreaderAsSqlDataReader=cmdQuery.ExecuteReader()

'Conteggio

DimcmdCountAsNewSqlCommand("SELECTCOUNT(*)FROMProducts")

DimcountAsInteger=CInt(cmdCount.ExecuteScalar())

EndSub

'Metodoasincrono

PrivateAsyncFunctionMethodAsync()AsTask

{

'Aggiornamento

DimcmdUpdateAsNewSqlCommand("UPDATEProductsSET…")

DimaffectedRowsAsInteger=AwaitcmdUpdate.ExecuteNonQueryAsync()

'Query

DimcmdQueryAsNewSqlCommand("SELECT*FROMProducts")

DimreaderAsSqlDataReader=AwaitcmdQuery.ExecuteReaderAsync()

'Conteggio

DimcmdCountAsNewSqlCommand("SELECTCOUNT(*)FROMProducts")

DimcountAsInteger=CInt(AwaitcmdCount.ExecuteScalarAsync())

EndFunction

Il testo del comando non deve essere necessariamente espresso per esteso. Infatti,DbCommand permette di eseguire anche stored procedure, specificando la tipologia delcomando mediante la proprietà CommandType. Tra le opzioni possibili, contenutenell’enumerazione System.Data.CommandType, il valore StoredProcedure consente dispecificare l’intenzione di invocare una stored procedure sul database. In tal caso, laproprietàCommandTextdelcomandodevecontenereilnomedellastoredprocedureinvecedeltestoSQLformattatoesplicitamente.

Per eseguire comandi SQL o stored procedure dotate di valori in ingresso, possiamousareiparametri.EssisonoistanzedelleclassichederivanodaltipobaseDbParameteresono caratterizzati da un nome identificativo, un valore, un tipo, una dimensione e unadirezione(input/output).CiascunparametropuòessereassociatoauncomandotramiteilmetodoAdddellaproprietàParameters(esempio10.6).

Page 262: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio10.6DimcmdQueryAsNewSqlCommand(

"SELECT*FROMOrders"&

"WHEREEmployeeID=@EmployeeID"&

"ANDOrderDate=@OrderDate"&

"ANDShipCountry=@ShipCountry"&

"ORDERBYOrderDateDESC")

Dimp1AsNewSqlParameter()

p1.ParameterName="@EmployeeID"

p1.DbType=DbType.Int32

p1.Direction=ParameterDirection.Input

p1.Value=1

Dimp2AsNewSqlParameter()

p2.ParameterName="@OrderDate"

p2.DbType=DbType.DateTime

p2.Direction=ParameterDirection.Input

p2.Value=NewDateTime(1996,8,7)

Dimp3AsNewSqlParameter()

p3.ParameterName="@ShipCountry"

p3.DbType=DbType.String

p3.Direction=ParameterDirection.Input

p3.Value="Italy"

cmdQuery.Parameters.Add(p1)

cmdQuery.Parameters.Add(p2)

cmdQuery.Parameters.Add(p3)

Un approccio alternativo all’uso dei parametri (purtroppo ancora molto diffuso fra glisviluppatori)consistenell’utilizzarelaconcatenazionedistringhe,alloscopodicomporreiltestodelcomandoSQLincludendoivaloriiningresso.

Anche se, come soluzione, può sembrare equivalente a quella basata su parametri eanche più veloce da implementare, l’uso della concatenazione rappresenta unapproccio sbagliato e, quindi, assolutamente da evitare per motivi di sicurezzaapplicativa.Infatti,lasempliceconcatenazionedistringhenonpermettedicontrollareseivalori in ingresso sono formattati correttamente. Pertanto, la concatenazione consentel’iniezione di codicemaligno all’interno del testo del comando SQL, con conseguenzeche, nella maggior parte dei casi, si possono rivelare disastrose. Molti attacchi alleapplicazioni sfruttanoproprio l’usodella concatenazionedi stringhenella formattazionedel codice SQL per poter eseguire comandi non previsti dallo sviluppatore e permodificareidaticontenutinelletabelledeldatabase.

Page 263: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

L’approcciobasatosuparametrigarantisce ilgiusto livellodi sicurezza,dalmomentoche non consente in alcunmodo l’iniezione di codice SQL. Per questomotivo, questasoluzioneèsempredapreferire.EssapermettediproteggersidagliattacchiditipoSQL-Injection(iniezionedicodiceSQLmaligno)egarantisceilcontrollosemanticodeidatiiningresso.Infatti,grazieall’usodeiparametri,laformattazionedidateenumerioppurelacodificadeicaratterispeciali,comel’apicesingolo,vengonoeseguiteinmodotrasparente,indipendentementedalleimpostazioniinternazionalidisistemaedaisettaggideldatabase(comenelcasodelsecondoparametrodell’esempio10.6).

Possiamo usare i parametri con tutti i managed data provider. La regola generaleprevedediutilizzareilnomedelparametroprecedutodalcarattere“@”comemarcatoreall’interno del testo del comando (esempio 10.6). Questa regola presenta però alcuneeccezioni.IdataproviderOLEDBeODBCutilizzanounformatodiversoperidentificarei parametri: il segnaposto è rappresentato dal carattere “?” (punto-di-domanda) el’associazione tra un marcatore e il parametro corrispondente dipende rigorosamentedall’ordinediapparizionedelpunto-di-domandaall’internodelcomandoSQL.

LetturadelrisultatodiunaqueryComeabbiamodetto,l’esecuzionedelmetodoExecuteReadercomportalarestituzionediunoggettocontenenteirisultatidell’interrogazione.Questooggetto,dettogenericamentedatareader,èun’istanzadiunadelleclassichederivanodaltipoastrattoDbDataReader,contenuto nel namespace System.Data.Common. Un data reader rappresenta un cursoreclient-sideditipoforward-onlyeread-only,checonsentediscorrereeleggereunoopiùresultset,generatidauncomandoassociatoaunaconnessione.

ADO.NET, al contrario del predecessore ADO, non supporta i cursori latoserver,mentresiconcentraprincipalmentesuirecordsetdisconnessi(DataSeteDataTable),cheverrannoillustratinellapartefinalediquestocapitolo.L’unicocursorepresenteinADO.NETèildatareader(cursoreclient-side,forward-onlyeread-only).

Graziealdatareader,possiamoaccedereaidatiunrecordallavolta,utilizzandoilmetodoRead.Dalmomentochelafunzioneritornailvaloretruefinchétuttiidatinonsonostaticonsumati, può essere usata come condizione d’uscita in un ciclo iterativo di lettura.Chiaramente,ilbloccoassociatoalciclodevecontenereilcodicepertrattareidatirelativialrecordcorrente(esempio10.7).

Laletturadeicampipuòessereeseguitainduemodi:

mediantelaproprietàindexer,chepermettedirecuperareilvalorediunacolonnanel formato nativo in base all’indice o al nome del campo; in questo casodobbiamoeseguireun’operazionedicasting,infunzionedeltipodidestinazione;

tramiteimetodiGetXXX,chepermettonodileggereicampiinfunzionedellaloroposizioneall’internodelrecord,ritornandodirettamenteunospecificotipodidato

Page 264: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

(per esempio, GetInt32 ritorna un intero, GetDateTime ritorna una data,GetStringritornaunastringa,ecc.).

Esempio10.7DimcmdAsNewSqlCommand("SELECT*FROMProducts")

DimreaderAsSqlDataReader=cmd.ExecuteReader()

Try

While(reader.Read())

'Vieneutilizzatalaproprietàindexer

DimproductIDAsInteger=CInt(reader("ProductID"))

'ProductNameèilsecondocampodelrecord

DimproductNameAsString=reader.GetString(1)

'...

EndWhile

Finally

'Chiusuradeldatareader

reader.Close()

EndTry

DalmomentochelaclasseDbDataReaderimplemental’interfacciaIDisposable,ilcodiceprecedentepuòesserescrittoinmodopiùcompatto,sfruttandoilcostruttoUsing.Ancheinquestocaso,valgonoleconsiderazionifatteinprecedenzaperlaclasseDbConnection.

Undata readerpuòcontenerepiùdiun resultset.Questoavvienequandoalcomandochehageneratoildatareadersonoassociatepiùquery.Inquestocaso,ildatareader,unavoltacreato,vienesempreposizionatosulprimoresultset.Perspostarsidaunresultsetaquello successivo è necessario utilizzare ilmetodo NextResult. Ilmetodo restituisce ilvalorefalsesenonesistonoaltriresultsetdaleggereall’internodeldatareadercorrente.

ProviderFactoryOltre alle classi illustrate nei paragrafi precedenti, il namespace System.Data.CommonincludelaclassestaticaDbProviderFactories,chehaloscopodifornirelefunzionalitànecessarie all’enumerazione e alla creazione degli oggetti factory specifici di ognimanagedprovider.

Tramite il metodo GetFactoryClasses, possiamo ottenere l’elenco dei data providerspecificatinelfilediconfigurazionedisistemamachine.configmentre, tramiteilmetodoGetFactory,siamoingradodicreareunospecificooggettofactoryinfunzionedelnomeinvariantecheidentificaunivocamenteilmanagedproviderdautilizzare(esempio10.8).

Page 265: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio10.8'Creazionedell'elencodeimanagedprovider

DimprovidersAsDataTable=DbProviderFactories.GetFactoryClasses()

'CreazionedelProviderFactorydiSQLServer

'L'istanzacreataèditipoSqlProviderFactory

DimfactoryAsDbProviderFactory=

DbProviderFactories.GetFactory("System.Data.SqlClient")

LeclassiderivatedaDbProviderFactory(peresempio,SqlProviderFactorynelcasodiSQLServer)consentono,alorovolta,diistanziareiprincipalioggettiperl’accessoaidaticomeunaconnessioneouncomando,eliminandol’accoppiamentotral’istanzacreataeilsuo contesto d’utilizzo. Sfruttando il polimorfismo e l’insieme di classi base astratteelencatenelprimoparagrafodelcapitolo,l’approcciobasatosulproviderfactorypermettediscriverecodicecheèindipendentedalparticolaremanagedproviderutilizzato(esempio10.9).

Esempio10.9'Creazionediunaconnessione

'Sel'oggettofactoryèditipoSqlProviderFactory,

'vienecreataeritornataunaistanzadiSqlConnection

DimconnAsDbConnection=factory.CreateConnection()

Iltiporitornatodaciascunmetododicreazionedell’oggettofactoryèsempreecomunqueil tipobaseastratto.Ciòchevariadivoltainvoltaèl’implementazionedelmetodo,cheistanziailtipospecificodioggettoasecondadelproviderfactory.

SupportospecificoperSQLServerADO.NET e il managed provider relativo a SQL Server contenuto nel namespaceSystem.Data.SqlClientpresentanoalcunecaratteristichechesonopropriedelleversionipiùrecentidiSQLServer(dallaversione2005inpoi).

Oltrealsupporto,aitipididatispecificidiSQLServer(comeiltipoXML),unodegliaspettipiù interessanti riguarda lapossibilitàdiaprirecontemporaneamentepiùresultsetnell’ambitodellastessaconnessione.QuestacaratteristicaprendeilnomediMARS,chestaperMultipleActiveResultSet.

L’esempio 10.10 riporta una delle situazioni più frequenti in cuiMARS può tornarecomodo,ovveroilcasoincuisiutilizziuncomandoSQLpereseguireunaggiornamentomentresiscorreunresultset.

Page 266: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio10.10'AperturadellaconnessioneaSQLServer2005/2008

DimconnAsNewSqlConnection(connectionString)

conn.Open()

'Esecuzionedelprimocomando

DimselectCmdAsNewSqlCommand(selectCmdText,conn)

UsingreaderAsSqlDataReader=selectCmd.ExecuteReader()

While(reader.Read())

'...

DimupdateCmdAsNewSqlCommand(updateCmdText,conn)

updateCmd.Parameters.AddWithValue("@Id",reader.GetInt32(0))

updateCmd.Parameters.AddWithValue("@FieldToUpdate",newValue)

'Esecuzionedelsecondocomando

updateCmd.ExecuteNonQuery()

EndWhile

EndUsing

conn.Close()

In ADO.NET la funzionalità MARS per connessioni a istanze di SQL Server2005/2008/2012/2014 è abilitata di default. In ogni caso, possiamo disattivarla,assegnando al parametro MultipleActiveResultSets della stringa di connessione ilvalorefalse(esempio10.11).

Esempio10.11<connectionStrings>

<addname="NoMars"

connectionString="...;MultipleActiveResultSets=false;"

providerName="System.Data.SqlClient"/>

</connectionStrings>

VediamooracomesfruttareADO.NETperlavorareinmodalitàdisconnessadaldatabase.

ModalitàdisconnessainADO.NETOltre alla modalità connessa che, come abbiamo visto, contempla l’utilizzo dei datareader, ADO.NET permette di lavorare sui dati anche in modalità disconnessa, ovverosenzachesiaattivaunaconnessioneverso la sorgentedati.Tuttavia,èutile sottolineare

Page 267: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

chelamodalitàdisconnessa,sebbenesiastataampiamenteadottatadaglisviluppatorinelleprimissime versioni del .NET Framework, oggi rappresenta un metodo assolutamentesuperatoe,diconseguenza,sconsigliatoperaccedereaidati.

L’avventoditecnologiealternativeepiùevolute,comeEntityFramework,oggettodelprossimocapitolo,nehannodecretatoinevitabilmentel’obsolescenza.Percompletezza,inquestocontestoci limitiamoariportareunvelocerichiamodeiconcettiprincipali,senzaentraretropponeidettagli.

Per poter lavorare sui dati in modalità disconnessa, ADO.NET include un oggettoparticolare, simile a un comando, detto genericamente data adapter, tramite il qualepossiamopopolareunoggettocontainerconleinformazionirecuperatedallasorgentedati.Uncontainerdidatièunoggettofinalizzatoaraccogliere,inmodostrutturatoeordinato,le informazioni che in esso vengono inserite, fornendo al tempo stesso una serie difunzionalitàperiltrattamentoelaletturadelsuocontenuto.

Il data adapter si comporta come tramite, in entrambi i sensi, tra la sorgentedati e ilcontainer.Infatti,adifferenzadelcomandodoveilresultsetvieneritornatosottoformadicursore read-only, il data adapter sfrutta l’oggetto container come raccoglitore delleinformazionirecuperatedallasorgentedati.InADO.NETesistonoduetipidicontainerdidati:ilDataSetelaDataTable.

Leclassi containerdiADO.NETnonsonoelementi specificidiunparticolaredata managed provider. Sono altresì dei semplici contenitori, che presentanounaseriedi funzionalità similiaquelleoffertedaundatabaseclassico, comel’organizzazione dei dati in tabelle, le relazioni, l’integrità referenziale, ivincoli, l’indicizzazioneecosìvia.Loscopodeicontainerèquellodiospitareinsiemididati,strutturatisecondounoschemaspecifico,mantenendoliattiviinmemoria affinché possano essere letti e modificati in modo semplice eimmediato. Inparticolare, ilDataSet èunoggettocompostodaun insiemeditabelle, rappresentate da altrettante istanze della classe DataTable e darelazioni di tipoDataRelation.Ciascuna tabella, a sua volta, è composta darighe(classeDataRow)ecolonne(classeDataColumn)epuòincluderevincolidiintegritàreferenzialeediunivocitàdeidati.

Il data adapter è una classe che deriva dal tipo base DbDataAdapter, contenuto nelnamespace System.Data.Common. Ogni managed provider presenta una suaimplementazione specifica, ma tutte le specializzazioni includono i membri utili alpopolamento e all’aggiornamento di un particolare container di dati. La tabella 10.4riportaleproprietàeimetodiprincipali.

Tabella10.4–MembriprincipalidellaclasseDbDataAdapter.Proprietà ometodo Descrizione

SelectCommand

Proprietàchepermettediimpostareilcomandodiselezionedelleinformazioniprovenientidallasorgentedati.Questocomandovieneutilizzatodaldataadapterdurantel’operazionedipopolamentodelcontainerdidatididestinazione(DataSetoDataTable).

Proprietàchepermettediimpostareilcomandodiinserimentodinuovirecordnell’ambitodellasorgente

Page 268: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

InsertCommand dati,utilizzatodurantel’operazionedisalvataggio(batchupdate).

UpdateCommandProprietàchepermettediimpostareilcomandodiaggiornamentodeirecordnell’ambitodellasorgentedati,utilizzatodurantel’operazionedisalvataggio(batchupdate).

DeleteCommandProprietà chepermette di impostare il comandodi cancellazionedei recordnell’ambito della sorgentedati,utilizzatodurantel’operazionedisalvataggio(batchupdate).

Fill(DataSet) MetodoperilpopolamentodiunDataSet.Ilmetodoèsoggettoaoverloading.

Fill(DataTable) MetodoperilpopolamentodiunaDataTable.Ilmetodoèsoggettoaoverloading.

Update(DataSet)Metodoperilsalvataggio(batchupdate)delcontenutodiunDataSetversolasorgentedati.Ilmetodoèsoggettoaoverloading.

Update(DataTable)Metodoperilsalvataggio(batchupdate)delcontenutodiunaDataTableversolasorgentedati.Ilmetodoèsoggettoaoverloading.

Dalmomentoche fungeda tramite“daeverso” lasorgentedati, ildataadapter includeinternamente quattro comandi (a cui corrispondono le quattro proprietà in tabella) chevengonoinvocatiperleoperazionidiletturaedisalvataggiodeidati(esempio10.12).Siadurante l’operazione di popolamento sia durante quella di aggiornamento (detta anchebatch update), il data adapter attiva, in modo trasparente, una connessione verso lasorgentedatieinvocaicomandiinrelazioneall’operazionechestacompiendo.

Esempio10.12DimconnAsNewSqlConnection("...")

'Infasedicreazioneoccorrespecificarelaconnessione

DimadapterAsNewSqlDataAdapter("SELECT*FROMProducts",conn)

'CreazionedellaDataTable

DimdtAsNewDataTable()

'PopolamentodellaDataTable

adapter.Fill(dt)

'ModificadeidaticontenutinellaDataTable…

'Batchupdate

adapter.Update(dt)

Laconnessione,associataalcomandodi selezioneall’attodellachiamatadelmetododipopolamentoFill,deveesserevalida,manonnecessariamenteaperta.Selaconnessionerisulta essere chiusa prima della chiamata della funzione di popolamento, essa vieneautomaticamente aperta e, successivamente, chiusa dal data adapter in modo del tuttotrasparente. Se, invece, la connessione risulta essere aperta prima della chiamata delmetodo Fill, essa viene lasciata aperta dal data adapter e deve essere chiusa inmodoesplicito.

Conclusioni

Page 269: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ADO.NETrappresenta il sottosistemadiaccessoaidatidel .NETFramework. IspiratosiprofondamenteadADO,ADO.NETfornisceaglisviluppatoriinambito.NETfunzionalitàsimiliaquellefornitedaADOaglisviluppatoriinambitoCOM.Peraltro,adifferenzadiADO,ADO.NETnonsupportapiùicursorilatoservermapermetteduemodalitàdistinteperl’accessoaidati.

ConADO.NETpossiamoeseguirecomandienavigareresultsetmentrelaconnessionealla sorgentedati è attiva, sfruttandoun cursore client-sidedi tipo forward-only e read-only,cheprendeilnomedidatareader(modalitàconnessa).

In alternativa, possiamo popolare container di dati quali DataSet e DataTable,sfruttandolefunzionalitàdiunoggettodataadapter,elavoraredirettamenteinmemoria,senza la necessità di mantenere attiva una connessione alla sorgente dati (modalitàdisconnessa).

Come abbiamo detto all’inizio del capitolo, oltre a consentire l’accesso diretto asorgenti dati di vario tipo,ADO.NET rappresenta l’infrastruttura base per la tecnologiaprincipale per l’accesso ai dati, cioè Entity Framework, che verrà descritto in modoapprofonditonelprossimocapitolo.

Page 270: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

11

Oltrel’accessoaidati:EntityFramework

Nel capitoloprecedente abbiamo illustrato comeADO.NET forniscaun’ottimabaseperaccedere ai dati. Oggetti come DbConnection, DbCommand, DbDataReader e DataSetoffronotuttociòdicuiabbiamobisognoperinteragireconundatabase.

Tuttavia, lavorare con questi oggetti in maniera diretta nel nostro codice significalegarloaldatabaseeallasuastruttura.Perquestomotivo,leapplicazionimodernefannousodiunaseriediclassicheastraggonoildatabasesottostantesiacomestrutturasiacomeinterazione.

Difatto,ilcodiceditaliapplicazioninonfausodeglioggettidiADO.NET,senoninuno strato strettamente dedicato all’interazione con il database. Quando sviluppiamoapplicazioni seguendo questo pattern, possiamo trovare un valido aiuto nei cosiddettiObject/RelationalMapperoO/RM(O/RMd’orainpoi).

Inquestocapitoloparleremodell’O/RMprodottodaMicrosoft:EntityFramework.Almomentodellastesuradiquestolibro,laversioneufficialediEntityFrameworkèla6.1.3edèsuquestaversionechesibasailcapitolo.Tuttavia,entroilprimotrimestredel2016MicrosofthainprevisionedirilasciareEntityFramework7.Questanuovaversionenonèunamiglioriadiquellaprecedente,bensìunaversionecompletamenteriscrittadazeropersupportarescenarichenonsonoancorasupportabiliconlaversioneattuale.

All’inizio del capitolo ci occuperemo di capire cosa sia un O/RM e come questo cipermetta di semplificare il codice di accesso ai dati. Dopo questa introduzione,cominceremo a parlare di Entity Framework e vedremo come generare un modello aoggetti e mapparlo sul database, sfruttando esclusivamente il codice. Successivamente,vedremo come effettuare le operazioni di lettura e scrittura, così da avere un quadrocompleto delle potenzialità di Entity Framework. Alla fine del capitolo introdurremoEntityFramework7,elencandolesuecaratteristicheemostrandocomesidifferenziadalsuopredecessore.

CosaèunO/RMPrimadiiniziarelaspiegazionediEntityFramework,èbeneaccennarecosasiaunO/RMe quale idea risieda alla base di questo strumento di sviluppo.Come detto poco sopra,mascherare la struttura e l’interazione con il database dietro alle classi, permette di

Page 271: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

costruire applicazioni fortemente disaccoppiate dal database; questa è un’ottima cosa alivellodisemplicitàdisviluppoemanutenzione.

Attraversol’usodiunO/RMpossiamocrearedelleclassicherappresentinoildominiodellanostraapplicazione,indipendentementedacomeidatisonostrutturatineldatabase.Saràpoicompitodiunospecificostratodell’applicazionetradurreirisultatidellequeryinoggettie,viceversa,tradurreglioggettiincomandiperaggiornareildatabase.L’insiemedelle classi che rappresentano ildominioprende ilnomediObjectModel (detto anchemodelloaoggettiosemplicementemodello).

Prendendo come esempio il database Northwind, possiamo creare le classi Order,OrderDetail eCustomer. In questo caso, le classi hanno una struttura speculare con letabelle del database, ma non sempre è così. La teoria che sta dietro agli oggetti ècompletamentediversadalla teoriacheèallabasedeidati relazionali equestadiversitàporta spesso (manon sempre) ad avere classi diversedalle tabelle. Il primoesempiodiquestadiversitàrisiedenelladiversagranularità.Uncliente,ingenere,haunindirizzodifatturazioneeunodispedizione(chepossonocoincidereomeno).Perrappresentarequestidati nel database, creiamo una tabella Customers con i campi indirizzo, C.a.p., città enazioneripetutiperentrambeletipologiediindirizzo.Quandoinvececreiamoleclassi,lacosamigliore è crearne una(AddressInfo) con le proprietà di un indirizzo e poi nellaclasseCustomeraggiungeredueproprietà(BillingAddresseShippingAddress)di tipoAddressInfo. Questo significa avere una tabella lato database e due classi lato ObjectModel,comeèmostratonellafigura11.1.

Figura11.1–Latabellaclientièdescrittaindueclassi.

Unaltroesempioèfornitodalladiversamodalitàdirelazionetraidati.Inundatabase,lerelazioni tra i record sono mantenute tramite foreign key, le quali altro non sono checolonne. Per esempio, per associare l’ordine a un cliente, mettiamo nella tabella degliordini una colonna che contenga l’id del cliente. Nell’Object Model le relazioni siesprimono usando direttamente gli oggetti. Quindi, per mantenere l’associazione tral’ordineeilcliente,aggiungiamolaproprietàCustomerallaclasseOrder,comeèmostratonellafigura11.2.

Page 272: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura11.2–Larelazionetraordinieclientièmantenutaconunaforeignkeysuldatabaseeconunaproprietàsulmodello.

Ledifferenzesiamplificanoulteriormentequandousiamol’ereditarietà.Utilizzarequestatecnicanelmondoaoggettièunacosanormalissima.Tuttavia,nelmondorelazionalenonesisteilconcettodiereditarietà.SupponendodiavereunmodelloconleclassiCustomereSupplier che ereditano dalla classe Company, come possiamo avere una similerappresentazione nel database? Possiamo sicuramente creare degli artifici che cipermettano poi di ricostruire le classi, ma si tratta comunque di accorgimenti volti acoprireunadiversitàdifondotrailmondorelazionaleequelloaoggetti.

Risolveremanualmentetuttequestecomplessità(eanchealtre)nonèaffattobanaleedèper questo motivo che, da tempo, esistono dei framework che coprono queste e altrenecessità. Questi framework prendono il nome di O/RM, in quanto lavorano come(M)apper tra (O)ggetti e dati (R)elazionali. Inquestomodo lediversità tra i duemondisonogestitedall’O/RM,lasciandociliberidipreoccuparcidelsolocodicedibusiness.

GliO/RMagisconocomemapper,cioèmappanoleclassielerelativeproprietàconletabelle e le colonne nel database. Il vantaggio che ne deriva è nel fatto che possiamoevitarediscriverequeryversoildatabase,mapossiamoscriverleversol’ObjectModelinun linguaggio specifico dell’O/RM, che poi si preoccuperà di creare il codice SQLnecessario. In termini di logica di business questo rappresenta un enorme vantaggio, inquantoglioggettirappresentanolalogicainmanieramoltopiùsemplicedelletabelle.Lostessoragionamentovalepergliaggiornamentisuldatabase.Noicipreoccupiamosolodimodificareglioggettiepoidemandiamoall’O/RMlapersistenzadiquestisuldatabase.Ora dovrebbe essere più chiaro cosa significhi avere un’applicazione disaccoppiata daldatabase.

Inconclusione,unO/RMèunapartedisoftwaremoltopotentema,allostessotempo,moltocomplessaepericolosa,poichéillivellodiastrazionecheintroducerischiadifarcidimenticare che c’è un database, e questo è negativo. Dobbiamo sempre controllare lequerygeneratedall’O/RMeverificareleistruzionidimanipolazionedati,peresseresicuricheleperformancecorrispondanoairequisiti.

Oracheabbiamocapitoquali compiti svolgeunO/RMpossiamovederecomequesticompiti siano svolti daEntityFramework e comepossiamousare questo strumento persemplificarelosviluppodelcodicediaccessoaidati.Ilprimopassoconsistenelcrearele

Page 273: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

classidelmodelloaoggettiperpoimapparlesuldatabase.

MappareilmodelloaoggettisuldatabaseVistochelaMdiO/RMstaperMapper,èfacileimmaginarechelafasedimappingtrailmodello a oggetti e il database sia quella più importante. In Entity Frameworkquest’operazionepuòessereeffettuatasfruttandoounfileXML,gestitotramiteildesignerdi Visual Studio (Database-First o Model-First) o il codice (Code-First). Stando allemetrichediMicrosoft,gliapproccibasatisulfileXMLeildesignerdiVisualStudiosonosempre meno utilizzati in favore dell’approccio via codice, quindi in questo capitoloapprofondiremo quest’ultimo, dando solo una rapida descrizione delle modalitàprecedenti.

InEntityFramework7, lemodalità dimappingDatabase-First eModel-FirstsonostateeliminateinfavoredellasolamodalitàCode-First.

Cominciamooraavederecomemappareilmodelloutilizzandoilcodice.

MappingconCode-FirstIlprimopassoperutilizzareEntityFrameworkèreferenziareilsuopackagetramitenuget.Per fare questo dobbiamo semplicemente aprire l’interfaccia di nuget in Visual Studio,cercareEntityFrameworkepoiaggiungereilpackagealprogetto.Unavoltafattoquestopossiamopassareacreareemappareilmodello.

Per mappare le classi al database tramite Code-First, dobbiamo svolgere tre attività:primascriviamoleclassi,poicreiamolaclassedicontesto(semplicementecontestod’orainpoi)equinditramitequest’ultimamappiamoleclassi.

Potenzialmente, il database potrebbe anche non esistere ed essere generatopartendo dalle classi. In questi casi un valido strumento è Code-FirstMigrationscheaiutaamantenereildatabaseallineatoalvariaredelmodello.

Inoltre, se scriviamo i nomi delle proprietà delle classi e del contesto sfruttandodeterminate convenzioni, non abbiamo nemmeno la necessità di scrivere il codice dimapping, in quanto Entity Framework è già in grado di dedurre automaticamente dalnome delle classi, delle loro proprietà e del contesto come il modello debba esseremappato.Riprendiamol’esempiodellasezioneprecedenteevediamoilcodicenecessarioacreareleclassi.

DisegnareleclassiScrivereunaclassedelmodelloaoggettièestremamentesempliceinquantoconsistenelcreare una classe con delle proprietà, esattamente come faremmo per qualunque altraclasse.NonèrichiestaalcunaintegrazioneconEntityFramework,comepossiamonotare

Page 274: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

nelcodicedell’esempio11.1.

Esempio11.1PublicEnumShippersAsInteger

SpeedyExpress=1

UnitedPackage=2

FederalShipping=3

EndEnum

PublicClassAddressInfo

PublicPropertyAddress()AsString

PublicPropertyCity()AsString

PublicPropertyRegion()AsString

PublicPropertyPostalCode()AsString

PublicPropertyCountry()AsString

EndClass

PublicClassCustomer

PublicSubNew()

Orders=NewHashSet(OfOrder)()

Address=NewAddressInfo()

EndSub

PublicPropertyCustomerID()AsString

PublicPropertyCompanyName()AsString

PublicPropertyContactName()AsString

PublicPropertyContactTitle()AsString

PublicPropertyPhone()AsString

PublicPropertyFax()AsString

PublicPropertyAddress()AsAddressInfo

PublicOverridablePropertyOrders()AsICollection(OfOrder)

EndClass

PublicClassOrder

PublicSubNew()

Order_Details=NewHashSet(OfOrder_Detail)()

ShipAddress=NewAddressInfo()

EndSub

PublicPropertyOrderID()AsInteger

PublicPropertyCustomerID()AsString

Page 275: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

PublicPropertyEmployeeID()AsSystem.Nullable(OfInteger)

PublicPropertyOrderDate()AsSystem.Nullable(OfDateTime)

PublicPropertyRequiredDate()AsSystem.Nullable(OfDateTime)

PublicPropertyShippedDate()AsSystem.Nullable(OfDateTime)

PublicPropertyShipVia()AsSystem.Nullable(OfShippers)

PublicPropertyFreight()AsSystem.Nullable(OfDecimal)

PublicPropertyShipName()AsString

PublicPropertyShipAddress()AsAddressInfo

PublicOverridablePropertyCustomer()AsCustomer

PublicOverridablePropertyOrder_Details()AsICollection(OfOrder_

Detail)

EndClass

PublicClassOrder_Detail

PublicPropertyOrderID()AsInteger

PublicPropertyProductID()AsInteger

PublicPropertyUnitPrice()AsDecimal

PublicPropertyQuantity()AsShort

PublicPropertyDiscount()AsSingle

PublicOverridablePropertyOrder()AsOrder

EndClass

Ilcodicemostrachiaramentealcunecaratteristichedelnostromodello:

le classi sono semplici classi POCO, con proprietà che rappresentano i dati enessuna relazione con l’O/RM.Questomodello potrebbe essere usato da EntityFrameworkcosìcomedaaltriO/RMsenzabisognodialcunamodifica;

le relazioni sono espresse tramite proprietà che si riferiscono direttamente a unoggettoincasodirelazioniunoauno(comedadettaglioaordine),ounalistadioggettiincasidirelazioniunoamolti(comedaordineadettagli).Questeproprietàsono chiamateNavigationProperty e possono esseremarcate comevirtualperabilitareillazyloading(tecnicadicuiparleremopiùavanti);

il tipo AddressIndfo è un tipo senza una chiave, referenziato da altri oggetti.QuestotipodiclasseèdefinitaComplexTypeeagiscecomesemplicecontenitoredi proprietà e non come tipo damappare verso una tabella. Le proprietà che siriferisconoauncomplextypesonochiamateComplexProperty;

glienumsonosupportaticomequalunquealtrotiponativo.

Oracheabbiamovistoilcodicedelmodelloandiamoavedereilcodicedelcontesto.

Creareilcontesto

Page 276: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Ilcontestoèlaclassecheagiscedapontetrailmondoaoggettidelmodelloeilmondorelazionaledeldatabase.Infatti,èattraversoquestaclassechepossiamomappareleclassiverso il database ed effettuare tutte le operazioni con il database, siano esse query omodifichedidatineglioggetti.

IlcontestoèunaclassecheereditadaDbContextechedefinisceunaproprietàditipoDbSet(OfT),chiamataEntitySet,perogniclassedelnostromodellomappataversounatabelladeldatabase(iltipoTcorrispondealtipodellaclasse).Nelnostrocaso,ilcontestoconterrà tre proprietà: una per la classeCustomer, una per la classeOrder e una per laclasseOrder_Detail.Questeproprietàrappresentanoilpuntodientrataperrecuperareemodificareoggettidaldatabase.L’esempio11.2mostrailcodicedelcontesto.

Esempio11.2PartialPublicClassNorthwindModel

InheritsDbContext

PublicOverridablePropertyCustomersAsDbSet(OfCustomer)

PublicOverridablePropertyOrder_DetailsAsDbSet(OfOrder_Detail)

PublicOverridablePropertyOrdersAsDbSet(OfOrder)

EndClass

Ora che abbiamo visto come creare la classe di contesto, vediamo come eseguire ilmappingdeglioggettiversoildatabaseattraversoquestaclasse.

MappingtramiteconvenzioniQuandoall’internodiunAppDomainuncontestovieneistanziatolaprimavoltaevieneeseguitalaprimaoperazione,EntityFrameworkanalizzaleproprietàditipoDbSet(OfT)delcontestoperrecuperarnelerelativeclassieverificaresequesterispettinodeterminateconvenzionichenepermettonoilmappingsenzanecessitàdiscriverecodice.Perchiariremeglioquestoconcetto,analizziamoleconvenzioniapplicandoleallaclasseOrder:

Lecolonnesuldatabasehannolostessonomedelleproprietà(perquantoriguardailnomedellatabellaparleremopiùavantidellaconvenzione).Nelcasodiproprietàsemplici all’interno di complex type, il nome del campo sul database vienecalcolato unendo il nome della proprietà complessa con quello della proprietàsemplice e separandoli con il carattere “_”. Se ci sono proprietà complesseall’internodiproprietàcomplesse,latecnicadicalcolononcambia,siunisconoinomi di tutte le proprietà complesse e infine si aggiunge il nome di quellasemplice.Nelnostrocaso, laproprietàCityall’internodellaproprietàcomplessaShipAddressvienemappatasullacolonnaShipAddress_City;

se una proprietà si chiama, indipendentemente dal case, ID, Key,

{NomeClasse}ID o {NomeClasse}Key (dove il segnaposto NomeClasse viene

Page 277: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

rimpiazzato dal nome della classe che contiene la proprietà) questa vieneautomaticamente eletta a chiave primaria della classe. Se la proprietà è di tipointero, questa è trattata come Identity. Nel nostro caso, la proprietà OrderID èautomaticamenteidentificatacomechiaveprimaria;

Iltipodelcamposucuilaproprietàèmappataèanalogoaltipodellaproprietà(intperitipiInt32,bitperitipiBoolean).LeproprietàditipoNullable(OfT)e leproprietàditipoStringsonoconsideratenullsuldatabase,lealtreproprietàsonoconsideratenotnull.Infine,leproprietàditipoStringsonoconsiderateunicodealunghezzamassima.Nelnostrocaso,laproprietàCustomerIDèmappatasuunacolonnaditipoint,mentrelaproprietàShipNameèmappatasuunacolonnaditiponvarchar;

Seunaclassehaunanavigationpropertyversoun’altraclasse,laproprietàconlostessonomeedello stesso tipodellachiaveprimariadellaclassecollegatavieneelettaautomaticamentea foreignkey.Nelnostrocaso, laproprietàCustomerIDèconsideratalaforeignkeyperlanavigationpropertyCustomer.

Alla lucedi queste convenzioni appare chiaro chebuonapartedel codicedimapping ègestitoautomaticamentedalleconvenzioni.Tuttaviac’èunapartedimappingcheancoravagestitaamanocomelalunghezzamassimadellestringhe,laconfigurazionedeinomidei campi quando sono diversi dalle proprietà e la configurazione di chiavi primariecompostedapiùproprietà.

MappingtramiteAPIPermappareunaclasseversoildatabaseusandoleAPIdiEntityFramework,dobbiamoeseguire l’override del metodo OnModelCreating. Questo metodo accetta in input unoggettoditipoDbModelBuilder. IlmetodoprincipalediquestaclasseèEntity,ilqualeaccetta il tipo della classe come parametro generico e restituisce un oggetto tramite ilquale specifichiamo prima una proprietà (sfruttando il metodo Property) e poi neinvochiamo i metodi di mapping relativi. Nella prossima tabella vediamo la lista deimetodidimappingprincipali.

Tabella11.1–Metodidimapping.Metodo Applicabilesu Scopo

HasMaxLength String Specificachelalunghezzamassimadelcampo

IsMaxLength String Specificacheilcampohalalunghezzamassima

IsFixedLength String Specificacheilcampoèalunghezzafissa

IsUnicode String Specificaseilcamposupportacaratteriunicode

HasColumnName Tuttiitipi Specificailnomedelcampomappato

HasColumnType Tuttiitipi Specifica il tipo del campo mappato (se diverso da quello calcolato dalleconvenzioni)

IsOptional Tuttiitipi Specificacheilcampoènull

IsRequiredTuttiitipi Specificacheilcampoènotnull

Page 278: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

HasDatabaseGeneratedOption Tuttiitipi SpecificaseilcampoèIdentity,Calcolatoonormale

HasPrecisionDecimal,

DoubleSpecificainteriedecimalidelcampo

Ora che abbiamo illustrato i metodi di mapping, vediamo nel prossimo esempio comeapplicarlipermapparecompletamentelaclasseOrder.

Esempio11.3modelBuilder.Entity(OfOrder)().Property(Function(p)p.CustomerID)_

.HasMaxLength(5).IsFixedLength()

modelBuilder.Entity(OfOrder)().Property(Function(p)p.ShipName)_

.HasMaxLength(40)

modelBuilder.Entity(Of Order)().Property(Function(p)

p.ShipAddress.Address)_

.HasColumnName("ShipAddress").HasMaxLength(60)

modelBuilder.Entity(Of Order)().Property(Function(p) p.ShipAddress.City)

_

.HasColumnName("ShipCity").HasMaxLength(15)

modelBuilder.Entity(OfOrder)()_

.Property(Function(p)p.ShipAddress.Country)_

.HasColumnName("ShipCountry").HasMaxLength(15)

modelBuilder.Entity(OfOrder)()_

.Property(Function(p)p.ShipAddress.PostalCode)_

.HasColumnName(“ShipPostalCode”).HasMaxLength(10)

modelBuilder.Entity(Of Order)().Property(Function(p)

p.ShipAddress.Region)_

.HasColumnName("ShipRegion").HasMaxLength(15)

Come possiamo vedere nell’esempio, lamaggior parte delle configurazioni dimappingriguardanole lunghezzee inomideicampi,vistocheil restodelmappingvienegestitotramiteconvenzioni.

L’ultima cosa da mappare è la proprietà chiave della classe Order_Detail. Poichéquestaclassehadueproprietàchecompongonolachiaveprimaria,EntityFrameworknonè in grado di intercettarla tramite convenzioni e quindi sarà compito nostro specificarlatramiteleAPI,comenell’esempio11.4.

Esempio11.4modelBuilder.Entity(OfOrder_Detail)()_

.HasKey(Function(p)NewWith{p.OrderID,p.ProductID})

IlmetodoHasKey accetta in input una lambda che restituisce una proprietà (nel caso la

Page 279: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

chiavesiacompostadaunasolaproprietà)ounoggettoanonimo(nelcasolachiavesiacompostadapiùproprietà,comenelnostrocaso).

L’ultimosteppermappareunmodelloaoggettiversoildatabaseconsistenell’associarele classi alle tabelle. Questo viene fatto tramite le proprietà di tipo DbSet(Of T) delcontesto:ilnomedellaproprietàcorrispondealnomedellatabellamappataperlaclasse.Nelcaso incui ilnomedella tabellanoncorrispondaalnomedellaproprietà,possiamousare ilmetodo ToTable dell’oggetto restituito dalmetodo Entity di DbModelBuilder.L’esempio11.5mostrailcodicepermapparelaclasseOrder_DetailsconlatabellaOrderDetails.

Esempio11.5modelBuilder.Entity(OfOrder_Detail)().ToTable("OrderDetails")

Oltre che tramite convenzioni eAPI, esiste un terzometododimapping che utilizza ledataannotationedicuicioccuperemonellaprossimasezione.

MappingtramitedataannotationIlmappingtramiteledataannotationprevedecheintestaallaclasseealleproprietàsianopresentialcuniattributichevengonointerpretatidalmotorediEntityFramework.Questiattributipermettonodispecificareilnomedellatabellasucuiunaclassemappa,ilnomedellacolonnasucuiunaproprietàmappa,iltipospecificodellacolonna,seèunaprimarykey, seèobbligatoria, la sua lunghezzamassimaealtroancora.Sebbenesiacomodo, ilmapping tramitedataannotationnoncopre tutte leesigenze,come invece fa ilmappingtramiteAPI.Latabella11.2mostraleprincipalidataannotation.

Tabella11.2–Dataannotationperilmapping.Attributo Applicabilesu Scopo

Table Classe Specificalatabellasucuilaclassemappa

Key Proprietà Specificachelaproprietàfapartedellachiaveprimaria

Column Proprietà Specificailnomeeiltipodellacolonnasucuilaproprietàmappa

DatabaseGenerated Proprietà Specificaselacolonnaèsucuilaproprietàmappaèun’identity,calcolataonormale

Required Proprietà Specificachelaproprietàèobbligatoria

StringLength Proprietà Specificalalunghezzamassimadellaproprietà

Aprescinderedallatecnicadimappingutilizzata,abbiamoscrittoilcodicenecessariopercominciareautilizzareEntityFramework.Tuttaviamancaunultimo importante tassellopercompletareilgiro:lastringadiconnessione.

ConfigurarelastringadiconnessioneConfigurare la stringa di connessione è estremamente semplice. L’unica accortezza da

Page 280: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

tenereamenteècheilnomedellachiavedellastringadiconnessionedeveaverelostessonome della classe di contesto. Nell’esempio 11.6 possiamo vedere la stringa diconnessioneperildatabaseNorthwind.

Esempio11.6<addname="NorthwindModel"

connectionString="

datasource=(local);

initialcatalog=northwind;integratedsecurity=True;

MultipleActiveResultSets=True;

App=EntityFramework"

providerName="System.Data.SqlClient"/>

Nelcaso incui lastringadiconnessionenonpossaavere lostessonomedellaclassedicontesto, nel costruttore di questa dobbiamo invocare il costruttore base, che accetta ininputunastringa,comeèmostratonell’esempio11.7.

Esempio11.7PublicSubNew()

MyBase.New("name=NorthwindModel")

EndSub

La stringa ha il formato “nome=chiave” dove chiave è la chiave della stringa diconnessionenelfilediconfigurazione.

TuttoilcodiceelaconfigurazionecheabbiamovistofinorapossonoesseregeneratidaVisualStudionelcasoildatabaseesistagià.

UtilizzareVisualStudioSindalleprimeversioniVisualStudiohaoffertouneditorvisualepercreareemodificarele classi del modello e il mapping partendo dal database. Con Visual Studio 2015 lapossibilità rimane,maconCode-Firstnonabbiamoundesignerperchénonabbiamounfile XML per il mapping. Tuttavia, possiamo utilizzare i tool di Visual Studio peranalizzareundatabaseesistenteegenerareilcodiceiniziale.Unavoltageneratoilcodice,sarànostrocompitomantenereilmodelloeildatabaseallineati.Perprimacosadobbiamocreareall’internodelnostroprogettounelementodi tipoADO.NETEntityDataModel.L’aggiuntadiquestoelementofapartireunwizardchecipermettediselezionareiltipodimapping che vogliamo utilizzare (Database-First,Model-First, Code-First con databasenuovo o Code-First con database esistente). Nel nostro caso selezioniamo l’ultimaopzione,comeèmostratonellafigura11.3.

Page 281: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura11.3–Leopzionidelprimostepdelwizard.

Il secondo step del wizard, mostrato nella figura 11.4, ci permette di selezionare ildatabaseversocuivogliamoeseguireilmappingedacuiilwizardgenereràilcodice.

Page 282: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura11.4–Lamascheraperselezionareildatabasedamappare.

Il terzoeultimostepdelwizardpermettediselezionare le tabellee levisteper lequalivogliamo generare il codice di mapping. La figura 11.5 mostra che nel nostro casoselezioniamoletabelleOrders,OrderDetailseCustomer.

Figura11.5–Lamascheraperselezionareglielementideldatabasedamappare.

CliccandosuFinish,ilwizardsichiudeefapartirelagenerazionedelcodicedelmodelloedelcodicedimapping.Ilprocessogeneraunaclasseperognitabellamappata(doveogniclasse ha unaproprietà per ogni colonnadella tabella) e la classe di contesto. Il codicegeneratofausodelledataannotationdovepossibileeusaleAPIdoveledataannotationnonarrivano.Oltreagenerareilcodice,ilprocessoaggiungelastringadiconnessionealfilediconfigurazionecosìchenoinondobbiamo farealtrochecominciarea scrivere ilcodicedellanostraapplicazione.

OracheabbiamovistocomeusareCode-First,andiamoascoprirevelocementeglialtrimodellidimapping.

MappingconDatabase-FirstNella modalità Database-First, il database viene creato prima del modello a oggetti e,successivamente, viene importato nel designer di Visual Studio, il quale generaautomaticamente le classi con unmapping1-1 con le tabelle del database.Non solo: ildesignerrecuperaanche lerelazioni tra tabelle, impostandoquesterelazionianche tra leclassi nel modello a oggetti. Il mapping viene espresso con un file XML, chiamatoEDMX,dovesonospecificateleclassi,letabelleelalororelazione.

Page 283: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Percreareilmodelloaoggetti,dobbiamooperareiseguentipassi:

aggiungiamo al progetto un oggetto di tipo “ADO.NET Entity Data Model”,esattamente come abbiamo visto con Code-First, e diamogli il nomeNorthwind.edmx.ClicchiamoOkperaprireilwizarddicreazione;

nella prima form del wizard selezioniamo “EF Designer from database” eclicchiamoNext;

nellaformsuccessivaselezioniamolaconnessionealdatabaseNorthwind(senonc’èlapossiamocrearealvolo),mettiamoilnomeNorthwindModeleclicchiamoNext;

nella terza eultima formespandiamo il nodo relativo alle tabelle e selezioniamoCustomers,OrderseOrderDetails;

clicchiamoFinishperlanciareilprocessodigenerazionedelmodello.

Ilprocessochevienescatenatoallafinedelwizardeffettualeseguentioperazioni:

siconnetteanugetperscaricareilpackagediEntityFrameworkeaggiungerloalprogetto;

generailfiledimapping(unfileXMLconestensione.EDMXchedescriveclassi,tabelleelalororelazione);

aggiungealprogettounfileditemplatecheanalizzailfiledimappingegenerailcodicedelmodello;

aggiungealfilediconfigurazionelastringadiconnessione.

Unavoltacheilprocessohaterminatolasuaesecuzione,VisualStudiomostraildesignerdiEntityFrameworkcomenellafigura11.6.

Figura11.6–Leclassigeneratedaldatabasemostratesuldesigner.

Leproprietàsemplici,definiteScalarProperties,sononelnodoPropertiesmentrequelleche puntano ad altre entità nel modello, definiteNavigation Properties, sono nel nodoNavigation Properties. Vi sono poi le Complex Properties, che appaiono nel nodoPropertiesmaconun’iconadifferente,cheledifferenziadalleproprietàsemplici.Infinecisonoleforeignkeyproperties,cioèleproprietàchemappanosucampideldatabasechesono foreignkey, che sonomostrate insiemealleScalarProperties. Ildesignerpermettenon solo di visualizzare il modello, ma anche di modificarlo. Attraverso il designerpossiamo infattimodificare nomi di proprietà, creare nuove classi emapparle con altretabelle, creare Complex Type, aggiungere o rimuovere Navigation Property, creare emappareenumealtroancora.

Page 284: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

L’approccio Database-First è molto semplice, in quanto il designer ci permette dimappare il modello a oggetti, astraendo tutta la complessità del file XML, creando leclassi dal database, generando il codice e gestendo anche la stringa di connessione.Vediamo ora come possiamo sfruttare ilmodello a oggetti (qualunque sia ilmetodo dimapping)perleggereepersistereidati.

RecuperareidatidaldatabaseLa ricercadi dati nel database avviene tramite gliEntitySet del contesto.Poiché il tipoDbSet(Of T) implementa indirettamente l’interfaccia IQueryable(Of T), questa classeesponetuttigliextensionmethoddiLINQ.Questononsignificaassolutamentecheidatisiano inmemoria. LINQ to Entities (il provider LINQ di Entity Framework) intercettal’esecuzionedellaqueryversol’EntitySetelatrasformainunExpressionTree,chevienepoiconvertitoinSQLgraziealleinformazionidimapping.IlrisultatoèchenoiscriviamoqueryLINQetuttoillavorodiconversioneèaffidatoaEntityFramework.

L’esempio11.8mostracomesiasemplicerecuperarelalistadeiclientiitaliani.

Esempio11.8Usingctx=NewNorthwindModel()

Dimcustomers1=FromcInctx.CustomersWherec.Country="Italy"

Dimcustomers2=ctx.Customers.Where(Function(c)c.Country="Italy")

EndUsing

L’esempio11.8portaadalcuneimportanticonsiderazioni.Laprimaèchenondobbiamogestireconnessioninetransazioninealtrioggettilegatiall’interazionecoldatabase.EntityFrameworkastraetuttopernoi,restituendocidirettamenteoggetti.

La seconda è che nelle query possiamo utilizzare sia la query syntax sia la normalesintassibasatasugliextensionmethod,manelsecondocasodobbiamoprestareattenzioneaquali extensionmethodutilizzare. Il provider diLINQ toEntities non supporta tutti imetodiLINQeirelativioverloadpoichéalcuninontrovanounacontropartesuidatabase,mentre altri non hanno la possibilità di essere tradotti in SQL. Gli extension methoddisponibili sono quelli di aggregazione, di intersezione, di ordinamento, dipartizionamento,diproiezione,diraggruppamentooltreaquellidiinsieme.Peravereunalistacompletadeimetodisupportatiediquellinonsupportati,possiamofareriferimentoaMSDN:http://aspit.co/agm.

Nonostantequesto,moltedellequerycheabbiamovistonelcapitolodedicatoaLINQrimangonoperfettamentevalideancheinLINQtoEntities.Peresempio,quandovogliamorecuperareunsolooggetto,imetodiFirsteSinglesonovalidi.LadifferenzarisiedenelfattochementreFirstvienetradottoinunaTOP1,SinglevienetradottoinunaTOP2,perverificare chenon siapresentepiùdiunelemento. Inoltre se la ricercadell’oggetto

Page 285: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

avvieneperchiaveprimaria,possiamoancheutilizzareilmetodoFinddellaclasseDbSetcomemostratonelprossimoesempio.

Esempio11.9Dimitem1=ctx.Customers.First(Function(c)c.CustomerID="ALFKI")

Dimitem2=ctx.Customers.Find("ALFKI")

Unacosache tornautilissima inLINQ toEntities sono leproiezioni.Molto spessononabbiamo bisogno di tutta la classe, ma solo di alcuni suoi dati. Specificando in unaproiezionequaliproprietàdobbiamoestrarre(comenell’esempio11.10),faremoinmodoche l’SQL generato estragga solo quelle, ottenendo così un’ottimizzazione delleperformance.

Esempio11.10Dim customers = ctx.Customers.Select(Function(c) New With {

c.CustomerID,c.CompanyName})

Esempio11.10–SQLSELECT

1AS[C1],

[Extent1].[CustomerID]AS[CustomerID],

[Extent1].[CompanyName]AS[CompanyName]

FROM[dbo].[Customers]AS[Extent1]

Quandounoggettovienerecuperatodaldatabase,vieneanchememorizzatoall’internodelcontesto,inuncomponentechiamatoObjectStateManager(statemanagerd’orainpoi).

Sonodueimotivipercuiquestocomportamentoènecessario.Innanzitutto,ognivoltache eseguiamo una query, il contesto (che è responsabile della creazione fisica deglioggetti)verificachenonesistagiàunoggettocorrispondente(ovveroconlastessachiaveprimaria)nellostatemanager.Incasoaffermativo,ilrecorddaldatabasevienescartatoeilrelativo oggetto dello state manager viene restituito. In caso negativo, viene creato ilnuovo oggetto, messo nello state manager e, infine, restituito all’applicazione. Questogarantiscechevisiaunsolooggettoarappresentarelostessodatosuldatabase.Inoltre,ilcontestodevemanteneretracciadituttelemodifichefatteaglioggetti,cosìchepoiquestepossanoessere riportate suldatabase. Il fattodi avereglioggetti inmemoria semplificaquestocompito.

OttimizzareilfetchingQuandorecuperiamoglioggetti,spessoabbiamobisognoanchedialtrioggetticollegati.

Page 286: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Per esempio, quando recuperiamo gli ordini, possiamo aver bisogno anche dei relatividettagli.

Nellamaggioranzadeicasi,lasoluzioneidealeèquelladirecuperaretuttiglioggettiinuna singola query. Il problema risiede nel fatto che LINQ to Entities ritorna solo glioggettispecificatidall’EntitySet.Questosignificachequandoeseguiamounaquerysugliordini, i dettagli vengono ignorati. Fortunatamente possiamo modificare questocomportamentoedireaEntityFrameworkqualidaticollegativogliamocaricareinsiemeall’entitàprincipale.

Per fare questo dobbiamo utilizzare il metodo Include della classe DbSet. Questometodo, in input, accetta una lambda che specifica la proprietà da caricare, così comemostratonell’esempio11.11.

Esempio11.11Dimorders=ctx.Orders.Include(Function(o)o.Order_Details)

Il codice SQL corrispondente a questa query mette in join le tabelle Orders e OrderDetails,recuperandoidatinecessari.

Sebbenerecuperareimmediatamenteidettaglisiaottimalenellamaggiorpartedeicasi,vi sonodelle situazioni in cui èmeglio recuperare solo gli ordini e accedere ai dettaglisoloquandosianorichiesti.Unclassicoesempiodiquestasituazionesiproponequandodobbiamo prendere tutti gli ordini e i relativi dettagli solo per quei dettagli checorrispondonoauncertocriterio(peresempio,solopergliordinidiuncertocliente).

InquesticasitornautileilmeccanismodiLazyLoading. IlLazyLoadingè la tecnicache permette di recuperare i dati di una proprietà di navigazione solo quando questa èsoggetta a un accesso. Questo significa che se carichiamo solo gli ordini accedendosemplicemente alla proprietà Order_Details di ognuno, Entity Framework va suldatabaseerecuperaidettaglidiquell’ordine.

Questo comportamento è attivo per default, ma possiamo comunque manipolarlotraversolaproprietàConfiguration.LazyLoadingEnabled(ditipoBoolean)delcontesto.Oltre a dover essere abilitato, per funzionare il Lazy Loading ha un altro prerequisitoovverochelaproprietàsiavirtuale.

L’accessoaunaproprietàdinavigazionescatenal’accessoaldatabaseperchéil tipo ritornato dalle query è in realtà un tipo derivato dalla classe cercata.Questo tipo esegue l’override del getter delle proprietà di navigazione,iniettando il codice di accesso al database. Questo è il motivo per cui leproprietà di navigazione devono essere virtuali per far funzionare il LazyLoading.

Oracheabbiamocapitocomeeffettuarelequery,passiamoavederecomescriveredatineldatabase.

Page 287: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

SalvareidatisuldatabaseSalvare i dati sul database significa persistere la cancellazione, l’inserimento e lemodifichedelleentità.QuestoprocessovienescatenatoattraversolachiamataalmetodoSaveChangesdelcontesto.QuestometodononfaaltrochescorrereglioggettimodificatimemorizzatinelcontestoecostruireilcodiceSQLperlapersistenza.

Ciò significa che il contesto deve conoscere lo stato di ogni singolo oggetto quandoeffettuailsalvataggio.Unoggettopuòessereinquattrostati:

Unchanged:l’oggettononèstatomodificato;

Modified:qualcheproprietàsemplicedell’oggettoèstatamodificata;

Added:l’oggettoèstatomarcatoperl’aggiuntasuldatabase;

Deleted:l’oggettoèstatomarcatoperlacancellazionedaldatabase.

Quandounoggettovienecreatodaunaquery,ilsuostatoèUnchanged.Nelmomentoincui andiamo a modificare una proprietà semplice o una complessa, lo stato passaautomaticamenteaModified.AddedeDeletedsidifferenzianodaglistatiprecedenti,inquantodevonoessereimpostatimanualmente.PersettarelostatodiunoggettosuAdded,dobbiamo utilizzare il metodo Add della classe DbSet(Of T), mentre per impostare unoggetto su Deleted, dobbiamo invocare Remove. Analizziamo ora queste casistiche indettaglio.

PersistereunnuovooggettoIn ogni applicazione che gestisce il ciclo completo di un’entità, il primo passo èl’inserimento.Comedettosopra,perpersistereunnuovooggettobastautilizzareilmetodoAdddellaclasseDbSet(OfT),passandoininputl’oggettodapersistere.L’effettoèquellodiaggiungerel’oggettoalcontestonellostatodiAdded.

Esempio11.12UsingctxAsNewNorthwindModel()

Dimc=NewCustomer()With{

.CustomerID="STEMO",

.CompanyName="StefanoMostarda",

.ContactName="StefanoMostarda",

.Address="ViaDelCorso14",

.City="Roma",.Country="Italy",

.PostalCode="00100",

.Region="Lazio",

.ContactTitle="Sig",

Page 288: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

.Phone="00000",

.Fax="00000"

}

ctx.Customers.Add(c)

ctx.SaveChanges()

EndUsing

Come possiamo notare nell’esempio 11.12, inserire un nuovo cliente è estremamentesemplice.Quando si deve inserire un ordine, invece, la situazione cambia leggermente,poichéunordinecontieneriferimentiaidettaglieancheunriferimentoalcliente.

In tal caso, il metodo Add si comporta in questo modo: scorre tutte le navigationpropertydell’oggettopassatoininput,cosìdaaggiungereglioggetticollegatialcontesto,mettendolinellostatodiAdded.Inquestomodo,possiamorichiamareunavoltasoltantoilmetodo Add, passando l’ordine, con il vantaggio che tanto i dettagli quanto il clienteverrannoaggiuntialcontestoinfasediinserimento.

Tuttavia, se per i dettagli questo rappresenta l’approccio corretto, per il cliente nonpossiamodire altrettanto, visto che, in realtà, nondeve essere inserito nuovamente. Perovviareaquestoproblema,possiamosemplicementeimpostareilcampoCustomerIDdellaclasseOrder,cosìdanondoverassociareall’ordinetuttol’oggettocliente.

Esempio11.13UsingctxAsNewNorthwindModel()

Dimo=NewOrder()With{

.CustomerID="STEMO",

.EmployeeID=1,

.OrderDate=DateTime.Now,

.RequiredDate=DateTime.Now.AddDays(10),

.ShipAddress="ViaDelCorso14",

.ShipCity="Roma",

.ShipCountry="Italy",

.ShipPostalCode="00100",

.ShipRegion="Lazio",

.ShipName="StefanoMostarda",

.ShipVia=1,

.Freight=8.53

}

o.Order_Details.Add(NewOrder_Detail()With{

.ProductID=1,

Page 289: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

.Discount=0,

.Quantity=10,

.UnitPrice=20

})

o.Order_Details.Add(NewOrder_Detail()With{

.ProductID=2,

.Discount=0,

.Quantity=30,

.UnitPrice=100

})

o.Order_Details.Add(NewOrder_Detail()With{

.ProductID=3,

.Discount=0,

.Quantity=20,

.UnitPrice=40

})

ctx.Orders.Add(o)

ctx.SaveChanges()

EndUsing

L’esempio11.13mostracomesiaestremamentesempliceaggiungerealdatabaseungrafodioggettimediamentecomplesso.Infatti,inserireunordinesignificaancheassociargliuncliente,perpoiinserirneidettagliche,alorovolta,referenzianounprodotto.Tuttoquesto,grazieaEntityFramework,ènotevolmentesemplificato.

Oracheabbiamoimparatoainserirenuovioggetti,passiamoadanalizzarnelarispettivamodifica.

PersisterelemodificheaunoggettoPermodificareuncliente,bastaleggerlodaldatabase,modificarneleproprietàeinvocareilmetodoSaveChangescomemostratonelprossimoesempio.

Esempio11.14UsingctxAsNewNorthwindModel()

Dimcust=ctx.Customers.Find("STEMO")

cust.Address="Piazzadelpopolo1"

ctx.SaveChanges()

EndUsing

Page 290: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Questa modalità di aggiornamento viene definita come connessa, poiché l’oggetto èmodificatomentreilcontestochelohaistanziatoèancorainvita.

Tuttavia non è sempre così. Prendiamo, per esempio, un Web Service che metta adisposizioneunmetodochetornaidatidiunclienteeunaltrocheaccettiunclienteelosalvi sul database.La cosa corretta, in questi casi, è creare un contesto diverso in ognimetodo.Questosignificachenonc’ènessuntracciamentodellemodifichefattesulclientequindiilsecondocontestononpuòsaperecosaècambiato.Quandoincontriamoquestotipodiproblema,siparladimodalitàdisconnessa,inquantolemodificheall’oggettosonofattefuoridalcontestochelohacreato.

In questi casi abbiamo a disposizione duemodalità per risolvere il problema.Con laprimaeffettuiamonuovamentelaqueryperrecuperareilclienteeimpostiamoleproprietàcon i dati chevengonopassati in input almetodo. Inquesto caso il codiceè identicoaquellovistonell’esempio11.14.

La seconda consiste nell’attaccare l’entità modificata al contesto, marcandola comeModified. Attaccare un’entità al contesto significa aggiungerla alla lista di quellememorizzate nello state manager. Quando un’entità viene attaccata al contesto,automaticamente va in stato di Unchanged, quindi va impostata manualmente suModified.Questosiottienerecuperandol’entryrelativaallaentitynellostatemanagereimpostandonelaproprietàStateaModified.L’esempio11.15mostracomeusarequestatecnica.

Esempio11.15'Metodochedelserviziotornailcliente

Usingctx=NewNorthwindModel()

returnctx.Customers.Find("STEMO")

EndUsing

'Ilclientaggiornailclienteechiamailserviziodiaggiornamento

Cust.Address="PiazzaVenezia10"

UpdateCustomer(Cust)

'Ilservizioaggiornailcliente

Usingctx=newNorthwindModel()

ctx.Customers.Attach(modifiedCustomer)

ctx.Entry(modifiedCustomer).State=EntityState.Modified

ctx.SaveChanges()

EndUsing

Quandosiparladiordiniedettagli,èimportantesottolineareunacosa.Seaggiungiamo,modifichiamo o cancelliamo un dettaglio in modalità disconnessa, anche impostandol’ordine come modificato non otteniamo l’aggiornamento dei dettagli. Per eseguire uncorrettoaggiornamento,dobbiamofareunacomparazionemanualetraglioggettipresenti

Page 291: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

suldatabaseequellipresentinell’oggettomodificatoecambiaremanualmentelostatodiognidettaglio.Dopolamodifica,èarrivatoilmomentodipassareallacancellazionedeidati.

CancellareunoggettodaldatabaseL’ultima operazione di aggiornamento sul database è la cancellazione. Cancellare unoggettoèestremamentesemplice,inquantobastainvocareilmetodoRemovedellaclasseDbSet(Of T), passando in input l’oggetto. C’è comunque una particolarità moltoimportanteda tenerepresente.L’oggettodacancellaredeve essereattaccatoal contesto.Questo significa che, anche in caso di cancellazione, abbiamo unamodalità connessa eunadisconnessa.

Nella modalità connessa possiamo semplicemente eseguire una query per recuperarel’oggettoeinvocarepoiRemove(esempio11.16).

Esempio11.16Usingctx=NewNorthwindModel()

Dimcust=ctx.Customers.Find("STEMO")

ctx.Customers.Remove(cust)

EndUsing

Anche nella modalità disconnessa abbiamo due tipi di scelta: recuperare l’oggetto daldatabaseeinvocareRemove(stessocodicedell’esempio11.16)oppureattaccarel’oggettoalcontestoepoichiamareilmetodoRemovecomenelprossimoesempio.

Esempio11.17Usingctx=NewNorthwindModel()

ctx.Customers.Attach(custToDelete)

ctx.Customers.Remove(custToDelete)

EndUsing

AggiornareidaticonEntityFrameworkètutt’altrochecomplesso,quindinonnecessitàdiulterioriapprofondimenti.NellaprossimasezioneinvecevedremobrevementequalisonolecaratteristichediEntityFrameworkchepossonotornareutilidurantelosviluppo.

FunzionalitàaggiuntivediEntityFrameworkOvviamente, in questo capitolo abbiamo trattato solo gli argomenti principali che cipermettonodisviluppareconEntityFramework.Infatti,esistonomoltealtrefunzionalitàche questo framework cimette a disposizione. In questa sezione elenchiamoquelle più

Page 292: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

comuni:

Concorrenza:EntityFrameworkgestiscelaconcorrenzapessimistica.L’unicacosachedobbiamofareperabilitarelaconcorrenzaèindicarenelmappingqualicampidevonoesserecontrollati.

EsecuzionedicodiceSQL:laclasseDbContextesponeleAPIpereseguirequeryeinviarecomandiutilizzandodirettamenteilcodiceSQL.

StoredProcedureeTable-ValuedFunction: le storedproceduree leTable-ValuedFunctionsonosupportatenativamentedaDatabase-FirstmanondaCode-First.PereseguireunastoredprocedureconCode-FirstbisognainviarealserverunaquerySQL.Lestoredprocedurepossonoessereutilizzateancheperaggiornare idatienonsoloperestrarli.

Code-Firstmigration:permettedicreare ildatabaseadesign-time,partendodalleclassidelmodelloaoggetti.Inoltre,permettedimodificareildatabasealcambiodelcodicedelleclassimappate.

Validazione: poiché nel mapping specifichiamo molte informazioni, come peresempio la lunghezza di una proprietà di tipo String, il contesto prima dipersistere le notifiche verifica che le proprietà siano conformi al loro mapping,evitandocosìdiarrivarealdatabasecondatinonvalidi.

Logging: Entity Framework ha un motore di logging integrato, dove possiamointercettare l’esecuzione dei comandi e generare un log per verificare che tuttovengageneratocorrettamente.

EntityFramework6èunO/RMmaturomasoffredialcunelacunedibasederivantidalfatto che quando è stato progettato oltre 10 anni fa doveva coprire esigenze diverse daquelledioggi.Perquestomotivosièresanecessarialasuariscrittura,chevedràlaluceconEntityFramework7.

EntityFramework7EntityFramework7èstatocompletamenteriscrittodallabasepersupportarescenarinonsupportati da Entity Framework 6 e che non si sarebbero potuti supportare con dellesemplicimodifiche.GliscenaricheMicrosoftintendesupportareconEntityFramework7sono:

Database relazionali:databasecomeSQLServer,Oracle,MySQL,ealtri ancora.QuestafunzionalitàèpresenteancheinEntityFramework6.

DatabaseNoSQL:unesempioè ilTableStoragediAzure.Questa funzionalità ènuovainEntityFramework7.

UniversalWindowsPlatform:EntityFrameworkdevegirareanchesulleUniversalWindows Platform quindi su app mobile e non solo. Per questo genere diapplicazioniiproviderdidefaultèSQLite.

Page 293: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

LinuxeOSX:EntityFrameworksupportail.NETCoreequindipotràgirareanchesuLinuxeOSXsiainapplicazioniASP.NET5siainapplicazioniconsole.

Comesipuòfacilmenteimmaginaredaquestalista,gliobiettiviperEntityFramework7sono molto ambiziosi e chiariscono perché una riscrittura del codice da zero si è resanecessaria.

Nonostantelariscritturadelmotore,ilmododiutilizzareEntityFramework7noncambiadimoltoperglisviluppatoririspettoaquellodelsuopredecessore.SialeAPIdimappingsialeAPIpereseguirequeryepersisteresuldatabaselemodificheaglioggettinonsonocambiate in modo significativo, quindi buona parte del codice scritto per EntityFramework6èfacilmentemigrabileaEntityFramework7.Tuttavia,EntityFramework7nonsupportatuttelefunzionalitàdiEntityFramework6,quindinonèdettochesipossafareunamigrazione.

Peresempio,EntityFramework7nonsupportaillazyloading,l’Entity/Tablesplitting(la possibilità di mappare una Entity su due tabelle), il logging integrato, metodi permanipolare le Entity con lo state manager, i complex type. Queste mancanze rendonoEntityFramework7unottimocandidato lìdovenonarrivaEntityFramework6 (UWP,Linux, OSX),ma in tutti gli altri casiMicrosoft stessa raccomanda l’utilizzo di EntityFramework6.

ConclusioniInquestocapitoloabbiamosolamenteprovatoascalfirelasuperficiediEntityFramework,evidenziandonelecaratteristicheprincipaliperpotercominciareautilizzarequestoO/RM.Ora siamo in grado di costruire emodificare unmodello sia con l’approccioDatabase-Firstsiaconl’approccioCode-First,disfruttarlopereseguirequerysuldatabasetramiteLINQtoEntitiesepersisteretuttiglioggettinecessari.

Tuttavia, inEntityFramework,c’èmoltodipiù.Comeabbiamovistonellapenultimasezionedelcapitolo,EntityFrameworkoffreunaseriedifunzionalitàchelorendonounostrumento completo per l’accesso ai dati. Con Entity Framework 7, la situazionemigliorerà ulteriormente, in quanto verranno coperti ancora più scenari e piattaformecomeUWP,OSXeLinux,ilchefacapirecomeMicrosoftstiainvestendomoltosuquestatecnologia,cheraffigurailpresenteeilfuturodell’accessoaidati.

Ora che abbiamo visto come accedere ai dati residenti su un database, nel prossimocapitolovedremounaltromododipersistereidati:XML.

Page 294: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

12

XMLeLINQtoXML

L’eXtensibleMarkupLanguage(XML)èunmetalinguaggiostandardcreatodalWorldWideWebConsortium(W3C),chehaormairaggiuntoidieciannidivitaedèdiventatouno strumento d’uso comune nelle applicazioni. Lo utilizziamo quotidianamente per leconfigurazioni, per lo scambio di dati tra diverse piattaforme oppure, grazie alla suasemplicità di utilizzo con strumenti di disegno e alla sua immediata leggibilità comelinguaggio dimarkup e di layout, tanto nell’ambitowebquanto in quelloWindows: nesonoun esempioXHTML (evoluzione dell’HTML)oXAML (linguaggio perWindowsPresentationFoundationeUniversalWindowsPlatformapp).

IlsupportoadXMLnel.NETFrameworkFin dalla prima versione del .NET Framework è presente un assembly di nomeSystem.Xml.dllchecontieneclassiper la letturae lamanipolazionedell’XML,ognunadellequaliaderisceaspecificistandardodiinvenzionedapartediMicrosoft,piùomenoimmediateecomodedautilizzareasecondadellasituazionechedobbiamofronteggiare.Inoltre, nell’assembly System.Xml.Linq.dll sono contenute classi, racchiuse sotto ilnome di LINQ to XML, che consentono di sfruttare LINQ e la query syntax comemetodologiaalternativadigestionedell’XML.

Obiettivodiquestocapitoloèillustrareilmiglioreutilizzodituttequesteclassi,alfinedi capire qual è lo strumento più adatto per la soluzione di un determinato problema,calcolandoneoneriebenefici.

Il documento mostrato nell’esempio 12.1 è utilizzato all’interno dell’intero capitolocome sorgente degli esempi d’applicazione delle varie tecnologie dimanipolazione deidocumentiXML.

Esempio12.1<?xmlversion="1.0"encoding="utf-8"?>

<products

xmlns="http://schemas.aspitalia.com/book40/products">

<!--Listaprodotti-->

Page 295: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<productidProduct="1"

idCategory="1">

<description>Prodotto1</description>

<details

xmlns="http://schemas.aspitalia.com/book40/details">

<detailname="Size"

value="10x20"/>

<detailname="Weight"

value="2"/>

</details>

</product>

<productidProduct="2"

idCategory="3">

<description>Prodotto2</description>

<details

xmlns="http://schemas.aspitalia.com/book40/details">

<detailname="Size"

value="40x35"/>

<detailname="Weight"

value="8"/>

</details>

</product>

<productidProduct="3"

idCategory="1">

<description>Prodotto31</description>

<details

xmlns="http://schemas.aspitalia.com/book40/details">

<detailname="Size"

value="10x25"/>

<detailname="Weight"

value="2"/>

</details>

</product>

</products>

L’infosetd’esempioracchiude,sottoilnodoprincipaleproducts,unaseriediprodotticonrelativecaratterischeedettagli,qualiladimensioneeilpeso.

Page 296: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Gestirel’XMLconlaclasseXmlDocumentLo strumento più semplice presente nel .NETFramework per la gestione di documentiXMLèrappresentatodallaclasseXmlDocumentchedescrive,secondolespecificheDOMlivello 2 (uno standard W3C), un documento XML in base a una struttura ad albero,quindiconpadriefigli,enepermettel’interrogazioneelamodifica.

IlfattochequestaclasseaderiscaallespecificheDOM,significacheseproveniamodaaltrilinguaggiotecnologie,comeJavaScript,PHP,ActionScriptoJava,abbiamogiàunacertafamiliaritàconimetodieleproprietàmesseadisposizione.

LaclasseXmlDocument rappresentadunqueildocumentoenepermette ilcaricamentomediante i metodi Load o LoadXml: il primo accetta, con vari overload, un URI, unoStream,unTextReaderounXmlReader(affrontatodiseguito),mentreilsecondoaccettadirettamentel’XMLcomestringanellasuaformatestuale.

Esempio12.2DimdocAsNewXmlDocument()

'Uri:percorsorelativoalfile

doc.Load("test.xml")

'Aperturadiunostreamsufile

UsingstreamAsStream=File.OpenRead("test.xml")

'OppurecaricamentodaunoStream

doc.Load(stream)

EndUsing

'OppurecaricamentoXMLdiretto

doc.LoadXml("<test/>")

Quando carichiamo un documento XML attraverso questa classe, questo vienerappresentatoinmemoriaconistanzedioggettispecificiperognielemento,attributoo,ingenerale, per qualsiasi tipologia di nodo dal quale è costituito. Questa distinzione èimplementatanelle classiofferte all’internodel .NETFrameworkepossiamocapirne lalogicaanalizzandolafigura12.1.

Figura12.1–FrazionamentodiundocumentoXMLsecondoDOM.

Page 297: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Nellafigura12.2èinvecevisibilel’interomodelloaoggettiperlarappresentazionediundocumentoXML.

Figura12.2–StrutturagerarchicadelleclassiSystem.Xml.

La struttura dei nodi che deriva dal caricamento del documento, prende origine dallaproprietàDocumentElementdellaclasseXmlDocument,ditipoXmlElement,erappresentailnodo radice obbligatorio. Da esso possiamo accedere agli altri elementi attraverso unaserie di proprietà base, definite a livello della classe XmlNode, come ChildNodes, perottenere una collezioni di nodi figli, FirstChild e LastChild, per ottenere il primo el’ultimofiglio,PreviousSiblingeNextSibling,perottenereinodifratelliprecedentiosuccessivi,presentisullostessolivello.

Possiamo poi ricavare informazioni generiche sul nodo, sfruttando la proprietàLocalName,perconoscereilnomedeltagodell’attributo,laproprietàNamespaceURI,perconoscere il namespace del nodo, oppure OuterXml e InnerXml, per ottenere il nodocorrentecomestringaXML,comprensivodeifigliodeisolinodichecontiene.

SempresullaclasseXmlNodeèdisponibile laproprietàAttributescherestituisceunacollezionediattributi(solosesitrattadiunelemento)mentre,conlaproprietàpredefinita,possiamoottenereglielementifigliconuncertonome.

Inoltre, a seconda della tipologia di nodi, abbiamo a disposizione proprietà emetodispecifici.AdesempiolaclasseXmlElementhaimetodiHasAttribute,GetAttributeeGetElementsByTagNameperconoscererispettivamenteseunelementohaunattributo,perottenerne il valore, oppure per recuperare la lista degli elementi figli in base al nome.Certamentequestocomportal’introduzionediapproccidiversiperottenereinformazionidi tiposimile, tuttaviaquestimetodirisultanopiùcomodidautilizzare,essendotipizzatiperglielementispecifici.

Page 298: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio12.3'Nomedeltagenamespacedell'ultimofiglio

Console.WriteLine("LocalName:{0}-Namespace:{1}",doc.DocumentElement.LastChild.LocalName,

doc.DocumentElement.LastChild.NamespaceURI)

'AttributoidProductsull'ultimofiglio(tagproduct)

DimproductAsXmlElement=

DirectCast(doc.DocumentElement.LastChild,XmlElement)

Console.WriteLine("idProduct:{0}",product.Attributes("idProduct").Value)

Console.WriteLine("idProduct:{0}",product.GetAttribute("idProduct"))

'XMLdelprimofigliodiproducts(ilcommento)

Console.WriteLine("Comment:{0}",doc.DocumentElement.FirstChild.OuterXml)

'Tagdescriptiondelsecondofiglio(tagproduct)

DimdescriptionAsXmlElement=

doc.DocumentElement.ChildNodes(1)("description",

"http://schemas.aspitalia.com/book40/products")

'InnerTextinterrogadirettamenteilvaluedeifigli

Console.WriteLine("Description:{0}",description.InnerText)'EntrodirettamentenelfigliocheèunXmlText

Console.WriteLine("Description:{0}",description.FirstChild.Value)

Nelcodicerappresentatonell’esempio12.3,possiamovedereall’operalevarieproprietàequali risultati si ottengono con l’XML di esempio illustrato a inizio capitolo. Notiamoinoltre l’indicazione del namespace del tag description, che eredita quello del tagcontenitoreproducts.Ilrisultatodell’outputdellaConsoleèvisibilenellafigura12.3.

Figura12.3–OutputottenutomedianteinterrogazioneconXmlDocument.

Otteniamocosìilnomeeilnamespacedeltagproduct,ilvaloredell’attributoidProduct,

Page 299: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ilvalorediOuterXmlperuncommentoelaletturadeltagdescription.

Qualificare i nodi con un namespace è importante per identificare in modounivocounastrutturaXMLinbaseaunoschemaXSD.Diconseguenza,anchenellaricercadiunelemento,nondobbiamolimitarcialLocalName,madiventaobbligatoriospecificareancheilnamespace.

Oltre a leggere un documento XML, possiamomodificarlo sempre sfruttando le stesseclassi. Le proprietàValue,InnerText eInnerXml non sono in sola lettura perciò, unavoltacheabbiamoottenutounnodo,lopossiamomodificare.

A questi si affiancano i metodi AppendChild, InsertAfter, InsertBefore,

RemoveAll,RemoveChildeReplaceChildperaggiungereunnodoincoda,primaodopounaltronododiriferimento,rimuoveretuttiinodiounospecificooppuresostituirneunoconunaltro.

Pernodo si intendeunoggettoche fapartediundocumentoXML.Qualsiasicommento, attributo, elemento, testo o dichiarazione XML rientra in questacategoria,comedimostratonellafigura12.2.

Dobbiamo sottolineare che nuovi nodi non si possono creare direttamente tramite ilcostruttoredelleclassi,maoccorreinvocareunaseriedimetodiCreate[tipoNodo]percreareunanuovaistanzaepoterlaaggiungereaunnodo,sfruttandoimetodiillustratiinprecedenza.

Infine, terminata l’elaborazionedeldocumento,possiamosalvarloconilmetodoSavedellaclasseXmlDocument,comemostratonell’esempio12.4.

Esempio12.4'Rimuovoilterzoprodotto

doc.DocumentElement.RemoveChild(doc.DocumentElement.LastChild)

'Tolgotuttiifiglidelsecondoprodotto

doc.DocumentElement.LastChild.RemoveAll()

'Creol'elementoproduct

DimproductAsXmlElement=doc.CreateElement("",

"product","http://schemas.aspitalia.com/book40/products")

'Impostol'attributoidProduct

product.SetAttribute("idProduct","4")

'Aggiungol'elementoprimadeglialtriprodotti

doc.DocumentElement.InsertBefore(product,

doc.DocumentElement.ChildNodes(1))

'Commentoall'internodeltagproduct

DimcommentAsXmlComment=doc.CreateComment("Nuovoprodotto")

Page 300: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

product.AppendChild(comment)

'SezioneCDATA

DimcdataAsXmlCDataSection=doc.CreateCDataSection(

"Testoliberocon<complesso>")

product.AppendChild(cdata)

'Creoelementodescription

DimdescriptionAsXmlElement=doc.CreateElement("","description",

"http://schemas.aspitalia.com/book40/products")

'CreounnodoXmlTextconladescrizione

description.InnerText="Prodotto4"

'Aggiungol'elementoaltagproduct

product.AppendChild(description)

'Salvoildocumento

DimswAsNewStringWriter()

doc.Save(sw)

L’XML che ottieniamo in output è mostrato nell’esempio 12.5, il quale ha perso unprodotto, ne contiene un altro senza nodi figli, mentre ne è presente uno nuovo concommentoesezioneCDATA.

Esempio12.5<?xmlversion="1.0"encoding="utf-16"?>

<productsxmlns="http://schemas.aspitalia.com/book40/products">

<!--Listaprodotti-->

<productidProduct="4">

<!--Nuovoprodotto-->

<![CDATA[Testoliberocon<complesso>]]>

<description>Prodotto4</description>

</product>

<productidProduct="1"idCategory="1">

<description>Prodotto1</description>

<detailsxmlns="http://schemas.aspitalia.com/book40/details">

<detailname="Size"value="10x20"/>

<detailname="Weight"value="2"/>

</details>

</product>

<product>

Page 301: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

</product>

</products>

LaclasseXmlDocument,quindi,èadattaperunamanipolazionefacileemoltointuitivadeldocumentoXML,soprattuttoseconosciamogià lespecificheDOM.Conquesta tecnical’interodocumentovieneanalizzatoecaricato inmemoriaperpoteressere interrogatoomanipolatofinoaquandononlosalviamoconilmetodoSaveversounoStream,unfilefisicoounTextWriter.Difatto,èquindiadattoperdocumentidipiccoladimensione,neiqualivogliamoprediligerelafacilitàdigestione.

LetturaescritturarapidaeleggeraLa classe XmlDocument appena analizzata è molto comoda e intuitiva da utilizzare, mapresentaildifettodicaricarel’interodocumentoinmemoria,inclusiimetadatiaggiuntivi,equindipuònonesserelasoluzionemiglioreseintendiamoelaboraredocumentiXMLdidimensioniconsiderevoli.Perovviareaquestolimite,nel.NETFrameworksonopresentile classi astratte XmlReader e XmlWriter, che ci consentono di leggere e scriveredocumenti XML sfruttando lo stesso di tipo di accesso ai nodi, ma con un approccioforward-only(senzapossibilitàdiandareindietro),insolaletturaperXmlReadereinsolascrittura per XmlWriter. Le principali implementazioni sono XmlTextReader eXmlTextWriter,lequalisonoingradodileggereescriveredocumentitestuali.

ÈbenericordarechelespecificheXMLInfoSetnonvincolanoalsoloformatotestualedatochequellochecontaèlarappresentazionelogicaedunquel’XMLpotrebbebenissimobasarsisuunacodificabinaria.

LeggereconXmlReaderPer la lettura, ilmetodo staticoXmlReader.Create dispone dimolti overload per aprireStream, TextReader o un URI e accetta, eventualmente, un parametro di tipoXmlReaderSettings,perimpostarealcuneopzioninellalettura,comeignorarecommentiospazibianchioppuresceglieredieffettuarevalidazionimedianteschema,piuttostochechiudereloStreamallachiusuradell’XmlReader.

Esempio12.6'Impostazionidicaricamentodelfile

DimsettingsAsNewXmlReaderSettings()

settings.IgnoreComments=True

settings.IgnoreProcessingInstructions=True

settings.IgnoreWhitespace=True

'Usingperchiudereilfileeliberarlo

Page 302: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Usingreader=XmlReader.Create("Test.xml",settings)

'Letturareader

EndUsing

Come già accennato in precedenza, la lettura avviene con un approccio forward-only,medianteuncursorechedecodifical’XMLprogressivamenteallalettura,passandodaunnodo all’altro, considerando come tali anche gli spazi bianchi tra i tag, le istruzioni diprocessamento,icommenti,lesezioniCDATAe,piùingenerale,qualsiasicontenutodeldocumento. È per questo che, nell’esempio 12.6, richiediamo esplicitamente di saltarealcuninodichenonriteniamonecessari.

Per scorrere un documento possiamo utilizzare il metodo principale Read, cherestituisce un boolean per indicare se il documento è giunto alla fine. Ogni suainvocazione determina il passaggio al nodo successivo e, tramite la classe XmlReader,possiamo ottenerne le relative informazioni. Le principali proprietà sono LocalName,NamespaceURI, NodeType, Value, HasAttributes e HasValue: non tutte sono peròsempredisponibili,poichévarianonelsignificatoasecondadelnodoincuil’XmlReaderèposizionato.

Possiamo sfruttare, in alternativa o come complemento almetodo Read, una serie dimetodi MoveTo[TipoElemento] che indicano di far posizionare il cursore su undeterminato tipo di nodo, restituendo true o false in base all’avvenuto successodell’operazione.Perfacilitareancordipiùletturadeinodi,imetodiReadContentAs[tipoCLR] e ReadElementContentAs[tipo CLR] permettono la lettura tipizzata, conconversioneautomaticadelcontenuto(asecondadelnodo)odelcontenutodell’elementoin cui si trova il cursore. L’esempio 12.7 mostra come usare questi metodi, sfruttandosemprelostessodocumentoXMLpresentatoall’iniziodelcapitolo.

Esempio12.7'Leggoilprossimonododallostream

Whilereader.Read()

'Stamponomedelnodo(attributooelemento)etipo

Console.WriteLine("LocalName:{0}-NodeType:{1}",reader.LocalName,reader.NodeType)

'Intercettol'iniziodiunnuovoelemento

Ifreader.NodeType=XmlNodeType.ElementThen

'Identificoincheelementomitrovo

SelectCasereader.LocalName

Case"description"

'Controllochel'elementononsiavuoto

IfNotreader.IsEmptyElementThen

Console.WriteLine("Description:{0}",

Page 303: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

reader.ReadElementContentAsString())EndIf

Case"product"

'Mispostosull'attributoidProduct

Ifreader.MoveToAttribute("idProduct")Then

'Seèandatoabuonfine,leggoilvalore

Console.WriteLine("idProduct:{0}",reader.Value)

EndIf

EndSelect

EndIf

EndWhile

Data la natura di XmlReader, non abbiamo la sicurezza della validità del documentoquandolosiapreconCreate,cosache,invece,puòassicurarelaclasseXmlDocument.Inquesto caso, infatti, dobbiamo sfogliare l’intero documento con ilmetodoRead così daprocederepassoperpassonell’analisidellostesso,finoadarrivareallafine.

ScrivereconXmlWriterPer la scritturadidocumentiXML, laclasseXmlWriter si comportacomeXmlReader edispone anch’essa di un metodo statico Create per scrivere XML con un approccioforward-only.

Ilsuoutilizzoèabbastanzasemplice,poichéèsufficienteinvocareimetodiWrite[tiponodo] o WriteStart[tipo nodo] e WriteEnd[tipo nodo] per i nodi complessi, dove“tipo nodo” dipende dalla posizione del cursore. Infatti è a carico nostro conoscerla einvocare i metodi più appropriati, pena un’eccezione a runtime. Nel codice 12.8 èmostrato come possiamo creare un documento XML e come sia necessario prestareattenzione alla corretta apertura e chiusura dei nodi. In realtà, in certe circostanze, ilmotore è in grado di chiuderli in modo automatico ma è buona norma farlo in modoesplicito,inmododaottenereunamigliorevisionediciòchestiamocreando.

Esempio12.8'Impostazionidiscrittura

DimsettingsAsNewXmlWriterSettings()

settings.Indent=True

settings.NewLineOnAttributes=True

DimnsAsString=

"http://schemas.aspitalia.com/book40/products"

DimstringWriterAsNewStringWriter()

Page 304: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

UsingwriterAsXmlWriter=XmlWriter.Create(stringWriter,settings)

writer.WriteStartDocument()

'Nuovotagproducts

writer.WriteStartElement("products",ns)

writer.WriteComment("Nuovoprodotto")

'Nuovotagproductconattributo

writer.WriteStartElement("product",ns)

writer.WriteAttributeString("idProduct","4")

'Nototestuale

writer.WriteElementString("description",ns,"Prodotto4")

'Chiudoitag

writer.WriteEndElement()

writer.WriteEndElement()

writer.WriteEndDocument()

EndUsing

La classe XmlWriter consente di specificare alcune opzioni per la formattazione deldocumentochevienegenerato,tracuil’indentazione(IndenteNewLineOnAttributes),letipologiedeicaratteriel’encodingdautilizzare.

Nella fase di scrittura abbiamo una certa tranquillità nel produrre un documento benformattato, dato che abbiamo un aiuto nella chiusura degli elementi, ma non abbiamoalcunacertezzachel’XMLsiavalidosecondounoschemaprefissato.

Le classi XmlReader e XmlWriter possono quindi sembrare scomode perché sonoverboseerichiedonodinonsbagliarenellanavigazionetraglielementimasono,difatto,ilmigliormodo per leggere e scrivere un documento se vogliamo impiegare il numerominorepossibiledirisorseeraggiungereilmassimodelleprestazioni.

LINQtoXMLGlistrumentivistifinorasonoiprincipali traquellidisponibilinel .NETFramework;venesonoanchealtri,comeXPath(affrontatosuccessivamenteeilcuiscopoèpiùorientatoa supportare le trasformazioni XSLT) i quali, purtroppo, richiedono la conoscenza diulteriorilinguaggi,chesonostandardeutilizzabiliancheconaltriambientielinguaggidiprogrammazione, ma che richiedono tempo, ulteriore esperienza e, spesso, spingono ilprogrammatorealimitarsiearipiegaresulsempliceDOM.

L’intenzionediLINQèquelladifornireununicomododiinterrogareidati,inmododapermetteredimuoversiagilmentecondiversesorgentitracuianchedocumentiXML.A questo scopo è stato aggiunto un nuovo assembly System.Xml.Linq.dll, il qualecontiene nuove classi (figura 12.4), racchiuse sotto il nome di LINQ to XML. Queste

Page 305: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

classi sono ingradodidecodificare l’XML,permettendocidi interrogareconfacilitàundocumentomediantelaquerysyntaxeleestensionidiLINQtoObject.

Figura12.4–StrutturagerarchicadelleclassidelnamespaceSystem.Xml.Linq.

La loro struttura è peraltro molto simile a quella vista nel caso di XmlNode, ma è piùottimizzata,poichénonsonopresentimembriinutilipercertetipologiedinodi.

InterrogareinodiconLINQLaclasseprincipaleèrappresentatadaXDocumentcheconimetodiLoad,ParseeSave,permettedicaricare,decodificareunastringaosalvareundocumentoXML.Daquesta,attraverso la proprietà Root, abbiamo accesso all’XElement radice, sul quale possiamoinvocare una serie di metodi per ottenere uno specifico elemento figlio o un attributo(classe XAttribute). L’esempio 12.9 mostra come leggere l’attributo idProduct sulprimo tag product. Da notare come gli oggetti XElement e XAttribute dispongano dioperatori di conversione espliciti, con i quali possiamoquindi effettuare il cast sul tipodesiderato;nelcasononsiapossibile,otterremoun’eccezione.

Esempio12.9'Caricamentodeldocumento

DimdocAsXDocument=XDocument.Load("test.xml")

'Recuperal'elementoproduct

DimproductAsXElement=doc.Root.Element(

"{http://schemas.aspitalia.com/book40/products}product")

'LetturaattributoidProduct

DimidProductAsInteger=CInt(product.Attribute("idProduct"))

Page 306: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Nell’esempio 12.9 sicuramente ci colpisce la particolare sintassi“{namespace}localName”utilizzataperqualificare correttamente l’elemento. In realtà ilmetodoElement,cherestituiscelalistadeglielementi,accettauntipoXNamecheunisceilnamespaceallocalName.

Grazie a un operatore di conversione implicito, possiamo utilizzare direttamente unastringacon lasintassispeciale,vistanell’esempio12.9. Inalternativa,possiamousare ilmetodo statico XName.Get o la classe XNamespace, per riutilizzare il namespaceconcatenandoloconillocalNameunaopiùvolte,comeillustratonell’esempio12.10.

Esempio12.10DimproductNsAsXNamespace=

"http://schemas.aspitalia.com/book40/products"

DimproductAsXElement=doc.Root.Element(productNs+"product")

QuantovistofinoranonbastacomunqueagiustificarelacreazionedinuoveAPI.Infatti,daessetraiamoilmassimoconunaseriedimetodicomeNodes,Elements,AttributesoDescendants,iqualirestituisconounIEnumerable<XNode>otipiderivatidaquest’ultimo.

Questi enumerabili sono ulteriormente gestibili con LINQ to Object e con alcuniextension method della classe System.Xml.Linq.Extensions, che permettono, a lorovolta,diottenerenodi,attributiedelementidiscendentioppureascendenti.

L’esempio 12.11 mostra all’opera alcuni di questi metodi combinabili con alcuneestensionidellaclasseEnumerable,applicandolialdocumentoXMLd’esempioperquestocapitolo,pereffettuarelasommaoppureottenereilprimonodo.

Esempio12.11'TuttigliattributiidProductdeglielementiproduct

ForEachattributeAsXAttributeIn

doc.Root.Elements().Attributes("idProduct")Console.WriteLine("idProduct{0}",CStr(attribute))

Next

'Ilprimonodo(commento)

Console.WriteLine("Comment:{0}",doc.Root.Nodes().First())

'Ilprimoelementoproduct

Dim product As XElement = doc.Root.Elements(productNs +

"product").ElementAt(1)

Console.WriteLine("Description:{0}",

CStr(product.Element(productNs+"description")))

'Sommadell'attributovaluepertutti

Page 307: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'idetailditipoWeight

DimsumAsInteger=(FromdIndoc.Root.Descendants(dns+"detail")

WhereCStr(d.Attribute("name"))="Weight"

SelectCInt(d.Attribute("value"))).Sum()

Console.WriteLine("Totalweight:{0}",sum)

Otteniamodiconseguenzal’outputvisibilenellafigura12.5.

Figura12.5–OutputottenutointerrogandoconXDocument.

DanotarecomeilToStringdiunnodo(ilcommento,inquestocaso)restituiscainformatestualel’interonodoXML.

ManipolazionedeinodiAnchelamodificaèresasemplicegrazieametodiedextensionmethodmoltoelastici,checonsentonodieliminarelistedinodi,dielementiediattributioppuredicrearefacilmentenuove istanze degli stessi, usando l’apposito costruttore. Quest’ultima caratteristica,mostrata nell’esempio 12.12, risulta infattimolto comoda e versatile, poiché durante lacreazionediunXElementpossiamopassareunoopiùnodifigli(ancheunIEnumerableoasuavoltaunoopiùXElement)che,automaticamente,vengonogestitie,asecondadeltipodinodo,emessicomeXMLnelcorrettoordine.Nelcasoditipiprimitivi,vieneusatocomenodoXText,dainserirenell’elemento.Lacompattezzaelacomprensionedelcodicechescriviamorendequestasoluzioneadattaancheinscenarimisti,neiquali,conLINQtoEntities,interroghiamodatabaseeproduciamocomerisultatoundocumentoXML.

Esempio12.12'Rimuovogliattributidelprimoelemento

doc.Root.Elements().First().RemoveAttributes()

'Rimuovoilsecondoeilterzoelementoproduct

doc.Root.Elements(productNs+"product").Skip(1).Take(2).Remove()

'Nuovotagproductdentroproducts

DimproductAsXElement=NewXElement(productNs+"product",

NewXComment("Nuovoprodotto"),

Page 308: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

NewXAttribute("idProduct",4),

NewXElement(productNs+"description","Prodotto4"))

doc.Root.Add(product)

Nell’esempio 12.12 vengono messi in mostra i principali metodi che abbiamo adisposizioneperlamanipolazionedeinodi:RemoveAttributes rimuovetuttigliattributiappartenenti al nodo, Remove rimuove l’intero nodo, mentre il metodo Add permette diaggiungere qualsiasi tipologia di nodo. Nell’esempio lo invochiamo passando unXElement creatomediante il costruttore cheoltre al nomedell’elementopuò ricevere lalistadinodifigli.IldocumentoXMLcreatoèquindivisibilenell’esempio12.13.

Esempio12.13<products

xmlns="http://schemas.aspitalia.com/book40/products">

<!--Listaprodotti-->

<product>

<description>Prodotto1</description>

<details

xmlns="http://schemas.aspitalia.com/book40/details">

<detailname="Size"value="10x20"

/><detailname="Weight"value="2"/>

</details>

</product>

<productidProduct="4">

<!--Nuovoprodotto-->

<description>Prodotto4</description>

</product>

</products>

Tra le varie altre funzionalità che offre la classe base XObject, da cui deriva XNode, imetodiAddAnnotation,Annotation e RemoveAnnotations possono essere sfruttati peraggiungereinformazioniaggiuntive(Object)all’oggetto,chenonvengonopoiemesseneldocumentoXMLma che possono servirci per l’elaborazione del documento stesso; glieventiChangingeChangedpermettono invecedi intercettare l’aggiunta, la rimozione, larinominaolavalorizzazione.

DiparticolareimportanzaèlaclasseXStreamingElement,chepermettedigenerareundocumento XML, consumandone i contenuti. Infatti, nonostante XDocument offra moltivantaggi, ha il difetto di mantenere in memoria l’intera struttura dati, comprese leeventuali liste di tipo IEnumerable passate. Queste ultime, in realtà, vengono subitoprocessate e modificarle in un secondo momento non produce alcun effetto. La classe

Page 309: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

XStreamingElement, invece,mantieneilcontenutocosìcom’èeloprocessaalmomentodell’emissionedelmarkup,cheavvieneinvocandoilmetodoSave.

Se incontra una lista enumerabile, questa viene sfogliata sul momento, riducendo alminimo le risorse impiegate: ovviamentequesto comportamentovaria inbase al tipodilista, poiché una normale collezione dispone già dei dati in memoria (portando quindipochibenefici),mentreunaTable<T>diLINQtoSQLounObjectQuery<T>diLINQtoEntitiescaricaunasingolarigapervoltadaldatabase,eseguendolaquerysoloall’effettivaconsumazionediessa,conunnettomiglioramentodellerisorseusate.

Infine, laparticolaritàdelmetodoSaveèdatadalfattoche,comunque,utilizzaalsuointernounXmlWriterperprodurreildocumento,rendendo,difatto,LINQtoXMLsolounwrappersulleclassibasilaridel.NETFramework.

LINQtoXMLconVisualBasicVisual Basic 14 e successive versioni, offre una sintassi particolare per semplificarel’interrogazionee la creazionedidocumentiXML,chenonhacorrispondenza inC#. Ilcompilatore Visual Basic ci permette, infatti, di dichiarare tag XML direttamente nelcodice, per rendere più leggibile ciò che si sta facendo. L’esempio 12.14 dimostra lasemplicitàdiquestacaratteristica.

Esempio12.14DimdocAsXDocument=XDocument.Load(file)

DimidProduct=doc.<products>.<product>.@idProduct

L’uso del punto, valido solo per elementi figli, può essere sostituito, per effettuare unaricercasuunqualsiasilivello,conlasequenza“…”,cheindicaunoperatorediscendente,.

Possiamoinoltrespecificareunprefissoeassociarloaunnamespacetramitelaparolachiave imports, come mostrato nell’esempio 12.15. Chiudendo il tag si ottiene unnormale IEnumerable come valore di ritorno, perciò possiamo sfruttare gli extensionmethoddiLINQtoObjectediLINQtoXMLperlesuccessivemanipolazioni.

Esempio12.15ImportsSystem.Linq

ImportsSystem.Xml.Linq

Imports<xmlns:p="http://schemas.aspitalia.com/book40/products">

Imports<xmlns:d="http://schemas.aspitalia.com/book40/details">

PublicClassVBParse

PublicSharedSubParse(ByValfileAsString)

Page 310: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'Caricamentodeldocumento

DimdocAsXDocument=XDocument.Load(file)

DimidProduct=doc.<p:products>.<p:product>.(1).@idProduct

Dimweight=doc…<d:detail>.@value

EndSub

EndClass

Dobbiamosottolineareche,aldilàdell’aspettostilisticodelcodice,chepuòpiùomenopiacere,ciòchevieneprodottodalcompilatoresonodellenormalilineedicodicebasatesulleclassiXElementeXAttribute,conimetodiElementseAttributes,offrendoegualiprestazionirispettoaquantovistoneiparagrafiprecedenti.

LamedesimasintassipuòinoltreessereutilizzatapergenerareistanzediXDocumentoXElement,asecondacheildocumentosiaprecedutoomenodalladichiarazioneXML(<?xml?>),cosìcomemostratonell’esempio12.16.

Esempio12.16DimdocAsXDocument=

<?xmlversion="1.0"?>

<p:products>

<p:productidProduct="4">

<!--Nuovoprodotto-->

<p:description>Prodotto4</p:description>

</p:product>

</p:products>

Nell’esempio12.16, ilnodocreatoèunXDocument, chepuòquindiessere interrogatoosalvato.

XMLdinamicoconVisualBasic14OltreallapossibilitàdigenerareXMLstatico,lasintassi<%=%>,conunasintassisimileaquelladiASP,permettedivalorizzarepartidell’XMLtramiteun’espressionespecifica.Inordineal tipodiquest’ultima,vienecreatounnodotestuale,piuttostocheunattributoounalistadisottonodi,grazieallaversatilitàchehaXElementnelgestirediversetipologiedi figli.L’esempio12.17mostracomevalorizzaregli attributi (danotare l’assenzadellevirgolette)ocomepossiamoinserireun’espressionepiùcomplessaper lagenerazionediunaporzionediXML.Essendoun’espressione,nonèpermessapiùdiunaistruzioneedèquasi obbligatorio ricorrere all’uso di LINQ, nonostante nulla vieti di chiamare unafunzionecheapplichilogichepiùcomplesse.

Esempio12.17

Page 311: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dimvalues()AsInteger={4,8,12}

DimdocAsXDocument=

<?xmlversion="1.0"?>

<p:productscount=<%=values.Length%>>

<%=FromvInvalues

Select<p:productidProduct=<%=v%>>

<p:description><%="Prodotto"&v%></p:description>

</p:product>%>

</p:products>

Il documento ottenuto dall’esecuzione dell’esempio 12.17, completamente compilato etradottoinchiamateaicostruttoridellevarietipologiedinodigenerati,èall’incircaquellodell’esempio12.18.

Esempio12.18<p:products count="4"

xmlns:p="http://schemas.aspitalia.com/book40/products">

<p:productidProduct="4">

<p:description>Prodotto4</p:description>

</p:product>

<p:productidProduct="8">

<p:description>Prodotto8</p:description>

</p:product>

<p:productidProduct="12">

<p:description>Prodotto12</p:description>

</p:product>

</p:products>

ConVisualStudio2015tuttoquestoècompletamenteintegratocontantodicolorazionedelcodice,permegliodistinguerlodalmarkup,comemostratonellafigura12.6(vengonousatil’azzurro,ilverdeeilrossoinduetonalità–ndr).

Page 312: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura12.6–IntegazionediLINQtoXMLinVisualStudio2015.

InoltreVisualStudio2015èingradodimostrarel’Intellisensesuinodicheinterroghiamo,seèingradodirisolvereunoschema,utilizzandoilnamespacepresentenelprogetto.

Figura12.7–L’IntellisenseoffertodaVisualStudio2015.

Perusufruirediquestafunzionalità,dobbiamoprimadituttocreareunfileXSDeinserirlonella solutioncorrentediVisualStudio2015.Se il namespaceviene riconosciuto (nellafigura12.6 lo schemahttp://schemas.aspitalia.com/book40/products) si ottiene unaiutoinbasealprefissochescriviamo,comedimostratonellafiguraquisopra.

InterrogarerapidamenteconXPathDocumentTrainumerosistrumentimessiadisposizionedal.NETFrameworkrientranoancheclassichepermettono l’utilizzodiXPathper l’interrogazionedidocumentiXML.XPathèunlinguaggio standardpromossodalW3C,che semplifica la ricercadeidatimedianteunasintassirivoltaallanavigazionetrainodieilfiltrodiessi.LacreazionediquestonuovolinguaggiohaprincipalmenteloscopodisupportareletrasformazioniXSLT(affrontantenelprossimoparagrafo),mapossonoesseresfruttateinalternativaaLINQperl’accessoaXML,segiàsiconoscetalesintassi.

Nonèfragliobiettividiquestolibrospiegarequestolinguaggio,mapossiamovedernealcuniesempidiutilizzo,associatiallerelativeclassidel.NETFrameworkchepermettonopoidiottenerneirisultatiedeventualmentedimanipolarel’XML.

Navigaretrainodi

Page 313: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

L’oggettoprincipaleperl’accessomedianteXPathèrappresentatodaXPathDocument.Lotroviamo nel namespace System.Xml.XPath e permette di caricare l’intero documentoXMLinmemoriamedianteURI,StreamoXmlReader,perciòdobbiamo fareattenzionealledimensionidel fileche intendiamocaricareperchéquestostrumentoè sottopostoalmedesimo limite che ha XmlDocument. Una volta creata l’istanza, l’unico metodo cheabbiamo a disposizione è CreateNavigator, il quale crea un oggetto di tipoXPathNavigator,fulcrodituttalanavigazionetrainodi.LostessometodoèdisponibileanchedallaclasseXmlDocument,datochel’approccioèsimile,permettendodiunireDOMallafacilitàdiricercadiXPath.

Attraverso il navigatore possiamo appunto spostarci tra gli elementi con una serie dimetodi di nome MoveTo*** che sono in grado di navigare sul rispettivo attributo,elemento, figlio, id o namespace. L’esempio 12.19mostra come caricare il documentopresoinesameinquestocapitoloecomespostarsi,conunaseriedimetodi,all’attributoidCategory.

Esempio12.19'Caricoildocumento

DimdocAsNewXPathDocument("test.xml")

Dimnavigator=doc.CreateNavigator()

'Navigosullaroot<products>

navigator.MoveToFirstChild()

'Navigosulprimo<product>

navigator.MoveToChild("product",

"http://schemas.aspitalia.com/book40/products")

'Mispostosull'attributodellacategoria

navigator.MoveToAttribute("idCategory","")

'Leggoilvalore

DimidCategoryAsInteger=navigator.ValueAsInt

Possiamo notare che diversi metodi, come MoveToFirstChild, MoveToChild eMoveToAttributepermettanodinavigaresulnododesideratosecondocertelogiche.Venesono anche altri, come MoveToParent o MoveToRoot, i quali sono tutti auto esplicativi,comepossiamovederenell’esempio12.19.

Qualunquestradautilizziamoperraggiungereilnodochedesideriamo,ciòchecontaèche abbiamo alcune proprietà le quali, in modo simile all’XmlReader, permettono diconoscere il tipo di nodo (NodeType), il nome (LocalName) e il namespace(NamespaceURI). La proprietà più importante è sicuramente Value, che restituiscesottoforma di stringa il valore del nodo, se disponibile.Abbiamo inoltre a disposizioneproprietàdinomeValueAsBoolean,ValueAsDateTime,ValueAsInteValueAsLongperottenereilvaloregiàtipizzato,selaconversionevaabuonfine.

Tutto questo, comunque, non paga la creazione di un ulteriore strumento di

Page 314: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

interrogazioneXML,perchéilveroscopoèquellodisupportareXPath.ImetodiSelecteSelectSingleNode servonoproprio a questo, in quanto accettano una stringaXPath dautilizzare per la selezione. Il primo restituisce l’intero resultset di nodi che ha trovatomentreilsecondorestituiscesemplicementeilprimodeinoditrovati.

Quindi, per leggere la categoria del primo prodotto, possiamo sfruttare la sintassi dinavigazionetrainodi,comenell’esempio12.20.

Esempio12.20DimdocAsNewXPathDocument("test.xml")Dimnavigator=doc.CreateNavigator()

'Creoilgestoredeinamespace

DimnsManagerAsNewXmlNamespaceManager(navigator.NameTable)

'Associoilprefissoalnamespace

nsManager.AddNamespace("p",

"http://schemas.aspitalia.com/book40/products")

'Navigodirettamentesull'attributo

navigator=navigator.

SelectSingleNode("/p:products/p:product[1]/@idCategory",nsManager)

'Leggoilvalore

DimidCategoryAsInteger=navigator.ValueAsInt

La sintassi /p:products/p:product[1]/@idCategory vuole indicare che, partendo dalnodo radice, il motore deve ricercare i tag products e, a sua volta, i tag product.Mediante le parentesi quadre, indichiamo un’espressione di filtro e, in questo caso, diprendere solo il primo elemento; da questo, poi, navighiamo nell’attributo idCategory.Otteniamo così, a nostra volta, un nuovo XPathNavigator, che ha un riferimento almedesimo XPathDocument ma si trova in un’altra posizione. Possiamo fare ulteriorispostamenti, ritornare a elementi padre oppure, comenell’esempio12.20, interrogare leproprietàdinostrointeresse.

LaclasseXmlNamespaceManagerpermettedimappareunaseriediprefissiconrelativinamespace, per utilizzarli in un successivo momento nelle espressioni XPath. Semprenell’esempio 12.20, il prefisso p viene utilizzato per fare riferimento a un precisonamespace.DobbiamoinfatticonsiderarecheXPathèmoltopotente,permettedifiltrare,convertire numeri e stringhe, utilizzare funzioni, lavorare per posizione, combinare inamespaceeusarespecialikeyword(detteaxis)perricercarenodidiscendenti,ascendenti,fratelliepadri.

Dato che l’espressione è una stringa che va interpretata dal motore di XPath permigliorare le prestazioni di esecuzione, possiamo anche compilare tale stringa con ilmetodo Compile e ottenere un XPathExpression che la rappresenta, pronta per essereeseguitaunaopiùvolte,comemostratonell’esempio12.21.

Page 315: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio12.21'Navigodirettamentesull'attributo

DimexpAsXPathExpression=navigator.

Compile("number(/p:products/p:product[1]/@idCategory)")

'Impostoilresolverdeinamespace

exp.SetContext(nsManager)

'Leggoilvalore

DimidCategoryAsInteger=CInt(navigator.Evaluate(exp))

Nell’esempiocompiliamol’espressioneeneteniamoilriferimentodatocheadognisuoutilizzodobbiamoimpostareilcontestoespecificarequalèilresolverdeinamespacedautilizzare. L’espressione può essere passata ai metodi Select e SelectSingleNode,oppure, se essa restituisce direttamente un valore (in questo caso il numero convertitodella categoria), può essere passata al metodo Evaluate e ottenere immediatamente ilvalorericercato.

ModificareinodiOltre apermettere lanavigazione tra i nodi, l’XPathNavigatorprevede lapossibilitàdimodificarli in modo molto simile a DOM. Tuttavia, non tutti i navigatori supportanoquesta funzionalitàperchéciòdipendedalla loroorigine: l’XPathDocument,adesempio,permette solo la lettura, a differenza dell’XmlDocument, che la permette attraverso ilproprionavigatore.

Nell’esempio12.22sfruttiamoproprioquestaclassepercaricareilfileXML;creiamounnavigatoreeusiamoilmetodoSetValuepercambiarneilvalore.

Esempio12.22'Caricoildocumento

DimdocAsNewXmlDocument()

doc.Load("test.xml")

'Creoilgestoredeinamespace

DimnsManagerAsNewXmlNamespaceManager(doc.NameTable)

'Associoilprefissoalnamespace

nsManager.AddNamespace("p",

"http://schemas.aspitalia.com/book40/products")

'CreoilnavigatoresuiXmlNode

Dimnavigator=doc.CreateNavigator()

'Ricercol'attributo

Page 316: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

navigator=navigator.

SelectSingleNode("/p:products/p:product[1]/@idCategory",nsManager)

navigator.SetValue("5")

Abbiamoinoltreadisposizioneuninsiemedimetodipercreareelementi,attributioppureperspostareoeliminare,iltuttosempreapplicandolialnodocorrentedinavigazione.

Nell’esempio 12.23, partiamo da un XmlDocument nuovo e con il metodoAppendChildElement creiamo il tag radice specificando il prefisso, il nome e ilnamespace.Successivamenteci spostiamosull’elementoappenacreatoe impostiamounattributo,valorizzandolo.

Esempio12.23DimdocAsNewXmlDocument()

Dimnavigator=doc.CreateNavigator()

'Creoiltag<products>

navigator.AppendChildElement("p","products",

"http://schemas.aspitalia.com/book40/products","")

navigator.MoveToFirstChild()

'Creol'attributocount

navigator.CreateAttribute("","count","","5")

IlmetodoAppendChildElementprevedeeventualmentediimpostareilvaloretestualedelnodo e anche CreateAttribute permette, come opzione, di specificare il prefisso e ilnamespace.

In ogni caso, una voltamanipolato il documento con il navigatore, per proseguire lemodifiche dobbiamo ricorrere ai metodi di salvataggio appartenenti al creatoredell’XPathNavigator. Nell’esempio 12.23, dobbiamo quindi invocare il metodo Savesull’oggettoXmlDocument.

TrasformareidocumenticonXSLTInunioneaXPathvièunaltro strumentochepuòesseremoltoutilequandodobbiamoprocessare documenti XML e produrne un secondo: XSLT. Acronimo di eXtensibleStylesheet Language Transformations, è un linguaggio standard che ha lo scopo diprodurre documenti txt, HTML oXML, data una sorgente XML. Su di essa possiamoricercarenodieleggereivalori,utilizzandotuttalasintassiXPath,eventualmenteanchesfruttandofunzioniesternedanoisviluppate.

Nel .NETFramework le trasformazioniXSLTsonosupportateesipossonoeffettuaremediante la classe XslCompiledTransform del namespace System.Xml.Xsl. UsandoquestooggettoquellochepiùcontaèconoscereillinguaggioXSLT,datocheciòchegli

Page 317: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

serveèlostylesheeteildocumentoXMLdatrasformare.

Lo stylesheet,di fatto, è anch’essounXMLche, attraversoalcuni tagdelnamespacehttp://www.w3.org/1999/XSL/Transform,permettediunireXMLconmarkupHTMLonormaletesto.Anchesenonèscopodiquestolibrospiegareinmodoapprofonditoquestolinguaggio,possiamovederneuncampionenell’esempio12.24.

Esempio12.24-test.xslt<xsl:stylesheetversion="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

xmlns:msxsl="urn:schemas-microsoft-com:xslt"

exclude-result-prefixes="msxslp"

xmlns:p="http://schemas.aspitalia.com/book40/products">

<xsl:outputmethod="html"

indent="yes"/>

<xsl:templatematch="/">

<html>

<body>

<table>

<xsl:for-eachselect="/p:products/p:product">

<tr>

<td>

<xsl:value-ofselect="p:description"/>

</td>

</tr>

</xsl:for-each>

</table>

</body>

</html>

</xsl:template>

</xsl:stylesheet>

Partendodall’elemento radicedinomestylesheet, identifichiamo la trasformazionedaapplicare.Con l’elementooutput impostiamo alcune direttive, come l’indentazione e iltipodioutputchevogliamoprodurre:HTML.Attraversoiltagtemplate,invece,andiamoaindicareche,afrontedelmatchsull’elementoradice(loslash/),ilmotoredeveapplicareil suocontenuto.Nell’esempio12.24, andiamoquindi a preparare le porzioni diHTMLchesonosemprepresenti,finoallatabella.Conunfor-eachandiamoaciclareilrisultatodiunaselecteffettuatasuun’expressioneXPath,lastessavistanelparagrafoprecedente,

Page 318: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

chevaaciclaresuiprodotti.Perognunodiessi,creiamouna rigacon relativacella,davalorizzareconilcontenutodelladescrizione.

LoscopodiquestatrasformazioneèquindipreparareunapaginaHTMLdatounXMLaderente allo schema preso in esame nell’arco di tutto questo capitolo. Creiamo quindiun’istanza della classe XslCompiledTransform e carichiamo la trasformazione test.xsltdell’esempio 12.24. Come il nome della classe suggerisce, una volta caricata latrasformazione, questa viene compilata e, mantenendone un riferimento, ci permette diusarlapiùvolteperottenereilmassimodelleprestazioni.

Successivamente, con ilmetodoTrasform, passiamo l’XMLda trasformare (esempio12.1)edovecaricareilrisultato,comemostratonell’esempio12.25.

Esempio12.25DimxsltAsNewXslCompiledTransform()

'CaricolatrasformazioneXSLT

xslt.Load("test.xslt")

'Trasformol'XMLelomostronellafinestradiOutput

xslt.Transform("test.xml",Nothing,Console.Out)

Pochelinedicodicebastanoperutilizzareunlinguaggiostandardeprodurredell’HTML,conmoltissimivantagginellavisualizzazionedicomerisulteràl’outputfinale.

Possiamoinfattivedere,nell’esempio12.26,comel’outputprodottorispettiesattamentequellocheeraintuibiletramitelatrasformazionedell’esempio12.24.

Esempio12.26<html>

<body>

<table>

<tr>

<td>Prodotto1</td>

</tr>

<tr>

<td>Prodotto2</td>

</tr>

<tr>

<td>Prodotto31</td>

</tr>

</table>

Page 319: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

</body>

</html>

Il secondo parametro del metodo Transform accetta facoltativamente unXsltArgumentList, il quale permette di passare parametri utili alla trasformazione oextension object: oggetti che permettono di estendere la trasformazione con funzionipersonalizzate.

ConclusioniIn questo capitolo abbiamo illustrato i principali strumenti per l’interrogazione, lacreazioneelamodificadidocumentiXMLoffertiall’internodel.NETFramework.

Abbiamovisto leclassiXmlReader eXmlWriter, le quali ci consentonodi ottenere ilmassimodelleprestazioniconuncertooneredi implementazionemache,di fatto,sonoallabasedituttiglialtristrumentimessiadisposizionenel.NETFramework.

ConXmlDocumentcivieneinveceoffertounsempliceapproccioDOMeperciòrisultautile se si ha esperienza con quest’ultimomentre, sfruttando LINQ toXML, possiamoottenere ilmassimo dei benefici derivanti dall’uso della query syntax e degli extensionmethod offerti da LINQ. Nel corso del capitolo abbiamo osservato come sia migliorel’organizzazione delle classi e come coprano correttamente tutte le tipologie di nodidisponibili. La versatilità di XElement permette di creare facilmente elementi, attributi,commenti e di manipolarli, spostandoci facilmente tra i nodi con metodi dai nomiautoesplicativi.

Qualora invece volessimo usare strumenti standard che dovremmo già conoscere,abbiamoadisposizioneXPathperlaricercadeinodieXSLTpereffettuaretrasformazionisuidocumenti.

A questo punto, abbiamo offerto una buona illustrazione di tutti gli strumenti adisposizione,cosìdaessereingradodideterminareilpiùadattoallevariecircostanzechepossiamoincontrarenelcorsodellosviluppodellenostreapplicazioni.

Page 320: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

13

IntroduzioneaXAML

IntroduzioneaXAMLXAML è un linguaggio dichiarativo dimarkup basato suXML, usato per inizializzarestruttureeoggetti.XAMLera l’acronimodiExtensibleAvalonMarkupLanguage,doveAvalonera ilnome incodicedellaprima tecnologiache lohausato inmodoestensivo:WPF. Decaduto il nome in codice, XAML è diventato ufficialmente l’acronimo diExtensibleApplicationMarkupLanguage.

PrimadiXAML lo sviluppodelle applicazioni in ambienteWindowsera interamentebasato sulle GDI/GDI+, usate ampiamente in WinForms: una tecnologia rilasciata nel2002conlaprimaversionedel.NETFramework.

ConXAML,per la primavolta in ambienteWindowsviene introdotto un linguaggiodichiarativo,percertiversisimilealbenpiùfamosoediffusoHTML.DaXMLeHTML,XAML prende la leggibilità tipica dei linguaggi dichiarativi. Il Markup è di sempliceinterpretazioneenonrichiedeparticolariconoscenzetecniche.

Questasemplicitànehadecretatoilsuccessotantoche,quandoneglianniWindowssièdiffuso su dispositivi diversi dal PC-desktop, è stato adottato anche su queste nuovepiattaforme. Ai giorni nostri, anche a seguito dell’unificazione della piattaforma disviluppo, loXAML è ancora la scelta più produttiva per la definizione dell’interfaccia.Questa uniformità va ad appannaggio del miglioramento dei tempi di sviluppo e dellasemplicitàdimanutenzione.

L’ambientedisviluppoA prescindere dalla tipologia di applicazione che vogliamo realizzare, a fornirel’infrastruttura di base è la classe Application. Nonostante le ovvie differenze, questaclasseaccomunatuttelepiattaformecheutilizzanoXAMLcomelinguaggiodichiarativoperlarealizzazionedelleinterfaccegrafiche.

LaclasseApplicationhaloscopodifornirel’infrastrutturanecessariaagestireilciclodivitadell’applicazione, le risorse (vedremo indettagliodi cosa si tratta più avanti nellibro),l’UIeilsistemadinavigazione.

OgniapplicazioneWPFoUniversalWindowsPlatformappè realizzatautilizzando ilVisualStudio,edècompostadauninsiemediassetchenecostituisconoilnucleominimo

Page 321: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

difunzionamento.L’organizzazionedell’IDEdiVisualStudio2015èvisibilenellafigura13.1.

La parte di definizione dell’interfaccia avviene mediante l’utilizzo del linguaggioXAML(sileggezamel)all’internodifileconl’omonimaestensione.xaml.Perognunodiquestifileesisteilcorrispettivo.cs,chiamatofiledicodebehind.Generalmente,questotipo di file è usato per la gestione degli eventi sollevati dall’interfaccia utente, come lapressionediunbottoneolagestionedelleanimazioni.

Figura13.1–L’IDEdelVisualStudio2015.

Il file di code behind non è strettamente necessario, e se la nostra UI è estremamentesemplicepossiamotranquillamenterimuoverlo.VisualStudiononpermettelacreazionedifilexamlchenesianoprivi.Quindiènecessario,unavoltarimossoilfile.csinutilizzato,rimuovere il riferimento aquest’ultimo.Per farlo è sufficiente identificarenel filexamll’attributox:Class,chegeneralmentetroviamoapplicatosulnodoroot,erimuoverlo.

Fin dall’introduzione dello XAML come linguaggio di design, Microsoft decise diaffiancare a Visual Studio un tool pensato per sfruttarne le sue spiccate potenzialitàmultimediali: Blend. Con il tempo, molte delle funzionalità di Blend sono stateincorporate in Visual Studio, con un’unica eccezione: la creazione delle animazioni.L’interfaccia utente di Blend è sempre stata differente da quella di Visual Studio. Conl’ultimo aggiornamento, Blend diventa Blend for Visual Studio 2015 e adotta il layoutdell’interfacciautentediVisualStudio,mantenendoperòilcaratteristicotemaDark.

La figura 13.2 mostra l’ide di Blend for Visual Studio: quest’ultimo può essereutilizzato sia comeprogrammastandalone sia, in alternativa, eseguitodaVisualStudiosemplicementedalmenucontestualesuqualsiasifileconestensioneXAML.

Page 322: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura13.2–L’IDEdiBlendforVisualStudio2015.

IlmarkupXAMLXAMLèun linguaggiodichiarativo, comeabbiamodetto, simileall’HTMLeall’XML.Dalprimoprendelasemplicitàmentredalsecondodesumeilrigoredellasintassiedellacorrettezza del formato. Un file XAML dichiara al suo interno una serie di elementi,ognuno dei quali rappresenta un’istanza di un oggetto. Dichiarare l’elemento <Grid> èl’equivalentedacodicedellacreazionediunanuovaistanzadelcontrolloGrid.IlcompitodiinterpretareitagpresentinelloXAMLediistanziareglioggettirelativièacaricodelparserXAML.

LasintassiAlloscopodipotergestirelacomplessitànecessariaallarealizzazioned’interfacceutentecomplesseearticolate,compostedadecinedioggetti,XAMLdisponedialcuneregoledisintassidausareinbasealproblemadarisolvere.

LasintassiObjectelementQuestotipodisintassirappresentaun’istanzadiunoggetto;ognielementoèformatodaunaparentesiangolareaperta“<”ilnomedellaclassedaistanziare,seguitodaunaslashedaunaparentesiangolarechiusa“>”.L’esempio13.1mostrailmarkupnecessarioacreareun’istanzadeltipoButton.

Page 323: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio13.1–XAML<Button>

Hello!

</Button>

Nelframmentodicodiceprecedente,l’inserimentodellasemplicestringaditesto“hello”èequivalenteaimpostarelaproprietàContentdellaclasseButton.

LasintassiPropertyattributePossiamo impostare le proprietà di unoggetto utilizzando il nomedella proprietà comeattributodiunelemento.Nell’esempio13.2impostiamoilcoloredisfondodiunbottone.Quindi il nome dell’attributo rappresenta il nome della proprietà e la stringa dopo ilsimbolodell’ugualenerappresentailvalore.

Esempio13.2–XAML<ButtonBackground="Blue"/>

Ci sono proprietà che comunque possono difficilmente essere rappresentate da unasemplice stringa. In questi casi possiamo ricorrere a una sintassi alternativa, chiamataPropertyElement.

LasintassiPropertyElementInquestotipodisintassi,ilvaloredellaproprietàèespressoutilizzandol’ObjectElement,mentre la proprietà da impostare segue la sintassi Type.PropertyName, come possiamovedere nell’esempio 13.3, e prende forma come elemento interno all’oggetto che laespone.

Esempio13.3–XAML<Button>

<Button.Background>

<SolidColorBrushColor="Red"/>

</Button.Background>

</Button>

Nel precedente esempio creiamo un’istanza di una classe Button e impostiamo laproprietàBackground,utilizzandounanuovaistanzadiSolidColorBrush.

Affinché sia possibile creare un’istanza della classe dichiarata nelmarkup, ènecessariocheiltipodispongadiuncostruttorepubblicoprivodiparametri.

Page 324: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

InamespaceInundocumentoXAML, l’elemento root dichiaraunoopiùnamespace comuni a ognipiattaforma:

xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation: conquestadichiarazioneèmappataunagrandequantitàdinamespacedellelibrerie;èilnamespacedidefaultenonnecessitaprefissi;

xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml: è un namespace asupportodellecaratteristichedellinguaggioXAML;tipicamentehailprefissoxepuòservire,comeabbiamovistomediantel’attributox:Class,alegareilfile.xamlalrelativofiledicodebehind.

Inamespace,indicanoalparserinqualeassemblycercareitipidautilizzarepercreareleistanzedeglielementidefinitineldocumentoXAML.PoichéunnamespaceXAMLpuòmappare più assembly e più namespace del CLR, è necessario che non vi siasovrapposizionedei nomi tra le classi, altrimenti il parsernon è ingradodi distinguerequaletipoistanziare.

Oltre ai namespace predefiniti, possiamo definirne di nuovi per utilizzare dei tipidefinitidanoi.

Esempio13.4PublicClassTestClass

PublicOverridesFunctionToString()AsString

Return"QuestoèuntiponondefinitonelCLR"

EndFunction

EndClass

Per utilizzare la classe dell’esempio 13.4 in un documento XAML, è sufficienteaggiungere in WPF all’elemento root il seguente namespace: xmlns:local="clr-namespace:Chapter13", mentre nelle Universal Windows Platform app:xmlns:local="using:Capitolo13". Con questa è possibile associare il namespace delCLRalnamespaceXAML.

Esempio13.5–XAML<UserControlx:Class="Chapter13.UserControl1"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

WindowTitle="Capitolo12"

WindowWidth="300"

WindowHeight="300"

Page 325: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

xmlns:local="clr-namespace:Chapter13">

<local:MyClass></local:MyClass>

</UserControl>

Quandoilparsersitrovaavisualizzareuntipodefinitodall’utente,nelcasoincuinonsitratti di un elemento visuale o non sia specificato diversamente, viene richiamato ilmetodoToString,cheognioggettodelCLRespone,comeèpossibilevederenellafigura13.3.

Figura13.3–Larenderizzazionedelnostrotipocustom.

Comepossiamocomprenderedall’esempio13.5edallafigura13.3,ilrischiodiriempirel’elemento root con definizioni di namespace è davvero alto. Per evitarlo solo nelleapplicazioniWPF,possiamoutilizzarel’attributoXmlnsDefinitionAttributeeassociarepiùnamespacedelCLRaunsolonamespaceXML.

IllayoutsystemOgnielementodell’interfacciaoccupaunospaziocheèchiamatoboundingbox,ilqualevienedefinitodallayoutsystem:èunprocessoricorsivochemisura,arrangia,disponeesioccupadellarenderizzazione.QuestoprocessoèfondamentaleperilfunzionamentodelleapplicazionirealizzateutilizzandoXAML,chesidifferenziadamoltialtriframeworkperladistinzionetraglielementifisicielogicichenecompongonol’interfaccia.

È possibile recuperare tutte le informazioni sullo slot occupato da ognielemento,utilizzandolaclasseLayoutInformation.

Elementifisicielogici

Page 326: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Quando in un documento XAML, attraverso il markup, definiamo gli elementidell’interfaccia,andiamoadelineare,atuttiglieffetti,unagerarchiaadalbero,chevienechiamataLogicalTree.Nell’esempio13.5, inpratica,abbiamocreatounagerarchiachehacomeradicel’oggettoUserControleununicofigliocostituitodall’oggettoButton.

Ognielementologicopuòessereformatodaunoopiùelementigrafici.Peresempio,ilcontrolloButtonècostituitodapiùelementivisuali,equestagerarchiaprendeilnomediVisualTree.

In genere, i controlli espongono proprietà che permettono di navigare e popolare ilLogical Tree. Per esempio, possiamo accedere al contenuto degli oggetti che ereditanodallaclasseContentControl,attraversolaproprietàContent.

Diversamente, nessun controllo espone la propria gerarchia visuale, che rimane“occultata”. Possiamo navigare attraverso il Visual Tree, utilizzando la classeVisualTreeHelper la quale espone una serie di metodi utili per recuperare ogniinformazionesull’aspettovisualediunelemento.

LadisposizionedeglielementiLadisposizione degli elementi di un‘interfaccia ha sempre un’importanza fondamentaleperl’usabilitàdiun’applicazione.Nell’ambitodelle tecnologieMicrosoft ladisposizionedeglielementièaffidataauntipoparticolaredioggetti.QuesteclassicheestendonoiltipoPanel sonopredisposte per posizionare gli elementi contenuti, in base ad alcune regoledipendentidaltipoutilizzato.

IpannelliLaclassePanel è una classe astratta che fornisce l’infrastruttura per la realizzazionediclassispecializzateper ilposizionamentodeglielementidell’interfacciautente.Aquestoscopo,esisteunaseriedipannellicherispondeallepiùsempliciesigenze:

Canvas:èilpiùsemplicedeipannelli.Glielementifigliosonodisposti,mediantecoordinate assolute, relativamente a una coppia di margini, attraverso leAttachedPropertyLeft,Top,RighteBottom;

Grid:glielementisonodispostiinrigheecolonne;

StackPanel: gli elementi sono disposti l’uno di seguito all’altro, verticalmenteoppureorizzontalmente,inbasealleproprietàOrientation;

VirtualizingStackPanel: la disposizione degli elementi è identica a quellaeseguita dallo StackPanel ma è ottimizzata per un numero elevato di elementi,calcolandosolamentequellieffettivamentevisibili.

Esempio13.6–XAML<UserControl

Page 327: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

xmlns="http://scriemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

Width="300"

Height="300">

<StackPanel>

<Button>1</Button>

<Button>2</Button>

<Button>4</Button>

<Button>5</Button>

<Button>6</Button>

</StackPanel>

</UserControl>

Nellafigura13.4,nell’immaginevienevisualizzatoilrisultatodell’esempio13.6.

Figura13.4–IButtonordinatidaunoStackPanel.

NelleUniversalWindowsPlatformappsonodisponibilipannellispecializzatipercreareletipiche interfacce delle applicazioni moderne. Come, per esempio, ilVariableSizedWrapGrid, con il quale è possibile disporre gli elementi sotto forma digrigliaedeciderelospaziodaallocareaognisingoloelemento.

Nellesempio13.7, invece, sostituiamo il panelloStackPanel con unCanvas.Oltre acambiareiltipodipannello,ènecessarioindicarecomedisporreivaribottoniall’internodelpannellostesso:possiamofarlousandoleAttachedProperty.

Page 328: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio13.7–XAML<UserControl

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:mc="http://schemas.openxmlformats.org/markup-

compatibility/2006"

Width="300"

Height="300">

<Canvas>

<Button>1</Button>

<ButtonCanvas.Top="90">2</Button>

<ButtonCanvas.Top="190">4</Button>

<ButtonCanvas.Top="300">5</Button>

<ButtonCanvas.Top="390">6</Button>

</Canvas>

</UserControl>

Nella figura13.5 possiamo apprezzare, oltre alla differente posizione degli elementi, lediverse dimensioni. Questo perché il Canvas, in modo differente da quanto fa loStackPanel,allocaaglielementifiglisololospaziodicuihannoeffettivamentebisognoenontuttolospaziodisponibile.

Anche solograzie a questi due semplici esempi, è possibile intravedere la flessibilitàdell’usodeipannelli rispettoalvecchioeunicomodello“cartesiano”tipicodiWindowsFormodialtrisistemioperativi.

I Pannelli, da soli, non possono essere usati per creare un interfaccia utente; servequalcosaconcuil’utentepossainteragire:icontrolli.

Page 329: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura13.5–IButtonordinatiall’internodiuncanvas.

IcontrolliL’interfacciadiognimodernaapplicazioneèformatadaunaseriedielementichepermetteall’utente di interagire con i dati dell’applicazione stessa. Questi elementi prendono ilnomedicontrolli.LeapplicazioniUniversaleWPFdispongonodiunalibreriacompletaegeneral purpose di controlli. Questi controlli permettono di realizzare le più complesseinterfaccegrafiche.

I controlli sono definiti lookless, cioè privi di look ma, benché questo non sialetteralmente corretto, si meritano questo appellativo per la loro capacità di cambiarecompletamente aspetto, ridefinendo il proprio Visual Tree con l’impostazione dellaproprietàTemplate.

Leclassiprincipali:UIElementeFrameworkElementOgnicontrolloereditaindirettamentedaltipoFrameworkElementchefornisceiservizidiLayout, ilsupportoalDataBindingagliStyleeaiTemplateedestende il supportoalleanimazioni,giàoffertodallaclasseUIElement.

LaclasseUIElement fornisceunsupportobaseallagestionedell’inputdell’utentealleanimazioniedesponeimetodicheleclassiderivatepossonosovrascrivereperparteciparealsistemadiLayout.

Icontrolli

Page 330: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dovendodividereicontrolli,possiamodistinguerliinduegrandicategorie:icontrollichederivanodirettamenteoindirettamentedallaclasseContentControlequellichederivanodaItemsControl.Unesempiodi classederivatadal tipoContentControl è il controlloButton.Nellasuasemplicità,introduceconcettichepossiamoapplicareancheacontrollinettamentepiùcomplessi.

Tutti i controlliderivatidallaclasseContentControl espongono la proprietàContentdeltipoObject.Ciòpermette,dalsempliceButtonalloUserControl,diospitarequalsiasitipodicontenuto,dallasemplicestringaditestofinoauncomplessoLogicalTree.

Per esempio, per visualizzare un’immagine all’interno di un Button, non dobbiamocreareunaclassepersonalizzataouncontrollodiversomapossiamopiùsemplicemente,come è possibile vedere nell’immagine 12.8, creare una nuova istanza del tipoImage eassegnarla alla proprietà Content. Utilizzando XAML, la procedura non è diversa daquelladiimpostareunaqualsiasiproprietà.

Esempio13.8–XAML<Button>

<ImageHeight="50"

Source="Desert.jpg"

Stretch="Fill"/>

</Button>

Naturalmente il contenuto non è limitato a un solo elemento ma, utilizzando i Panel,possiamoarrangiarepiùelementiall’internodiunButton,esattamentecomeaccadeperunoUserControl.AncheseilContentControlpuòcontenere,nondirettamente,piùdiunelemento, va considerato che ha come contenuto sempre e solo un figlio. PossiamosuperarequestolimiteutilizzandolaclasseItemsControl.

Il tipo ItemsControl espone il proprio contenuto attraverso la proprietà Items ed è laclassebaseper una serie di controlli, come laListBox, un controllo utile per gestire lavisualizzazione e la selezione di uno o più elementi. La capacità di selezionare non èfornita dalla classe ItemsControl ma da Selector, uno dei suoi tipi derivati.Diversamente da quanto avviene in altre piattaforme di sviluppo, il contenuto dellaListBox può essere qualsiasi tipo di oggetto, dalla semplice stringa, passando per leimmagini,finoapoterutilizzare,perunsingoloitem,ungrafocomplessodielementi.

Esempio13.9–XAML<ListBox>

<ImageHeight="80"

Source="3.1.png"

Stretch="None"/>

Page 331: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<ImageHeight="80"

Source="xp.png"

Stretch="none"/>

<ImageHeight="80"

Source="vista.png"

Stretch="none"/>

<ImageHeight="80"

Source="8.png"

Stretch="none"/>

</ListBox>

Non esistono limiti alla composizione del layout: possiamo realizzare le più complesseinterfacceutente,combinandotuttiicontrollipresentinellevariepiattaforme.Nellafigura13.6possiamovedereilcontrolloListBoxcreatonell’esempio13.9.

Figura13.6–IlcontrolloListBox.

Lapossibilitàdiutilizzareperognisingoloelmentodellalistaqualsiasitipodicontenutononpone limiti alla quantità o all’aspetto che ognunodi essi può assumere.Nel nostrocaso ogni elemento è rappresentato da un’immagine,ma possiamo adattare l’output, incasodinecessità,avisualizzazionidifferenti.

LagraficaCon XAML è possibile soddisfare tanto le esigenze del grafico quanto quelle delprogrammatore.Conpocherighedimarkupèpossibilecreareunanutritaseriedioggetti,finalizzati a rendererizzare forme sullo schermo. Poiché questi elementi ereditano da

Page 332: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

FrameworkElement,possonoessereinseritidirettamenteall’internodiPaneloincontrollicome Button o ListBox. Tutti questi elementi, che ereditano dalla classe base Shape,espongonoleseguentiproprietà:

Fill:ditipoBrush,rappresentailriempimentodellaforma;

Stroke:ditipoBrush,rappresentailriempimentodelbordodellaforma;

StrokeThickness:ditipoTrickness,specificalospessoredelbordodellaforma.

Utilizzando i tipi derivati da Shape, possiamo disegnare: Ellipse, Line, Path,

Polygon,Polyline,Rectangle,nell’ordine,perdisegnareun’ellisseouncerchio,unalinea,unafiguracomplessa,unpoligono,unapolilineaounrettangolo.

Esempio13.10–XAML<Button>

<Grid>

<RectangleFill="Red"

Width="45.6"

Height="48.8"

HorizontalAlignment="Left"

VerticalAlignment="Top"/>

<EllipseFill="#FF3694FF"

Margin="157.4,0,45.6,0"

Width="70.4"/>

<PathFill="#FF7F7F7F"

Stretch="Fill"

HorizontalAlignment="Left"

Margin="72.3,6.5,0,3.7"

Width="58.9"

Data="M72.299999,30.2L86.999997,6.5000006130.2,32.100001

98.199997,44.100001z"/>

</Grid>

</Button>

Nell’esempio 13.10 abbiamo inserito, all’interno di un Button, una serie di forme; perognuna abbiamo specificato il colore di riempimento, impostando la proprietà Fill ealcuneproprietàperaggiustarnelaposizione.

Ipennelli:ilBrushDisegnareunaformanonavrebbesensose,unavoltalanciatal’applicazione,questanon

Page 333: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

fossevisibile.Dobbiamoquindiriuscireavisualizzareunaformachesiacolorata.

ConXAMLpossiamocolorareglioggetti,utilizzandoleclassiderivatedaltipoBrush,lequalifornisconounmododifferentediapplicareilcoloreaunaforma:

SolidColorBrush: è il riempimento più semplice, rappresentato da unriempimentopienodiuncoloreuniforme,chepuòessere impostatoattraverso laproprietàColor;

LinearGradientBrush: rappresenta una sfumatura che ha un’origine e una fine,che possiamo specificare impostando le proprietà StartPoint e EndPoint. Traquestiduepunti,icolorichecostituisconolasfumaturapossonoessereillimitatiepossonoessereimpostatimedianteGradientStops;

RadialGradientBrush: (solo WPF) è simile al LinearGradiendBrush ma lasfumaturaèradialeepossiamoimpostarnel’aspettomedianteleproprietàRadiusXeRadiusY;

ImageBrush: il riempimento non è più un colore ma un’immagine, per coprirecompletamentel’oggettoalqualeèapplicata.

Nell’esempio13.11creiamouncerchioelocoloriamomedianteungradientecompostodatrecolori.

Esempio13.11–XAML<Ellipse>

<Ellipse.Fill>

<LinearGradientBrushEndPoint="0.5,1"StartPoint="0.5,0">

<GradientStopColor="#FFEA0F0F"Offset="0"/>

<GradientStopColor="Black"Offset="1"/>

<GradientStopColor="White"Offset="0.477"/>

</LinearGradientBrush>

</Ellipse.Fill>

</Ellipse>

Possiamo disegnare forme di qualsiasi genere sfruttando iPathma, per effetti davverosorprendenti,nonpossiamononcitareletrasformazioni.

LetrasformazionisuglioggettiNessun sistema grafico potrebbe dirsi completo se non disponesse di un sistema perelaborare l’aspetto dei propri elementi. ConXAML possiamo applicare trasformazioni,come la scala non uniforme, semplicemente impostando la proprietà RenderTransform,esposta da qualsiasi tipo erediti direttamente o indirettamente dal UIElement. Tutte letrasformazioni messe a disposizione ereditano dal tipo Transform e ognuna di esse

Page 334: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

conferisceuneffettodifferenteall’elementoalqualeèapplicata:

TranslateTransform: trasporta l’elemento al quale è applicata, specificando lecoordinatexeymedianteleproprietàXeY;

SkewTransform: applica una trasformazione di slittamento, impostando leproprietà AngleX e AngleY. Per esempio, un rettangolo cui viene applicata unatrasformazionediquestotipopuòdiventareuntrapezio;

ScaleTransform:applicaunatrasformazionediscalatura,controllabileattraversoleproprietàScaleXeScaleY;

RotateTransform: applicauna trasformazionedi rotazione,dellaqualepossiamocontrollare l’angolomediante laproprietàAngle, e il centromedianteCenterXeCenterY.

Esempio13.12–XAML<RectangleFill="#FFFE1F1F"

Width="50"

Height="50">

<Rectangle.RenderTransform>

<RotateTransformAngle="-42"/>

</Rectangle.RenderTransform>

</Rectangle>

<RectangleFill="#FFFE1F1F"

Width="50"

Height="50"

Grid.Column="1">

<Rectangle.RenderTransform>

<ScaleTransformScaleX="0.6"/>

</Rectangle.RenderTransform>

</Rectangle>

<RectangleFill="#FFFE1F1F"

Width="50"

Height="50"

Grid.Row="1"

Grid.Column="1">

<Rectangle.RenderTransform>

<TranslateTransformX="42"

Y="35"/>

</Rectangle.RenderTransform>

Page 335: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

</Rectangle>

<RectangleFill="#FFFE1F1F"

Width="50"

Height="50"

Margin="46.4,41"

Grid.Row="1">

<Rectangle.RenderTransform>

<SkewTransformAngleX="-31"/>

</Rectangle.RenderTransform>

</Rectangle>

Nell’esempio13.12,almedesimorettangolovieneapplicataognivoltaunatrasformazionedifferente,producendoglieffettichepossiamovederenellafigura13.7.

Figura13.7–Unaserieditrasformazioniapplicataadalcunielementi.

LaproprietàRenderTransformaccettaunasolaistanzadeltipoTransform, impendendo,difatto, lapossibilitàdiapplicareunacollezionedi trasformazioni.Perovviareaquestoproblema, possiamo utilizzare il tipo TransformGroup, il quale eredita dal tipoTransform,applicandocosìpiùtrasformazioni,aggiungendoleallacollezioneChildren.Dobbiamo prestare attenzione all’ordine nel quale sono dichiarate le trasformazioniall’interno della collezione, in quanto l’ordine può produrre effetti differenti se, peresempio,primadiruotareunoggetto,loabbiamoprecedentementespostato.

LetrasformazioniapplicatemedianteRenderTransformnoninfluenzanoaltrielementise non quello che imposta la proprietà. É possibile invece, solo in WPF, mediante laproprietà LayoutTransform, modificare anche il layout degli elementi circostanti. Peresempio, se ingrandiamo un elemento, quelli nelle vicinanze si sposteranno diconseguenza.

Page 336: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

LeanimazioniQuello che differenzia le nuove tecnologie da quelle esistenti su Windows primadell’avventodiWPFè la totale integrazionedel sistemadi animazioni direttamenteneitipichecostituisconolebasidel.NETFramework.

ConXAMLpossiamo animare gli elementi dell’interfaccia, alternandone le proprietà(peresempio,modificandolaproprietàOpacityperfarappariredalnullaunoggetto).

Affinchéquesto siapossibile, sononecessari alcuni requisiti: laproprietàdeveessereuna DependecyProperty mentre l’oggetto che la espone deve ereditare daDependencyObject.

Le animazioni sono create utilizzando la classe Storyboard e impostandone una oalcune. Difficilmente queste ultime sono create utilizzando l’ambiente RAD di VisualStudioocreateamano,maèpiùrealisticopensarecheiltuttoavvengautilizzandoBlend,il quale nasce non solo per facilitare il disegno delle interfacce basate su XAMLma,soprattutto,percreareaccattivantianimazioni.

Con Blend, realizzare un’animazione è semplicissimo: è sufficiente creare un nuovoStoryboarddalpannello“ObjectandTimeline”,posizionarelatestinadiriproduzione(larigagiallasullostoryboard)ecambiareivaloridelleproprietàchevogliamoanimare.Peresempio, per animare la posizione di un elemento dell’interfaccia, sarà sufficientetrascinarlonell’artboard:Blend forVisualStudio registrerà inostri spostamentiecreeràl’animazione.

Leanimazionisupportatepossonoesserelineari,ovveroconunandamentocostanteneltempo, variando una proprietà solo da un valore all’altro.Ma possono anche utilizzarekeyframe, ovvero fotogrammi chiave, nei quali una determinata proprietà deveraggiungereundeterminatovalore.

Lafigura13.8mostral’interfacciadiBlendforVisualStudiodurantelaregistrazionediunoStoryboard:asinistrapossiamonotare la timeline, lostrumentocheciconsentedicontrollareiltempodiognisingolaanimazione.

Page 337: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura13.8–BlendforVisualStudiodurantelaregistrazionediun’animazione.

La registrazione dello storyboard nella figura 13.8, ovvero la registrazione di come leproprietàcambianoneltempo,generaloXAMLchepossiamovederenell’esempio13.13.

Esempio13.13–XAML<Storyboardx:Name="Chapater13Storyboard">

<DoubleAnimationDuration="0"

To="6.816"

Storyboard.TargetProperty="(UIElement.RenderTransform).

(CompositeTransform.TranslateX)"

Storyboard.TargetName="rectangle"

d:IsOptimized="True"/>

<DoubleAnimationDuration="0"

To="-181.3"

Storyboard.TargetProperty="(UIElement.

RenderTransform).(CompositeTransform.TranslateY)"

Storyboard.TargetName="rectangle"

d:IsOptimized="True"/>

</Storyboard>

Vista la complessità dello XAML necessario a creare anche una semplice animazione,BlendforVisualStudioè,senzadubbio,unostrumentoindispensabileperlarealizzazionedianimazioni,chepermettedicreareevisualizzareintemporealel’animazionesenzalanecessità di eseguire l’applicazione.Spesso le animazioni sono eseguite in seguito a un

Page 338: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

determinatoevento;periniziarel’esecuzionediun’animazione,èsufficienteutilizzarenelcode behind il metodo Begin: quindi, utilizzando il nome assegnato allo Storyboard,possiamoscrivere:Chapater13Storyboard.Begin.

ConclusioniXAML rappresenta, senza dubbio, una rivoluzione per il layer di presentazione diWindows.L’integrazioneconleDirectXelapossibilitàdicrearegraficheraffinatesenzaalterarne la logica di funzionamento, rende questo strumento indispensabile per creareinterfacceall’avanguardia.

La possibilità di creare grafi complessi di oggetti risponde alle esigenze di produrreinterfacce ricche di dettagli e sempre più orientate a fornire all’utente un’esperienzaappagante.

La possibilità di utilizzare riempimenti, come immagini, oggetti visuali, video egeometrie,consentediottenereunagammadieffettimoltocomplessi.

La possibilità di animare ogni singola proprietà di ogni oggetto apre scenari che, inpassato,noneranosemplicementeimmaginabili, lasciandounospaziosemprepiùampioallacreatività.

Nel prossimo capitolo proseguiremo il viaggio all’interno XAML, affrontandotematichepiùavanzatequaliildatabinding,glistili,itemplate,inmododacomprendereeapprofondirelepotenzialitàcheoffrequestatecnologiaesapersceglierecomeequandoapplicarla.

Page 339: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

14

SviluppareconXAML-Concettiavanzati

Nel capitolo precedente abbiamo introdotto XAML, analizzando quali sono le sueprincipali caratteristiche ed evidenziando qual è il netto distacco rispetto alle vecchieapplicazionibasatesuldisegnoconposizioniassolute,checontraddistingueVisualBasic(fino alla versione 6),WinForm,MFC e, in generale,Win32. Proseguiamo ora questoviaggio,affrontando le funzionalitàpiùevolutediXAML,moltedellequalisononuoveperilmondodellosviluppodiapplicazioni.

XAMLpresentaunbuonnumerodidifferenzetraivariframework,soprattuttoinWPF:trattare ogni singola differenza richiederebbe la scrittura di un altro libro. Perciò, comeabbiamogiàfattonelcapitoloprecedente,ancheinquestocercheremodiillustrarnetuttelecaratteristichecomunitraiframework,senzaentraretropponeldettaglio,macercandodiesporrequalisonoleenormipotenzialitàdiquestolinguaggio.

Comeabbiamogiàillustratonelcapitoloprecedente,tramiteXAMLdichiariamoclassi,impostiamo proprietà e definiamo layout complessi, il tutto sfruttando controlli cherappresentanofunzionalitàlogiche.Rispettoadaltriframeworkperò,XAMLvaoltreecipermette di personalizzare tutti i controlli in ogni loro aspetto grafico, attraverso itemplate. L’insieme dei colori, dei pennelli, delle trasformazioni e delle animazionipossonoquindiessereracchiusisottoglistyleedesserepoiapplicatipiùvoltesudiversioggetti. Ildata binding è un altro incredibile strumento dalle enorme potenzialità, chepermettediautomatizzareilprocessodivisualizzazioneemodificadeidati,permettendoanchescenarimaster/detaileilpienosupportoallavalidazione.

Inquestocapitolovedremotuttoquesto,partendodacomepossiamodefinireoggettieutilizzarliquandoneabbiamolanecessità.Iniziamoquindidallerisorse.

DefinireeriutilizzarelerisorseUnodeicomportamentipiùnaturalitenutitantodaglisviluppatoriquantodaidesigner,èquello di cercare di organizzare i contenuti di un’applicazione inmodo da favorirne lamanutenzioneeilriutilizzo,dividendoicontenutisecondolelogichepiùadeguate.

NelleUniversalWindowsPlatformapp,questaesigenzanonvieneamancare,datocheè molto comune riutilizzare oggetti e valori, come colori, pennelli e immagini. Persoddisfare questa esigenza, ogni elemento visuale ha a disposizione una proprietà

Page 340: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Resourceschepermettedimantenereundizionariodichiaviconilororelativivalori,perpoifarneriferimentonelcontestoincuisonostatedefinite.

Poniamodivolerdefinireunpennello,usatocomesfondoinpiùpartidell’applicazione;per farlo, dobbiamo dichiarare il pennello allo stesso modo di come normalmentefacciamo sull’elemento al quale vogliamo applicarlo. Tutto questo è illustratonell’esempio14.1.

Esempio14.1-XAML<Page

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Page.Resources>

<SolidColorBrushx:Key="RedBrush">Red</SolidColorBrush>

</Page.Resources>

</Page>

Nell’esempio precedente sfruttiamo la property syntax per popolare la proprietàResources,inquestocasodiunapagina,nellaqualedefinireglioggetti.L’unicorequisitorichiesto è identificare la risorsa con una chiave (attraverso l’attributo x:Key), che èunivocaall’internodelcontestoincuièstatadefinita.

Percontestointendiamol’elementoall’internodelqualelarisorsaèstatadefinitaetuttoil ramo di figli che gli appartengono. Ciò significa che l’elemento stesso (e quellidiscendenti) può utilizzarla, e per farlo dobbiamo sfruttare una delle numerosemarkupextensionpresentiinXAML,inmodospecificoquelladinomeStaticResource.

LemarkupextensionsonounaparticolarecaratteristicadellinguaggioXAMLesicontraddistinguonodalleparentesigraffenellavalorizzazionedegliattributi.Permettonodiampliareilprocessodiinizializzazionedeglielementiattraversoprocessi personalizzati. Vengono sfruttate per fornire funzionalità quali lerisorse,ildatabindingel’assegnazionedeivalori.

PoniamoquindidiavereunpulsantesulqualeimpostarelaproprietàBackgroundcon larisorsa RedBrush. Utilizziamo la markup extension per farne riferimento in base allachiave,comemostratonell’esempio14.2.

Esempio14.2-XAML<Page>

<Page.Resources>

<SolidColorBrushx:Key="RedBrush">Red</SolidColorBrush>

<Page.Resources>

Page 341: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<ButtonBackground="{StaticResourceRedBrush}">StaticResource</Button>

</Page>

Ilrisultatodell’esempio14.2èvisibilenellafigura14.1,inun’applicazioneUniversal.

Figura14.1–Ilpulsanteconbackgroundimpostatotramiterisorsa.

Poichélarisorsaèdefinitaalivellodifinestra,ilbottone,cheèfiglio,puòaccedereallarisorsa evalorizzare lo sfondo.Questa caratteristica, daun lato comportaunamaggioreattenzione nel porre le risorse, ma permette anche scenari più complessi. Per esempio,possiamo definire delle risorse all’interno di un pannello, per il solo fine di renderledisponibili per i propri figli. In casodiomonimie, tra l’altro,vieneutilizzataquellapiù“vicina” a chi ne fa richiesta, dato che la ricerca della risorsa avviene partendodall’elemento e quindi salendo nell’albero degli elementi, fino ad arrivareall’applicazione.

Questo comporta la possibilità di definire risorse a livello globale, attraverso il fileApp.xamlpresenteintutteletipologiediapplicazione,agendosullaproprietàResources.In Expression Blend o in Visual Studio 2015, infatti, per ogni risorsa che andiamo acreare, viene sempre chiesto se bisogna definirla in uno degli elementi padre rispetto aquellochenehabisogno,alivellodifinestra,oppurealivellodiapplicazione.

Inoltre,nellerisorsepossiamoinserirequalsiasioggettomanaged,datocheXAMLnonèunlinguaggiostrettamentelegatoalladefinizionedilayout.Possiamodichiararenumericherappresentanodimensionipercertiaspettidell’applicazione,maancheliste,pennelli,colori,animazioni,trasformazionieperfinoelementivisuali.

Le risorse di XAML non vanno confuse con quelle degli assembly .NET conestensione.resx.Nelcasodegliassembly,lerisorsesonofilebinariinclusineifile .dll e possono essere letti e processati a seconda della tipologia di file.Vengonosfruttateperincludereilbinariodiimmaginiefont,mentrelerisorsedel markup XAML contengono le dichiarazioni degli oggetti da istanziare aruntime.

Bisognaevidenziarechelarisoluzionedellerisorseavvieneinfased’inizializzazionedelmarkup e cioè, in pratica, nel costruttore della classe rappresentante l’applicazione, lapaginaolafinestra,quindinonc’èundecadimentodelleprestazionie,difatto,questoèequivalenteadaverdichiaratoilvalorediunaproprietànelclassicomodo.

Sebbenesiapossibilecambiarelerisorsediunoggettodacodice,aruntime,invirtùdiquantodetto,talimodifichenonsirispecchierannosuglioggetticaricatimasolosuquellicheverrannoistanziatisuccessivamente.

InWPF,masoloconquestoframework,possiamoutilizzarelamarkupextensionDynamicResource che risolve questo problema, monitorando le risorse e

Page 342: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

rispecchiandoinautonomiaicambiamentiapportati.

Nel caso si voglia permettere all’utente di selezionare un tema o uno skin da dareall’applicazione,sarànecessario riavviare l’applicazioneecambiare le risorseprimacheessevenganoutilizzate,oppure, ricaricare lafinestrao lapaginaperunapprocciomenoinvadente.

CreareegestiregliStyleL’utilizzodellerisorsecipermettedicentralizzareeorganizzaremeglioleinformazioni,inparticolar modo quelle inerenti il layout. Con gli Style possiamo fare molto di più:racchiudereinununiconomeuninsiemediproprietàecomportamenti,daassociarepoiaunelemento.Rispettoalmondoweb,gliStyle sonoparagonabili aglistiliCSS e sonofondamentali per il rendering a video dei controlli. Questi ultimi, infatti, rappresentanofunzionalità logiche,manondefiniscononientenell’aspetto, poiché tutto è affidato allostilepredefinito.

PercapirequindigliStyle,supponiamodiavereunpulsantealqualevogliamodarelosfondorossoeimpostareilcoloredeltestoinbianco.

Invece di impostare tali proprietà sul controllo, definiamo uno stile tra le risorse dinome“RedButton”,comemostratonell’esempio14.3.

Esempio14.3-XAML<Page.Resources>

<Stylex:Key="RedButton"

TargetType="Button">

<SetterProperty="Background"

Value="Red"/>

<SetterProperty="Foreground"

Value="White"/>

</Style>

</Page.Resources>

Nell’esempio possiamo notare come, prima di tutto, per ogni stile vada specificata latipologiadielementoacuièdedicato, inquestocaso ilButton.Seguonopoi,medianteoggettiSetter,levalorizzazionidelleproprietàappartenentiall’oggettoButton,mediantelacoppiaPropertyeValue.

Unavoltacheabbiamodefinito lostile,nonci restacheutilizzarlocomeuna risorsa,comemostratonell’esempio14.4,impostandoloattraversolaproprietàStyle,disponibileperognielementovisuale.

Page 343: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio14.4-XAML<ButtonStyle="{StaticResourceRedButton}">Firstbutton</Button>

<ButtonStyle="{StaticResourceRedButton}">Secondbutton</Button>

Nellafigura14.2possiamovederechelostilevieneapplicatoeilrisultatoèilmedesimocheotterremmoimpostandoleproprietàsull’elementostesso.

Figura14.2–Duebottoniconunostyleapplicato.

Sebbene dobbiamo specificare la destinazione di ogni Style mediante la proprietàTargetType,glistilinonsonovincolatiaunospecificotipodioggetto.Infatti,possiamoassegnarlo a un generico UIElement, classe base di tutti gli elementi, oppure a unButtonBase, classebasediCheckBox,Button oRadioButton, e ottenere così uno stileapplicabileapiùoggetti.

NelladichiarazionedelloStylenonèperòobbligatorioindicarelachiavedellarisorsa.Seomessa, la risorsaassumeilnomestessodella tipologia.Quellocheotteniamoèunostileimplicitopertuttiglielementidiqueltipo.Questosignificachepossiamoometterelavalorizzazione della proprietà Style, vista nell’esempio 14.4, e ottenerne il medesimorisultato.

Le possibilità però non finiscono qui. Gli stili possono ereditare da un altro stile,impostando la proprietà BasedOn. Questo ci permette di organizzare gli stili conimpostazioni base che poi specializziamo man mano a seconda del controllo, comeillustratonell’esempio14.5.

Esempio14.5-XAML<Stylex:Key="BaseStyle"TargetType="Control">

<SetterProperty="Margin"

Value="4"/>

</Style>

<Stylex:Key="RedButton"

BasedOn="{StaticResourceBaseStyle}"

Page 344: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

TargetType="Button">

<SetterProperty="Background"

Value="Red"/>

<SetterProperty="Foreground"

Value="White"/>

</Style>

Non è fondamentale che lo stile dal quale ereditiamo abbia il medesimo TargetType.Infatti,nell’esempio14.5lostilebaseèapplicatoatuttiicontrolli,iqualidispongonodiunaproprietàMargin.

Occorre evidenziare che, anchenelle risorse e inparticolare,negli stili, èpienamenteutilizzabiletuttalasintassiXAML,quindilaproprietàValuediunSetterpuòcontenereoggettipiùcomplessie,mediantelapropertyelementsyntax,valorizzaretrasformazioni,animazioni e quant’altro, così come utilizzare una risorsa che abbiamo definito inprecedenza.

ModellareillayoutconiTemplateAbbiamo già accennato al fatto che i controlli delle applicazioni basate su XAMLrappresentanounafunzionelogica.IlButtonhauneventoClickedesegueuncomando,laListBoxcontieneunalistadielementierestituiscel’elementoselezionato,laCheckBoxhaunostatodiselezionatoononselezionato.Questisonosoloalcuniesempidicontrollinella cui implementazione non c’è alcun riferimento a come devono apparire, néinformazionisucomecambiareinfunzionedellostato.Questecaratteristichesonoaffidateaglistilieaitemplate,chedeterminanol’aspettodiognicontrolloe,allostessotempo,cipermettonodiridefinirliinbaseallenostrenecessità.

L’aspetto predefinito di ogni controllo è determinato dal tipo di applicazione(WPF o Universal Windows Platform) e dal tema del sistema operativo. InWindowsPresentationFoundation,sonosupportatiglistilidiWindowsClassic,WindowsXP,WindowsVista eWindows 7, sfruttando le tabelle dei colori deltemacorrente.NelleUniversalWindowsPlatform, invece, il temaèunivocoepuò essere chiaro o scuro, e possiamo scegliere se sfruttare gli accenti sceltidall’utentealivellodisistemaoperativo.

Itemplaterappresentanoladefinizionedicomeuncontrollodeveessererappresentatoinmanieravisuale.Rappresentanounmodello,basatoasuavoltasuelementiprimitivi,comerettangoli,bordiepannelli,esiappoggianosuglistatiperfornirel’interazioneconl’utentedell’interfaccia. Le tipologie di template sono molteplici, a seconda dello scopo chedevonosoddisfare:

ControlTemplate:utilizzatopermodellareicontrollieilloroaspetto;

DataTemplate:utilizzatopermostrareidatiall’internodilisteoContentControl;

Page 345: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ItemsPanelTemplate:utilizzatopermodellare ilpannellocontenitoridi controllichemostranoliste.

PartiamodaiControlTemplate,chesonofondamentalipertuttoilmotoredell’interfacciadiun’applicazione.

PersonalizzareuncontrolloconilControlTemplatePercapiremeglioilconcetto,proviamoapersonalizzareunaCheckBox,incuiilnormalelook&feelèquelloprevistodalsistema. I templatedaapplicareaicontrolli sonodi tipoControlTemplate e, normalmente, vengono definiti nelle risorse. Al loro interno nondobbiamo fare altro che inserire gli elementi visuali, per dare alla nostra CheckBoxl’aspettochedesideriamo.

Nell’esempio 14.6, attraverso un Grid, posizioniamo un rettangolo a fianco delcontenuto, inmodochequesto riempia tutto lo spaziodisponibile. Indichiamo inoltre ilTargetType del template, in modo da specializzare il template e le proprietà a cuifacciamoriferimento:laCheckBox.

Esempio14.6-XAML<ControlTemplatex:Key="PointCheckBox"

TargetType="CheckBox">

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinitionWidth="Auto"/>

<ColumnDefinition/>

</Grid.ColumnDefinitions>

<EllipseStroke="DarkRed"

x:Name="square"

Width="14"

Height="14"/>

<ContentPresenterGrid.Column="1!/>

</Grid>

</ControlTemplate>

DifondamentaleimportanzaèilContentPresenter,chefungedasegnaposto,aindicarecheinquelpuntovapostoilcontenutodellaCheckBox.LaproprietàContent,infatti,cheilcontrolloespone,puòcontenerequalsiasitestooelemento.

Nell’esempio14.7noncirestachedefinireleCheckBoxeutilizzareiltemplatequandolodesideriamo,attraversol’omonimaproprietàTemplate.

Page 346: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio14.7-XAML<CheckBoxIsChecked="True"

Content="IsCheckedatrue"/>

<CheckBoxTemplate="{StaticResourcePointCheckBox}"

IsChecked="True"

Content="IsCheckedatrue"/>

<CheckBoxTemplate="{StaticResourcePointCheckBox}"

Content="IsCheckedafalse"/>

C’èancoraun’ultimacosadafare:abbiamodetto,infatti,chelaCheckBoximplementalalogica, perciò espone una proprietà IsChecked che indica se l’utente ha premuto ilpulsante sull’elemento. Tale proprietà determina anche lo stato visuale del controllo, eattraverso quest’ultimo possiamopersonalizzare l’aspetto del controllo stesso a secondadellesituazionipreviste.NelcasodellaCheckBox,sonoprevistiduestatidinomeCheckedeUnchecked,chepossiamodefinirenelTemplateeutilizzareperanimareglielementi,

Per esempio, possiamo riempire di colore rosso il rettangolo che abbiamo definitonell’esempio 14.6. Modifichiamo quindi il ControlTemplate aggiungendo un oggettoVisualStateManager,comenell’esempio14.8.

Esempio14.8-XAML<ControlTemplatex:Key="PointCheckBox"

TargetType="CheckBox">

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinitionWidth="Auto"/>

<ColumnDefinition/>

</Grid.ColumnDefinitions>

<EllipseStroke="DarkRed"

x:Name="square"

Width="14"

Height="14"

Margin="2"

VerticalAlignment="Center"/>

<ContentPresenterVerticalAlignment="Center"

Grid.Column="1"/>

<VisualStateManager.VisualStateGroups>

<VisualStateGroupx:Name="CheckStates">

Page 347: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<VisualStatex:Name="Checked">

<Storyboard>

<ObjectAnimationUsingKeyFrames

Storyboard.TargetName="square"

Storyboard.TargetProperty="Fill">

<DiscreteObjectKeyFrameKeyTime="0:0:0">

<DiscreteObjectKeyFrame.Value>

<SolidColorBrushColor="Red"/>

</DiscreteObjectKeyFrame.Value>

</DiscreteObjectKeyFrame>

</ObjectAnimationUsingKeyFrames>

</Storyboard>

</VisualState>

<VisualStatex:Name="Unchecked">

</VisualState>

</VisualStateGroup>

</VisualStateManager.VisualStateGroups>

</Grid>

</ControlTemplate>

Come possiamo vedere nell’esempio, la collezione VisualStateGroups ci permette didefinireunoopiùVisualStateGroupilqualerappresentaungruppodistativisuali.Ognistato, identificato dall’oggetto VisualState, ci permette di definire una Storyboard,quindiunaseriedianimazionidaeseguirequandolostatovisualecambia.Quindi,grazieaglistrumentidianimazione,nell’esempio14.8cambiamolaproprietàFilldelrettangolodi nome square. Nella figura 14.3 possiamo vedere il risultato a partire dai controllidefinitinell’esempio14.7:ilprimoconlostilepredefinito,ilsecondoeilterzoconquellopersonalizzato.

Figura14.3–LeCheckBoxconiltemplatepersonalizzato.

L’esempio della CheckBox è semplificato, ma il meccanismo descritto sta alla base del

Page 348: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

funzionamentodituttiicontrollidiognitipologiadiapplicazione.

OgniVisualStateGroup,infatti,rappresentauninsiemelogicodistaticheuncontrollopuò avere, e in genere disponiamo di più gruppi per poter impostare più animazionicontemporaneamente.LamaggiorpartedeicontrollipredisponeigruppiCommonStateseFocusStates, i quali possono avere rispettivamente gli stati Normal, PointerOver (oMouseOversesuWPF)ePressedperilprimo,mentreperilsecondoFocuseUnfocused.Ogni gruppo può essere in uno di questi stati, perciò possiamo specificarecontemporaneamenteanimazioniperilpassaggiodelmouseeanimazioniperilfattocheilcontrolloabbiaonoilfocusdatastiera.Visonopoiglistatispecificidiuncontrollo,chepossiamo personalizzare consultando la documentazione ufficiale, oppure affidandoci aVisualStudio2015oaExpressionBlendperottenereunaiutodapartedeldesigner,checisuggerisceglistatichepossiamopersonalizzare.

OltreaiVisualStatedefinitidaiframework,possiamoanchesfruttarestatipersonalizzatidefinibili su qualsiasi elemento, anche al di fuori del template. Sono molto utili, peresempio,alivellodipagina,perchécipermettonodivariareelementiall’internodiessa,cambiandolostatocorrente.NelleUniversalWindowsPlatformapp,inoltre,disponiamodi uno speciale trigger, di nome AdaptiveTrigger, che è in grado di innescare lo statoquando viene soddisfatta la condizione impostata in funzione della dimensione dellapagina.Loscopoèquellodipoteradattareicontenutiall’internodellapaginaasecondache l’applicazione venga eseguita su mobile, tablet o desktop. Nell’esempio 14.9possiamovedereall’operaquestospecialetrigger.Conessopossiamoindicarelalarghezzaminima della pagina (MinWindowWidth) e l’altezza minima della pagina(MinWindowHeight)affinchélostatovengacambiato.

Esempio14.9-XAML<Grid>

<VisualStateManager.VisualStateGroups>

<VisualStateGroup>

<VisualState>

<VisualState.StateTriggers>

<AdaptiveTriggerMinWindowWidth="700"/>

</VisualState.StateTriggers>

<VisualState.Setters>

<SetterTarget="mainPanel.Orientation"Value="Horizontal"/>

</VisualState.Setters>

</VisualState>

</VisualStateGroup>

</VisualStateManager.VisualStateGroups>

<StackPanelx:Name="mainPanel"Orientation="Vertical">

Page 349: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<TextBlock>Primoelemento</TextBlock>

<TextBlock>Secondoelemento</TextBlock>

</StackPanel>

</Grid>

Oltreaspecificare il trigger, lostatociconsentediusare laStoryboard,comegià fattonell’esempio14.8,maancheunoopiùSetter,oggetticheinmodopiùimmediatoimpostauna proprietà di un elemento (nomeElemento.Proprieta), ma senza transizione.Nell’esempio 14.9 andiamo a variare l’orientamento del pannello qualora la larghezzadellapaginasuperii700pixeleffettivi(pixeldelloschermorapportatiaiDPI).

Ritornando alla funzionalità che può sfruttare i VisualState, i template, dobbiamoaggiungere che sono importanti anche per il caricamento dei dati. Infatti, possiamosfruttarliperpreparareDataTemplate,modellichehannoilcompitodicaricare il layoutperunospecificooggetto,presente,peresempio,all’internodiunalista.

IldatabindingNellamaggiorpartedelleapplicazioni,loscopoprincipaleèmostraredatiprovenientidadatabase, servizi, oppure dal web, per permetterne la consultazione, la modifica, lacancellazioneol’inserimento.Poichéquestaesigenzaèmoltofrequenteepresentaspessole medesime dinamiche, in XAML abbiamo un meccanismo che ci facilita questeoperazioni:ildatabinding.

Conquesto termine indichiamo il legamechecreiamo tracontrolli e sorgentedati, inmododarifletterelemodificheapportatealcontrollosullasorgente,eviceversa.Questomeccanismoècomplessoma,allostessotemporisultasempliceemoltopotente,specieseloconfrontiamoconmeccanismisimilidialtriframework.Iniziamoaesplorarlo.

MostrareleinformazioniconildatabindingPer comprendere le potenzialità del data binding, supponiamo di avere una struttura diinformazionifattadicategorieerelativiprodotti.Questidatisonodefinitimanualmente,comenell’esempio14.10,conduecategorieerelativiprodotti,mapossonoproveniredaqualsiasialtrotipodifonte,comeilweboundatabase.

Esempio14.10DimlistAsCategory()={

NewCategory()With{

.Products=NewProduct(){

NewProduct()With{

.Description="Cat1-Prodotto1",

Page 350: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

.Id=1

},

NewProduct()With{

.Description="Cat2-Prodotto2",

.Id=2

}

},

.Description="Categoria1",

.Id=1

},

NewCategory()With{

.Products=NewProduct(){

NewProduct()With{

.Description="Cat2-Prodotto3",

.Id=1

},

NewProduct()With{

.Description="Cat2-Prodotto4",

.Id=2

}

},

.Description="Categoria2",

.Id=2

}

}

Possiamodecideredi caricarequeste informazioni scegliendo, tra i controlli disponibili,quello che più rispecchia le funzionalità a noi necessarie poiché, indipendentemente daquelloscelto,ilmododiprocedereèautonomo.

Esistonomoltimodipercaricare idati,maquellopiùusatocercadimantenere ilpiùpossibile la separazione dell’interfaccia dal codice, evitando che quest’ultimo facciariferimenti diretti a elementi. L’oggetto “list”, definito nell’esempio 14.10, infatti, puòessere associato alla proprietà DataContext della finestra o della pagina in fase dicaricamentoiniziale,comemostratonell’esempio14.11.

Esempio14.11ProtectedOverridesSubOnNavigatedTo(ByValeAsNavigationEventArgs)

Me.DataContext=list

Page 351: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndSub

Conquesta istruzione, impostiamo la listadicategoriecomecontestodatidell’elementoradice. L’elemento stesso e quelli figli, da questo momento, possono accedere a taleoggettoeleggerneleproprietà.

Tutti gli ItemsControl, come i controlli ListView, GridView, per citarne alcuni,dispongono di una proprietà ItemsSource, che può essere valorizzata anche da codiceoppuremedianteildatabinding.Lamarkupextension{Binding}serveproprioaquesto:leggedalcontestodatiattuale.Nell’esempio14.12,carichiamocontalesintassilalistadicategorie.

Esempio14.12-XAML<ListViewItemsSource="{Binding}"

x:Name="categories">

</ListView>

Nell’esempio precedente non viene passata una specifica informazione aggiuntiva, aindicare che il motore di data binding deve caricare l’oggetto stesso, cioè la lista dicategorie. Eseguendo il codice, otteniamo la lista delle categorie, come è visibile nellafigura14.4.DasubitopossiamonotarechenonabbiamodovutopreoccuparcideitempiedellacreazionedeiListViewItem,necessariapopolarelaListView.

Figura14.4–ListViewcondatabindingapplicato.

Possiamo anche notare che l’aspetto non è quello che ci attenderemmo, dato cheotteniamo il nome completo del tipo dell’oggetto Category. Possiamo sfruttare laproprietàDisplayMemberPath, per indicare quale proprietà utilizzare per la descrizione,mailmetodopiùcompletoeaffascinanteconsistenellosfruttareiDataTemplate.

Tramitequestiultimi,inmodosimilealControlTemplate,possiamodefinirel’aspettodadareaognielementodellalistaevisualizzareleinformazionichevogliamo.Ampliamoquindiilmarkupdell’esempio14.12edefiniamounDataTemplate tra lerisorse.Inessopossiamo mettere qualsiasi elemento che desideriamo, tra cui shape, immagini o,

Page 352: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

addirittura, video.Nell’esempio14.13 ci limitiamo a porre un rettangolo a fianco delladescrizionedellacategoria.

Esempio14.13-XAML<DataTemplatex:Key="CategoryTemplate">

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinitionWidth="Auto"/>

<ColumnDefinition/>

</Grid.ColumnDefinitions>

<RectangleFill="Red"

Width="10"

Height="10"/>

<TextBlockText="{BindingPath=Description}"Grid.Column="1"/>

</Grid>

</DataTemplate>

Il termine DataTemplate sta a indicare che il template ha lo scopo di servire lavisualizzazione di dati. Sfruttando lo stesso meccanismo del DataContext, vistonell’esempio14.11, troviamoall’internodel template ilcontestodati:questoè ilsingoloelementodellalistae,nelcasodell’esempio14.13,èl’oggettoCategory.Inquestomodo,possiamo effettuare il data binding facendo riferimento alla proprietà Descriptionattraversol’attributoPathdell’espressione.Definitopoiiltemplate,nonrimanealtrocheutilizzarlo,referenziandoloattraversolaproprietàItemTemplatedellaListView.

Esempio14.14-XAML<ListViewItemsSource="{BindingPath=.}"

x:Name="categories"

ItemTemplate="{StaticResourceCategoryTemplate}">

</ListView>

Rispettoadaltriapprocci,quellooffertodaXAMLpresentainnumerevolivantaggi,datoche non ci sono limiti all’interfaccia che possiamo realizzare, rendendola dinamica, asecondadelcontestodeidati. Inoltre, ilmeccanismodidatabindingèmoltoversatileeconsenteanchescenaripiùcomplessi,doveidatielelistesonorelazionatitraloro.

Scenarimaster/detailconildatabindingIl meccanismo di data binding copre la maggior parte delle esigenze che possiamoincontrare.Traqueste lanecessitàdisupportarescenari incui laselezionesuunaprima

Page 353: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

lista,determinailcaricamentodiundettaglioodiunasecondalista,acascata.

Poniamo ora una seconda ListView che deve caricare i prodotti della categoriaselezionatasullaprimaListView.LaproprietàPathpuòcontenere,separandodalpunto,la navigazione sotto proprietà, perciò attraverso SelectedItem possiamo ottenere laCategory selezionata, e al suo interno leggere le proprietà che vogliamo. Nel casodell’esempio14.15,carichiamolalistadeiprodottinellasecondaListBox.

Esempio14.15-XAML<ListView ItemsSource="{Binding Path=SelectedItem.Products,

ElementName=categories}"

DisplayMemberPath="Description">

</ListView>

Bastanopocherighedimarkupperottenereduelistecollegatetraloro:nelselezionarelacategoria, la listadeiprodotti cambieràautomaticamente.Nell’esempiopossiamonotarechedobbiamoinoltrespecificaresuqualeoggettointerrogarelaproprietàSelectedItem:inquestocasolaprimaListViewdinomecategories(vediesempio14.12).Nellafigura14.5possiamovederesiailDataTemplateapplicatoallaprimalista,sialalistadeiprodottifunzionaleallacategoriaselezionata.

Ilmeccanismodidatabindingquidescrittononhalimitiperquantoriguardailnumerodi listeannidatechepossiamocaricare,e inquestomodocipermettedi soddisfareogninostra esigenza. Per esempio, nel DataTemplate delle categorie potremmo caricaredirettamente la lista dei prodotti, mostrandoli come un unico elemento di selezione,insieme alla categoria. Le fonti dati, come abbiamo potuto vedere, non si limitano alDataContext impostato da codice, ma possono coprire ogni esigenza. Nella prossimasezionedaremounosguardoallepossibilitàintalsenso.

Page 354: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura14.5–DueListViewcollegatemediantedatabinding.

LefontidatiperildatabindingLe espressioni di data binding affrontate nei primi esempi fanno un uso implicito delcontesto dati corrente.Nella finestra principale è il DataContext di uno degli elementimentre, nel DataTemplate è il contesto specifico del ListViewItem, come nel casodell’esempio14.13.

Inalternativa,però,possiamosfruttare,comegiàanticipato, laproprietàElementNamedell’oggettoBindingperinterrogare,sempremediantelaproprietàPath,leproprietàdiunelemento.Seabbiamounacaselladitestoeun’etichettaincuiriportareiltestoimmessodall’utente, ci basta dare un nome al primo controllo e referenziarlo nell’espressione didatabinding,comemostratonell’esempio14.16.

Esempio14.16-XAML<TextBoxx:Name="myText"/>

<TextBlockText="{BindingPath=Text,ElementName=myText}"/>

LamarkupextensionBinding,cosìcometuttelealtrediXAML,prevedediseparareogniproprietàconunavirgolaedivalorizzarlaconun’assegnazione.Nell’esempio,indichiamodicaricarelaproprietàTextdell’oggettoTextBoxdinomemyText. Inoltre,datoche taleproprietàpuòvariare(nellospecificoèunaDependencyProperty),ilmotorelaagganciaefa sì che ognimodifica che effettuiamo alla casella di testo, si rifletta automaticamentesull’etichettasottostante,comevisibilenellafigura14.6.

Page 355: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura14.6–IldatabindingmedianteElementNameinazione.

La proprietà ElementName è specifica per sorgenti di tipo elementoma, come abbiamovistonelparagrafoprecedente,nonvi sono limiti sul tipodi sorgentedati.LaproprietàSourcevieneincontroancheaquestaesigenza,consentendocidivalorizzarlaconqualsiasiistanzaetipo.

Abbiamo visto, nella sezione dedicata alle risorse, come in esse possiamo dichiararequalsiasioggetto;perquestomotivoistanziamolaclasseProductcomeabbiamogiàfattonell’esempio 14.10. Questa volta però lo facciamo da markup, come mostratonell’esempio14.17.

Esempio14.17-XAML<Pagexmlns:l="using:ASPItalia.Books.Chapter14">

<Page.Resources>

<l:Productx:Key="myProduct"

Id="1"

Description="Prodotto1"/>

</Page.Resources>

Nonc’èalcunadifferenzarispettoall’istanziarequestaclassedacodice,con l’eccezionedelfattochel’istanzavienemantenutaall’internodellerisorse.

Possiamo quindi caricare tale oggetto mediante la proprietà Source e la markupextensionStaticResource:l’esempio14.18mostracomefare.

Esempio14.18-XAML<TextBlockText="{BindingPath=Description,

Source={StaticResourcemyProduct}}"/>

Nell’esempio notiamo, prima di tutto, l’utilizzo di unamarkup extension all’interno diun’altra,cherendecomunque leggibile tutta l’espressione.Datoche lasorgentedatiè il

Page 356: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

prodotto,noncirestacheindicaredileggereladescrizioneattraversolaproprietàPath.

LaformattazionedeidatiFinora leespressionididatabindingcheabbiamoanalizzatosi sono limitateamostraresemplicementeilvaloredellaproprietàdiunoggetto.Semprenell’otticadilimitarel’usodicodiceperpersonalizzarel’interfaccia, ilmotoredidatabindingoffrelapossibilitàdiformattareivalori.

Il metodo, comune a tutti i framework basati su XAML, consiste nello sfruttare laproprietàdinomeConverter,checipermettedispecificareunconvertitoredivalori:unaclassecheimplemental’interfacciaIValueConverter.

Creareunconverterèpiuttostosemplice,datocheimembririchiestisonodue:

Convert: richiamato quando il motore vuole prendere il valore originale econvertirlonelvalorefinale;

ConvertBack:richiamatoquandoilmotoredeveriversareicambiamentieffettuatisuldestinatariodiun’espressionedibindingsullasorgentedati.

Supponiamo di voler cambiare il colore della data in funzione del fatto che il giornoattualesiapariodispari.Primadituttocreiamoilnostroconvertitore,comenell’esempio14.19.

Esempio14.19PublicClassDateToColorConverter

ImplementsIValueConverter

PublicSharedReadOnlyInstanceAsNewDateToColorConverter()

PublicFunctionConvert(valueAsObject,targetTypeAsType,parameter

As

Object,languageAsString)AsObject

DimdAsSystem.DateTime=DirectCast(value,System.DateTime)

Ifd.DayMod2=0Then

ReturnNewSolidColorBrush(Colors.Green)

Else

ReturnNewSolidColorBrush(Colors.Red)

EndIf

EndFunction

Public Function ConvertBack(value As Object, targetType As Type,

parameterAs

Object,languageAsString)AsObject

ThrowNewNotImplementedException()

Page 357: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndFunction

EndClass

L’implementazione del convertitore non fa altro che leggere il parametro value, chediamo per scontanto sia una data e, in base al giorno delmese, restituisce un pennelloverde piuttosto che rosso. Tornando al markup, non ci resta quindi che valorizzare laproprietà Foreground del testo, sempre con l’espressione Binding, indicando comeSourceladataattualementre,comeconvertitore,quellocreatonell’esempio14.20.

Esempio14.20-XAML<Page.Resources>

<l:DateToColorConverterx:Key="converter"/>

</Page.Resources>

<TextBlockText="{BindingPath=Data}"

Foreground="{BindingPath=Data,Converter={StaticResource

converter}}"/>

Il motore leggerà allora la data, la passerà al convertitore e quest’ultimo restituirà unBrush,cheverràpoiassegnatoallaproprietàForegrounddeltesto.Danotarecome,ancheper far rifermento al DateToColorConverter, dobbiamo prima di tutto istanziarlo nellerisorse.

Nellafigura14.7,poichéil22èunnumeropari,l’etichettasaràdicoloreverde.

Figura14.7–ConverterapplicatoalForegrounddiunTextBlock.

Lepossibilità offerte dal data binding non finiscono qui. Possiamo infatti gestire anchecomeilmotorelegalasorgentealcontrollochemostraleinformazioni.

LemodalitàdidatabindingFinoraabbiamoutilizzatoilmotoredidatabindingperleggereivaloriemostrarliavideo.Abbiamo già visto, però, come nell’esempio 13.20 il motore sia in grado di ripeterel’operazionedicaricamentodeidatiognivoltachelasorgentecambia.QuestoèpossibilegrazieallaproprietàMode,ilcuivaloreèautomaticoedipendedallasorgentedati,mapuò

Page 358: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

assumereiseguentivalori:

OneWay: i valori della sorgente dati vengono riversati sul destinatario e questaoperazionevieneripetutaognivoltachelasorgentecambia;

OneTime: ivaloridellasorgentevengonoriversatiunasolavolta, ignorandopoi isuccessivicambiamenti;

TwoWay:ivaloridellasorgenteedeldestinatariovengonosincronizzati,perciòognimodificaapportataaunadellepartisiriflettesull’altra.

Di particolare importanza è la modalità TwoWay che, di fatto, ci aiuta nel prepararemascheredimodificadeidati.MediantecontrollicomeTextBox,CheckBoxoComboBox,possiamo infatti permettere la modifica dei dati e, automaticamente, riversarli sullasorgentedati,senzadoverricorrereall’usodicodice.

Nell’esempio14.21utilizziamotaleproprietàperforzareildatabindingaeseguireunavoltasolal’operazionedicaricamento.

Esempio14.21-XAML<TextBlockText="{BindingPath=Text,

Mode=OneTime

ElementName=myText}"/>

Le potenzialità del data binding sono dunque innumerevoli. Purtroppo alcune sonospecifichediWPFenon trovanopostoall’internodiquestaguida.Traqueste rientra lapossibilità di effettuare data binding multipli, di dare una priorità alle espressioni, diinteragireconleinterfaccedivalidazionepresentinel.NETFrameworkefornirefeedbackvisiviincasodierrore.

Comunque,all’internodelportalewebdellacommunityWinFXItalia,troviamoarticoliescriptdimaggioreapprofondimento..

GestireglieventiGlieventisonounacaratteristicachepermettedi reagire,mediantecodice,alverificarsideicambidistato.AbbiamogiàintuitocheinXAML,diversamentecheinaltriambiti,glieventi spesso non sono necessari, perché le logiche dei controlli, il data binding e iVisualStatesonosufficientiacoprirelamaggiorpartedelleesigenze.

Inognicaso,tuttiglielementivisualihannounsetdieventibaseperogniaspettolegatoall’input da parte dell’utente. Su ogni UIElement troviamo per questo eventi comeKeyDownoKeyUp,perlagestionedellatastiera,TappedoDoubleTappedperintercettareilclick con mouse o la pressione da touch. Questi sono solo alcuni esempi dato che, inrealtà,glieventisonomolteplicieingradodifarciintercettareognidinamicadiinput.Aquestidobbiamopoiaggiungerequellispecificideicontrolli:peresempio,unpulsanteha

Page 359: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

l’eventoClick,mentreunaListViewhal’eventoSelectionChanged.

Ilmodopiùsempliceper intercettareunodiquestieventi,èdichiarare l’eventocomeattributosull’elementoespecificareilnomedelmetododachiamare.Nell’esempio14.22,possiamovederecomeintercettarel’eventoLoadedsullapagina.

Esempio14.22-XAML<Pagex:Class="Events"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

Loaded="Page_Loaded">

LafunzionePage_Loadedèpoidefinitanelcode-behind,peressererichiamatanonappenalapaginahacompletatol’operazionedicaricamento.

Esempio14.23PrivateSubPage_Loaded(senderAs[Object],eAsRoutedEventArgs)

EndSub

Glieventinonsonoperòtuttidellostessotipo;quelloLoaded,vistonell’esempio14.22,èdi tipodiretto (perciòviene invocatosolosull’elementosuicuièstatoscatenato)maneesistono anche di tipo bubble, cioè che si propagano dall’elemento che li ha generati erisalgono tutto l’albero degli elementi, fino ad arrivare a quello radice. Si prestano asoddisfare eventi come Tapped, per essere intercettati abbracciando più elementicontemporaneamente.

Con il markup dell’esempio 14.24, dove abbiamo una Grid e un Rectangle,intercettiamoalivellodipaginaedirettangolol’eventodipressione,ditipobubble.

Esempio14.24-XAML<Windowx:Class="Events"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

MouseUp="Window_MouseUp">

<GridBackground="LightGray">

<RectangleWidth="100"

Height="100"

MouseUp="Rectangle_MouseUp"

Fill="Red"/>

</Grid>

</Window>

Nel code-behinddefiniamoquindi i due eventi.Perprovare le funzionalitàdi bubbling,

Page 360: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

inibiamo i click effettuati sul rettangolo enotifichiamocon il nomedell’oggetto chehageneratol’evento.

Esempio14.25PrivateSubPage_Tapped(senderAsObject,eAsTappedRoutedEventArgs)

Dimmd=NewMessageDialog("Pulsantepremutosu"+e.OriginalSource.

[GetType]().Name)

md.ShowAsync()

EndSub

Private Sub Rectangle_Tapped(sender As Object, e As

TappedRoutedEventArgs)

e.Handled=True

EndSub

Eseguendo il codice, notiamo che l’evento Tapped della pagina viene sollevato aprescindere dall’area in cui clicchiamo, anche se non abbiamo intercettato direttamentel’evento sulla griglia o sul rettangolo. Grazie alla proprietà Handled, inoltre, quandocliccheremo sul rettangolo inibiremo la propagazione dell’evento su quello a livello difinestra.Comevediamodallafigura14.8,difatto,solocliccandosullaGridotterremoilmessaggio,mentrecliccandosulRectanglenonotterremonulla.

Figura14.8–LapropagazionedeglieventiintercettataemostrataattraversounaMessageBox.

Ilmeccanismodescrittoregolatuttalagestionedegliinputall’internodiun’applicazione,per cui la sua comprensione è molto importante. È grazie a questa caratteristica checontrolli come Button possono esporre l’evento Click, indipendentemente dal lorotemplate. In questo modo, tutti gli eventi Tapped generati dagli elementi che dannol’aspetto al pulsante, vengono intercettati in modo da fornire un unico evento cherappresentalafunzionalitàlogicadelpulsante:ilclick.

Conclusioni

Page 361: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

XAMLèunlinguaggiocherivoluzionailmododicreareapplicazioniperdesktop,tableto mobile. Introduce molti concetti nuovi ed estende il lavoro di realizzazione diun’applicazione,comprendendoancheunanuovafiguraprofessionale:quelladeldesigner.

In questo capitolo abbiamo dimostrato come, attraverso stili e template, possiamocambiare il modo di concepire i controlli e quindi l’interfaccia grafica. Possiamomodificarecompletamenteilloroaspetto,condividereinformazionitrapiùelementie,coniVisualState,fornireun’esperienzapiùricca,senzal’ausiliodicodice.

Abbiamo quindi illustrato come il motore di data binding sia capace di soddisfaremoltissime esigenze – gestisce la validazione, la conversione dei dati, la formattazione,scenari master/details in modo completamente automatizzato – il tutto utilizzando unlinguaggiodichiarativo.

Inoltre, abbiamo analizzato il sistema di eventi che sta alla base degli elementi epermetteilfunzionamentodeicontrolli.

DuecapitolinonsonosufficientipercomprendereappienotuttoquellochestadietroaXAML,mapossonobastareperaiutarviacapirnelepotenzialità.Aquestopuntononciresta che applicare quanto appreso su questo linguaggio nel mondo delle UniversalWindowsPlatformapp.

Page 362: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

15

UsareXAML:WindowsStoreapp,WPFeSilverlight

Nei due capitoli precedenti abbiamo visto come funzionaXAML, che è alla base dellerecentitecnologiedisviluppoMicrosoftperisistemioperativiclient.

Con XAML, infatti, è possibile sviluppare applicazioni per il Windows Store (perUniversalWindowsPlatformapp)eWPF.

Ciascunadiquesteimplementazionioffrecaratteristichedifferenti,cherendonoXAMLin grado di sfruttare il massimo vantaggio e offrire il meglio dei suoi vantaggi allosviluppatore.

In questo capitolo vi presentiamo una rapida panoramica di queste implementazioni,sviluppandoalcuniesempi.

ApplicazioniUniversalUniversal Windows Platform app supporta piattaforme differenti dalle classiche Intelx86/x64,poichégiraanchesuARM(icosiddettiSOC,SystemOnaChip),consentendodicreareapplicazionichepossonogiraresuitradizionalisistemidesktop,suiportatili,oltreche sui tablet, sia puri sia ibridi. Per questomotivo,Microsoft ha introdotto un nuovoruntime,denominatoWindowsRuntimeo,piùsemplicemente,WinRT.

WinRToffreunaseriedifunzionalitàcomunialleapp,comeiservizidiaccessoall’UI,alle risorse hardware, allo storage o al networking, come tradizionalmente è sempreavvenuto in Windows. Lo fa mettendo a disposizione degli sviluppatori una serie difunzionalitàdirettamentesopraalWindowsCore,cioèalcuorediWindows.

Inoltre,WinRTgestisceilsandboxingdelleapplicazioni,facendoinmodocheognunasia limitata ad accedere solo a un’area specifica di memoria e disco, migliorando lastabilità complessiva e la sicurezzadel sistema,grazie all’usodiun runtimebroker checontrolla,peresempio,chesololeAPIdichiaratedalcreatoredell’appnelmanifest(unasorta di carta d’identità che lo sviluppatore deve allegare a ogni app) venganoeffettivamenteinvocate.

Per uno sviluppatore abituato al .NET Framework, come vedremo, si tratta solo di

Page 363: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

utilizzare quello che già conosce,ma in una chiave differente, con l’aggiunta di alcunenovità specifiche introdotte dal .NET Framework 4.5. WinRT, infatti, ci consente disfruttare l’ultimaversionedel .NETFramework,conirelativi linguaggi:nelnostrocasovuoldirepoterutilizzareVBsenzalimitazionidisorta.

LeapplicazioniperWinRTsonoutilizzabilisiaconla tastierasiaconilmouse,cometradizionalmentefattosuWindows,siaattraversoiltouch.Inquestocapitolocercheremodi inquadrare meglio i tool e le metodologie necessarie a costruire applicazioni perWindows8sfruttandoWinRT.

In realtà, WinRT è basato su un’anima COM, lo stesso COM che probabilmenteabbiamo utilizzato in qualche applicazione in passato (e imparato ad amare e odiare):tuttavia, i problemimaggiori diCOM, come la gestione delle reference e il versioning,sono assorbiti in toto da WinRT, con il risultato che non dovremo mai subirne leconseguenze. I componenti, per esempio, non sono più di sistema, ma locali a ogniapplicazione.Questoèunconcettogiànotoachihadimestichezza,peresempio,con ilmeccanismodigestionedellereferencelocali,tipicodel.NETFramework.

In realtà, siamo di fronte a un’evoluzione di COM che prende molto dal .NETFramework, conun sistemadi namespace, unmodello a oggetti ben ingegnerizzato, untypesystemespandibile.

Grazieaquestaimpostazione,WinRTsupportaessenzialmentetremodellidifferentidisviluppo:

XAML,C#eVB,conil.NETFramework4.5;

HTMLeJavaScript,sfruttandoChakra,l’enginediInternetExplorer10;

XAMLeC++,perapplicazioninative.

Ciascuna di queste opzioni è identica, in termini di funzionalità accessibili allosviluppatore, a una qualsiasi delle altre: questo meccanismo risulta possibile perché lefunzionalità implementate attraverso le API di WinRT sono rese accessibili aglisviluppatoriattraversounponte,cheleadattainbasealledifferentinecessitàdeidifferentilinguaggi:questipontiprendonoilnomediprojection.

Leprojectionsonoilsistemaattraversoilqualeunodeilinguaggisupportatiproiettasestesso inWinRT. O, se vogliamo, il sistema attraverso il quale le API diWinRT sonoproiettatepersupportareillinguaggio/tecnologianellesuepeculiarità.

Leproiezioni,poi,sioccupanodiadattarelevarietipologieditipiallinguaggio.Questofa sì una collection venga rappresentata da un oggettoWinRT di tipo IVector, che inrealtàhaunmetodoAddnel .NETFramework,mausa la funzionepush seutilizzatodaJavaScript,consentendoaglisviluppatoridiadattarsimoltopiùfacilmentealframework,senzadoverrinunciareallerispettiveabitudinieconvenzioni.

In base a queste considerazioni, la preferenza nell’utilizzare una strada piuttosto cheun’altraèessenzialmentesoggettiva:andremoautilizzare la tecnologiacon laqualegiàsiamo in grado di produrre un risultato migliore, con la certezza che, tra l’altro,eventualmente è possibile mischiare le varie opzioni durante la creazione delle nostre

Page 364: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

applicazioni.

Chiaritiquestiaspetti,cosaciserveperiniziareasviluppareappperilWindowsStore?Cibastaconoscereunpo’diXAML,introdottoneiduecapitoliprecedenti,(ovviamente)VisalBasiceavereVisualStudio2015installatosuWindows8.xosuWindows10.Nelprimo caso, ovviamente, non sarà possibile testare le applicazioni sulla macchina disviluppomasolosudeviceremoti.

ItoolpersvilupparePer sviluppare applicazioni per WinRT è necessario, obbligatoriamente, dotarsi comeminimo di Windows 8.1: anche se Visual Studio 2015 è installabile su Windows 7,mancherebbeilrelativoruntime,cheèpresentesolosuWindows8.

Attraversoildownloaddeitool,sihaaccessoaunaseriedifunzionalitàchediseguitosarannoanalizzateneldettaglio.Tuttiitooloffertisonodisponibiligratuitamente.

Troviamo un riepilogo dei download all’indirizzo:http://www.winrtitalia.com/sviluppo/. I tool gratuiti, offerti all’interno di VisualStudioCommunity,presentanoalcune limitazioni rispettoalleversioniapagamento,maconsentonodi partire con lo sviluppodi app inWinRT senza grosse limitazioni.Tutti iconcettieisuggerimenticontenutiinquestolibrosonosfruttabiliancheconVisualStudioCommunity.

Per quanto riguarda lo sviluppo di UniversalWindows app, vengono aggiunti nuovitemplate di progetto, oltre a un nuovo designer. Torneremo fra poco su queste duetipologiediprogetti,analizzandoneledifferenze.

Page 365: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura15.1–IprogettiaggiuntivipercreareapplicazioniUniversalWindowsPlatformoffertiinVisualStudio2015.

Creando un nuovo progetto di tipo “Blank Project”, come è visibile nella figura 15.1,possiamonotarecome ildesignerdiVisualStudio2015sia integratoconmolticoncettimutuatidaBlendeportidiversenovitàperchièabituatoasviluppareconWPF.

Figura15.2–L’ambientespecificoperlosviluppodiUniversalWindowsPlatformapp,all’internodiVisualStudio2015.

Comeabbiamoillustrato,ilnuovodesignerdelloXAMLèmutuatodaquellodiBlend,untoolcheaffiancaVisualStudiopergestiredesign,eUX.

Visual Studio 2015 introduce quattro tipi differenti di progetti, all’interno del nodoWindowsStore:

BlankApp:èuntemplateminimo,all’internodelqualevieneaggiuntosoloquellocheèstrettamentenecessario;

ClassLibrary:consentedicreareuncomponentesottoformadiclasslibrary;

Windows Runtime Component: per creare componenti che possano essereriutilizzatiinWinRT,aprescinderedallinguaggio;

UnitTestLibrary:consentedicreareunprogettoadhocperfareUnitTestinginapplicazioniperWindows8.

L’uso di ciascuna di queste tipologie di template di progetto va a coprire esigenzeparticolari. Tuttavia, al contrario di quanto succedeva con Windows 8.x, non esistonotemplate per la configurazione iniziale di un’applicazione.Sono stati rimossi i templateper le Grid App e Split App, in virtù del nuovo modello a layout responsivo delleapplicazioniWindows10.

Page 366: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Rispettoalpassato,ilnumeroditemplatesièridotto,Percompensarequestaperditaèstato creato un nuovo progetto su GitHub, denominato Template 10(https://github.com/Windows-XAML/Template10). Questo progetto affronta leproblematichericorrentinellosvilupponelleUniversalWindowsPlatformapp,spaziandodalmodellodilayoutfinoadaffrontaretematichecomeilMVVM.Questeproblematichesonoaffrontateinmodopiùaderenteaipatterncheinpassato;inoltreilprogetto,essendoospitato su GitHub, beneficia di uno sviluppo continuo e costante, che garantiscemiglioramenticontinui.

LaprimaappperilWindowsStoreAggiungiamo una nuova soluzione, in cui andremo a creare la nostra prima app.Dopoaver scelto il linguaggio (ViB nel nostro caso) vedremo apparire una serie di file chevarianoasecondadeltipoditemplatescelto.

Partiamo, per semplicità, con il Blank. Per mandare in esecuzione l’applicazione, cibasteràpremereF5,comesiamogiàabituatiafare.Quellocheavvienedietrolequinteèche la nostra app viene compilata all’interno di un package, che prende l’estensione.appx.

Questoèunconcettogiànoto,seabbiamodimestichezzaconWindows8.xoWindowsPhone Runtime: di fatto, questi package sono degli archivi compressi, con estensionecustom,alcui interno,unavoltascompattati, troveremoilcontenutoveroeproprio.Nelcaso di un .appx, oltre alla nostra app compilata, troveremo anche un insieme diinformazioni,tracuiunmanifest,all’internodelqualel’appdichiaralecapabilities,cioèlecaratteristichechesupporta.

La gestione delle capabilities è essenziale ed è contenuta in un file XML, chiamatoPackage.appxmanifest, che può essere anche aperto da Visual Studio con un editorvisuale,chepossiamovederenellafigura15.3.

È attraverso questo tool che possiamo specificare le informazioni relative al titolodell’app,allesuelivetile(wideenormali)e,tralealtrecose,alleiconevisualizzateconlenotifichepush.

Dato che non tutti i computer di sviluppo saranno dotati di monitor ruotabilinell’immediato,VisualStudiointegrauntoolper testarequestiaspetti.Quest’ultimo, tral’altro, è molto interessante a prescindere da questa funzionalità, perché consente diemulareancherisoluzionidifferenti,simularelaposizionegeografica,simulareiltouchecatturarescreenshot.

Page 367: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura15.3–VisualStudio2015ciconsentedigestireleinformazionidelmanifestdell’applicazioneinmanieravisuale.

Nellafigura15.4possiamovederecomel’apppossaesseretestataaunarisoluzionemoltoelevata(27’’–2560x1440)inportrait,senzaperquestoaverbisognodiunhardwarechesiaeffettivamentedotatodiquestecaratteristiche.

Page 368: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura15.4–IlSimulatorsimularisoluzionidifferenti,ruotaildevice,gestiscelageolocalizzazioneesimulailtouch.

AvviandociperlaprimavoltaallascritturadiapplicazioniperWinRT,potremmorimanerespiazzatidallasuacaratteristicatipicadieseguiretutteleoperazioniinmanieraasincrona,comegiàanticipatonell’introduzione,all’iniziodiquestocapitolo.Nell’ideadiMicrosoft,tutte le applicazioni devono essere fast and fluid, cioè veloci e fluide: inevitabilmente,questositraduceinunaseriedibestpracticechelosviluppatoredeveseguire.

Lasceltadell’asincronoèdettatadaunaragioneprecisa:c’èunsolothreadchehaunacoda delle operazioni da compiere sulla UI, per cui, ogni volta che viene richiestal’esecuzionediun’operazione,ènecessarioattenderechelealtresianostatecompletate.Intutto questo, se le chiamate non fossero asincrone, il thread principale resterebbebloccato. Per capirci meglio, in uno scenario del genere, anche il semplice clic su unbottoneinibirebbequalsiasialtraoperazionecome,peresempio,un’animazione,perchéilflussosarebbeinevitabilmentelegatoalcompletamentodelcodicenell’eventhandler.

Sfruttando ilmodello asincrono, invece,WinRTè in gradodi non rallentare in alcunmodo l’applicazione e, al tempo stesso, di eseguire più operazioni in parallelo. Èpossibile, infatti, avere più thread, che vengono utilizzati in maniera automatica perrendereleoperazioniilpiùfluidepossibile,benchéquellolegatoalrenderingdell’UIrestisoltantouno.

WinRTèmulti-threading,contuttiivantaggichequestocomportainquegliscenariin

Page 369: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

cuiènecessarioeseguirepiùoperazioniincontemporaneacome,peresempio,nelcasodianimazionimoltocomplesse.Il.NETFramework4.5introducedeicostruttiadhoc,chesibasano (ed estendono) sulla Task Parallel Library (TPL), già introdotta con il .NETFramework4.0equirivistaperessere integratadirettamente inVisualStudio2015.PerunatrattazionedellaTPLvirimandiamoalcapitolo8.

Tuttoquesto si traduce,pernoi sviluppatori, nelpoter scrivere il codicedell’esempio15.1.

Esempio15.1PrivateAsyncSubMyMethod()

Dimresults=AwaitGetDataAsync()

'altrocodice…

Ifresults.Count>0Then

EndIf

EndSub

Comesipuònotaredaquestoesempio,grazieall’usodiasync/await, ilcodicediventamoltopiùsempliceeleggibile,purmantenendolasuaasincronicità:pernoisviluppatorièundoppiovantaggio,perchéabbiamocodicesemplificatoeapplicazionichenonbloccanol’UI.

Supponiamodivolercaricaredelleinformazionidaremoto,daunfeedRSS.Cibasteràscrivereuncodicecomequellodell’esempio15.2,avendocuradisalvareleinformazioniall’internodiunaObservableCollection.

Esempio15.2Private Function GetDataAsync() As Task(Of ObservableCollection(Of

SampleDataItem))

DimclientAsNewSyndicationClient()

DimfeedUriAsNewUri("http://feed.aspitalia.com/feed.xml")

Dimfeed=Awaitclient.RetrieveFeedAsync(feedUri)

DimfeedItems=feed.Items.OrderByDescending(Function(x)

x.PublishedDate).Take(10)

Dimgroup=NewSampleDataGroup("ID","ASPItalia.com","","",

"")

Dimitems=NewObservableCollection(OfSampleDataItem)()

ForEachitemAsvarInfeedItems

items.Add(NewSampleDataItem(item.Id,System.Net.WebUtility.

HtmlDecode(item.Title.Text),"",Nothing,"","",group))

Next

Page 370: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Returnitems

EndFunction

Comesipuòapprezzare,èsufficienterestituireiltipogenericoutilizzatodaTask<T>,nelnostrocasounacollectiongestitaattraversoObservableCollection<T>.Dietrolequintevieneeseguito il taskequindi,nellachiamatadell’esempio15.2,avremodirettamente iltipo generico, cioè la nostra collection. In più, il binding di XAML ci semplifica tuttiquesti aspetti, poichémostrerà in automatico gli elementi,manmano che li andiamo ainserire. Per ottenere l’ui della figura 15.5, abbiamo utilizzato un ListView, andando amettereinbindinglenostreinformazioni.IlrisultatoècheilcontrolloListViewmostrerài nostri dati con i template predefiniti, su cui possiamo apportare personalizzazioni. Ilrisultatoèvisibilenellafigura15.5,nellaqualeabbiamocreatounsempliceDataTemplatecompostodauncontrolloImageeuntemplatenelqualeandiamoacaricaredirettamenteunfeed,mostrandoneidati.

Figura15.5–Ilrisultatodellanostrasempliceappchemostraifeed.

Aquestopunto,dopoavercaricatoilfeed,dobbiamogestireilclicksulsingoloelemento.L’esempio15.3mostracomeabbiamofatto.

Esempio15.3-XAML<GridView

x:Name="itemGridView"

AutomationProperties.AutomationId="ItemsGridView"

AutomationProperties.Name="Items"

TabIndex="1"

Grid.RowSpan="2"

Page 371: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Padding="116,136,116,46"

ItemsSource="{BindingSource={StaticResourceitemsViewSource}}"

ItemTemplate="{StaticResourceStandard250x250ItemTemplate}"

SelectionMode="None"

IsSwipeEnabled="false"

IsItemClickEnabled="True"

ItemClick="ItemView_ItemClick"/>

<ListView

x:Name="itemListView"

AutomationProperties.AutomationId="ItemsListView"

AutomationProperties.Name="Items"

TabIndex="1"

Grid.Row="1"

Visibility="Collapsed"

Margin="0,-10,0,0"

Padding="10,0,0,60"

ItemsSource="{BindingSource={StaticResourceitemsViewSource}}"

ItemTemplate="{StaticResourceStandard80ItemTemplate}"

SelectionMode="None"

IsSwipeEnabled="false"

IsItemClickEnabled="True"

ItemClick="ItemView_ItemClick"/>

Esempio15.3-VBPrivate Sub ItemView_ItemClick(sender As Object, e As

ItemClickEventArgs)

DimurlAsString=DirectCast(e.ClickedItem,MyData).Id

Me.Frame.Navigate(GetType(DetailsPage),url)

EndSub

La pagina su cui andremo a navigare mostrerà un controllo WebView, che presenteràl’URLall’internodiunbrowser:ilrelativocodiceèdisponibilecongliesempidellibro.

QuantoabbiamodettofinoinquestomomentovalesiachelanostraapplicazionesitroviaessereeseguitasulDesktopsiasudispositivimobile,comeTabletesmartphone.

Inquest’ultimocaso,però,dobbiamoprestareattenzioneadalcunidettagli,come,peresempio,lagestionedeltastoback.

Windows10uniformaanchequestoaspetto.Adessoleapplicazionieseguite inTabletModeoffronountastobackdisistema,simileaquantogiàavvenivainWindowsPhone.

Page 372: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

La gestione è molto semplice e adotta il classico paradigma GetForCurrentView.Utilizzando quindi la classe statica SystemNavigationManager, possiamo richiamare ilmetodo GetForCurrentView e recuperare così l’oggetto SystemNavigationManager sulqualepossiamosottoscriverel’eventoBackRequested,comevienemostratonell’esempio15.4.

Esempio15.4PublicSubNew()

Me.InitializeComponent()

DimnavigationManager=Windows.UI.Core.SystemNavigationManager.

GetForCurrentView()

navigationManager.BackRequested+=NavigationManager_BackRequested

EndSub

Inquestomodoèsemplicissimocostruireunapplicazioneche,grazieallayoutfluidochelenuoveUniversalWindowsAppmettonoadisposizione,siadattiallevarie risoluzionidisponibilinonchéaivaritipididevice.

Costruire applicazioni per WinRT richiede una conoscenza approfondita dellapiattaforma:inquestepochepagineabbiamosolovistoquanto,conoscendoXAMLeVB,diventifacile,divertenteevelocecostruiresempliciapp.Mapermuoversiinscenaripiùcomplessiènecessarioapprofondireinmanieraspecifical’argomento.Perquestomotivo,vi consigliamo il libro “Sviluppare applicazioni perWindows8 conXAML,C# eVB”edito da Hoepli, che potete facilmente trovare sul portale della Libreria Hoepli,all’indirizzo:www.hoepli.it.

Adesso che, con l’analisi delle caratteristiche dello XAML abbiamo introdotto leapplicazioni per Universal, possiamo procedere rapidamente ad analizzare quanto siapossibilefareconXAMLeWPF.

ApplicazionidesktopconWindowsPresentationFoundationDalmomentocheabbiamoanalizzato leWindowsStoreappe leapplicazioniWindowsPhone, è giunta l’ora di affrontare un’altra tipologia di applicazioni che possiamorealizzare,sempresfruttandoXAML:leapplicazionidesktop.Inrealtà,questatipologiaèstatalaprimaadadottarequestolinguaggioperladefinizionedellayout,permettendopoil’evolversi di tutte le altre piattaforme. Il framework di riferimento per le applicazionidesktop è Windows Presentation Foundation (WPF) ed è stato introdotto con il .NETFramework3.0,giànel2006.Èun’alternativaalleWinForme,ingenerale,atuttequelletecnologiechesfruttanoWin32(leAPInativediWindows)perlosviluppodell’interfacciadesktop.

Page 373: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Rappresentaquindiunasvoltamoltoimportanterispettoalpassato,perchéportaconséunadifferenzafondamentale:inWin32ogniframeworkcheutilizziamononèaltrocheunwrapperversoleAPInative,lequalidisegnanol’interfacciaconipregieilimitidiAPIinC,cheportanoconsépiùdidieciannidievoluzione.Questofasìche,indipendentementedallinguaggioutilizzato,leapplicazioniabbianotuttelostessostilegraficoeaderiscanoaltemadelsistema.ConWPF,invece,Win32èmessocompletamentedaparteesostituitoconDirect3Dcomeenginegrafico.Questopermettedicreareunnuovomodellodilayoutda sfruttare con XAML, per la generazione di un’interfaccia che viene renderizzata avideo inmodoaccelerato, tramiteGPU,consentendocidiutilizzare anche strumentipiùavanzati,qualitrasformazioni,effettie3D.

Creare un’applicazione WPF è piuttosto semplice, come del resto lo è per le altretipologie, enon richiedenessun toolaggiuntivo,perchégià supportatodaVisualStudio2012.Nellacreazionediunnuovoprogetto,troviamolerelativevociconilprefissoWPFall’internodelmenuWindows,comevienemostratonellafigura15.6.

Figura15.6–CreazionediunnuovoprogettoWPF.

È importante non confondere tali voci conWindows FormsApplication, poiché questeultimerappresentano ilvecchiomodellodi sviluppo,basatosuWin32.Un’altraopzionerilevanteèlaversionedel.NETFramework,visibilesemprenellafigura15.11,nellapartesuperiore.ContrariamentealleWindowsStoreappoaWindowsPhone,doveabbiamoadisposizione solo un subset, in WPF disponiamo dell’intero .NET Framework 4.5.Possiamo quindi utilizzare i componenti tipici degli ambienti server oppureADO.NET,creare servizi distribuiti o sfruttare COM. Il mondo desktop, inoltre, non pone limiti:

Page 374: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

possiamoeseguirecodiceinbackground,accedereaqualsiasifileocartella,interagirecontuttol’ecosistemaWin32esfruttarealmassimotuttelecaratteristichedellamacchina.Percontro,questomondoèmaggiormentesoggettoaproblemidisicurezzaedèdisponibilesolosuWindows,quindisupiattaformex86ex64.

CreazionediunprogettoPartendo dalla figura 15.11, nella quale selezioniamo la voce WPF Application,proseguiamocreandoilprogetto.Quellocheritroviamoèunapprocciodeltuttosimileaquantogiàvistoperlealtretipologiediapplicazioni.IlfileApplication.xamlrappresental’entry point dell’applicazione, nel quale posizionare le risorse e dove viene indicata lavistainizialedacaricare,comeèpossibilenotarenell’esempio15.5.

Esempio15.5-XAML<Applicationx:Class="Application"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

StartupUri="MainWindow.xaml">

<Application.Resources>

</Application.Resources>

</Application>

L’attributoStartupUri indica la finestradaavviareal lanciodell’applicazione.Essendoun’applicazionedesktop,nondisponiamodipaginemadi finestre,chepossiamogestirecome vogliamo. Il template predefinito crea per noi una MainWindow, con i consuetipatternXAMLe codice.Di conseguenza, l’elemento radicedel fileMainWindow.xaml èWindow,maalsuointernotrovanospazioinormalielementiecontrollicheaccomunanotutteletipologiedellevarieapplicazioni.Nell’esempio15.6possiamovedereunpulsanteinseritoalcentrodellafinestra.

Esempio15.6-XAML<Windowx:Class="MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="MainWindow"

Height="350"

Width="525">

<Grid>

<ButtonHorizontalAlignment="Center"

Page 375: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

VerticalAlignment="Center"

Content="Pulsante"/>

</Grid>

</Window>

AquestopuntopossiamoavviareilprogettopremendoF5eotterremolafinestravisibilenellafigura15.7.

Figura15.7–UnasempliceapplicazionedesktopinWPF.

Come possiamo notare, è una finestra desktop che possiamo ingrandire,minimizzare oridimensionareapiacimento.Ilpulsante,inoltre,disponedelloskindisistema(inquestocasoWindows8),poichéWPFdisponedimolteplicistilietemplategiàpreconfezionati,chevengonosceltiasecondadelsistemaoperativoedeltemascelto.Difatto,quindi,nonusiamoilrenderingdiWin32,comegiàanticipato,maemuliamol’interfacciadelsistemaconl’enginediWPF.

La cromatura della finestra è l’unico fra gli elementi appartenenti aWin32 che nonpossiamo personalizzare a piacimento con stili e template,ma solo tramite le proprietàmesse a disposizione dal sistema. Le finestre, quindi, sono la spina dorsale delleapplicazioniWPFedunquemeritanounapprofondimento.

GestirelefinestreLafinestraèquelcomponentesulqualepossiamoagiresoloattraversoproprietàchepoiagiscono sul sistema operativo, e la sua cromatura non può essere personalizzata.Possiamo cambiarne però le caratteristiche tipiche, quali l’icona, il titolo e altreinformazioni sul dimensionamento della finestra. Nell’esempio 15.7 possiamo vederedefinitetuttequesteproprietàprincipali.

Esempio15.7-XAML<Windowx:Class="MainWindow"

Page 376: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Height="350"

Width="525"

Icon="icon.png"

Title="MainWindow"

ResizeMode="CanResize"

ShowInTaskbar="True"

WindowStartupLocation="CenterScreen"

WindowState="Maximized">

Molteproprietàhannounnomeautoesplicativoepossiamofacilmenteintuirecosafanno.Altre, invece, come ResizeMode servono per scegliere se dare la possibilità diridimensionare la finestra; WindowsState definisce se avviare massimizzata la finestra;WindowsStartupLocation permette di indicare se avviare la finestra al centro delloschermo.Infine,ShowInTaskbar(normalmentegiàatrue),permettedimostrare–odinonfarlo – la finestra nella taskbar di sistema, la quale consente all’utente di passare daun’applicazione a un’altra o di visualizzare un’anteprima della finestra, come è visibilenellafigura15.8.

Figura15.8–Taskbarconl’anteprimadellafinestra.

Ingeneresirendevisibilesololafinestraprincipaleesinascondonotuttelefinestrefiglie.Una caratteristica delmondodesktop, infatti, è quella di gestire l’esperienza dell’utenteattraversoaltrefinestre,ingeneremodali.

Un’altraproprietàmoltointeressanteèWindowsStyle,chepermettediscegliereiltipodi cromatura della finestra. Tra i valori più interessanti può assumere ToolWindow, cherende più adatta la finestra a essere un pannello di strumenti agganciato alla finestraprincipale, oppure None, che nasconde l’intera cromatura, permettendoci di creare

Page 377: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

un’esperienzainteramenteinXAML,ancheaschermopieno.

Sebbene all’interno della finestra possiamo utilizzare tutti i pannelli e i controlli delmondoXAML,èspessoutiledividerelogicamentel’esperienzadell’utente,portandolasufinestredifferenti,daapriresoloquandorisultinecessario.Unnuovocliente,ildettagliodiunordineouna sceltaobbligatoriaper l’utente sonoalcuniesempiche trovano rispostanella creazione di una nuova finestra. Per farlo dobbiamo innanzitutto aggiungere unaWindow al nostro progetto. La voceAdd Window sotto ilmenu Project ci permette difarlo facilmente e avere un nuovoXAML da riempire, che per l’occasione chiamiamoChildWindow.Comesuggeritoinprecedenza,impostiamoShowTaskbarafalsee,comesifa generalmente, diamo una dimensione fissa e non ridimensionabile alla finestra. Aquesto punto possiamo creare la finestra e mostrarla quando necessario, per esempiopremendosulpulsantecreatoinprecedenzanellafinestraprincipale.Sfruttandoildesignerpossiamoeffettuareundoppioclickconilmousesulpulsante,perottenerelatocodicelagestionedell’eventoClickdelButton,cosìcomeabbiamoillustratonelcapitolo14.

Permostrarelafinestradobbiamoinnanzituttoistanziarelaclassechelafinestrastessarappresenta.Questocipermette, tramite costruttore,dipassareparametri e informazioniutiliallafinestracheandiamoadaprire.Unavoltaottenutal’istanza,possiamooptareperduemetodi:ShowoShowDialog.Ilprimomostralafinestraepermetteall’utentedipassareda una finestra all’altra, mentre il secondo mostra la finestra modale, cioè impedisceall’utente di interagire con altre finestre dell’applicazione, finché la prima finestra nonvienechiusa.Nell’esempio15.8utilizziamounafinestramodale.

Esempio15.8PublicClassMainWindow

PrivateSubButton_Click(senderAsObject,eAsRoutedEventArgs)

'Creol'istanza

DimchildAsNewChildWindow()

'Finestramodale

DimrAsBoolean=child.ShowDialog()

EndSub

EndClass

Un’altra caratteristica delmetodo ShowDialog, è il fatto che non ritorna fino a quandol’utentenonhachiusolafinestra.Quindiilcodicesuccessivo,definitodopolachiamataaShowDialog, viene eseguito solo dopo la chiusura, di cui facoltativamente possiamoconoscere l’esito. Nell’esempio, la variabile booleana r ci permette di conoscere se lafinestra è stata chiusa premendo x sulla cromatura o se, dal punto di vista logico dellafinestra,èstatachiusaperchéleoperazionisisonoconcluse.

Perdareesitopositivo,invece,dobbiamomodificarelaChildWindoweposizionareunbottoneOKoChiudichealClickvalorizzilaproprietàDialogResultdellafinestra,comepossiamovederenell’esempio15.9.

Page 378: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio15.9PublicClassChildWindow

PrivateSubOK_Click(senderAsObject,eAsRoutedEventArgs)

Me.DialogResult=True

EndSub

EndClass

La valorizzazione della proprietà scatena anche la chiusura della relativa finestra,permettendo a chi l’ha aperta, di leggere il valore. Consideriamo inoltre che, poiché lafinestraèrappresentatadaunaclasse,sudiessapossiamoporreproprietàcheespongonoulteriorivalori,daleggerepoidall’esterno,unavoltachiusalafinestra.

L’uso delle finestre, sebbene sia dominante nelle applicazioni desktop, non è l’unicoapprocciochepossiamosfruttareconWPF,maabbiamocomunqueun’alternativa.

LebrowserapplicationQuanto visto finora ha come risultato la compilazione di un applicativo exe, che vienelanciatocomeprocessoall’internodiWindowsesfruttailmeccanismoafinestretipicodelmondodesktop.Incontrapposizioneaquestotipodiesperienza,WPFpermetteanchelarealizzazionediapplicazionichepossonovivereall’internodelbrowser,purrichiedendol’intero .NET Framework. Non dobbiamo farci ingannare: non ha nulla a che fare conl’HTML e tutto questo funziona solo su Windows. Questo tipo di applicazione è dasceglieresevogliamodareesperienzepiùsimilialWeb,basatesupagineelapossibilitàdiandareavantieindietro,cosìcomefacciamoquandonavighiamo.

Percrearequestotipodiapplicazionedobbiamoricorrere,comepossiamovederenellafigura15.11,allaWPFBrowserApplication.Quellocheotteniamoèunprogettodeltuttosimile a quanto visto in precedenza. La differenza risiede nel file Page1.xaml arappresentarelaprimapaginadavisualizzarequandoapriamol’applicazione.Netroviamounestrattonell’esempio15.10.

Esempio15.10<Pagex:Class="Page1"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="Page1">

<Grid>

</Grid>

</Page>

A questo punto proviamo a posizionare il medesimo pulsante dell’esempio 15.12 e ad

Page 379: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

avviarel’applicazioneconF5.Otteniamol’aperturadelbrowserelavisualizzazionedellapagina,comepossiamovederenellafigura15.9.

Possiamonotarecomelabarradegli indirizzipuntiaunfileconestensione.xbap.Sitrattadiun fileXMLchedescrive labrowserapplicationecontiene le informazioni sulfile .exe. Quello che produce la compilazione di Visual Studio 2012, è sempre uneseguibileconlerelativeDLL.Ilfile.xbap,però,cipermettedicaricareiltuttosuunsitointernet, permettendo a chiunque di usare l’applicazione. Se gli utenti dispongono del.NET Framework 4.5 e utilizzano un browser compatibile, un componente di nomeClickOncescaricaoaggiornal’eseguibilecontutteledipendenzeeloavviaall’internodelbrowser.

Figura15.9–LanostraprimaWPFBrowserApplication.

Possiamoquindiintuireche,sebbeneilframeworksialostesso,gliscopisonodifferenti.Oltre a questo, anche se abbiamo a disposizione tutte le API del .NET Framework, dialcune di queste è vietato l’uso. Per esempio, non possiamo aprire finestre o scrivereliberamentesufileocartelle,maperquantoriguardaloXAMLnonabbiamolimiti.Datoche non possiamo aprire finestre, le pagine sono l’alternativa obbligatoria. Sempre nelmenuProjecttroviamolavoceAddPage,laqualecreaunasecondapaginanellostessomodo di quanto visto nell’esempio 15.9. A questo punto, per navigare da una paginaall’altraquandopremiamosulpulsante,dobbiamousareilmetodoNavigate,comevienemostratonell’esempio15.11.

Esempio15.11ClassPage1

PrivateSubButton_Click_1(senderAsObject,eAsRoutedEventArgs)

Me.NavigationService.Navigate(NewUri("Page2.xaml",UriKind.

Relative))

EndSub

EndClass

Losviluppo,quindi,nonsidiscostadimoltodaquelloafinestre,equellochecambiaèsolol’esperienzachevogliamooffrireainostriutenti.

Page 380: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ConclusioniIn questo capitolo abbiamo analizzato le caratteristiche principali delle tipologie diapplicazione e dei relativi framework che si basano sulloXAMLper la definizione dellayout.Nellospecifico,abbiamovistocomeiniziarenellosviluppoperilWindowsStore,WindowsPhoneeWPF,soffermandocisulledifferenzetraunatipologiael’altra.Sebbenel’approccio a pagine sia utilizzabile su tutte le piattaforme, vi sono alcune piccoledifferenzelegateall’ambienteincuiquestedevonovivere.

Tutto ciò è stato solo un assaggio di queste applicazioni, poichémeritanomolto piùspazio, ma pensiamo sia stato sufficiente per permetterci di capire quale strumentoscegliere, a seconda dell’obiettivo che vogliamo raggiungere. Sicuramente imparareXAMLpremiaperlapossibilitàdiriutilizzodelmarkup,dellayoutedelleconoscenzechepossiamosfruttareagevolmentesupiùpiattaforme.

Avendochiaritoquestoaspetto,noncirestacheabbandonarelosviluppoclientsideperdedicarcialWeb, inquantonelprossimocapitoloparleremodiASP.NETedellenovitàintrodottenell’ultimaversionedaASP.NETWebFormseMVC.

Page 381: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

16

ApplicazioniwebconASP.NET

NeicapitoliprecedentiabbiamoiniziatoacapirecomeVisualBasicpossaessereapplicatocon profitto allo sviluppo di applicazioni perWindows, nel caso specifico, utilizzandoXAML.NelcorsodiquestocapitolotratteremoinvecelosviluppodiapplicazionibasatesuASP.NET,dandounrapidosguardoadalcunedellenovitàintrodottenellaversione4.6.

ASP.NET rappresenta una delle tecnologie più utilizzate all’interno del .NETFrameworkedèallabasedellagrandediffusionediquest’ultimo.Consentedicreare,conun paradigma molto semplice, applicazioni di qualsiasi tipo: combinando bene glistrumenti offerti da .NET Framework, Visual Basic e Visual Studio, è possibile creareapplicazioni di tutte le qualità e dimensioni, da quelle più semplici, fino alle classicheapplicazionienterprise.

Essendodi fattodestinatoa rappresentare la sola interfacciagrafica,ASP.NETsfruttamoltedelletecnologieall’internodel.NETFramework,oltreovviamenteaVisualBasicinquantolinguaggio.Cominciamodaunaprima,rapidaanalisidiquellocheciconsentedifare,perpoisoffermarcisualcunefralenovitàdell’ultimaversione.

LaprimapaginaASP.NETQualora fossimo totalmente digiuni di ASP.NET, è utile sottolinearne alcunecaratteristiche peculiari. Prima di tutto, ASP.NET supporta due modalità per crearel’interfacciautente:

ASP.NETWebForms: è il modello classico, dove ogni pagina viene chiamataWebForms;

ASP.NETMVC:giuntoallaversione5(econla6previstaalrilascionelcorsodelprimo trimestre del 2016), è l’implementazione del patternMVC (Model-View-Controller)perapplicazioniASP.NET.

Generalmente, ilmodellomaggiormenteutilizzatoèWebForms,cheoffreunapprocciobasatosucontrolliedeventi,moltosimileaquantopossibilenellosviluppoRAD(RapidApplication Development) con le Windows application. Viceversa, ASP.NET MVCconsenteuncontrollomaggioreinfasedidefinizionedelmarkupegarantisce,soprattutto,la possibilità di testare il codice.Sequesto aspetto dovesse risultare cruciale,ASP.NETMVC è in grado di garantire questa caratteristica. All’interno di questo capitolo vi

Page 382: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

proponiamounavelocetrattazionedientrambi.

CreareunprogettoASP.NETPercrearelaprimapaginabasatasuWebForms,possiamoselezionare,dall’appositavoceall’interno di Visual Studio, un nuovo sito web. È possibile creare un sito web senzaprogetto,oppureunprogettoditipositoweb.Inbaseaquestascelta,cambiailmodellodicompilazione e di distribuzione. Nella figura 16.1 è riportata la schermatamostrata daVisual Studio in fase di creazione di un nuovo progetto. Dopo aver scelto ASP.NET,dovremoscegliereWebFormsdallamascherasuccessiva.

Figura16.1–LepossibiliscelteinfasedicreazionediunprogettoconVisualStudio.

Nel caso optassimo per il sito web, per mettere in produzione il sito sarà necessariocopiare tutti file all’internodelpercorso. In tal caso, èpossibile fareunamodifica aunsingolo file senza necessità di caricare l’intera applicazione, ma applicando le solemodifiche.

Ilprogettoweb,viceversa,habisognodiunacompilazioneperognimodificachevienefatta.Infasedideployment(cioèdimessainproduzione),sarànecessariocopiaretutti ifile, con l’esclusione di quelli che hanno estensione .cs, il cui contenuto è compilatoautomaticamente.

Page 383: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Inentrambiicasi,ladirectory/bin/,postasottolarootdell’applicazione,contienetuttigli assembly che sono utilizzati all’interno dell’applicazione. Nel caso del sito web,vengono poi utilizzati altri tipi di risorse particolari, contenuti nelle directory riportatenellatabella16.1.

Tabella16.1–LedirectoryspecialidiASP.NET.Directory Descrizione

/bin/ ContienegliassemblygeneratiattraversoVisualStudiooppurecontenentioggettiditerzeparti.

/App_Code/ È una directory pensata permemorizzare classi in formato sorgente, da compilare al volo insiemeall’applicazione.Supportaunsololinguaggiopervolta.

/App_Data/Può contenere file di appoggio, come “txt” o “XML”, piuttosto che file di databaseAccess oSQLServer Express. È, più in generale, una directory pensata per contenere file, che sono protetti daldownloadmachesipossonosfruttarenellepagine.

/App_Themes/ Includeifilelegatiaitemi,funzionalitàintrodottainASP.NETapartiredallaversione2.0.

/App_WebReferences/ Includeifilegeneratiperl’utilizzodellereferencediwebservice.

/App_LocalResource/ Contieneifiledirisorse,spessoutilizzatiperlalocalizzazione,malocaliallesingolepagineweb.

/App_GlobalResource/ Èilcontenitoredellerisorseglobali,cuihannoaccessotuttelecomponentidell’applicazione.

Tantochesiscelgadiutilizzareilsitoweb,quantodiusareilprogettoweb,lacreazionedellepagineall’internononsubisceparticolaricomplicazioni.Allafine,ilprogettowebèpreferito all’interno dello sviluppo in team e per applicazioni di cui si voglia gestire inmanierapiùrigorosailciclodisviluppo.

Per utilizzare ASP.NET 4.6, è sufficiente accedere alle proprietà del progetto (o delsito),allavoceBuildequindiaTargetFramework,specificandolaversione4.6.Questaazioneci consentedimigrare inuncolpo soloeventuali applicazioni esistentibasate suversioniprecedentiWebForms.

SviluppareconWebFormsLepagineASP.NETsonospessochiamateWebForm,perchéall’internodiquesteultimeèpresente un tag form particolare, con l’attributo runat impostato sul valore “server”.Questacaratteristica,applicataaiframmentidicodiceHTML,lirendecontrolliserver.Icontrolliserversonoistanzediclassicheproduconounmarkupesonoingradodifornireuncomportamento.

LasemplicepaginaASP.NETècontraddistintadall’estensione.aspxedègeneralmentesuddivisainalmenodueparti,unadenominatamarkupel’altracodice.Spessoilcodiceècontenuto, per questioni di separazione logica, all’interno di un file separato, che perconvenzione ha estensione.aspx.cs. In base al tipo di progetto prescelto, come vienespiegato nella parte precedente, il file con il sorgente può essere modificato senzanecessità di compilazione. La classe da cui tutte le pagine derivano èSystem.Web.UI.Page:questogarantiscechetuttesicomportinoallostessomodo.

Generalmente,ilmarkupècompostosiadaframmentidiHTMLsiadaservercontrol.Questi ultimi si riconoscono a colpo d’occhio, perché generalmente sono nella formariportatanell’esempio16.1.

Page 384: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio16.1<asp:TextBoxid="FirstName"runat="server"/>

Lasintassiparticolarechecontraddistingue icontrollièdi tipoXML,quindi il tagdeveesserewellformed,cioèbenformato.Ilprefisso“asp:”è,ingenere,riservatoaicontrollidisponibiliall’internodiASP.NET,mentreilsuffissoèilnomeveroepropriodellaclasseche sarà istanziata. I controlli che sonodotati di questo prefisso vengono chiamatiwebcontrol.

Resta possibile aggiungere l’attributo runat="server" a qualsiasi frammento diHTML: in questo caso si parla diHTMLControl. Questi ultimi hanno un modello aoggetti che ricalca quello dei tag dell’HTML a cui si riferiscono,mentre iweb controlhannodallaloroparteunmodelloaoggetticherendecontrollimoltodiversinelmarkupma,inrealtà,moltosimilinelmodelloaoggetti.Questorappresentaunvantaggio,perchérende più facile un loro eventuale interscambio: per impostare il testo, per esempio,useremo la proprietà Text, per impostare un URL di navigazione quella NavigateUrl.Questoportaasemplificarel’approccioinfasedicreazione.

HTMLeiwebcontrolpossonoessereapprofonditisuhttp://aspit.co/agwehttp://aspit.co/agx.

Tanto gliHTMLquanto iweb control producono alla fine codiceHTML,ma lo fannograzieauncomponenteparticolare,chesichiamapageparser.Questocomponenteèingrado di garantire che noi possiamo scrivere il markup nella maniera classicama che,contestualmente,aruntimeiframmentivengonoautomaticamentetradottiincodice.Anoiresta il vantaggio di poter scrivere l’interfaccia in maniera semplice e veloce, con ilrisultato di poter programmare i controlli posizionati nella pagina, impostandone leproprietàe,soprattutto,potendonegestireglieventi.

Glieventi,ilPostBackeilViewStateIcontrolliposizionati all’internodallaWebFormsono,a tuttigli effetti,deglioggetti equindi, come tali, sono dotati di eventi. Per mostrare al meglio questo concetto,componiamounaformcomequelladell’esempio16.2.

Esempio16.2<formrunat="server">

Inserisciiltuonome:

<asp:TextBoxid="FirstName"runat="server"/><br/>

<asp:Buttonid="ConfirmButton"runat="server"Text="Conferma"

OnClick="ShowFirstName"/>

</form>

Page 385: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Selanciatonelbrowser,questosnippetproduceunaschermatasimileaquelladellafigura16.2.

Figura16.2–Lanostraprimapagina.

Quandopremiamosulbottonediconferma,inautomatico,vienefattouninviodellaform.Quest’azioneprendeilnomediPostBack,perchélaformvienenuovamenteinviataaséstessa.Attraversoquestaoperazione,ASP.NETricevenuovamentelapaginaecapiscechec’èda intercettare l’eventodi click, richiamando l’eventhandler specificatonelmarkupdefinitoattraversol’attributoOnClick,comenell’esempio16.3.

Esempio16.3SubShowFirstName(ByValsenderasObject,ByValeasEventArgs)

'…codice

EndSub

Comesipuònotareanchenellafigura16.2, laTextBoxhamantenuto lostatosenzachenoi dovessimo effettivamente gestirlo manualmente. Questa caratteristica fa partedell’infrastrutturadiASP.NETesibasasuunconcettonotocomeViewState.

IlViewState consente allepaginedimantenere lo statodei controlli attraverso i variPostBackeconcorrealsupportodeglieventiall’internodelsistema.QuestidueconcettisonoessenzialialfunzionamentodiunapaginaASP.NET.Nellatabella16.2sonovisibiliglieventidellaWebForm,riportatiinordinediinvocazione.

Tabella16.2–GlieventidallaWebForm,inordinediinvocazione.Evento Descrizione

PreInitSi verifica prima dell’inizializzazione della pagina. Serve per impostare master page e theme, oggetto delcapitolo7.

Init Siverificaall’inizializzazionedellaclasserappresentatadallapaginaedè,difatto,ilprimoveroevento.

InitComplete Siverificasubitodopol’eventoInit.

LoadState SegnailcaricamentodellostatodellapaginaedeicontrollidalViewState.

PreLoad Siverificaprimadelcaricamentodellapagina.

Load Siverificaalcaricamentodellapagina,successivamenteall’inizializzazione.

LoadComplete Siverificasubitodopol’eventoLoad.

PreRender Siverificasubitoprimadelrenderingdellapagina.

SaveState Salvalostatodeicontrolliall’internodelViewState.

Page 386: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Render Siverificaalrenderingdellapaginaesegnalagenerazionedelcodice(X)HTMLassociato.

UnLoadSi verifica allo scaricamento dell’istanza della pagina. Non corrisponde al Dispose della stessa, perchéquest’ultimoègestitodalGarbageCollector.

È importante sottolineare che il rendering della pagina avviene quando la stessa arrivanello stato di “Render”. Non si tratta tanto di un vero e proprio evento come gli altri,quantodiunostatospecifico,chevienesfruttatoperfargenerarel’outputaicontrolli.Finoaquelmomento,qualsiasiscritturadirettasullostreamdirispostaavràl’effettodiinseriredeltestoprecedenteaquellochesaràgeneratopoidaicontrolli.

InteragireconlapaginaAttraverso l’uso dei controlli, diventa possibile racchiudere il flusso logico di una dataoperazioneall’internodiunasingolapagina:questoconsentediincorporareetenereunititutti i pezzi di un’ipotetica serie di passaggi. Possiamo comporre facilmente il layout,nascondendo a piacimento gli oggetti, attraverso l’uso della proprietà Visible, che èdisponibile su tutti i controlli (perché derivano tutti dalla classe base Control, paginainclusa). Inoltre, ASP.NET è dotato di un controllo specifico, chiamato Wizard, checonsente di strutturare rapidamente una serie di passaggi da far compiere all’utente. Ingenerale,èutilesoffermarsiperunattimosuicontrolliditipocontainer.Si trattadiunparticolare tipo di controlli che, a differenza degli altri, è in grado di funzionare dacontenitore. Questo significa che controlli di questo tipo possono raggruppare altricontrollie,seimplementanol’interfacciaINamingContainer,assicuranoaglistessicheilloroIDsaràgeneratounivocamente.Quandounnostrocontrolloècontenutoall’internodiuncontrollodiquestotipo,lostessononèdirettamenteaccessibileutilizzandol’ID,comefaremmoconuncontrollocontenutodirettamentenellapagina,mavaricercatoall’internodiquellocheèchiamatoalberodeicontrolli,checontienetuttalastrutturadellapagina,usandoilmetodoFindControlsulcontenitore.

Quando dobbiamo semplicemente racchiudere controlli e non vogliamo influenzarnecosìtantoilcomportamento,possiamooptareperPlaceHolder,cheoffreilvantaggiodiraggruppare e nascondere (o visualizzare) un gruppo di controlli, senza agiresingolarmente sugli stessi. L’esempio 16.3 può quindi essere adattato per mostrare ilrisultatodopoilclickenascondere,contestualmente,laformdiimmissionedati.Ilcodicenecessariositrovanell’esempio16.4.

Esempio16.4-Markup<formrunat="server">

<asp:PlaceHolderid="EntryForm"runat="server">

Inserisciiltuonome:

<asp:TextBoxid="FirstName"runat="server"/><br/>

<asp:Buttonid="ConfirmButton"runat="server"Text="Conferma"

Page 387: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

OnClick="ShowFirstName"/>

</asp:PlaceHolder>

<asp:PlaceHolderid="Results"runat="server"Visible="false">

Iltuonomeè

<asp:Literalid="SelectedFirstName"runat="server"/>

</asp:PlaceHolder>

</form>

Esempio16.4-VisualBasicSubShowFirstName(ByValsenderasObject,ByValeasEventArgs)

EntryForm.Visible=false

Results.Visible=true

SelectedFirstName.Text=FirstName.Text

EndSub

Unavoltalanciatoavideo,otterremounrisultatosimileaquellodellafigura16.3.

Figura16.3–Laformprimaedopoilsubmit.

Aquesto punto si pone un problema: come fare inmodo che la formnon possa essereinviata se i campi non sono compilati correttamente? Per questo scenario, ASP.NETdisponediuninsiemedicontrollicheprendonoilnomedivalidatorcontrol.

ValidazionedelleformUna delle funzionalità più utilizzate dagli sviluppatori web è la validazione dei daticontenutiall’internodiunaform.ASP.NETsupportanativamentequestoscenariograzieaigiàcitativalidatorcontrol.Sitrattadiunafamigliadicontrollichevengonoassociatiai controlli di inserimento e sono in grado di effettuare una convalida tanto lato clientquantolatoserver.L’usointalsensoèvisibilenell’esempio16.5.

Esempio16.5Inserisciiltuonome:

<asp:TextBoxid="FirstName"runat="server"/>

Page 388: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<asp:RequiredFieldValidatorrunat="server"

ControlToValidate="FirstName"

ErrorMessage="*"/>

La chiave di tutto risiede nella proprietà ControlToValidate, che accetta l’ID delcontrollo da convalidare, sul quale viene applicata la convalida. La proprietàErrorMessage, invece, consente di specificare un messaggio di errore. Come il nomestessosuggerisce,questocontrolloverificacheilcamposiaeffettivamenteriempito.Perlealtrepossibilitipologiedivalidazione,ASP.NETfornisceadeguaticontrolli,cheabbiamoschematizzatonellatabella16.3.

Tabella16.3–IcontrollidivalidazionediASP.NET.Controllo Descrizione

RequiredFieldValidator Effettuailcontrollopiùsemplice:verificachecisiadeltesto.

RangeValidatorVerificache ilvaloredelcontrolloacuièassociatosiacompreso tra ivaloridelleproprietàMinimumValueeMaximumValueperiltipospecificatoattraversoType.

CompareValidator

Può comparare il valore di due controlli, attraverso la proprietà ControlToCompare, oppurerispetto aunvalore fisso, conValueToCompare.LaproprietàType specifica il tipo di valoredellaconvalida,mentreOperatorlatipologiadioperatoredautilizzare.

RegularExpressionValidatorSfrutta una regular expression, specificata nella proprietà ValidationExpression, pereffettuareicontrollidiconvalida.

ValidationSummary

Mostraun riepilogodeivalidator chenonhannopassato la convalida, leggendo laproprietàErrorMessage, sepresente,altrimentisfruttandoText.LaproprietàDisplayMode consente discegliereiltipodiformattazionedadareall’elencodeglierrori.

Per essere certi che la convalida sia avvenuta, lato server, dobbiamo richiamare laproprietà IsValid della classe Page: se dimenticassimo di farlo, l’effetto sarà di nonverificare la convalida, dato che quella client-side può essere aggirata disattivando ilsupportoaJavaScript.

Conlarelease4.5èstatointrodottoilsupportoallaunobtrustivevalidation,migliorandol’output generato e utilizzando i più recenti standard. Per attivare questa funzionalità,occorreagiresulweb.config,aggiungendoilcodicevisibilenell’esempio16.6.

Esempio16.6<add name="ValidationSettings:UnobtrusiveValidationMode"

value="WebForms"/>

Infine, è possibile creare validazioni custom, utilizzando il controllo CustomValidator,oppureimplementandounpropriocontrolloderivatodallaclasseBaseValidator,cheèincomuneatuttiquesticontrolli.

MantenereillayoutconlemasterpageNellosviluppodiapplicazioniwebèessenzialechetuttelepaginemantenganounlayoutcomune.Atalproposito,ASP.NETintroduceiconcettidimasterpageecontentpage.

Page 389: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Unamasterpage rappresenta una sorta di template che, oltre a contenuti dinamici estatici, contiene alcune aree rappresentate da altrettanti controlli di tipoContentPlaceHolder.Questisarannoriempiticonicontenutidefinitinellevariesezionidellecontentpageassociate,chesonochiamatecontentpage.

Unamasterpageèunfileconestensione.masterehaunasintassideltuttoanalogaaquelladiunanormalepaginama ladirettiva@Pageèsostituitacon [email protected] content page è una normaleWeb Form, che contiene unicamente controlli di tipoContent e alla quale è associata una master page. Inoltre, per ogni controllo di tipoContentdellapaginadicontenuto,deveesistereuncontrolloditipoContentPlaceHoldernella master page. Ciascun controllo Content include il contenuto effettivo per ogniplaceholderpresentenellamasterpage.LacorrispondenzatraiduetipidicontrollosibasasulvaloredelleproprietàIDeContentPlacholderID.

Peresempio,perrappresentarelatipicastrutturadiunsito,con3aree(centrale,destraesinistra) chepossono essere specializzatenelle content page, dovremousareunamasterpagecomequellanell’esempio16.7.

Esempio16.7<%@MasterLanguage="VB"%>

<formrunat="server">

<divclass="left">

<asp:ContentPlaceHolderID="Left"runat="server">

<div>Sinistra</div>

</asp:ContentPlaceHolder>

</div>

<divclass="body">

<asp:ContentPlaceHolderID="Body"runat="server"/>

</div>

<divclass="right">

<asp:ContentPlaceHolderID="Right"runat="server">

<div>Destra</div>

</asp:ContentPlaceHolder>

</div>

</form>

Non è sempre obbligatorio sovrascrivere i placeholder. Per questomotivo, nella paginadell’esempio16.8vengonosoltantodefinitelapartecentraleequelladidestra.Possiamonotarel’usodell’attributoMasterPageFilesulladirettiva@Page,cheindicaeffettivamenteilpercorsovirtualedelfile.master.

Page 390: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio16.8<%@PageLanguage="VB"MasterPageFile="Site.master"%>

<asp:ContentID="Body"ContentPlaceHolderID="Body"runat="server">

<div>Contenutolocaledellapagina</div>

</asp:Content>

<asp:ContentID="Right"ContentPlaceHolderID="Right"runat="server">

<div>Partedestrapersonalizzata</div>

</asp:Content>

Una volta eseguita questa pagina all’interno del browser, otterremo un effetto simile aquellochepossiamovederenellafigura16.4.

Figura16.4–Eccocomeappareunacontentpagedopochelamasterpageèstataapplicata.

L’usodiquesta tecnicaèmoltopotenteeconsente, tra l’altro,di annidareanchemasterpagetraloro.Maggioriinformazionisonodisponibiliall’indirizzohttp://aspit.co/agy.

Èpossibileassegnareunamasterpageanchedacodice,programmaticamente,all’internodell’eventoPre_Initmostratoinprecedenza.

Visualizzaredati:ildatabindingAl giorno d’oggi, i dati in un’applicazione web vengono recuperati dai contesti piùdisparati, che possono essere un semplice file di testo, un documento XML, un webserviceoundatabaserelazionale.Perfacilitareilrecuperodeidatielaloropresentazioneall’interno delle applicazioni web mediante un’architettura che permetta di astrarre daltipodi fontedati,ASP.NETintroduce ilconcettodidatabinding.Daunpuntodivistatecnico, il databindingè semplicemente l’associazionediuna fontedati auncontrollo,garantitadallapossibilitàdellapaginadidistingueretracreazioneecaricamentodeidatineicontrolli.

I controlli che supportano la visualizzazione dei dati vengono chiamati data boundcontrolo,piùsemplicemente,datacontrol.Spessosiconfondeildatabindingconl’usodellaproprietàDataSource,cheicontrollidataboundoffrono.Questaproprietàaccettaunoggetto di tipo IList, IEnumerable o ICollection (e, ovviamente, qualsiasi tipo cheimplementi una di queste tre interfacce) e, quindi, si presta a garantire la possibilità di

Page 391: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

essereutilizzataconqualsiasifontedati,chenonsiaesclusivamenteundatabase.

Quellocheavvienedietrolequinte,dopoaverassociatolasorgente,èmoltosemplice:

vienevalutatoilcontenutodellaproprietàDataSource;

se vi sono elementi all’interno della sorgente, viene effettuato un ciclo che limostraavideo,asecondadellalogicacheimplementailcontrolloacuilasorgenteèassociata.

Questomeccanismoèdeltuttotrasparente,perchénondobbiamofarealtrocherichiamareilmetodoDataBindsulcontrolloalqualeabbiamoassociatolasorgente.Questometodoèpresente direttamente sulla classeControl del namespaceSystem.Web.UI, da cui tutti icontrolliderivano.

IlistcontrolAnche se possiamo applicare il data binding a qualsiasi proprietà di un controllo,generalmentesipreferiscesfruttareidatacontrol,chespessosonodotatidi template.Cisono controlli speciali però, come DropDownList o RadioButtonList che, purappartenendoaquestafamiglia,hannounlayoutprefissato.Generalmente,persemplicità,questi vengonodefiniti list control (perché ripetono liste).La fase di data binding restaperòidentica.Unmodellodilistcontrolsipuòvederenell’esempio16.9.

Esempio16.9<asp:DropDownListID="DropDownList1"

DataTextField="CompanyName"

DataTextFormatString="-{0}"

DataValueField="CustomerID"

runat="server"/>

Esempio16.9-VisualBasicDropDownList1.DataSource=customers

DropDownList1.DataBind()

Da notare l’uso delle proprietà DataTextField e DataTextFormatString, che indicanorispettivamentelaproprietàdautilizzarepervisualizzareeperformattareildato,mentreDataValueField serve a indicare qual è il valore da associare al controllo.Nel codice,invece, possiamo notare come venga assegnata, attraverso la proprietà DataSource, lasorgente(cheèprelevatagrazieaEntityFrameworkesalvatainunacollectionlocale)ecome questa venga effettivamente interrogata all’invocare del metodo DataBind.L’esecuzionedellapaginaèriportatanell’immagine16.5.

Page 392: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura16.5–LaDropDownListconlasorgentedatiassociata.

Ancheinpresenzadidatiprelevatidafontidatidiverse,tuttoilcodiceeilmarkupvistofinoranoncambieranno:èquestoilpuntodiforzachestaallabasediquestatecnica.

UtilizzareitemplateASP.NETsupportadiversitipidicontrolliconsupportoperitemplate.Rispettoaquantoofferto,valelapenacitareiseguenti:

Repeater:èuncontrollomoltosempliceche,datountemplate,loripetepertuttiglielementidellasorgentedati;

GridView: mostra in forma tabellare la sorgente dati, permettendone lapaginazioneel’ordinamento,elamodificadellerighe;

DetailsView:mostrainformatabellareunasingolarigarecuperatadallasorgentedati,permettendonel’inserimentoelamodifica;

FormView: simile al DetailsView, permette un layout personalizzato per larappresentazionedeidati;

ListView:consentelavisualizzazioneconuntemplatepersonalizzato(sonofornitialcuni template conVisualStudio2010), supportandopaginazione,ordinamento,modificaeinserimento,conmaggioreestendibilitàrispettoaicontrolliesistenti.

Page 393: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

La scelta di questi controlli stabilisce le modalità di visualizzazione, inserimento emodifica che vogliamo utilizzare all’interno della pagina. Dal punto di vista dellefunzionalità,invece,consentonodisfruttarelemedesimecaratteristiche,percuispessocisonopuntiincomunetracontrollidiversi,conovviedifferenzedettatedalladiversaresagrafica. In maniera molto semplificata, Repeater viene utilizzato quando vogliamosemplicementemostraredeidati.ListView, invece,cigarantisce lamassimaflessibilità,GridViewcioffreunarappresentazioneinformatodigriglia,eDetailsVieweFormView,invece,lapossibilitàdiagiresuunsoloelementoallavolta.

ItemplatesonogestitiattraversounaclasseditipoITemplate,un’interfacciaparticolareche viene poi implementata da una classe generata al volo attraverso il page parser.Generalmente, questi controlli sono dotati di template specifici per i diversi stati. Peresempio, ItemTemplate è il template per il singolo elemento, mentre inveceHeaderTemplaterappresental’intestazione.

Per poter comporre il template e posizionare il contenuto della sorgente dati neitemplate,dobbiamoutilizzarel’istruzionedibinding<%#…%>.Sitrattadiunadirettivaparticolare,cheilpageparserriconosceechefasìcheciòcheècontenutovengainvocatoinsiemeall’eventoDataBinding,chesiverificaquandoilcontrolloscatenaildatabinding.Questicontrollioffronoaccessoaidatiattraversol’interfacciaIDataItemContainer,chenoi spesso utilizziamo grazie alla proprietà Container del template, come possiamovederenell’esempio16.10.

Esempio16.10<asp:Repeaterid="CustomerView"runat="server">

<ItemTemplate>

<%#Container.DataItem%><br/>

</ItemTemplate>

</asp:Repeater>

Ilcodiceprecedenterappresentaavideounelencodielementi.Datochenonèspecificatodiversamente, viene invocato il metodo ToString che, in questo caso, produce lavisualizzazionedelnomedellaclasse.Perpoteraccederealleproprietà,lanuovaversioneconsente di specificare il tipo messo in binding, senza più dover fare il casting comerichiestonelleversioniprecedenti.Ilcodicenecessarioaimplementarequestoscenarioèvisualizzatonell’esempio16.11,dovelaproprietàItemTypeindicailtipodautilizzareneitemplatedibinding.

Esempio16.11<asp:Repeaterrunat="server"ItemType="MyModel.Customer">

<ItemTemplate>

<%#Item.CustomerName%>

Page 394: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

</ItemTemplate>

</asp:Repeater>

Grazieall’usodiquestanuovasintassi,abbiamoacquisito ilvantaggiodipotersfruttarel’Intellisense,evitandodicommettereerroriesenzalanecessitàdiutilizzarelareflection,comeavvieneconleversioniprecedenti.Grazieallenovitàintrodotteconquestarelease,anche i controlli legati alla modifica dei dati hanno la possibilità di sfruttare nuovefunzionalità che semplificano gli scenari più diffusi. Per prima cosa, i controlli datasource,introdotticonleprecedentiversioni,sonodeprecati:questononvuoldirechenonpossanoessereutilizzati,masignificacheoravienesuggeritounnuovoapproccio,cheèuna variante di quanto già abbiamo visto per il binding. Il codice dell’esempio 16.12mostracomefare.

Esempio16.12-griglia.aspx<asp:GridViewrunat="server"

SelectMethod="GetCustomers"ItemType="MyModel.Customer">

...

</asp:GridView>

Esempio16.12-griglia.cs.aspxPublic Function GetCustomers(<QueryString("n")> name As String) As

IQueryable(OfCustomer)

Dimcustomers=db.Customers

IfNotString.IsNullOrEmpty(name)Then

customers=customers.Where(Function(f)f.Name.Contains(name))

EndIf

Returncustomers

EndFunction

In particolare, stiamousandoEntityFramework all’internodel codiceVisualBasic, perfarci restituire i clienti. Grazie al fatto che i metodi qui riportati restituiscono un tipoIQueryable<T>,ilrisultatocheotteniamoècheilcontrolloricostruiràicriteridiricercasottoformadilambda,cosìcheEntityFrameworkpossaprodurrel’esattorisultato.Inaltreparole,potremoimplementarepaginazioni,ricercheoordinamentisenzadoverfaremoltoaltroeconlacertezzachelaquerycheverràinviataaldatabasesaràcreatanellamanieramigliore possibile, con i dati effettivamente visualizzati dal controllo come risultatodell’esecuzionedellaquerystessa.

Possiamovederelagrigliacreatanellafigura16.6.

Page 395: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura16.6–Lagrigliaconidatideiclientiinbinding.

L’uso dell’attributo all’interno dei parametri supportati dal metodo è un’altra novità(mutuata daASP.NETMVC), che prende il nome dimodel binding. In pratica, stiamoindicando che la sorgente dei dati è in querystring. Il risultato è che se passiamo allapagina un valore specifico (per esempio, griglia.aspx?n=Daniele), ci ritroveremo laproprietàvalorizzata.Possiamorecuperarequestivaloridallesorgentipiùdisparate,comelaform,icookieolasession.

Lostessoidenticoapproccioèpossibileinfasediaggiornamentooinserimentodeidati.Peresempio,possiamospecificareilmetodochesioccuperàdieseguirel’aggiornamento,comenell’esempio16.13.

Esempio16.13-Griglia.aspx<asp:GridViewrunat="server"

UpdateMethod="UpdateCustomers"ItemType="MyModel.Customer">

...

</asp:GridView>

Esempio16.13-Griglia.cs.aspxPublicSubUpdateCustomer(casCustomer)

EndSub

Lacosa interessantediquestoapproccioèche riceveremo, inautomatico, idati caricatiall’interno del tipo specificato per la griglia: questo vuol dire che non dovremopreoccuparcidiconversionioaltriaspettiechepotremosemplicementeaggiornareidati–cosa che, nel caso di Entity Framework, è ancora più semplice fare. Poi basterà farel’attachalcontestodell’entitàemodificarneidati.All’internodelcodicedisponibileconil libro è presente un esempio completo, che mostra come si possa implementarefacilmentequestoscenarioconleWebFormsinASP.NET4.6.

Page 396: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

CreareURLperlaSEOASP.NET supporta nativamente una funzionalità che prende il nomediURL routing echeconsentedirigirarelerichiestesuunapagina,afrontediunURLpiùlungo.

LaSEO(SearchEngineOptimization)èunatecnicavoltaaottimizzarel’indicizzazionedi un sito all’interno dei motori di ricerca. In applicazioni dal contenuto dinamico, èfrequente l’usodi parametri inseriti inquerystring, per caricare informazioni e generarepagineperognispecificarichiesta.Questoapprocciononèilmiglioredaadottare,perchénon contiene informazioni utili nell’URL. Queste informazioni, come una descrizionebreve,possonoessereutilitantoaimotoridiricercaquantoall’utenteche,daunURL,puòcapiremeglioilcontenutodiunindirizzo.

Per sfruttare l’URL routing in ASP.NET, possiamo registrare gli URL da gestire nelglobal.asax,comeèvisibilenell’esempio16.14.

Esempio16.14–VisualBasicSubApplication_Start(ByValsenderAsObject,

ByValeAsEventArgs)

RouteTable.Routes.Add("ProductsRoute",

newRoute("products/{ProductID}/{ProductName}",

newPageRouteHandler("~/products.aspx")))

EndSub

La routedefinita rendepossibile il fatto che tutte le chiamate effettuate aURLdel tipo“products/15/ Libro-ASPNET”, vengano in realtà rigirate alla pagina specificata, cioè“products.aspx”. All’interno di questa pagina, potremo accedere al valore di uno o piùparametri, come mostrato nell’esempio 16.15, tanto da markup, usando una sintassiparticolare(cheprendeilnomediexpressionbuilder),quantodacodice.

Esempio16.15<asp:Literalrunat="server"Text="<%$RouteValue:ProductName%>"/>

Esempio16.15-VisualBasicDimproductNameasString=Page.RouteData("ProductName").ToString()

Inoltre, possiamo creare un link che sfrutti la route, utilizzando il codice dell’esempio16.16.Utilizzandoquestatecnica,alvariaredelpercorso,inautomatico,ilinkseguirannolastessastrada,evitandocididoverlidefiniremanualmente.

Esempio16.16

Page 397: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<asp:HyperLink

NavigateUrl="<%$RouteUrl:RouteName=ProductsRoute,ProductID=15,

ProductName=Libro-ASPNET%>"

runat="server">LibroASP.NETconID=15</asp:HyperLink>

Questo motore supporta diverse caratteristiche avanzate, come vincoli sui parametri ovalorididefaultperglistessi.

GestionedelleareeprotetteASP.NEThasemprefornitounsupportospecificoperareeprotette,cheperònegliultimiannisièmoltoevoluto.

Per quanto riguarda la protezione, sono supportati i due scenari più diffusi, cioèl’autenticazioneintegratadiWindowsequellaattraversounaform.Nelprimocasoafaretuttoèilwebserver,nelsecondodobbiamodefinirenoidelcodice.

Perlimitarequestanecessità,ASP.NEThainizialmenteintrodottounmeccanismonotocomeMembershipAPI,checonsentedidefinireunproviderchefa tutto il lavoro.Perquantoriguardairuoli,invece,avevamoadisposizioneleRolesAPI.Inentrambiicasisitratta di funzionalità che si basano sul ProviderModel Design Pattern, che prevede ladefinizione di un provider che implementa concretamente la strategia e di una serie diprovider, che possono essere definiti nel web.config. I provider, basati su una classeastratta in comune, possono essere scambiati tra loro, modificando il funzionamentointerno di queste due funzionalità. ASP.NET supporta inoltre una serie di controlli,chiamati security control, che offrono un supporto nativo alle funzionalità di login,creazioneutenteerecuperopassword.

È possibile approfondire ulteriormente la questione, che qui richiederebbe unatrattazionemoltoampia,suhttp://aspit.co/agz.

Di recente, per riflettere i cambiamenti legati a questi ambiti, è stato introdotto unnuovomeccanismo,notocomeASP.NETIdentity.Piùmodernoefacilmenteestendibile,ASP.NETIdentityvieneintrodottogiàconitemplatepredefinitiinfasedicreazionediunnuovoprogettoesupportascenarimoltopiùavanzati,comeladefinizionediundatabasecon schema libero (sfruttando Entity Framework o scrivendo provider specifici), ilsupporto a login attraverso i social network (Twitter, Facebook, Google e MicrosoftAccount, senza scrivere codice), l’autenticazione two-factor e molto altro ancora.ASP.NETIdentitypuòessereapprofonditosuhttp://aspit.co/aqo.

ASP.NETMVCASP.NETMVCèl’alternativaadASP.NETWebForms,checonsentediimplementareil

Page 398: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

pattern MVC. Per creare una nuova applicazione di questo tipo, dobbiamo creare unnuovoprogettoall’internodiVisualStudio,comepossiamovederenell’immagine16.7.

Figura16.7–LasceltadelprogettoconASP.NETMVC.

All’internodiunprogettochefausodiASP.NETMVC,illavoroèdivisoequamentetracontroller,cheintegralalogicasottoformadicodiceVisualBasic,view,cherappresental’interfaccia(contienecioèl’HTML)emodel,cherappresentaidatichecontrollereviewsi scambiano. Secondo questo pattern, infatti, controller e view non hanno cognizionel’uno dell’altro e sono slegati tra loro, per favorire la testabilità del codice. Una parteinteressantediASP.NETMVCènelfattocheimplementailconcettodiconventionsoverconfiguration (le convenzioni vincono sulla configurazione). Questo è particolarmentevisibile quando diamo un’occhiata al meccanismo di attivazione dei controller edell’associazionedellaviewalcontrollerstesso.

Inparticolare,uncontrollerèunaclassechederivadallaclasseControllerechehanelsuffissoilnomeControllereoffredeimetodiparticolari,chiamatiaction,cherestituisconoun tipo derivato daActionResult. Possiamo vedere un semplice controller nell’esempio16.17.

Esempio16.17

Page 399: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

PublicClassHomeController

InheritsSystem.Web.Mvc.Controller

'GET:/Home

FunctionIndex()AsActionResult

Dimcustomers=db.Customers.OrderBy(Function(f)f.ID).Take(5)

ReturnView(customers)

EndFunction

EndClass

Comesirichiamaquestaaction?Semplicementeaquestoindirizzo:/Home/Index.

Comesipuònotare,laconvenzioneindicacheilcontrollerèstabilitodalprimopezzodell’URL,mentrel’actiondalsecondo.Indexèanchel’actiondidefault,quindipuòessereomessa. Anche ASP.NET MVC utilizza le route di ASP.NET, che possono esserepersonalizzateagendosulfile\App_Start\RouteConfig.vb.

Aquestopunto,abbiamocapitocomeaverelaview:perconvenzione,saràricercatounfilechesichiamaIndex.cshtmlsotto ilpercorso \Views\Home.Anche inquestocaso, ilnomedelcontrolleredell’actionsonoutilizzatipercomporredinamicamenteilpercorsonelqualeandarearecuperarelaview.Poichéabbiamopassatonelcontrollerunelencodiclienti,lanostraviewsaràtipizzatausandoilmodel.Seaggiungiamounaviewutilizzandol’apposita voce diVisual Studio, ci verrà proposto in automatico di utilizzare i tipi cheabbiamodisponibili,semplificandocilavita,comevienemostratonellafigura16.8.

Figura16.8–CreareunaviewtipizzataconASP.NETMVC.

L’esempio 16.18 contiene il codice necessario a mostrare a video i dati recuperati daldatabase,usandoEntityFramework.

Esempio16.18

Page 400: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

@ModelTypeIEnumerable(OfMyMvcApplication.Customer)

<ul>

@ForEachitemInModel

@<li>@item.Name</li>

Next

</ul>

Comesipuònotare,facciamosemplicementeuncicloemostriamoavideoidatiprelevatidaldatabase:ASP.NETMVC,insomma,nonhailconcettodidatabinding,perchébastaavereunaviewtipizzataedestrarreopportunamenteleinformazioni.LasintassiutilizzataprendeilnomediRazoredèspecificaperASP.NETMVC:nonècomplessadaimparare,perchéhapocheesempliciregole,chesonoillustratesuhttp://aspit.co/0u.

CreareformconASP.NETMVCPossiamosfataresubitounmito:ASP.NETMVCvabenissimoanchepercrearemascheredi inserimentodati.Anzi,grazie aiwizard integrati all’internodiVisualStudio,diventasemplicissimo,infasedicreazionediuncontroller,fargenerareinautomaticoleactioneleviewnecessarie:bastaselezionareiltemplatechefariferimentoaEntityFrameworktraleopzionidiscaffoldingepoispecificarelaclassedimodelloequellaconilcontext.

Avremouncontrollerconcodicesimileaquellodell’esempio16.19.

Esempio16.19PublicClassAdminController

InheritsSystem.Web.Mvc.Controller

'GET:/Admin/Edit/5

FunctionEdit(OptionalByValidAsInteger=Nothing)AsActionResult

DimcustomerAsCustomer=db.Customers.Find(id)

IfIsNothing(customer)Then

ReturnHttpNotFound()

EndIf

ReturnView(customer)

EndFunction

'POST:/Admin/Edit/5

<HttpPost()>

FunctionEdit(ByValcustomerAsCustomer)AsActionResult

IfModelState.IsValidThen

db.Entry(customer).State=EntityState.Modified

Page 401: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

db.SaveChanges()

ReturnRedirectToAction("Index")

EndIf

ReturnView(customer)

EndFunction

EndClass

Il codice è interessante perché ci mostra come implementare una form con ASP.NETMVC:ilprimometodo,infatti,rappresentalachiamatachevienefattapervisualizzarelaformdiinserimentodati,alcuiinvioverràinvocatalaactioncherispondesoloalmetodoPOST,echeinfattièdecorataconl’attributoHttpPost.Inquestometodo,idativengonorecuperati, modificati e salvati con Entity Framework: se tutto va a buon fine, saremoinviati alla action di default, che mostra l’elenco delle informazioni. Ma come si fa arenderizzareunaformdentrounaview?Occorreimplementareuncodicesimileaquellodell’esempio16.20.

[email protected]

@UsingHtml.BeginForm()

@Html.ValidationSummary(True)

@<fieldset>

<legend>Customer</legend>

@Html.HiddenFor(Function(model)model.Id)

<divclass="editor-label">

@Html.LabelFor(Function(model)model.Name)

</div>

<divclass="editor-field">

@Html.EditorFor(Function(model)model.Name)

@Html.ValidationMessageFor(Function(model)model.Name)

</div>

<divclass="editor-label">

@Html.LabelFor(Function(model)model.City)

</div>

<divclass="editor-field">

@Html.EditorFor(Function(model)model.City)

@Html.ValidationMessageFor(Function(model)model.City)

</div>

...

Page 402: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<inputtype="submit"value="Save"/>

</fieldset>

EndUsing

Possiamonotarel’usodeglihelperLabelFor,EditorForeValidationMessageFor,chein automatico, andando a lavorare con i tipi delle proprietà del modello, ci dannorispettivamente il titolo, un editor per il tipo che tiene conto di come è fatto e unmessaggiodivalidazione.Questefunzionalitàlavoranoconledataannotations,introdottenelle versioni precedenti del .NET Framework. Queste sono un modo per annotare earricchire lenostreclassicon informazioniaggiuntive,come la tipologiadicampo, seèobbligatorio, oltre che con il modello stesso, che in questo caso è basato su EntityFrameworkepuòavereattributicheincludonoquesteinformazioni.

Ingenerale, l’intentodiquestaprima introduzioneèpiùchealtroquellodidarviunarapidapanoramicasuquellocheASP.NETMVCconsentedifareepermettervidicapirecheèmoltopiùsemplicediquantosipossapensare,perchémetteHTMLel’HTTPapiùstrettocontattocon losviluppatore,datochenoncisonoarteficicostruiti intorno,comenel caso di ASP.NETWeb Forms. L’esempio allegato al libro contiene una trattazionecompleta di quanto abbiamo introdotto con questi ultimi esempi, che possono servirecome base di partenza per continuare a esplorare ASP.NET. Per il resto, occorresottolineare chemolte delle nozioni valide per ASP.NETWeb Forms (autenticazione eautorizzazione in particolare) valgono anche per ASP.NET MVC, perché, di fatto,entrambisonobasatisullostessoruntimeehannoaccessoallestessefunzionalitàdibase.

Apartire daASP.NETCore 1, l’unica alternativa possibile èASP.NETMVC6: saràpossibilecontinuareautilizzarelostessomodellodiprogetto,basandoilnostrolavorosul.NET Framework, oppure sfruttarne uno nuovo, basato su .NETCore 1 (introdotto nelcapitolo1)eingradodifarfunzionareleapplicazionibasatesuASP.NETMVCanchesuLinuxeMacOSX,oltrechesuWindows.

Inun’ottica di investimento in chiave futura,ASP.NETMVC, rispetto aWebForms,garantisce un miglior supporto cross platform e un nuovo runtime ottimizzato per leperformance,lascalabilitàeilcloud.

ConclusioniASP.NETèunatecnologiamoltoestesaecomplessa,percuiquestocapitolohaavutoloscopo precipuo di presentarne una rapida introduzione. Per approfondimenti specifici,rimandiamoailibri“ASP.NET4.5eASP.NETMVC4inC#eVB–GuidaCompletaperlosviluppatore”e“ASP.NETCore1 -Guidacompletaper lo sviluppatore”,chepotretetrovareinquestastessacollana.

Parte del successo del .NET Framework è da ricercare in ASP.NET: la sua fortediffusione ha permesso a tanti sviluppatori di imparare ad apprezzare anche altretecnologieall’internodelframework,contribuendoafavorirneun’ulterioresviluppo.

Page 403: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

InsiemeconASP.NETWebForms,ilsupportoperilmodelloaeventi,ildatabindingelagestionedelle areeprotette rappresentano sicuramentegli argomenti principali da cuipartire. D’altro canto, ASP.NETMVC consente di sfruttare al meglio HTML e HTTP,dandociilmassimocontrolloeconsentendocianchelatestabilità.

Per ulteriori approfondimenti, vi invitiamo a consultare il sito ASPItalia.com,all’indirizzohttp://www.aspitalia.com/.

Ora che abbiamo terminato la breve trattazione di ASP.NET, possiamo passare aesaminareunatecnologiache,anchesenonstrettamentelegataalWeb,consentedicreareunaparte essenziale per lo scambiodei dati: i servizi.Nel prossimo capitolo parleremoquindidiapplicazionidistribuite.

Page 404: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

17

Creareapplicazionidistribuite

NelcapitoloprecedenteabbiamoimparatoarealizzareapplicazioniwebconVisualBasice, nello specifico, attraverso il framework ASP.NET. Abbiamo visto che ci sono duetecnologiechepossiamosfruttareperlarealizzazionedipaginedinamiche:WebFormseMVC.MailWebnonèsoloHTMLeanzi,negliultimiannisistatrasformandosemprepiùinservizicheespongonoAPIperl’accessoelamanipolazionedidati.HTTP,infatti,èun protocollo molto semplice, implementato da qualsiasi dispositivo, framework elinguaggio. È perciò interoperabile e dà un controllo completo sulla richiesta,permettendocidiesseriliberinelsuoutilizzo.

Perquestomotivoiservizisonoampiamentisfruttati,soprattuttoperlarealizzazionediapplicazionimobile,masistannodiffondendosemprepiùancheinambitoenterprisepercomunicazioniservertoserver.

In questo capitolo vogliamo presentarvi la tecnologia di riferimento nell’ambitoMicrosoftperrealizzazionediservizieinparticolarediquelliRESTful.Questihannolaparticolarità di sfruttare appieno il protocollo HTTP impiegando i metodi HTTP comeGET, POST, PUT e DELETE (e non solo) rispettivamente per accedere, aggiungere,modificare e cancellare una risorsa rappresentata dal suo URI. Più avanti nel capitoloaffronteremouno standarddinomeOData, cheestendequesto concettodefinendodelleregolechecipermettonodieffettuarequeryedinavigaretra idati. Infine,parleremodicomerealizzareapplicazionireal-timesfruttandoicanalibidirezionalidicomunicazionee,inparticolare,iWebSocket.

PartiamoquindidacomerealizzareserviziRESTfulattraversounframeworkdedicatodinomeASP.NETWebAPI.

IserviziRESTfulconASP.NETWebAPIAbbiamovistocheASP.NETè il frameworkdi riferimentoper tuttociòche riguarda ilmondo web. Si suddivide in vari strumenti a seconda dell’obiettivo da raggiungere eASP.NETWebAPIèquelloufficialeperlarealizzazionediserviziHTTP.Molticoncettisu cui si basa sono i medesimi di ASP.NETMVC, come il routing delle richieste sucontrolleroilbindingdelmodelloperlerichiesteelerisposte.ComeperASP.NETMVC,anche per ASP.NET WebAPI dobbiamo sempre distinguere quale runtime vogliamosfruttaree,diconseguenza,lelimitazionioledifferenzecheneconseguono.Sesfruttiamo

Page 405: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

il .NETFramework4.6,utilizziamounframeworkcostruitoafiancodiASP.NETMVC,simile,comeabbiamogiàdetto, inmolticoncettimaancheconclassidalnomeuguale,peròappartenenti anamespacediversi.ConASP.NETCore1, invece,grazieallanuovaarchitettura,ASP.NETWebAPIeASP.NET

MVCsi fondono, condividendogranpartedel codice.Tuttoquestocomunquenoncideve spaventare, perché sebbene cambi molto sotto il cofano, i servizi scritti con unaversione possono facilmente essere portati su un’altra, apportando piccole modifiche,proprioperchéiconcettieimodisonoglistessi.

QuandovogliamosfruttareASP.NETWebAPI,quindi,dobbiamopartire sempredallaversione del .NET Framework da sfruttare. Esso può vivere da solo o in unione adASP.NETMVC,spuntandogliappositiflag,comesipuònotarenellafigura17.1.

Figura17.1–SelezionediunprogettoASP.NETWebAPIperASP.NET4.6oASP.NETCore1.

Una volta creato il progetto, oltre alle risorse web e ai controller di ASP.NETMVC,possiamo trovare anche una classe di nomeValuesController all’interno della cartellaControllers.Questaclasseèdefinitacomesipuòvederenell’esempio17.1.

Esempio17.1PublicClassValuesController

Page 406: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

InheritsApiController

'GET:api/Values

PublicFunction[Get]()AsIEnumerable(OfString)

ReturnNewString(){"value1","value2"}

EndFunction

'GET:api/Values/5

PublicFunction[Get](idAsInteger)AsString

Return"value"

EndFunction

'POST:api/Values

PublicSubPost(<FromBody>valueAsString)

EndSub

'PUT:api/Values/5

PublicSubPut(idAsInteger,<FromBody>valueAsString)

EndSub

'DELETE:api/Values/5

PublicSubDelete(idAsInteger)

EndSub

EndClass

Possiamo subitonotare che alnomedella classe segue il suffissoController comenelcaso di ASP.NET MVC. Questo significa che il controller appena definito rispondeall’indirizzo speciale api/nome e, nel caso dell’esempio specifico, all’indirizzoapi/values. A differenza di ASP.NET MVC, tutti i servizi che andiamo a definirerientranosottoilpercorsoapi,perdistinguerlidaquellidedicatiallarealizzazionediviste.Inoltre la classe non eredita da Controller, ma da ApiController, e fornisce metodispecifici per la realizzazione di servizi. Questa distinzione non è presente se stiamousandoASP.NETCore1.

Proseguendo con l’analisi dell’esempio 17.1, possiamo notare varie funzioni, aventinomiGet,Post,Put eDelete.Comepossiamo immaginare, queste funzionihanno ilcompito rispettivo di restituire una risorsa, aggiungerla, aggiornarla e cancellarla. Percapirecosaquestosignifichi,sfruttiamounostrumentodinomeFiddler,ilqualepermettedi intercettare tutte le richieste HTTP, anche quelle fatte dai browser, ma anche dicomporre richieste e analizzarne il contenuto. Procediamo quindi eseguendo la nostraapplicazionewebconF5eapriamoFiddler.Nellasezionecomposerpossiamosceglierediutilizzare il metodo HTTP GET con l’indirizzo di testhttp://localhost:50277/api/values,comenellafigura17.2.

Page 407: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura17.2–CreazionediunarichiestaGETtramiteFiddler.

PremendoilpulsanteExecutecreiamounarichiestaHTTPcomequelladell’esempio17.2.

Esempio17.2GEThttp://localhost:50277/api/valuesHTTP/1.1

User-Agent:Fiddler

Host:localhost:50277

Larispostacheotteniamoèinvecevisibilenell’esempio17.3.

Esempio17.3HTTP/1.1200OK

Content-Type:application/json;charset=utf-8

Expires:-1

X-Powered-By:ASP.NET

Date:Fri,31Jul201514:46:49GMT

Content-Length:19

["value1","value2"]

Possiamo notare che la risposta ottenuta è serializzata in JSON, un formato moltocompatto proveniente da JavaScript e manipolabile ormai da qualsiasi linguaggio. Inquesto caso quello che otteniamo è un array di stringhe e da questo si evince che lafunzionechiamatasullaclasse

ValuesController è il metodo Get, senza parametri. Possiamo effettuare la stessachiamata inserendo l’indirizzo in un browser, il quale, in modo predefinito, effettuasempreunachiamataGET.Ilrisultatoèlavisualizzazionedellestringheavideo.

Se invece eseguiamo la chiamata adapi/values/5 (o qualsiasi altro numero valido)otteniamo l’invocazione della seconda funzione Get, la quale accetta un intero. Questoperché il motore è in grado di distinguere le chiamate a seconda del percorso e dei

Page 408: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

parametri che passiamo. Il parametro id è speciale, come in ASP.NETMVC, e vienerecuperato dall’ultima parte dell’indirizzo. Come possiamo facilmente intuire, secambiamoilmetodoHTTPinPUT,POSToDELETEotteniamol’invocazionedellealtrerispettivefunzioni.Questomeccanismoèallostessotemposemplice,mapotente,poichésfruttabiledaqualsiasi tecnologia, da JavaScript all’internodi unapagina Internet, a unsemplicegeneratoredirichieste,comeFiddler.

Quello che fa ASP.NETWebAPI, quindi, è trasformare le richieste nell’invocazionedella rispettiva funzione e tradurre poi la relativa risposta. Trovare il significato e larispettiva implementazione spetta a noi; l’esempio 17.1, infatti, non esegue alcunaoperazioneedènostrocompitoinvocarequerysuldatabaseometodisuserviziapplicativiperl’esecuzionematerialedellarichiesta.

LaserializzazioneeilmodelbindingLatrasformazionedellerichiesteedellerisposteèmoltopotenteedèingradodigestireancheoggetticomplessi.Invecedirestituireunastringa,possiamocreareunoggettopiùcomplesso,comenell’esempio17.4.

Esempio17.4PublicFunction[Get](idAsInteger)AsCustomer

ReturnNewCustomer()With{

.FirstName="Pippo",

.LastName="Pluto"

}

EndFunction

Ciòcheotteniamodaun’interrogazionealservizioèilJSONvisibilenell’esempio17.5.

Esempio17.5{FirstName:"Pippo",LastName:"Pluto"}

LaserializzazioneèaffidataaJson.NET,unpotentemotoreopensourcecheèingradoditrasformare in JSON tutte le classi e i membri pubblici, anche di grafi complessicontenentiproprietàalorovoltaditipocomplesso.

Un aspetto interessante del motore di ASP.NETWebAPI sta nel supporto a onorarel’headerHTTPAccept.Conesso,chiesegue la richiestapuòchiedere inche formatosiaspetta larisposta,sequest’ultimoèsupportatodalservizio.InserendoquindiunheaderAccept: application/json (o omettendolo) otteniamo quindi una serializzazione inJSON,comeabbiamogiàvisto.Conl’headerAccept:text/xml,invece,indichiamochevogliamolarispostaserializzatainXML(tral’altroilcomportamentopredefinitodimoltibrowser).Inquestocaso,vienesfruttatalaclasseDataContractSerializerperprodurre

Page 409: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

l’XMLvisibilenell’esempio17.6.

Esempio17.6<Customer

xmlns="http://schemas.datacontract.org/2004/07/Capitolo17.Controllers">

<FirstName>Pippo</FirstName>

<LastName>Pluto</LastName>

</Customer>

Questi due formati sono quelli direttamente supportati da ASP.NET WebAPI, mapossiamoscriveredeiformatterpersonalizzatiperaggiungernealtri.

Possiamo sfruttare gli oggetti complessi anche come parametri di input nelle nostrefunzioni,comenell’esempio17.7.

Esempio17.7PublicSubPost(customerAsCustomer)

'TODO:chiamataaldb

EndSub

Inquestocaso,ilbodydellarichiestaHTTPdevecontenereilclienteserializzatoinJSONo XML. Per far sì che ASP.NET WebAPI sappia che motore usare per la creazionedell’oggettoCustomer, esiste un altro headerHTTP che lo standard indica di usare perquesti scopi:Content-Type.Questo header può assumere imedesimi valori diAccepterichiede che il servizio lo supporti. Comunque, grazie ad ASP.NET WebAPI, nondobbiamofarnull’altrochelavorareadaltolivellospecificandocheoggettovogliamo.Inquesto caso il processo che viene invocato si chiamamodel binding e seguedinamichemolto flessibili per la trasformazione della richiesta verso l’invocazione della funzione.Per esempio, possiamo inserire parametri aggiuntivi alla funzione, come nell’esempio17.8.

Esempio17.8PublicFunction[Get](idAsInteger,withDetailsAsBoolean)AsCustomer

'TODO:chiamata

ReturnNewCustomer()

EndFunction

Ilmotoreèingradodirecuperareilvaloredallaquerystringedeffettuarelaconversionedeltipo,permettendocidiinvocarel’indirizzoapi/customers/5?withDetails=true.

Così facendo, rendiamo obbligatorio l’utilizzo del parametro withDetails, ma

Page 410: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

possiamo sfruttare i parametri opzionali o i default value per permettere di invocare lafunzioneanchesenzaspecificareilvalore.

LeactioneimetodiHTTPLefunzionicheabbiamovistofinorarispecchiamosempreilmetodoHTTPchevogliamosupportarema,inrealtà,questaèsolounaconvenzione.Ilmotore,inrealtà,èingradodiidentificarelefunzioniconirispettivimetodiancheconnomiaventicomeprefissoGet,Put,Post,Deleteecosìvia.QuestosignificacheunafunzioneGetCustomerèinvocabileallostessomododiquantovistofinora.Nelcasoincuiquestaconvenzionecistiastretta,possiamo utilizzare qualsiasi nome e ricorrere all’uso degli attributi che, come inASP.NETMVC, sono determinanti per personalizzare i comportamenti. Nel caso delleaction, possiamo sfruttare gli attributi HttpGet, HttpPost, HttpPut e HttpDelete permarcarelefunzionicherispondonoairispettivimetodiHTTP,comenell’esempio17.9.

Esempio17.9<HttpGet>

PublicFunctionFindCustomer(idAsInteger)AsCustomer

ReturnNewCustomer()

EndFunction

<HttpPut>

PublicSubUpdateCustomer(customerAsCustomer)

'TODO:implementare

EndSub

Qualoranonbastasse,con l’attributoAcceptVerbspossiamoelencare la listadeimetodiHTTP ai quali la funzione risponde. Oltre ai quattro visti finora, ce ne sono tanti altriprevistidallostandardHTTP.

Leconvenzioninonsonol’unicomodoperindicareilpercorsoconcuiraggiungereuncontrollereunaaction.NonsemprevogliamooffrireunapproccioCRUDQ(Create,Read,Update, Delete, Query) al nostro servizio, ma vogliamo esporre API mirate ad azionispecifiche,comelaconfermadiunordine,lagenerazionediunreportecosìvia.Inquesticasipossiamosfruttarel’attributoRouteAttributecheciconsentedispecificarel’interoindirizzorelativoconilqualeraggiungerel’azione,comenell’esempio17.10.

Esempio17.10<Route("api/customers/confirm/{id}-{code}")>

<HttpPut>

PublicSubConfirm(idAsInteger,codeAsString)

'TODO:implementare

Page 411: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndSub

Nelcodiceèmostratocomepossiamospecificareilpercorsoassolutoancheignorandoilnome del controllo o cambiando il percorso iniziale api stabilito per ogni servizio.All’interno dell’indirizzo possiamo inoltre indicare dei segnaposti, identificati dal nomecontenuto tra graffe. Essi devono necessariamente essere divisi da un separatore erappresentano iparametriche la funzionesiaspetta.Nell’esempio17.10richiediamounid intero seguito dal code come stringa. Da notare, infine, che è sempre buona normaspecificareconl’attributoiltipodimetodoHTTPsupportato,alfinedimirarealmegliolafunzione. Qualora, infatti, la richiesta venga fatta a un indirizzo corretto ma con unmetodoHTTPsbagliato,vienegenerataautomaticamenteunarispostaditipo405MethodNotAllowed.Seinvecel’indirizzoèsbagliato,vienegeneratoun404NotFound.QuestistatuscodesonounaltrofattoreimportantechecontraddistingueiserviziRESTfulperchérappresentanol’esitodell’operazione

LetipologiedirisultatodelleactionFinora abbiamo visto semplici definizioni di funzioni, le quali restituiscono void o unoggetto,primitivoocomplessochesia.Sel’esecuzionedelnostrocodicevaabuonfine,larispostageneratacontieneilrisultatoserializzato,maanchel’esitodell’operazione: lostatus code.Nell’esempio 17.3 abbiamo potuto notare il 200 OK che indica appunto lacorrettaelaborazionedellarichiesta.Unafunzionecherestituiscevoid,invece,determinaun204NoContent,mentreun’eccezionegeneraun505InternalServerError,perciòinquestomodopossiamodecidere come informare chi fa la richiesta dell’esito.Questoperò non è sempre sufficiente, perché la nostra funzione può necessitare di effettuarevalidazioniodicontrollarel’esistenzadell’elementosucuistalavorando.

In questi casi dobbiamo cambiare la firma della funzione e far restituire un tipoIHttpActionResult. Esistono molteplici classi che implementano questa interfaccia aseconda che vogliamo restituire uno specifico status code, con o senza oggetto daserializzare.

Nell’esempio17.11 possiamo vedere come sfruttare questa interfaccia per rispondereconlostatuscodeadeguatoinbaseall’esitodell’operazione.

Esempio17.11PublicFunction[Get](idAsInteger)AsIHttpActionResult

DimcustomerAsCustomer=FindCustomerOnDatabase(id)

IfcustomerIsNothingThen

'RitornaNotFoundResult

ReturnNotFound()

EndIf

'RitornaOkNegotiatedContentResult

Page 412: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ReturnOk(customer)

EndFunction

Dal codice notiamo alcune funzioni speciali fornite dalla classe ApiController, qualiNotFoundeOk rispettivamentepercreareunarispostacheidentifichiunerrore404oun200conl’oggettodellarisposta.Sonodisponibilidiversefunzioniasecondadellostatuscodechevogliamogenerare,comeRedirect,BadRequestoilpiùgenericoStatusCode.

Se invece tutto questo nonbastasse, la nostra funzione può restituire direttamente unHttpResponseMessage, oggetto con il quale abbiamo il completo controllo di tutta larisposta,dagliheaderHTTPfinoalbinariodelbody.Questooggettovacreatopartendodallarichiesta,espostadallaproprietàRequest,sempredellaclasseApiController.

Esempio17.12PublicFunction[Get](idAsInteger)AsHttpResponseMessage

'Risposta200

Dim response As HttpResponseMessage =

Request.CreateResponse(HttpStatusCode.OK)

'Impostoilcontenutodellarisposta

response.Content=NewStringContent("hello",Encoding.Unicode)

'Controllol'headerdicache

response.Headers.CacheControl=NewCacheControlHeaderValue()With{

.MaxAge=TimeSpan.FromMinutes(20)

}

Returnresponse

Nell’esempio 17.12 possiamo vedere la prima istruzione che ha il compito di generarel’HttpResponseMessage.Sonodisponibilivarioverloadchepermettonodispecificarelostatuscodechevogliamo,ilcontenutodaserializzareeilcontent-typedaimpostare.

Unavoltageneratol’oggetto,abbiamoaccessoatutteleinformazioni.Primatratutteèla proprietà Content che rappresenta il contenuto che segue gli header HTTP.Nell’esempioimpostiamounoStringContent,cioèunastringachevienepoitrasformatainbinarioattraversolespecificheUnicode.LaproprietàHeaders,invece,cidàaccessoaldizionariodegliheader,consentendocidipersonalizzaregli aspetti relativiallacache,alcontenuto, ai cookieo alle informazionipersonalizzate.Nell’esempio17.12 impostiamouna cache di 20 minuti che consente al browser o, in generale, al client di evitare dieffettuareulteriori richiestenell’intervallodanoi indicato. Infine, la funzione restituiscel’oggettodellarisposta,ilqualegeneraquantoèvisibilenell’esempio17.13.

Esempio17.13

Page 413: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

HTTP/1.1200OK

Cache-Control:max-age=1200

Content-Length:10

Content-Type:text/plain;charset=utf-16

Date:Fri,31Jul201520:05:13GMT

hello

TornandoallaproprietàContent,impostatanell’esempio17.12,dobbiamoaggiungerechepuòesseredidiversetipologie,lecuipiùimportanti,oltrealgiàmostratoStringContent,sono:

StreamContent: scrive il contenuto leggendolo direttamente da uno Stream dibyte,ottenuto,peresempio,daunfile;

ByteArrayContent:scriveilcontenutodaunarraydibyteinmemoria;

FormUrlEncodedContent: scrive il contenuto effettuando l’encoding URL di undizionariochiavevalore.Peresempio:param1=valore1&param2=valore2;

MultipartContent: scrive il contenuto aggregando più contenuti separati da unboundaryspecialetraquelliindicatiinprecedenza.

AnchelarichiestaèrappresentatainmodomoltosimiledallaclasseHttpRequestMessage.Può essere letta, come abbiamo già visto nell’esempio 17.12, dalla proprietà Request,oppure,equestoèilmetodoconsigliato,comeparametrodirettamentedellafunzione.Conessa possiamo accedere in modo grezzo alla richiesta, leggere gli header e i byte delcontenuto,comenell’esempio17.14.

Esempio17.14PublicFunction[Get](requestAsHttpRequestMessage)AsTask(Of

HttpResponseMessage)

'HeaderIf-Match

Dimtag=request.Headers.IfMatch.First().Tag

'Leggoilcontenutocometesto

Dimtext=Awaitrequest.Content.ReadAsStringAsync()

Returnrequest.CreateResponse(HttpStatusCode.OK)

EndFunction

Nell’esempio leggiamo un header e, cosa più interessante, leggiamo il contenuto dellarichiestacomestringa.Danotarel’usodellafunzioneasincronaReadAsStringAsync,datochenonesistonolecorrispondentifunzionisincrone,perunaquestionediscalabilità.Ciòsignificacheanchelanostrafunzionedevediventareasincrona,maquestononcostituisceunproblema.ÈsufficienteapporrelaparolaasyncefarrestituireunTask<T>,invececheT, dove T può essere un HttpResponseMessage, un IHttpActionResult o un nostrooggetto. Il motore di WebAPI si fa carico di gestire la rientranza del thread e il

Page 414: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

marshallingdelcontestodellarichiesta.

Quantoabbiamovistofinoraèsufficienteperesporreunserviziowebadeguatoaitempimoderni,maconunpo’diesperienzaciaccorgeremochespessoiservizisonoripetitivitraloroelaloroimplementazioneèmoltosimile.LoscaffoldingdiVisualStudio2015civieneinaiuto.

LoscaffoldingdelleWebAPILarealizzazionediunservizioèchiaramenteanostradiscrezione.Essopuòfornire,comeabbiamo visto, operazioni specifiche in base alle logiche di business, oppure offrire unapproccio più aperto di lettura e manipolazione dei dati. Se stiamo utilizzando tuttetecnologieMicrosoft,moltoprobabilmentestiamosfruttandoancheEntityFrameworkperfacilitarciinquestogeneredioperazioni.

Lo scaffoldingdiVisualStudio2015è l’ideale inquestogeneredi situazioni,perchédataun’entitàcipermettediottenereautomaticamenteunserviziocontutteleoperazionidi CRUDQ effettuate direttamente su Entity Framework. Di fatto è un generatore dicodice, dal quale possiamo partire, eventualmente, per apportaremodifiche.Quando daVisualStudio2015sullacartellaControllersaggiungiamounnuovocontroller,civienepropostalafinestradellafigura17.3.

Figura17.3–CreazionediuncontrollerWebAPItramitescaffolding.

PossiamovedereevidenziatalavocechegeneraleazioniattraversoEntityFramework.IlmeccanismoèdeltuttosimileadASP.NETMVC,cheabbiamosfruttatonelcapitolo16,einfattipossiamovederelerelativevoci.Seproseguiamo,civienediconseguenzachiestoqualèilcontestodiEntityFrameworkdautilizzareel’entitàchevogliamoesporre,oltrealnomedelcontroller.Iltuttocivienemostratoconalcunecomboboxchecipermettonodi

Page 415: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

selezionareoggetticreatiprecedentemente,comeèvisibilenellafigura17.4.

Figura17.4–Finestraperlaconfigurazionedelloscaffolding.

Confermando la finestra, viene così generata una classe EFCustomersController, dellaqualepossiamovedereunestrattonell’esempio17.15.

Esempio17.15PublicClassEFCustomersController

InheritsApiController

PrivatedbAsNewSampleContext()

'GET:api/EFCustomers

PublicFunctionGetCustomers()AsIQueryable(OfCustomer)

Returndb.Customers

EndFunction

'GET:api/EFCustomers/5

PublicFunctionGetCustomer(idAsInteger)AsIHttpActionResult

DimcustomerAsCustomer=db.Customers.Find(id)

IfcustomerIsNothingThen

ReturnNotFound()

EndIf

ReturnOk(customer)

EndFunction

'POST:api/EFCustomers

Public Function PostCustomer(customer As Customer) As

IHttpActionResult

IfNotModelState.IsValidThen

ReturnBadRequest(ModelState)

Page 416: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndIf

db.Customers.Add(customer)

db.SaveChanges()

ReturnCreatedAtRoute("DefaultApi",NewWith{

.id=customer.Id

},customer)

EndFunction

EndClass

Possiamo notare che vengono generate tutte le operazioni, come nell’esempio17.1,maimplementatesfruttandoEntityFramework.VieneistanziatoilcontestoalivellodiclasseesonosfruttatilaproprietàCustomerseilmetodoSaveChangesperaccederealDbSeteapportareicambiamenti.PermotividispazioabbiamoomessolealtreoperazionidiPutoDelete,ma l’implementazione è del tutto simile.Come inASP.NETMVC, anche nellenostreWebAPI disponiamo della proprietà ModelState, che sfruttiamo per capire se larichiestaricevutaèvalidaoppureno.Perstabilirlo,ilmotoredivalidazionesfruttaledataannotation, quel meccanismo già sfruttato nel capitolo 16 per mostrare l’HTML dimodificadiunaproprietà,einoltreconsenteaEntityFrameworkdimodellareildatabaseinmodo opportuno. Lo stesso serve anche per capire se una proprietà è obbligatoria equaliregoledeverispettare.NelnostrocasolaclasseCustomerècosìdefinita.

Esempio17.16PublicClassCustomer

PublicPropertyId()AsInteger

Get

Returnm_Id

EndGet

Set

m_Id=Value

EndSet

EndProperty

Privatem_IdAsInteger

<Required>

<MaxLength(200)>

PublicPropertyFirstName()AsString

Get

Returnm_FirstName

EndGet

Set

Page 417: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

m_FirstName=Value

EndSet

EndProperty

Privatem_FirstNameAsString

<Required>

<MaxLength(200)>

PublicPropertyLastName()AsString

Get

Returnm_LastName

EndGet

Set

m_LastName=Value

EndSet

EndProperty

Privatem_LastNameAsString

EndClass

DifattorendiamoobbligatorioFirstNameeLastNameeconsentiamounmassimodi200caratteri, indipendentementedal formatoJSONoXMLutilizzatodalla richiesta. Incasocontrario,l’invocazionediBadRequestgeneraunerrore404BadRequesterispondeconglierroridivalidazione.Nell’esempio17.17vediamolarispostaHTTPottenutainseguitoaunarichiestaerrata.

Esempio17.17HTTP/1.1400BadRequest

Content-Type:application/json;charset=utf-8

Date:Sat,01Aug201509:53:16GMT

Content-Length:172

{"Message":"Therequestisinvalid.","ModelState":{"customer.FirstName":

["Il campo FirstName è obbligatorio."],"customer.LastName":["Il campo

LastNameèobbligatorio."]}}

Lo scaffolding è sicuramente uno strumento molto comodo, ma la realizzazione di unservizioinquestomodononèsufficienteperscenarirealidiutilizzo.L’interrogazionedeidati tramite richiestaGETè limitataal semplice recuperodi tutte leentità. IlprotocolloODatavaoltre questa limitazione, definendo alcune specificheper rendere i servizi piùcompleti.

SupportareilprotocolloOData

Page 418: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

LostandardOpenDataProtocol(OData)èormaigiuntoallaversione4ehaloscopodidefinire delle regole per consumare servizi principalmente orientati ai dati. Sebbene iserviziRESTfulsfruttinolecaratteristichediHTTPperindicarechevogliamoottenereomodificare una risorsa, non sono sufficienti per indicare, per esempio, quanti recordvogliamoottenere,seordinarli,filtrarliecosìvia.Dovremmoquindisfruttareilcontenutodi una richiesta per definire un’entità oppure sfruttare la query string per indicare tuttequeste informazioni, e infine documentare il tutto per istruire chi fa la richiesta. LostandardODatadefiniscegiàtuttoquesto,inmododiaveredellespecifichecrossplatformecrosslanguage,conilvantaggiodiparlarelastessalinguaoltreche,equestononèpoco,averegiàframeworkchesappiamoparlareOData.ASP.NETWebAPIèunodiquestieinpochipassicipermettedirealizzareservizichesupportinolostandard.

Il primo passo da fare è installare il pacchetto NuGet con IDMicrosoft.AspNet.WebApi.OData il quale contiene le estensioni necessarie per farfunzionare il tutto. Successivamente, dobbiamo modificare il file WebApiConfig.cscontenuto nella cartella App_Start, nel quale vengono configurati tutti gli aspetti delleWebAPI.NellafunzioneRegisterdobbiamoaggiungerelachiamataall’extensionmethodAddODataQueryFilter,comevienemostratonell’esempio17.18.

Esempio17.18PublicNotInheritableClassWebApiConfig

PublicSharedSubRegister(configAsHttpConfiguration)

'WebAPIconfigurationandservices

config.AddODataQueryFilter()

'WebAPIroutes

config.MapHttpAttributeRoutes()

'Altro...

ConquestasempliceistruzioneabilitiamoODataatutti iservizidelnostroprogettoeinparticolare lo abilitiamo su tutte le action che restituisconounIQueryable<T>, come lafunzione GetCustomers dell’esempio 17.15. Questa interfaccia, che Entity Frameworksupporta,permettedieffettuarequeryLINQeditradurlepoiinquerysuldatabase,conilmassimo dell’ottimizzazione. In questo modo, quando effettuiamo una richiesta GETpossiamo sfruttare tutte le estensioni definite da OData per l’interrogazione, quali$expand,$filter,$inlinecount,$orderby,$select,$skip,$top.Sono tuttiparametriquery string che permettono rispettivamente di caricare entità figlie, filtrare i record,ottenere il numero degli elementi, ordinare, selezionare solo alcuni campi, saltare oottenere solo alcuni record. All’indirizzo http://aspit.co/a6b possiamo trovaremaggioridettagli riguardanti le specifiche,mapossiamovederesubitoqualchesempliceesempiodirichiesteGET:

api/efcustomers?$skip=10&$top=5:recupera5recordsuccessiviaiprimi10;

api/efcustomers?$filter=indexof(FirstName,'pippo')gt0:filtracercando

Page 419: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

pipponellaproprietàFirstName;

api/efcustomers?$select=FirstName&$orderby=LastName: seleziona solo laproprietàFirstNameeordinailrisultatoperLastName.

Poche parole chiave sono sufficienti per ottenere già molto nell’interrogazione di unservizio,idealepergliscenaripiùcomuni.

OData,però,famoltodipiùedefinisceanchealtriaspetti.Primofratuttièlacapacitàdioperaresupiùentità,consentendodinavigare,peresempio,all’internodegliordinidiunclienteodifiltrareinbaseaproprietàcomplessefiglie.Ilservizioquindinondiventapiù dedicato a una singola entità, ma all’intero contesto. Per questo motivo, ODataprevede anche la possibilità di esporre dei metadati, utili a capire quali sono le entitàesposte e quali proprietà contengono, per poi generare dei proxy per i vari linguaggi.Infine,ODataconsenteanchedieffettuareoperazionimassive(piùCreate/Update/Delete)contemporaneamente in una sola richiesta, rendendola di fatto transazionale. Supportainoltrelapossibilitàdieffettuaremergeepatchdelleentità.

AncheinquestocasoilframeworkdedicatoadASP.NETWebAPIcivieneinaiuto,madobbiamoscrivereunpo’dicodiceinpiù.Loscaffoldingcipuòdareunamanoancheinquestoaspetto.

EffettuareloscaffoldingperODataNella figura17.3 possiamo vedere che, oltre allo scaffolding classico, esiste anche unoscaffoldingdedicatoaOData.Ilmeccanismoèilmedesimomalaclassecheotteniamoèdifferente.EssaereditadaODataControllerevengonosfruttatinuoviattributiperistruireil motore di binding su come prendere l’id o gestire il patching. Possiamo vederne unestrattonell’esempio17.19.

Esempio17.19PublicClassODataCustomersController

InheritsODataController

PrivatedbAsNewSampleContext()

'GET:odata/ODataCustomers

<EnableQuery>

PublicFunctionGetODataCustomers()AsIQueryable(OfCustomer)

Returndb.Customers

EndFunction

'GET:odata/ODataCustomers(5)

<EnableQuery>

Public Function GetCustomer(<FromODataUri> key As Integer) As

SingleResult(Of

Page 420: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Customer)

Return SingleResult.Create(db.Customers.Where(Function(customer)

customer.Id=key))

EndFunction

'PUT:odata/ODataCustomers(5)

PublicFunctionPut(<FromODataUri>keyAsInteger,patchAsDelta(Of

Customer))AsIHttpActionResult

'Validazionedell'entità

Validate(patch.GetEntity())

IfNotModelState.IsValidThen

ReturnBadRequest(ModelState)

EndIf

DimcustomerAsCustomer=db.Customers.Find(key)

IfcustomerIsNothingThen

ReturnNotFound()

EndIf

'Modifical'entitàappenarecuperatadaldb

patch.Put(customer)

Try

db.SaveChanges()

CatchgeneratedExceptionNameAsDbUpdateConcurrencyException

'Gestionediconflittidiversione

IfNotCustomerExists(key)Then

ReturnNotFound()

Else

Throw

EndIf

EndTry

ReturnUpdated(customer)

EndFunction

EndClass

Notiamo subito che il codice è più complesso. Le funzioni di GET sono marcate conl’attributo EnableQueryAttribute, che è facoltativo ma permette di specificare qualioperazioni di query consentire. Per esempio, potremmo decidere di non consentirel’ordinamento o di limitare il numero di record che possiamo restituire. L’attributoFromODataUriAttribute, invece, indica che il parametro key arriva dall’indirizzo ed ècontenutonelleparentesitonde.ODataprevedecheessovengaspecificatocosì,come,per

Page 421: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

esempio,odata/ODataCustomers(5).LafunzionediPUTèinvecepiùarticolata,perchégestisceilpatching,l’eventualeconflittodiversione,oltreallagiàvistavalidazione.

Una volta fatto lo scaffolding, dobbiamo però effettuare un’ultima modifica al fileWebApiConfig.cs.Dobbiamoistruireilmotoreconunnuovoendpointchesiaingradodiaggregarepiùservizifacentipartedellostessoinsieme,consentendocosìdinavigaretraloroeottenereimetadati.Nell’esempio17.20vediamoilfilemodificato.

Esempio17.20PublicNotInheritableClassWebApiConfig

PublicSharedSubRegister(configAsHttpConfiguration)

'WebAPIconfigurationandservices

config.AddODataQueryFilter()

'Creoilsetdientità

Dimbuilder=NewODataConventionModelBuilder()

builder.EntitySet(OfCustomer)("odatacustomers")

'ConfigurazioneOData

config.Routes.MapODataServiceRoute("odata", "odata",

builder.GetEdmModel())

Una volta fatto questo, tramite l’indirizzo odata/$metadata possiamo ottenere ladescrizione del nostro servizio, con entità e relative proprietà, come viene mostratonell’esempio17.21.

Esempio17.21<?xmlversion="1.0"encoding="UTF-8"?>

<edmx:Edmxxmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"

Version="1.0">

<edmx:DataServicesxmlns:m="http://schemas.microsoft.com/ado/2007/08/

dataservices/metadata"m:DataServiceVersion="3.0"

m:MaxDataServiceVersion="3.0">

<Schemaxmlns="http://schemas.microsoft.com/ado/2009/11/edm"

Namespace="Capitolo17.Data">

<EntityTypeName="Customer">

<Key>

<PropertyRefName="Id"/>

</Key>

<PropertyName="Id"Type="Edm.Int32"Nullable="false"/>

<Property Name="FirstName" Type="Edm.String" Nullable="false"

Page 422: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

/>

<Property Name="LastName" Type="Edm.String" Nullable="false"

/>

</EntityType>

</Schema>

<Schemaxmlns="http://schemas.microsoft.com/ado/2009/11/edm"

Namespace="Default">

<EntityContainer Name="Container"

m:IsDefaultEntityContainer="true">

<EntitySet Name="odatacustomers"

EntityType="Capitolo17.Data.Customer"

/>

</EntityContainer>

</Schema>

</edmx:DataServices>

</edmx:Edmx>

All’indirizzo odata/odatacustomers troviamo l’entità Customer, sulla quale possiamoeffettuare le classiche operazioni. La speciale implementazione però, ci permette dieffettuarequeryinGETsuodata/odatacustomers(1)/ordersperaccedere,peresempio,agli ordini del cliente con id 1. In questo caso dobbiamo creare un altro servizio perserviregliordinieaggiungerloallaregistrazionedelmodellofattanell’esempio17.19.

IserviziOData,quindi,siprestanomoltobeneperl’interrogazioneemanipolazionedistrutture dati, ma in ASP.NET è disponibile un altro framework, che copre un’altraesigenza:lacreazionediservizireal-time.

Createservizireal-timeattraversoSignalRComeabbiamodettoall’iniziodelcapitolo,iservizisonodiffusiinqualsiasitipologiadiapplicazione.Tramiteiclient,dallepagineHTMLfinoalleappmobile,essipermettonodiinterrogareemodificareidati.Il loroampiousohaportatoaunaseriediottimizzazioniper migliorare il traffico di rete, la loro efficienza e la velocità di comunicazione. Suquestoaspetto,sonosemprepiùiclientchenecessitanodiinformazioniinreal-time,cioèchegiunganoilprimapossibilealclientnonappenaquestesonodisponibili.Notifichediunsocialnetwork,informazionisultraffico,sistemidichatemonitoraggiodiattivitàsonoalcuni degli esempi che siamo ormai abituati ad utilizzare che sfruttano comunicazionireal-time.

Perottenerequestogradodiprestazioni,ilprotocolloHTTPèstatoestesoconunnuovostandard di nomeWebSocket, che ha lo scopo dimantenere un canale bidirezionale traclient e server. In questo modo il canale è sempre pronto e permette al client dicomunicarealserverma,fattoancorapiùimportante,permettealserverdicomunicareal

Page 423: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

client,unacosachenonpossibile tramite ilnormaleHTTP.Con ildiffondersidiquesteesigenze e dell’implementazione di questo protocollo, anche IIS e ASP.NET si sonoattrezzati con strumenti che permettono di realizzare scenari real-time. Lo strumentodisponibileperfarloconASP.NETsichiamaSignalRepermettedicrearedelleAPIRPC,cioè che permettono al client e al server di invocare funzioni l’uno con l’altro.Da unaparte fornisce l’infrastruttura per ASP.NET per gestire le connessioni e permettere diinvocare i client, dall’altra mette a disposizione librerie in più linguaggi, comeObjectiveC, Java, JavaScript, Visual Basic e C#, le quali gestiscono in autonomia laconnessioneelamantengonoincasodiinterruzioni.

Cosaancorapiùimportante,SignalRpermettedicreareservizireal-timesfruttandopiùtrasporti. Il citatoWebSocketè ilmiglioreperquestoobiettivo,manonèsupportatodatutti i web server e da tutti i client, perciò SignalR si fa carico di utilizzare tecnichealternativepersimulareunacomunicazionebidirezionale.QuestetecnichesonoilServerSentEvent,ilForeverFrameel’AJAXLongPollinge,sostanzialmente,sfruttanol’HTTPoalcunecaratteristichedeibrowserper cercaredimantenerecanali sempreattivi con ilserver,inmododareagirenonappenasuccedequalcosa.Comunque,comeabbiamodetto,questidettaglisonoautomaticamentegestitiinmododasupportarelatotalitàdeibrowseredellepiattaforme,epossiamosemplicementegoderediquestomotore.

Per partire dobbiamo prima di tutto scaricare il pacchetto NuGet con IDMicrosoft.AspNet.SignalRe,successivamente,dobbiamocreareunhub.

L’hubcomeserviziobidirezionaleL’hubèilpuntodiincontrotrailclienteilserveredefinisceleAPIRPCcheilservereiclientmettono a disposizione. Un hub è sostanzialmente una rappresentazione logica epermette alle connessioni fisiche, mantenute da SignalR, di veicolare messaggi a unaspecificaoperazionedelclientodelserver.Perquestomotivoesisteunhubsulserver,maaltrettanto un hub sul client, che è speculare alle operazioni del server. Sul client èpresente una sola istanza che permette di invocare operazioni e agganciare gli eventi,mentresulserver l’unica informazionepersistentesonoleconnessionichecreanol’hub,fannoeseguirel’operazionerichiestaelorilasciano.

Dopo questa breve introduzione quindi, partiamo nella creazione di hub, passandosempredalmenudiVisualStudio2015perl’aggiuntadiunnuovoelemento.Comevienemostratonellafigura17.5,disponiamodiunavoceapposita.

Page 424: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura17.5–CreazionediunnuovohubdaVisualStudio2015.

L’hub è una normale classe che ha la particolarità di ereditare da Hub, del namespaceMicrosoft.AspNet.SignalR.Hub. In esso definiamo tutte le operazioni, sotto forma dimetodi/ funzioni, che vogliamo rendere richiamabili dal client. Nell’esempio 17.22possiamovederelaclassechevienegeneratadaVisualStudio2015.

Esempio17.22PublicClassCustomersHub

InheritsHub

PublicSubHello()

Clients.All.hello()

EndSub

EndClass

Il metodo Hello, in modo molto simile a quanto facciamo con ASP.NET WebAPI,rappresentaunafunzioneinvocabiledalclient.Questo,dipersé,nonrappresentanientedinuovo, dato che anche i servizi RESTful sono così; è interessante invecel’implementazione, poiché viene invocata una omonima funzione hello sull’oggettoClients.All.Inrealtàquestafunzionenonesisteo,meglio,nonèdefinitaesipresumecheilclient laesponga,e tramite l’esposizionediun tipodynamic riusciamoa invocarequalsiasifunzionenoivogliamo.Questosignificacheasuavoltailserviziochiamatuttiiclient connessi nello stesso momento e inoltra il saluto. SignalR si fa caricoautomaticamentedisaperequalisonoiclientconnessiediinvocarneilmessaggio,iltuttoin real-time, senza preoccuparci dello strato di trasporto.Clients è una proprietà dellaclasse Hub che, come vedremo, ci consente di invocare tutti o alcuni client. Ci sono

Page 425: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

situazioni in cui vogliamo richiamare i client in altri contesti, come all’interno di unapaginaweb o di un servizio. In questi casi possiamo facilmente ottenere un’istanza delcontestodiunhuberitrovarciconlamedesimaproprietàClients,comevienemostratonell’esempio17.23.

Esempio17.23PrivateSubSayHello_Click(sAsObject,eAsEventArgs)

Dim context = GlobalHost.ConnectionManager.GetHubContext(Of

CustomersHub)()

context.Clients.All.hello()

EndSub

Possiamo sostituire questo esempio banale con una definizione di hub più realistica.Sempreintemadiclienti,l’utentepotrebberichiederel’esecuzionediunprocessolungo,comeun’esportazione, e di ricevereunanotificaquando il processo termina.L’esempio17.24mostraun’ipoteticaimplementazione.

Esempio17.24PublicClassCustomersHub

InheritsHub

PublicFunctionExportData(idAsInteger)AsBoolean

Task.Run(Function()

'Simulooperazionelunga

Thread.Sleep(3000)

'Notificoilchiamatedell'avvenutaoperazione

Clients.Caller.exportDataReady("download/"+id)

EndFunction)

EndFunction

Ilcodiceècommentatonellesuepartipiùsalienti.DanotarechelafunzioneExportDatasi completa immediatamente, invocando l’esportazione su un altro thread. Quandol’esportazioneèterminata,invochiamopoiexportDataReadypernotificareilrichiedentedell’esportazione,identificatodaun’altraproprietàspecialeClients.Caller.

Una volta creato l’hub, non ci resta che abilitare a livello di intera applicazione ilsupporto a SignalR. Per farlo, abbiamobisogno di una classe diStartup diOWIN, unlayer di astrazione verso il web server. Anche in questo caso ci viene in aiuto VisualStudio 2015, sempre nella finestra di un nuovo elemento, attraverso l’elemento OWINStartup Class. Il suo scopo è permettere di configurare gli aspetti del web serverattraverso extension method appositamente creati sull’interfaccia IAppBuilder.Nell’esempio 17.25 è visibile l’unica istruzione da chiamare necessaria per abilitare

Page 426: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

SignalR.

Esempio17.25<Assembly:OwinStartup(GetType(Capitolo17.Startup))>

NamespaceCapitolo17

PublicClassStartup

PublicSubConfiguration(appAsIAppBuilder)

app.MapSignalR()

EndSub

EndClass

EndNamespace

Finoraabbiamovistocomeimplementarelaparteservereabbiamoparlatosolamentedelclient,perciòègiuntoilmomentodicapirecomepuòinterfacciarsiconunhub,invocareun’operazioneoricevereunevento.Abbiamoadisposizionemolti linguaggie inquestolibrovogliamoaffrontarequellopiùinerenteallosviluppoconASP.NET:JavaScript.

UtilizzareSignalRdaJavaScriptJavaScriptèillinguaggioutilizzatonellepagineHTMLpermanipolareilDOM,effettuarerichiesteAJAXe,ingenerale,perrenderedinamichelepagineclientside.AssociatoaunhubdiSignal,JavaScriptrendelepaginepiùfruibiliepiùmoderne,evitandopollingdapartedelclient.Perpoterlousare,dobbiamousufruiredellalibreriaJavaScript(ilpluginper jQuery), che viene installata tramite NuGet. Nella pagina HTML dove vogliamoutilizzarlo,ènecessarioquindi referenziare jQuerye la libreriaperSignalR,comevienemostratonell’esempio17.26.

Esempio17.26<html>

<head>

<script type="text/javascript" src="Scripts/jquery-1.10.2.min.js">

</script>

<script type="text/javascript" src="Scripts/jquery.signalR-

2.1.2.min.js">

</script>

<scripttype="text/javascript"src="signalr/hubs"></script>

<scripttype="text/javascript">

$(function(){

//inizializzazione

Page 427: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

})

</script>

</head>

Nelcodiceprecedenteèpresente l’inclusionediquattroscript. Iprimiduecheabbiamogiàcitato,unafunzioneutileperinizializzarel’hubeutilizzarloeunpercorsospecialeasignalr/hubs,generatograzieaquantofattonell’esempio17.24.Questoscriptcontienela definizione di funzioni JavaScript sulla base degli hub che abbiamo definito,permettendocidiconsumarlifacilmente.

Procediamooraainizializzareesfruttarequindiilnostrohub.TramitejQueryabbiamoadisposizione l’oggettoconnection, ilqualecontiene le funzionicomunie l’accessoalnostrohub.Nell’esempio17.27possiamovederecomeottenereilnostrohub,intercettarelafunzioneinvocatadalservereinvocarelafunzionesulserver.

Esempio17.27$(function(){

//Inizializzazione

varcustomersHub=$.connection.customersHub;

//Intercettoilcompletamentodell'export

customersHub.client.exportDataReady=function(uri){

//Stampoaconsole

console.log("Downloaddisponibile"+uri);

}

//Avviolaconnessione

$.connection.hub.start().done(function(){

console.log("Exportincorso…");

//Inviolarichiestadiexport

customersHub.server.exportData(6);

});

})

Possiamonotare che la funzione invocabiledal serverviene impostataprimadi avviaretuttalaconnessioneeinvocatatramitestart.Poichéilprocessoèasincrono,lafunzionedone ci permettedi conoscerequando il canaledi comunicazioneè attivoedi invocarel’esportazione. Chiaramente questa parte di codice sarebbe più opportuno che fossechiamabile dal click di un bottone. Eseguendo questa pagina possiamo quindi ottenerel’invocazionedelmetododiesportazionee,dopotresecondi,lastampaaconsoledell’uriperildownload.

Possiamoapprezzaredaquestopiccoloesempiocomebastinopochelineedicodiceperottenere una comunicazione bidirezionale, che ci permette di ignorare tutte le

Page 428: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

complicazionidellacomunicazione.

ConclusioniInquestocapitoloabbiamoaffrontatoglistrumentidiASP.NETdedicatiallosviluppodiservizimoderni, al passo con le esigenze attuali.Siamopartiti daASP.NETWebAPI, ilframework ufficiale Microsoft dedicato allo sviluppo di servizi basati su HTTP e, inparticolarmodo,RESTful.AbbiamovistocomepossiamosfruttareapienolecapacitàdiHTTP, con imetodi, gli status code e il bodydelle richieste.Tuttoquestovienegestitoautomaticamentedalframework,chetrasformalerichiestemappandolesuinostrioggettieistradandoleallarispettivafunzioneperpoiserializzarneilrisultato.Abbiamovistocomepersonalizzare alcuni aspetti di questo motore e come avere il pieno controllo dellarichiestaedellarisposta.

Con lo scaffolding, poi, possiamo farci aiutare da Visual Studio per ottenere lagenerazione del codice per il CRUDQ di un’entità, basandoci su Entity Framework.Sempresfruttandoquestoframework,possiamousareleestensioniperODataperesporreservizicherispondanoaunostandardperl’interrogazioneelamanipolazionedidati.

Infine,abbiamovistocomecreareservizi real-timesfruttandoSignalR,unframeworkchesifacaricoditutteleproblematicheditrasportopermetterciadisposizioneAPI-RPCbidirezionalitraclienteserver.

Chiudiamo questi due capitoli dedicati alle tecnologieweb e passiamo, nel prossimocapitolo,aunatematicagenericarelativaallasicurezza,percapirequalisonoglierroripiùcomunidanoncommettereequalistrumentiabbiamoadisposizioneperlasicurezzadelleinformazioni.

Page 429: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

18

Lasicurezzanelleapplicazioniperil.NETFramework

Nel corso dei precedenti capitoli abbiamo esaminato le varie funzionalità del .NETFramework e il loro utilizzo nella programmazione con Visual Basic. Grazie a talistrumenti abbiamo la possibilità di sviluppare applicazioni in modo semplice ma,nonostante questo, non dobbiamo dimenticare l’uso che può essere fatto del nostrosoftware, sia da parte degli utenti sia dagli altri sviluppatori, nel caso in cui il nostrocodicepossaessereutilizzatoointegratodaaltri.

Nelcorsodeglianni,l’affermazionedelpersonalcomputercomestrumentodilavoroesvagohaaumentatolamaturitàdell’utenteinmateriadiagilitàd’usodeinostrisistemi.Dicontroècresciutadiparipassolamalizianelcercaremetodidiutilizzodiversidaquelliprevisti,aprendo,piùomenovolontariamente,tuttaunaseriediscenariincuil’integritàdellenostreapplicazioniarrivaspessoaessereeffettivamentecompromessa.

Quello che accade solitamente è che, in qualità di progettisti, teniamo uncomportamento corretto nei confronti delle interfacce, dei dati che immettiamo, dei filechecarichiamo,ecc..;questociportaa trascurarealtrecoseche, invece,possonoesseremesse in atto da personaggimeno corretti di noi. Il normale utente, infatti, finisce perscavalcare l’utilizzo che abbiamo pensato, ritenendo di poter ottenere di più dalprogramma,adesempio,immettendodatiquasisenzasenso,allimitedelcomprensibile.

Mac’èdipiù:l’utentemalizioso,inoltre,utilizzavolontariamenteleproprieconoscenzeinformaticheperimmetteredati,alloscopodiottenere,adesempio,informazionicuinondovrebbe avere accesso. Oltre a questo, non dobbiamo dimenticare che la nostraapplicazione risiede su un PC o su un server e, pertanto, potrebbe non essere isolatarispettoallealtreapplicazioni,chepotrebberocercaredirecuperaredatiorisorseprivate.Anchelapossibilitàdirealizzareapplicazioniweblerende,perproprianatura,accessibilidamoltiutenti,conleimplicazionipotenzialicheabbiamocitato.

Nelcorsodelcapitolointrodurremoquindiglistrumentimessiadisposizionenel.NETFrameworkpercercaredirendereilnostrosoftwareilpiùsicuropossibile.

Progettareapplicazionisicure

Page 430: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Nel contesto che abbiamo introdotto, possiamo dire che il concetto di sicurezza diun’applicazionesiestendesiaalivelloapplicativo,relativocioèallemodalitàdiutilizzo,sia a quello architetturale, riferendoci con questo termine al codice che può essereeseguitoneiconfrontidelsistemacheospital’applicazionestessa.

Negli anni, la cultura della programmazione hamaturato una vera e propria dottrinadellasicurezza,incentratasulprincipiodisecuritycomerequisitoenoncomeaccessorioalle funzionalità.Questocomportache,nelleprimefasidiprogettazionediunsoftware,alcune delle prime scelte architetturali e tecnologiche siano fortemente influenzate dallivello di sicurezza che l’applicazione deve rispettare, più precisamente al livello dirischionelqualeilsistemaincorreduranteilpropriociclodivita.

Dobbiamoconsiderare ilconcettodi requisitopropriocomeelementochedeveessereintrodotto e seguito in tutto il corso dello sviluppo, scartando la possibilità che laprotezionedelcodiceelasicurezzaapplicativapossanoessereaggiunteconfacilitàinunsecondomomento.

Sicurezzaby-designÈpropriol’onerechecomportalariscritturadimoltepartidiuncodicepocosicuro,chedeveportarciametabolizzareilprincipiodisicurezzaby-design:cosìcomeprogettiamole interfacceutente e lemodalitàd’utilizzo,dobbiamoprogettare il livellod’interazioneconilsistemaoperativo,conl’hardwareeanchetralevariepartidell’applicazionestessa.

È curioso come Microsoft stessa abbia contribuito alla crescita della cultura dellasicurezzaancheacausadeicostantitentatividiviolazionedeiproprisistemioperativiedei propri software (come Internet Explorer), come conseguenza della loro notevolediffusione:inquestocontestoil.NETFrameworkènatoconsolidebasie,oltreadessereuna delle piattaforme di sviluppo più sicure, ci mette a disposizione una robustaarchitetturaconlaqualepossiamocapillarizzareillivellodiisolamentodelleporzionidicodice,inmodocheeseguanosoltantoquellopercuisonoprogettateesolonelcontestoperilqualesonostateprogettate.

IlmodellodisicurezzadelCLRIlmodellodi sicurezzadel .NETFramework4prevedeche le autorizzazioni a eseguirespecifiche operazioni siano elaborate in funzione dell’identitàdelprocesso che eseguel’applicazione, quindi relative alla tipologia di utente autenticato nel sistema operativo,combinateconquelledell’hostincuièeseguital’applicazionestessa.

Dobbiamo considerare un host come l’infrastruttura che ospita l’applicazione, siaessailsistemaoperativostessooppureunbrowsermaancheClickOnceeASP.NET.

Talemodelloèstatointrodottonellaversione2.0ma,altempo,l’utilitàeraristrettaallasola verifica del codice. Con l’introduzione di Silverlight, talemodello di sicurezza ha

Page 431: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

evoluto il concetto di sandbox quale ambiente isolato in cui viene eseguito il codice,considerandolo parzialmente sicuro (partial trust), quindi con limitate funzionalitàproprioper eliminare le possibili violazioni ai dati dell’utente.Un’applicazione lanciatadalsistemaoperativoedarigadicomandovieneeseguita inambientefulltrust,quindiconsiderata completamente attendibile, e le sue possibilità d’azione sono vincolate alleautorizzazionidell’utenteealleAccessControlList(ACL)impostatesullerisorse.Neglialtri contesti, invece, l’application domain che si crea all’interno dell’host eredita lepermessionsdell’host stesso e anche tutti gli altri assembly caricati vengonoeseguiti intalesandbox.

InquestoscenariofannoeccezionegliassemblyregistratinellaGlobalAssemblyCache(GAC),chepossonochiamarecodicedichiaratoSecurityCritical,poichédiventanofullytrusted,cioècompletamenteattendibili.

Perridurrepossibiliattacchidielevazionediprivilegi,dovutialfattocheassemblyinGACpossonoeseguirecodicecritico,èstataridottalapossibilitàcheassemblyeseguitiinsandbox partial trust richiamino assembly full trust. Tale possibilità è vincolata a duespecifici attributi a livello di assembly: SecurityTransparent eAllowPartiallyTrustedCallers. Con questi attributi rendiamo possibile che il nostrocodicesiarichiamatoinmodosicuroanchedaassemblypartialtrust,poichéilcodicenonpuòeseguirenessunadelleseguentioperazioni:

eseguirecodiceunsafe;

eseguirecodiceP/InvokeeCOM;

eseguirel’assertdellepermissions;

chiamaremetodidel.NETFrameworkdichiaraticomeSecurityCritical.

Inpratica,utilizzandounodeidueattributi,rendiamoilcodicesicuroindipendentementedaiprivilegidellasandbox.

Mentre con SecurityTransparent tutti i metodi vengono considerati sicuri(transparent), con AllowPartiallyTrustedCallers possiamo andare a specificare,metodopermetodo,qualipossonoeseguireoperazioni,percosìdire,rischiose.

In linea di principio possiamo affermare che un codice SecurityTransparent cheeseguecorrettamentelepropriefunzionipuòessereutilizzatointuttiicontesti,senzachesi incorra in problemi di sicurezza. Qualora, invece, avessimo la necessità di eseguireoperazionipotenzialmentepericolose,potremosfruttareilnuovomodellodisicurezza,ilTransparencymodel,perridurreirischiinsitiintalecodice.

TransparencymodelPerfacilitareladistinzionetrametodisicurieinsicuri, ilmodelloSecurityTransparencydel CLR 2.0 è stato evoluto al Level 2 Security Transparency, così chiamato perdifferenziarlo dal Level 1 delle precedenti versioni. In esso abbiamo la possibilità didichiarare il codice come SecurityTransparent, SecuritySafeCritical e

Page 432: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

SecurityCritical.

Abbiamo introdotto l’attributo SecurityTransparent nel precedente paragrafo. Adifferenzadiquesto, tutto ilcodicedecoratoconSecurityCriticalpuòessereeseguitoda altro codice SecurityCritical, pertanto solo da assembly dichiarati dall’host comefulltrust,oppureanchedacodicedecoratoSecuritySafeCritical.

PossiamoconsiderareilcodicedescrittocomeSecuritySafeCriticalcomeuncodicepotenzialmente sicuro, se eseguito con determinati privilegi. Poiché i metodiSecuritySafeCritical possono essere eseguiti da codice SecurityTransparent epossonoeseguirecodiceSecurityCritical,dobbiamoconsiderarlicomeunpontetragliambienti trusted e untrusted. Pertanto nel codice SecuritySafeCritical dobbiamoassicurarcidieffettuareidovuticontrollisullepermissionsdell’applicationdomainincuistagirandol’applicazione.

Figura18.1–AccessoalcodicenelLevel2SecurityTransparencymodel.

Uno dei vantaggi offerti dal Transparency Model risiede proprio nell’attributoSecuritySafeCritical. Con esso, quindi, possiamo far utilizzare funzionalità diassembly full trust anche da codice in esecuzione in sandbox a ridotti privilegi, senzaesporreilnostrocodicepotenzialmentepericolosoarischidiviolazioni.

Oltreaunaccuratounittestingdelcodice,dall’SDKdelFrameworkpossiamoutilizzare il tool SecAnnotate.exe (.NET Framework Security TransparencyAnnotator) per analizzare le violazioni che il nostro codice, che usa iltransparent model, esegue nei confronti del codice critical. Possiamo trovaremaggiori informazioni su MSDN (in inglese) alla seguente pagina:http://aspit.co/aid.

Nel.NETFrameworkpossiamoverificareipermessidell’applicationdomainattraversoleclassi di tipo IPermission, in particolare CodeAccessPermission ePrincipalPermission.

Page 433: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IlconcettodiPermissionInlineagenerale,ilprincipiodelleclassiIPermissionèquellodiinterporsiall’esecuzionediun’operazione,controllandoleeffettiveautorizzazioniintuttolostackdellechiamate,all’internodell’applicationdomain.

Nello specifico, laclassePrincipalPermission riguarda l’identità dell’utente a cui èassociata l’esecuzione interna dell’applicazione, in un contesto di autenticazione eautorizzazione legata a ruoli. L’utilizzo forse più noto di tale classe è nell’ambitowebASP.NET,nelquale iproviderMembershipeRolepossonodefinire,anchesudatabase,l’identitàdell’utenteloggatooltreallapropriaappartenenzaadalcuniruoli.Questiruolieidentità sonosfruttati inPrincipalPermission con cuipossiamovincolare l’esecuzionedelcodicesoloagruppiristrettidiutenti.

Ilcontrollodelleautorizzazionivieneeffettuatoattraversoimetodi:

Demand:controllatuttiglieffettivichiamantilungolostack;

LinkDemand:verificasoloildirettochiamante;

Assert: dichiara che il chiamante è autorizzato, scavalcando i privilegi definitidall’applicationdomain.

L’utilizzo di PrincipalPermission è abbastanza circoscritto a quanto abbiamo detto;riguardo invece alla classe astratta CodeAccessPermission, troviamo molteimplementazioni, ciascuna per un preciso ambito di utilizzo come, ad esempio,SmtpPermission,WebPermission,FileIOPermission,UIPermission,ecc.L’elencoèveramenteestesomailloroambitodiutilizzoèintuibiledalnomestessoecomunquesibasasempresullachiamataaimetodicheabbiamoelencato.

Seprendiamo,per esempio, la classeSmtpPermission, possiamovedere chequesta èutilizzata nel metodo Inizialize, richiamato direttamente dal costruttore della classeSmtpClient.Nel codice dell’esempio 18.1 troviamo un estratto di talemetodo. In essopossiamo capire che il controllo sulle autorizzazioni alla connessione a un server Smtpvieneeffettuatodirettamente almomentodell’istanzadell’oggetto.Qualoranonci sia illivellosufficientediautorizzazioni,ilmetodoDemandlanciaunaSecurityExceptioncheinterrompeimmediatamenteilflussodiesecuzionedelcodice.

Esempio18.1PrivateSubInitialize()

If((Me.port=SmtpClient.defaultPort)OrElse(Me.port=0))Then

DimpAsNewSmtpPermission(SmtpAccess.Connect)

p.Demand()

Else

DimpAsNewSmtpPermission(_

SmtpAccess.ConnectToUnrestrictedPort)

Page 434: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

p.Demand()

EndIf

Me.transport=NewSmtpTransport(Me)

'....

Cosìcomeavviene inSmtpClient, l’utilizzodelle classi di tipoCodeAccessPermissionviene fatto internamente inmolte classidelFramework.Ovviamentepossiamo farneunutilizzo diretto anche nel nostro codice e possiamo anche creare le nostre classiIPermissionpersonalizzateperlanostralogicainterna.

Con la classe PermissionSet abbiamo la possibilità di raggruppare più oggettiIPermission, inmodo da poter verificare più autorizzazioni con una sola chiamata delmetodoDemand.Nellosnippet18.2possiamovederneunsempliceesempio.

Esempio18.2Dimps1AsPermissionSet=NewPermissionSet(PermissionState.None)

ps1.AddPermission(NewSmtpPermission(SmtpAccess.Connect))

ps1.AddPermission(NewFileIOPermission(

FileIOPermissionAccess.Read,"c:\myfolder"))

Ps1.Demand()

L’utilità principale della classe PermissionSet la possiamo trovare nella dichiarazionedelleautorizzazionicomplessivediunapplicationdomainchepossiamocreare runtime,comevedremoneiprossimiparagrafi.

DefinizionedellePermissioninmododichiarativoOltre all’uso imperativo delle classi IPermission che abbiamo appena visto, possiamomarcareinostrimetodicongliattributicorrispondentialleclassi,inmododarenderepiùconcisoilcodice,migliorareleprestazionidiesecuzioneepermetterealCLRdiconoscereinanticipoillivellodipermessinecessarioall’assembly.

Esempio18.3<PrincipalPermission(SecurityAction.Demand,Name="Billy")>_

PublicSubGetData()

....

Nelcodicedell’esempio18.3vincoliamol’esecuzionedelmetodoGetDataalsoloutentediusername“Billy”.

Creareunasandboxperisolarecodiceesterno

Page 435: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DopocheabbiamoappresoiprincipigeneralidellasicurezzaarchitetturaledisponibilenelFramework,possiamoentrareneldettagliodiunodegliusipiùinteressantichepotremmoaverelanecessitàdiaffrontare:l’isolamentodicodiceesternoallanostraapplicazioneinunasandboxaridottiprivilegi.

Comeabbiamospiegato,ilconcettosibasasulleautorizzazionialivellodiapplicationdomain, quindi con la classe AppDomainSetup possiamo creare la nostra sandbox,assegnargli il livello di autorizzazioni che riteniamo sufficiente per ridurre i rischi disicurezza,edeseguireuncodice,adesempio,caricatoaruntimedaunassemblyesterno.

Per comprendere alcune implicazioni, procediamo creando una piccola applicazioneWPFdi esempio;perprimacosadecoriamo la classedelloUserControl principale conl’attributoSecurityTransparent,seguendoiprincipidicuiabbiamoparlatoneiparagrafiprecedenti,cosìcomeillustratonell’esempio18.4.

Esempio18.4ImportsSystem.Security

<Assembly:SecurityTransparent()>

ClassMainWindow

..

Ciòsucuidobbiamoriflettereèilfattodiavereuncodiceinunalibreriaesternachepossaeseguire solo certe operazioni; quindi aggiungiamo una Class Library alla nostrasoluzione,conunaclassedinomePluginElementeinessaprepariamoduemetodi,cosìcomeilllustratonelcodicedell’esempio18.5.

Esempio18.5<Assembly:AllowPartiallyTrustedCallers()>

PublicClassPluginElement

InheritsMarshalByRefObject

<SecurityCritical()>

PublicSubDirectWriteFile(ByValdataAsString,ByValpathAsString)

DimdataStreamAsStream=File.OpenWrite(path)

DimstrAsStreamWriter=NewStreamWriter(dataStream)

str.Write(data)

str.Close()

dataStream.Close()

EndSub

<SecuritySafeCritical()>

PublicSubWriteFile(ByValdataAsString,ByValpathAsString)

Page 436: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Dim p As New FileIOPermission(FileIOPermissionAccess.Write, New

String()

{path})

p.Demand()

DirectWriteFile(data,path)

EndSub

EndClass

Decoriamo la classe con l’attributo AllowPartiallyTrustedCallers. In questo modoconsentiamo all’assembly SecurityTransparent (la nostra applicazione principale) dieseguirealcunimetodidiquestaclasse.IlmetodoDirectWriteFilescrivedirettamentesufile system al path passato come parametro; decoriamo questo metodo conSecurityCritical perchè esso accede a una risorsa fisica dellamacchina dell’utente epotrebbeessere,perquesto,veicolodiviolazionidisicurezza.

NelmetodoWriteFile, invece, richiamiamoDirectWriteFilemanonprimadi avereseguitounDemanddelFileIOPermission,inscrittura,sulpathpassatocomeparametro.Ilfattodiavereffettuatoquestocontrollo,cipermettedidichiararequestometodocomeSecuritySafeCritical, quindi utilizzabile da classi in sandbox partial trust. Comeabbiamo detto, tale metodo può richiamare il codice SecurityCritical, che accedeesplicitamentealfilesystem,chiudendoilciclodisicurezza.

Per poter essere eseguita all’interno di un application domain separato, laclassedeveereditaredaMarshalByRefObject.

Per utilizzare la nostra libreria non rimane che creare un application domain che, nelcodice 18.6 è chiamato sandbox, e andare a eseguire il metodoCreateInstanceAndUnwrap,ilqualerecuperal’oggettodicuipossiamoeseguireilcastaPluginElement.

Esempio18.6DimplgAsPluginElement

PublicSubNew()

InitializeComponent()

Dimps1AsPermissionSet=NewPermissionSet(PermissionState.None)

ps1.AddPermission(NewSecurityPermission(_

SecurityPermissionFlag.Execution))

ps1.AddPermission(NewFileIOPermission(_

FileIOPermissionAccess.Write,"d:\"))

DimdomainSetupAsAppDomainSetup=_

AppDomain.CurrentDomain.SetupInformation

DimsandboxAsAppDomain=AppDomain.CreateDomain("sandbox",_

Page 437: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Nothing,_

domainSetup,ps1)

plg=DirectCast(sandbox.CreateInstanceAndUnwrap("Plugin",_

"Plugin.PluginElement"),PluginElement)

EndSub

Come abbiamo potuto vedere nel codice precedente, con un oggetto PermissionSetandiamo ad aggiungere gli oggetti IPermission, che contraddistinguono i permessidell’application domain. In particolare, concediamo la possibilità di eseguire codiceesterno e solo di scrivere sul path d:\ . Con CreateDomain otteniamo effettivamentel’istanza del nuovo application domain, nel quale andiamo a istanziare l’oggettoPluginElement,dell’assemblyPlugin.

Infine,nellanostraapplicazioneaggiungiamotrepulsantieitrecorrispondentimetodigestori degli eventi Click: nel primo andiamo a scrivere sul file system direttamentedall’applicazione,comedalcodicedell’esempio18.7.

Esempio18.7PrivateSubButton_Click(ByValsenderAsSystem.Object,_

ByValeAsSystem.Windows.RoutedEventArgs)

DimdataStreamAsStream=File.OpenWrite(_

String.Format("d:\file1.txt"))

DimstrAsStreamWriter=NewStreamWriter(dataStream)

str.Write(TextBox2.Text)

str.Close()

dataStream.Close()

EndSub

Se le ACL impostate sul disco d:\ non impediscono la scrittura all’utente che eseguel’applicazione, il codice non solleva alcuna eccezione perchè, come abbiamo detto,l’applicazione lanciata direttamente viene eseguita in un contesto full trust, quindicompletamenteattendibile.

Se invece proviamo a richiamare il metodo DirectWriteFile (ricordiamo,SecurityCritical)cosìcomedacodice18.8,riceviamounaMethodAccessException.

Esempio18.8PrivateSubButton_Click_2(ByValsenderAsSystem.Object,_

ByValeAsSystem.Windows.RoutedEventArgs)

'System.MethodAccessExceptionwasunhandled

'Message=Attemptbysecuritytransparentmethod

Page 438: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

''WpfApplication1.MainWindow.Button_Click_2(System.Object,System.Windows.RoutedEventArgs)'

'toaccesssecuritycriticalmethod

''Plugin.PluginElement.DirectWriteFile(System.String,

System.String)'failed.plg.DirectWriteFile(TextBox4.Text,"d:\writeDirectDaPlugin.txt")

EndSub

Come possiamo intuire, in questo caso è corretto richiamare il metodo WriteFile(SecuritySafeCritical), il cui Demand di FileIOPermission sarà correttamentesuperatoseandremoascriveresuunfilesud:\,cosìcomedaesempio18.9.

Esempio18.9PrivateSubButton_Click_1(ByValsenderAsSystem.Object,_

ByValeAsSystem.Windows.RoutedEventArgs)

plg.WriteFile(TextBox3.Text,"d:\writeDaPlugin.txt")

EndSub

In questa serie di esempi, seppur semplici, abbiamo visto come sia possibile isolare ilcontesto di esecuzione di un codice, anche di una libreria esterna, creando sandbox aridotti privilegi e riducendo così i rischi di violazioni di sicurezza che questo tipo dioperazionipuòcomportare.

PrincipidicrittografiaNei paragrafi precedenti abbiamo illustrato come sia possibile organizzare le classi e,complessivamente, lenostre applicazioni, inmododa ridurre i rischidi sicurezza legatiallaviolazionedeglialtridatipresentisullamacchina.Oltreaquantoanalizzato,èusualeaveredeidatiche,ancheincasodiaccessodapartedialtriutenti,nonsianodirettamenteleggibili dagli esseri umani, in quanto cifrati. All’interno del .NET Framework sonodisponibilimolte classi per gestire dati riservati e rendere il loro immagazzinamento inmemoriao il loro scambiopiù sicuro. Il concettodi crittografia si basa sul principiodimodificarelarappresentazionedeidatiinmodotalechenonsianoleggibilidirettamente,chesolol’applicazionepossaconoscerneilvalorerealeechenonsiapossibilerisalirealvaloreoriginale,senoninpresenzadiprecisecondizioni.

Comevedremoneiparagrafisuccessivi,moltedelleoperazionidicrittografiasibasanosul principio di modificare i dati in funzione di un preciso valore, detto comunementechiave, valore che, a sua volta, può avere un livello di sicurezza dettato dallariproducibilità dello stesso e dalla difficoltà con la quale può essere conosciuto da altriutentioltrealcifratore.

Page 439: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

WindowsDataProtectionUna delle soluzioni più immediate che abbiamo a disposizione nel Framework èrappresentata dalla classe ProtectedData del namespaceSystem.Security.Cryptography,presentenell’assemblySystem.Security.dll.Taleclasseimplementa la cifratura basandosi sul servizio di data protection (DPAPI) esposto dalsistemaoperativostesso.ConiduemetodistaticiProtecteUnprotectpossiamocifrareedecifrareinostridatirappresentatisottoformadiarraydibyteeabbiamolapossibilitàdidefinire un livello di decifrabilità nel contesto di sistema o al solo utente autenticato,grazie al parametro DataProtectionScope. Nel codice 18.10 possiamo vedere comecifrare una semplice stringa; con DataProtectionScope.CurrentUser l’algoritmo usacomechiavelapassworddell’utente.

Esempio18.10DimdataAsString="testodacifrare"

DimdataByteAsByte()=_

System.Text.Encoding.UTF8.GetBytes(data)

DimentropyAsByte()=_

System.Text.Encoding.UTF8.GetBytes("chiaveulterioresicurezza")

DimdataCriptedAsByte()=_

ProtectedData.Protect(dataByte, entropy,

DataProtectionScope.CurrentUser)

Comepossiamovederenelcodice,èpossibileaggiungereun’ulteriorechiavedaaffiancareaquella derivata dalDataProtectionScope. Il livello di sicurezzadi questamodalità sibasa essenzialmente sulla complessità della password scelta dall’utente. L’utilitàmaggiorediquestaclasserispondeessenzialmentealleesigenzediunaapplicazionechememorizzi,anchesufilesystem,delleinformazioniallequalisolol’utentepuòaccedereinchiaro.

CrittografiasimmetricaLasemplicitàdelleDataProtectionAPIisolatuttaviailloroambitodiapplicazioneall’usolocalediinformazionicifrate;qualoraavessimolanecessitàditrasferireidatie,quindi,diproteggerli dalla vista e dalla modifica da parte di utenti non autorizzati, è necessarioadottare sistemi di cifratura basati su chiavi esterne, a cui solo i legittimi destinataripossanoavereaccesso.

Dobbiamopensarealconcettodicifratura inunambitopiùampioenonstrettamentelegatoall’informatica:storicamente,infatti,lacrittografiahasempreavutounruolochiaveinambitomilitare.Inquelcampolariservatezzadelleinformazionièdivitaleimportanzaperl’esitodelleoperazioni.Èpropriodatalecontestochelosviluppodellacrittograficahatrattolemaggiorispinteevolutive,ancorprimadellosviluppodisistemidielaborazione

Page 440: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

assistiti da calcolatori; agli inizi del novecento sono state sviluppatemoderne, per cosìdire,modalitàdicodificaedecodificadimessaggibasatisuun’unicachiave.Taletipodicrittografia, detta simmetrica, si basa proprio sull’uso della stessa chiave per cifrare edecifrareuncertodato.

Nel .NETFramework la classe astratta che descrive leAPI di cifratura simmetrica èSymmetricAlgorithm, dalla quale deriva una serie di classi ciascuna con la propriaimplementazione dell’algoritmo, in funzione della lunghezza della chiave, e quindi disicurezzagenerale.Possiamovederelagerarchiaditaliclassinellafigura18.2.

Figura18.2–GerarchiadelleclassiSymmetricAlgorithm.

Ogni classe astratta corrispondente al nome dell’algoritmo sviluppato haun’implementazioneconcretae,comedetto,essedifferisconotraloroperlalunghezzainbitdellachiave;quidiseguitonetroviamounelencoconirelativivalori:

Rijndael:128,192e256bit;

Aes:128,192e256bit;

DES:64bit;

TripleDES:128e192bit;

RC2:da40a128constepdi8bit.

Perutilizzareunadiquesteclassiènecessario,quindi,generareunachiavedigrandezzacorrispondenteaquellarichiestadall’algoritmo.Talechiave,espressasottoformadiarraydi byte, può essere generata in diversi modi, così come possiamo vedere nel codicedell’esempio18.11.

Page 441: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio18.11'generazioneautomaticadaparteprovider

DimcryptoProviderAsNewTripleDESCryptoServiceProvider()

key=cryptoProvider.Key

vector=cryptoProvider.IV

'dichiarazioneesplicitadiretta

key={234,12,67,245,66,99,_

22,214,6,88,124,44,_

221,34,9,22}

'utilizzodellaclassePasswordDeriveBytes

DimpasswordAsString="passwordpergenerarechiave"

DimsaltAsString="saltpergenerarechiave"

DimpasswordByteAsByte()=_

System.Text.Encoding.UTF8.GetBytes(password)

DimsaltByteAsByte()=System.Text.Encoding.UTF8.GetBytes(salt)

DimkeyGeneratorAsNewPasswordDeriveBytes(passwordByte,saltByte)

key=keyGenerator.CryptDeriveKey("TripleDES","SHA1",192,vector)

Possiamo generare una chiave dichiarando direttamente un array di byte, oppure, comepossiamovederenelcodice,possiamofarlagenerareautomaticamentedalproviderscelto(nell’esempioTripleDESCryptoServiceProvider).

Inoltre,abbiamolapossibilitàdiutilizzarelaclassePasswordDeriveBytes,conlaqualepossiamo generare una chiave riferendoci a una password arbitraria, combinata a uncodice“salt”perulterioresicurezza. Internamente,anchequestaclassesiappoggiaaunalgoritmosimmetricodicifratura,chepossiamodichiararenelmetodoCryptDeriveKey,generatoredellachiavedesiderata.

IlvettoreidentificatoconlaproprietàIVdiSymmetricAlgorithmconcorreallacodificadelmessaggioinsiemeallachiavesegreta.Poiché,aparitàdichiave,ilrisultato della cifratura di un dato è costante, l’utilità del vettore è quella diinserireun’ulterioreelementodicifraturadavariareaognispecificacodifica,ad esempio, in corrispondenzadella trasmissione delmessaggio attraverso larete.

Generatalachiaveeilvettoreperlacifratura,possiamocriptareunmessaggioattraversoilmetodoCreateEncryptordellaSymmetricAlgorithmsceltaeutilizzaretaleoggettoperpopolareunCryptoStreamqualestreamintermedioaquellousatopergestireilmessaggiocriptato.Nell’esempio18.12 abbiamo scritto in un file un semplice testo, associando ilFileStreamdelfileconilCryptoStreampopolatodaidaticifrati.

Page 442: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio18.12DimdataByteAsByte()=_

System.Text.Encoding.UTF8.GetBytes("testodacifrare")

Using encryptor As ICryptoTransform =

cryptoProvider.CreateEncryptor(key,vector)

UsingstreamAsStream=File.Create("d:\encrypted.txt")

UsingcryptoStreamAsCryptoStream=_

NewCryptoStream(stream,encryptor,CryptoStreamMode.Write)

cryptoStream.Write(dataByte,0,dataByte.Length)

cryptoStream.FlushFinalBlock()

EndUsing

EndUsing

EndUsing

Perprocederealladecrittazionedeltestopresentenelfileèsufficientecreareun’istanzadiICryptoTransform attraverso il metodo CreateDecryptor, utilizzando chiave e vettorecon le quali è stato cifrato il dato. Come possiamo vedere nel codice 18.13, possiamorecuperareilmessaggiooriginaleaprendounCryptoStreaminlettura,passandol’oggettoICryptoTransformdopoaverassociatotalestreamalFileStreamdelfilecifrato.

Esempio18.13Using encryptor As ICryptoTransform =

cryptoProvider.CreateDecryptor(key,vector)

UsingstreamAsStream=File.OpenRead("d:\encrypted.txt")

UsingcryptoStreamAsStream=_

NewCryptoStream(stream,encryptor,CryptoStreamMode.Read)

UsingreaderAsNewStreamReader(cryptoStream)

tb2.Text=reader.ReadToEnd()

EndUsing

EndUsing

EndUsing

EndUsing

Per risalire al testo leggibile non ci rimane che aprire uno StreamReader con ilCryptoStreamdaleggere.

Cablare lachiavedicifraturanelcodicenonèunabuonapraticapoiché toolcome Reflector rendono molto semplice la decompilazione degli assembly. Incerticontesti,potrebbeessereutileusareleDataProtectionAPI,percifraretalechiaveduranteilsetupdell’applicazioneememorizzarlanelregistrodisistema

Page 443: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

osufilesystem.

A fronte di una facilità d’implementazione, semplificata dalle classi presenti nelFramework,ladifficoltàmaggiorerimanenelloscambiarelachiavedall’autoreagliutentiautorizzati, i quali sono responsabili della segretezza di tale chiave per mantenere invigoreilsistemadiriservatezzadeidati.Comepossiamointuire,questoonererappresentaunfortevincoloallarobustezzadelmodelloepotrebberisultaretroppodeboleperalcunitipologiedidati.

Inoltre, poiché i dati sono cifrati con la medesima chiave posseduta da mittente edestinatario,ilsistemasimmetricononpermettel’identificazioneunivocadell’autorediunmessaggio e dell’integrità stessa del dato, che può essere manipolato da un attoreintermedio,ovviamenteinpossesso,piùomenolegittimo,dellachiavedicifratura.

Per far fronte a tali vincoli è stato sviluppato il modello a chiave asimmetrica, cheillustreremonelprossimoparagrafo.

CrittografiaasimmetricaLa cifratura asimmetrica si basa sul principio di elaborazione dei dati attraverso unacoppiadichiavi,diverseenonriconducibilil’unaall’altra.Talecoppiaècostituitadaunachiave pubblica, che viene impiegata per cifrare i dati, e una privata che, incombinazione con quella pubblica, consente la decifratura. In tale modello, quando unmittente deve inviare un messaggio riservato a un destinatario, chiede la sua chiavepubblicaecifra ilmessaggiosecondounodeglialgoritmidisponibili.Alla ricezionedelmessaggio, solo il destinatario in possesso della chiave privata, accoppiata a quellapubblicaconcuièstatocifratoilmessaggio,puòeffettuareladecifratura.

Poichélacifraturaeladecifraturaconglialgoritmiasimmetricièabbastanzaonerosaintermini di elaborazione macchina, spesso viene utilizzata per cifrare una chiavesimmetrica, con cui viene elaborato il dato riservato. La chiave può essere scambiatacontestualmentealmessaggiocifrato.

Analogamenteallacifraturasimmetrica,nelFrameworkabbiamounaseriediclassicheimplementano algoritmi di cifratura asimmetrica; il più noto è sicuramente RSA(acronimo dei cognomi degli inventori), i cui principi sono stati descritti nel 1977.Nelgraficodifigura18.3possiamotrovareunoschemadelleclassianostradisposizione.

Page 444: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura18.3–GerarchiadelleclassiAsymmetricAlgorithm.

Cerchiamo di comprendere l’utilizzo della cifratura asimmetrica utilizzando l’algoritmoRSAinmododacriptareunachiavedautilizzarenellacifraturasimmetricadiun testo,cosìcomeabbiamodescrittopocosopra.Laprimaoperazionesaràquelladigenerare lacoppiadichiavi,pubblicaeprivata.Nell’esempio18.14andiamoascrivereleduechiavisuduefileXML.

Esempio18.14UsingasCryptoProvider=NewRSACryptoServiceProvider()

File.WriteAllText("d:\PublicKey.xml",

asCryptoProvider.ToXmlString(False))

File.WriteAllText("d:\PublicAndPrivate.xml",

asCryptoProvider.ToXmlString(True))

EndUsing

Grazie al metodo ToXmlString, le chiavi vengono rappresentate sotto forma di stringacomeinfosetXML,inmododasemplificarnelascritturasufilesystem.

Comeabbiamovistonelparagrafoprecedente,andiamoafarcrearechiaveevettorealprovider di cifratura simmetrica, nell’esempio, TripleDESCryptoServiceProvider.Successivamente,andiamoaleggerelachiavepubblicae,conquesta,andiamoaeffettuarela cifratura di chiave e vettore, attraverso il metodo Encrypt diRSACryptoServiceProvider.

Infine, cifriamo il messaggio riservato con chiave e vettore originali e l’algoritmosimmetricodesiderato,cosìcomedescrittonell’esempio18.15.

Esempio18.15

Page 445: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

'creazionechiavesimmetricapercifratura

DimcryptoProviderAsTripleDESCryptoServiceProvider=New

TripleDESCryptoServiceProvider()

DimkeyAsByte()=cryptoProvider.Key

DimvectorAsByte()=cryptoProvider.IV

'letturachiavepubblicapercifraturaasimmetrica

DimpublicKeyOnlyAsString=File.ReadAllText("d:\PublicKey.xml")

'cifraturaasimmetricadellachiavesimmetrica

UsingasCryptoProviderAsRSACryptoServiceProvider=New

RSACryptoServiceProvider()

asCryptoProvider.FromXmlString(publicKeyOnly)

keyCrypted=asCryptoProvider.Encrypt(key,True)

vectorCrypted=asCryptoProvider.Encrypt(vector,True)

EndUsing

'datiriservati

DimdataByteAsByte()=System.Text.Encoding.UTF8.GetBytes(data)

'cifraturasimmetricaconchiaveevettoreautogenerati

UsingencryptorAsICryptoTransform=_

cryptoProvider.CreateEncryptor(key,vector)

UsingstreamAsStream=File.Create("d:\encrypted.txt")

UsingcryptoStreamAsCryptoStream=_

NewCryptoStream(stream,encryptor,CryptoStreamMode.Write)

cryptoStream.Write(dataByte,0,dataByte.Length)

cryptoStream.FlushFinalBlock()

EndUsing

EndUsing

EndUsing

Al momento di voler decifrare il messaggio, dobbiamo decrittare chiave e vettoreutilizzandolacoppiachiavepubblicaeprivataconl’algoritmoasimmetrico,perfinireconla decifratura simmetrica del messaggio. Grazie al metodo FromXmlString possiamoagevolmenterecuperareilvaloredellacoppiadichiaviinnostropossessoedeffettuareladecifraturaconilmetodoDecryptdiRSACryptoServiceProvider.

OltreaFromXmlStringeToXmlString,abbiamolapossibilitàdirappresentarele chiavi pubbliche e private sotto forma di array di byte, grazie ai metodiImportCspBlobeExportCspBlob.

Nell’esempio18.16possiamovedereun’implementazioneditaleprocedura.

Page 446: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio18.16DimkeyDecryptedAsByte()

DimvectorDecryptedAsByte()

'letturachiavepubblicaeprivata

Dim publicPrivate As String =

File.ReadAllText("d:\PublicAndPrivate.xml")

'decifraturachiavesimmetricaevettore,conalgoritmoasimmetrico

UsingasCryptoProviderAsRSACryptoServiceProvider=New

RSACryptoServiceProvider()

asCryptoProvider.FromXmlString(publicPrivate)

keyDecrypted=asCryptoProvider.Decrypt(keyCrypted,True)

vectorDecrypted=asCryptoProvider.Decrypt(vectorCrypted,True)

EndUsing

'decifraturadatiriservaticonchiavesimmetricadecifrata

UsingencryptorAsICryptoTransform=_

cryptoProvider.CreateDecryptor(keyDecrypted,vectorDecrypted)

UsingstreamAsStream=File.OpenRead("d:\encrypted.txt")

UsingcryptoStreamAsStream=_

NewCryptoStream(stream,encryptor,CryptoStreamMode.Read)

UsingreaderAsNewStreamReader(cryptoStream)

tb3.Text=reader.ReadToEnd()

EndUsing

EndUsing

EndUsing

EndUsing

Con questo semplice esempio abbiamo illustrato un’implementazione concretadell’utilizzodellacifraturaasimmetrica,nellaqualesiècercatodiottimizzareprestazioniedefficienza.

Comeabbiamocompreso,rispettoallacifraturasimmetricanonabbiamolanecessitàdiscambiare la stessa chiave tramittente e destinatario: gli attori condividono soltanto lachiave pubblica. In taluni contesti, potrebbe essere necessario aggiungere un ulteriorelivellodisicurezza,legandol’autenticitàdellechiaviauncertificatodigitaledisicurezza,rilasciato da una authority autorizzata. Grazie alle classi del namespaceSystem.Security.Cryptography.X509Certificates, abbiamo la possibilità di gestireanchequestiscenari.

Cifraturairreversibile:hashing

Page 447: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Lacaratteristicaprincipaledellemodalitàdicifraturacheabbiamovistofinoraèquelladipoterrisalirealvaloreoriginale.Conglialgoritmidihashing,invece,possiamocalcolareuncodicedilunghezzafissainrelazioneallastrutturadeibytediuncertomessaggio,siaesso un documento o una semplice stringa. La relazione univoca che si crea tra unmessaggioe ilpropriohashèdettatadal livellodicomplessitàdell’algoritmo:poiché lohashhaunalunghezzafissacaratteristicadell’algoritmostesso,piùestesoè l’hashepiùdifficilisonolepossibilitàdicollisione (cioè icasi incuiduedatidifferentiabbiamolostessohash).

Uno degli utilizzi più comuni degli algoritmi di hashing è l’elaborazione dellepassword di autenticazione, i cui hash vengonomemorizzati su database al posto delvalore reale immessodall’utente. Inquesto caso, per autenticare l’utente, l’applicazionenonesegueunconfrontodirettotrailvaloresudatabaseequelloimmessodall’utentemadellohashdeldatoprovenientedallamascheradilogin.L’aspettoimportantediunhash,infatti, è che non possibile risalire al dato originale, quindi non ci sono rischi sullamanipolazionedi tale codice senonattraversoundictionaryattack, cioè attraverso unconfronto massivo del codice con una serie di codici hash corrispondenti a un estesodizionario. È proprio per ridurre tali rischi che viene sempre consigliato all’utente diinserirepasswordcomplesseedicambiarleperiodicamente.

La classe PasswordDeriveBytes, che abbiamo utilizzato negli esempiprecedenti,impiegapropriounalgoritmodihashingpercrearelechiavi.Inoltreaggiunge due ulteriori livelli di sicurezza, combinando un codice “salt” allapasswordedeseguendo,progressivamente,unhashingricorsivoparialnumerodiiterazionidesiderato.

Grazieallarelazioneunivocachesicreatraundatoeilpropriohash,inunatrasmissionepossiamosfruttareilcodicepercontrollarecheildatononsiastatomanipolatoduranteunafaseintermedia.Questoperchè,comeabbiamodetto,ancheunapiccolamodificaaundocumento causa una diversità nella propria rappresentazione di byte e quindi all’hashcorrispondente.

Possiamosfruttarequestacaratteristica,adesempio,duranteloscambiodichiavidicuiabbiamo parlato nei paragrafi precedenti, condividendo anche l’hash di tali chiavi, perassicurarci chequeste sianoeffettivamentecorrispondenti all’hashdelle chiavioriginali,controllandoquindichenessunosisiainterpostonelloscambiodati.

Nel.NETFrameworktroviamounanutritaseriediclassicheimplementanoalgoritmidihashing con una struttura molto simile a quella che abbiamo visto per la cifraturasimmetricaeasimmetrica.Senzaentrareneldettagliodiciascunaclasse,comeabbiamoaccennato,questevarianoinfunzionedellalunghezzadelcodicehashelaborato.

LaclassepiùnotaèMD5.Essaimplementaunalgoritmoa128bitequindigeneraunhashdi16byte.Sebbenesiailmenosicurodalpuntodivistadellecollisioni,lacomoditàdi questo algoritmo risiede nella rappresentabilità dell’hash sotto forma di Guid,trattandosidiundatodi16byte.

Questolivellodisicurezzapuòesseresufficientepermolticontesti.Incasodinecessità

Page 448: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

di una codifica più estesa, possiamo utilizzare le classi SHA160, SHA256, SHA384 oSHA512 che,comepossiamo intuiredalnome, implementanoalgoritmi rispettivamentea160, 256, 384 e 512 bit. Il loro utilizzo è estremamente semplice: attraverso ilmetodoComputeHash possiamo passare l’array di byte corrispondenti al dato su cui calcolarel’hash,oppurepossiamopassaredirettamentelostreamdiundocumentodaelaborare.Nelcodicedell’esempio18.17,possiamovedereunasempliceimplementazionecheconfrontairisultatideivarialgoritmi.

Esempio18.17DimdataAsByte()=_

System.Text.Encoding.UTF8.GetBytes(tb4.Text)

Dimhash1AsByte()=MD5.Create().ComputeHash(data)

Dimhash2AsByte()=SHA1.Create().ComputeHash(data)

Dimhash3AsByte()=SHA512.Create().ComputeHash(data)

tb5.Text=GetHexadecimal(hash1)

tb6.Text=GetHexadecimal(hash2)

tb7.Text=GetHexadecimal(hash3)

'rappresentazioneesadecimalediunarraydibyte

FunctionGetHexadecimal(ByValhashAsByte())AsString

DimsBuilderAsNewStringBuilder()

DimiAsInteger

Fori=0Tohash.Length-1

sBuilder.Append(hash(i).ToString("x2"))

Nexti

ReturnsBuilder.ToString()

EndFunction

Nell’immagine18.4possiamoconfrontarevisivamenteirisultatidell’hashingdellaparola“p@ssw0rd”.

Figura18.4–Hashingconvarialgoritmielalororappresentazioneesadecimale.

IlmetodoComputeHashcirestituiscel’hashsottoformadiarraydibyte;perottenereunarappresentazione a stringa abbiamo la possibilità di usare il metodoConvert.ToBase64String oppure di elaborare i singoli byte dell’hash e convertirli nelloro valore esadecimale, così come abbiamo realizzato nell’esempio 18.17, nel metodo

Page 449: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

GetHexadecimal.

FirmaregliassemblyNell’esempio18.4abbiamoillustratol’isolamentodelcodiceprovenientedaunassemblycaricatodinamicamente.Sebbenelasandboxcipermettaunbuonlivellodisicurezza, intalecontestosiamoancorasoggettiadattacchiditampering,cioèdimanomissionedegliassemblydapartediterzi,chepossonocosìinserireilpropriocodice,vanificandotutteleprecauzioniadottate.

Per sopperire a queste problematiche abbiamo la possibilità di applicare una firmadigitale ai nostri assembly, in modo da permettere al CLR di verificare l’integrità delcodiceebloccarneilcaricamento.Ilprocessodifirmapassaattraversolagenerazionediunacoppiadichiavi,pubblicaeprivata;adifferenzadellacifraturaasimmetrica,dicuiabbiamoparlatoneiparagrafiprecedenti,l’hashdell’assemblyvienecifratoconlachiaveprivata,mentrelachiavepubblicavieneinclusanellalibreriastessa.

Almomentodelcaricamentodella libreria, ilFrameworkdecifra l’hashdell’assemblycon la chiave pubblica inclusa, verifica che l’hash dell’assembly in elaborazionecorrispondaconquellodecifratoe,incasodidifferenze,neimpedisceilcaricamento.

La procedura di firmapuò essere fatta da riga di comando con il tool sn.exe inclusonell’SDKdel.NETFramework,oppuregestitainformavisualeconVisualStudio.Nelleproprietà di un progetto, infatti, troviamo la maschera “Signing”, come visibile nellafigura18.5.

Figura18.5–GestionedellafirmadiunassemblyconVisualStudio.

Page 450: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Con l’apposizione di una firma digitale, all’assembly viene anche attribuito uno strongname, che contraddistingue in modo univoco la libreria nei confronti di tutte le altrepresentinelsistema,ancheaparitàdinomesufilesystem.

Validazionedeidatiimmessidall’utenteNeiparagrafiprecedentiabbiamoillustratoiprincipidiprogettazionedelleclassiecomecerti tipi di dati possano essere protetti dall’accesso di utenti non autorizzati. Ancheprogettandol’applicazioneconicriteripiùrigidi,possiamoancoraincorrereinviolazionidisicurezzalegateall’implementazionedellelogicheapplicative,inparticolare,inquellelegateall’accessoallebasidati.

Comeabbiamodettoall’iniziodelcapitolo,nondobbiamotrascurarel’usochel’utentefinale può fare della nostra applicazione, facendo particolare attenzione ai dati cheimmettenellemaschere,specialmenteaqueidaticheinteragisconoconildatabase.

ProteggersidaattacchiSQLInjectionGli attacchi di SQL Injection si riferiscono a quegli scenari in cui i dati immessidall’utenteconfluisconodirettamentenellacomposizionedellequerysudatabase.Senzaalcuncontrollodapartedelprogrammatore,l’utentepotrebbeimmetterealcunicodiciperandareacrearequeryinatteseerecuperaredatiacuinondovrebbeavereaccesso,senonpropriodanneggiandol’interabasedati.

Questo scenario si riferisce a un codice scritto comenell’esempio18.18, nel quale ilvaloreimmessodall’utentenelleTextBoxvieneformattatonellaquery.

Esempio18.18'!!!codiceinsicuro

DimqueryAsString=_

String.Format("SELECT*FROMUsersWHEREUsername='{0}'_

ANDPassword='{1}'",tbxUsername.Text,tbxPassword.Text)

In questo caso, se l’utente inserisce nella TextBox il proprio username con la seguentesintassi: “Billy’;–” la query che andrà in esecuzione sul database sarà quelladell’esempio18.19.

Esempio18.19SELECT * FROM Users WHERE Username=“Billy’;–– AND Password='valore

inutile'

Con tale string SQL l’utente avrà una lista dei dati di autenticazione di tutti gli utenti,

Page 451: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

poichélapartedicodicedopoilcarattere“–”nonverrebbeelaborata.

A questo fatto e a situazioni simili possiamo far fronte utilizzando l’oggettoSqlParameter, inmododa farcomporre laqueryall’oggettoSqlCommand diADO.NET.Possiamovederneun’implementazionenelcodicedell’esempio18.20.

Esempio18.20DimconnectionAsNewSqlConnection("stringadiconnessione")

DimqueryAsString="SELECT*FROMUsersWHEREUsername=@Username"

DimcommandAsNewSqlCommand(query,connection)

DimparamAsNewSqlParameter("@Username",SqlDbType.NVarChar,100)

param.Value=tbxUsername.Text

command.Parameters.Add(param)

DimreaderAsSqlDataReader=command.ExecuteReader()

Nel caso in cui non sia possibile utilizzare le query parametriche, nei contesti in cui sivuolecomunqueconcedereall’utentelapossibilitàdicomporrelepropriequery,sidevesemprecontrollarecheidatiimmessisianoconsoniall’applicazione,effettuandocontrollisultipoconicorrispondentimetodiTryParse,disponibiliinognitipodivalore.

Nonostantepossaapparirecomeunabanalità,questotipodiaccorgimentoèignoratodamolte applicazioni e sitiweb, anche importanti, esponendo i dati a visibilità e gestionearbitrarie.Èbenericordarechelevigentinormativesullaprivacyesultrattamentodeidatipersonalici richiedonounaparticolareattenzioneproprio inmateriadipubblicazionedidatisensibili,comenell’esempiocheabbiamoappenariportato.

ConclusioniLa realizzazione di software sicuro è un argomento sempre più rilevante per la buonariuscitacommerciale di un prodotto; anchegli utenti stannomaturando la sensibilità aquesto tipo di argomento, ponderando il livello di sicurezza come fattore di scelta tra idiversi prodotti presenti sul mercato. Nonostante l’informatica non sia più una scienzasperimentale, le metodologie di sviluppo del software sono ancora molto artigianali,lasciando al singolo programmatore la creatività e l’onere di implementare la logicaapplicativae,contemporaneamente,iprincipiarchitetturaliequellidisicurezza.

In questo contesto il .NET Framework ci mette a disposizione delle linee guida eun’infrastrutturadiclassiutiliallagestionedellasicurezza,a livelloarchitetturalecon ilTrasparencyModelmaancheperlagestionedeidatiriservati,conl’implementazionedialgoritmidicifraturasimmetrica,asimmetricaedihashing.

Nelcorsodelcapitoloabbiamointrodottoiprincipiel’usodiquestistrumenti,cercandodi analizzare i casi più frequenti chepossiamo incontrarenello sviluppodi applicazioni

Page 452: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

sicure.Ovviamentel’argomentoèmoltopiùvastodiquantoèstatopossibileillustrarenelcapitoloe,percertiversi,èmoltocomplessooltreaessereincostanteevoluzione;tuttaviapossiamoconsiderarequantospiegatocomeunatrattazionepropedeutica,taledarenderepiùsempliceal lettorel’approfondimentodellostudiodellaspecificaletteraturapresenteanchenelladocumentazioneufficiale.

Page 453: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

19

Gestionedifile,registryenetworking

Nei capitoli precedenti abbiamo visto come realizzare diverse tipologie di applicazioni:web, desktop, servizi, e come farne il deploy. Spesso può capitare che queste ultimedebbanointeragireconilFilesystem,perleggere,scrivereo,semplicemente,pereseguiredellericerche.Laprimapartedelcapitoloèdedicataproprioaquest’argomento:vedremoquali sono le classi del .NETFramework che possiamo utilizzare permanipolare file edirectory.

Successivamente sposteremo la nostra attenzione verso la gestione del registro diWindows,ilcuiscopoèquellodimemorizzareungrannumerodiimpostazioni.Capiremoqualisonolemodalitàperinterrogarloemodificarneilcontenuto.

Nella seconda parte, invece, analizzeremo gli strumenti mediante i quali possiamointeragirecapillarmentecon le singole tipologiedi risorse remote,attraverso la rete,peravere così una conoscenza generale di come sia possibile gestire esplicitamente iprincipalimodellidicomunicazione.

GestionedelFilesystemCon il termine informatico File system intendiamo il meccanismo per organizzare,recuperareemanipolareleinformazioniresidentisuunsupportodiarchiviazione,siaessounHarddisk,unCD-ROMounamemoriaflash.

SistemioperativiqualiMS-DOSo leprimeversionidiWindows,utilizzavanounfilesystem chiamato File Allocation Table (FAT e il suo successore FAT32), il cui scopo,inizialmente,erasoloquellodimemorizzare informazioni instrutturechiamate file,chepotevanoesserecatalogateall’internodicontenitoridettidirectory.InseguitoifilesystemsisonoevolutifinoadarrivareaNTFS,cheoggiequipaggiatuttelemoderneversionidiWindows ed è in grado di sfruttare supporti a elevata capienza come quelli odierni e,soprattutto, di fornire servizi aggiuntivi, quali, ad esempio, una gestione avanzata dellasicurezzaedellepermissiondiaccessoallevarierisorse.

Organizziamoleinformazioni:DirectoryeFileTuttiitipinecessariagestirefileedirectorysonoraggruppatinelnamespaceSystem.IO.

Page 454: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Inparticolare,perquantoriguardaquesteultime,possiamofareaffidamentosudueclassi:DirectoryeDirectoryInfo.Laprimaesponesolometodistaticie, in talmodo, risultautilepercompiereoperazionisaltuariesulledirectory,comecrearneoeliminarneuna.

La seconda, invece, èunaclassed’istanza, e il suousoèpertantoconsigliato tutte levolte in cui dobbiamo compiere più operazioni, poiché alcune proprietà e parte delcontesto di sicurezza sono valutate solo in fase di creazione della stessa classe;DirectoryInforappresentainfattiunveroepropriomodelloaoggettidiunadirectorydelfilesystemecometale,possiamoutilizzarlo,adesempio,comeargomentodiunmetodo,inluogodiunasemplicestringa.

Questi due oggetti possono essere utilizzati per tutti le comuni operazioni che, daprompt dei comandi o dall’interfaccia diWindows Explorer, siamo abituati a compieresulledirectory.

Neiprossimiparagrafivedremoqualcheesempiosucomecreare,spostare,copiareedeliminarefileodirectory,mettendoinluceledifferenzedeterminatedall’utilizzodelleduetipologiedioggetti.

CreazionediunadirectoryLacreazionediunadirectorytramitelaclasseDirectoryInfopuòessereportataatermineconpocheesemplicioperazioni.Nelcodicedell’esempio19.1,abbiamocreatounanuovaistanza della classe DirectoryInfo, passando al costruttore una stringa contenente ilpercorso sul quale vogliamo compiere le nostre operazioni, ossia una directorydenominata“Capitolo20”all’internodi“Documenti”.

Esempio19.1ModuleModule1

SubMain()

Dim dInfo As DirectoryInfo = New

DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments),"Capitolo20"))

Try

dInfo.Create()

Console.WriteLine("Directorycreatacorrettamente")

CatcheAsException

Console.WriteLine("Impossibile creare la directory: {0}",

e.ToString())

EndTry

Console.ReadLine()

EndSub

Page 455: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndModule

Invecedicomporreilnomecompletodelpercorso,concatenandodirettamentelestringhe,abbiamo utilizzato il metodo Path.Combine: si tratta di un helper che risulta moltocomodo nellamanipolazione di questo tipo di stringhe, senza doverci preoccupare, peresempio,diincludereoverificarelapresenzadelcarattere“\”.

Una volta ottenuta l’istanza del tipo DirectoryInfo, non dobbiamo far altro cherichiamarne ilmetodo Create affinché la directory venga fisicamente creata. La figura19.1mostral’outputsuconsoledell’esempioprecedente.

Figura19.1–L’outputdellaconsoleapplication.

Nell’esempio 19.1, abbiamo utilizzato il metodo Environment.GetFolderPath perrecuperare il percorso della cartella “Documenti”. Esso accetta un parametro di tipoSpecialFolder;sitrattadiunenumerato,icuivalorisonoriassuntiintabella19.1.

Tabella19.1–L’enumeratoreSpecialFolder.Nome Significato

ApplicationData Directoryutilizzataperidatirelativiall'applicazione

Desktop DirectoryutilizzataperilDesktop

ProgramFiles Directoryprogrammi

MyComputer Directory"Risorsedelcomputer"

MyMusic Directory"Musica"

MyPictures Directory"Immagini"

MyDocuments Directory"Documenti"

È indispensabile comporre i percorsi usando Environment.GetFolderPath el’enumeratore SpecialFolder, così possiamo evitare di cablare nel codice il percorsofisico della directory, il quale non varia solo in base alla lingua utilizzatama potrebbecambiare tra unaversione e l’altra del sistemaoperativoo addirittura esseremodificatodall’utente.

LaclasseEnvironmentespone ilmetodoGetLogicalDrives,checirestituisceunarraycontenteilnomedituttiidrivelogicipresentinelsistema.

In un caso come quello appena esaminato, in cui dobbiamo compiere una singolaoperazionedicreazionediunadirectory,l’usodeltipostaticoDirectoryèpiùimmediatoeconciso.Comepossiamovederenell’esempio19.2, infatti, inquestocasoèsufficienteinvocareilmetodoCreateDirectorypassandoilpercorsodesiderato.

Esempio19.2

Page 456: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

ModuleModule1

SubMain()

Try

Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment

SpecialFolder.CommonDocuments),"Capitolo19"))

Console.WriteLine("Directorycreatacorrettamente")

CatchexAsException

Console.WriteLine("Impossibile creare la directory: {0}",

ex.ToString())

EndTry

Console.ReadLine()

EndSub

EndModule

ImetodiCreateeCreateDirectory,espostirispettivamentedallaclasseDirectoryInfoeDirectory,hannounoverloadcheaccettaunparametrodeltipoDirectorySecurity,cosìda poter specificare il livello di protezione e le autorizzazioni per la directory appenacreata.

EliminareunadirectoryNel paragrafo precedente abbiamo visto come sia semplice creare una directory;l’eliminazione è assolutamente analoga e non presenta, come possiamo vederenell’esempio19.3,particolaridifficoltà.

Esempio19.3ImportsSystem

ImportsSystem.IO

ModuleModule1

SubMain()

Dim dInfo As DirectoryInfo = New

DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments),"Capitolo20"))

Try

dInfo.Create()

Console.WriteLine("Directorycreatacorrettamente,premiuntastoper

eliminarla")

Console.ReadLine()

Page 457: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

dInfo.Delete()

Console.WriteLine("DirectoryEliminatacorrettamente")

CatchexAsException

Console.WriteLine("Sièverificatounerrore:{0}",ex.ToString())

EndTry

Console.ReadLine()

EndSub

EndModule

Ilcodicedell’esempio19.3,infatti,riutilizzainteramenteilcodicecheabbiamovistonelparagrafo precedente e, più precisamente, nell’esempio19.1, per costruire un’istanza diDirectoryInfo tramite la quale creare una directory su file system. Successivamentepossiamo procedere alla sua eliminazione, invocando ilmetodo Delete. La figura 19.2mostral’outputdiquestoesempiosullaconsole.

Figura19.2–L’outputdellaconsoleapplication.

Ilcodicedell’esempio19.4èanalogoall’esempio19.3,masfrutta laclasseDirectory;esso rappresenta un primo caso in cui si nota il vantaggio della soluzione basatasull’istanza rispettoaquestoapprocciochesfruttametodi statici. Inquestocaso, infatti,siamo costretti a utilizzare una varibile temporanea per memorizzare il percorso delladirectory,cosìdapassarlosiaalmetodoCreatesiaaquelloDelete.

Esempio19.4ImportsSystem

ImportsSystem.IO

ModuleModule1

SubMain()

Dim myPath As String =

Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments),"Capitolo19")

Try

Directory.CreateDirectory(myPath)

Console.WriteLine("Directory creata correttamente, premi un tasto

pereliminarla")

Console.ReadLine()

Page 458: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Directory.Delete(myPath)

Console.WriteLine("DirectoryEliminatacorrettamente")

CatchexAsException

Console.WriteLine("Impossibile creare la directory: {0}",

ex.ToString())

EndTry

Console.ReadLine()

EndSub

EndModule

Quando si eliminano delle directory con il codice mostrato nell’esempio 19.3 e 19.4,propriocomeavvienedalpromptdeicomandi,dobbiamoprestareattenzionealfattoche,nelcasoincuinonsianovuote,vienesollevataunaIOException.

Nell’esempio19.5 abbiamo utilizzato ilmetodo CreateSubdirectory per aggiungereunasottodirectoryalladirectorycreatatramiteDirectoryInfo.

Esempio19.5ModuleModule1

SubMain()

Dim dInfo As DirectoryInfo = New

DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments),"Capitolo20"))

Try

dInfo.Create()

dInfo.CreateSubdirectory("Esempio19.4")

Console.WriteLine("Directory e sotto directory creata

correttamente,premiun

tastopereliminarla")

Console.ReadLine()

dInfo.Delete(True)

Console.WriteLine("DirectoryEliminatacorrettamente")

CatchexAsException

Console.WriteLine("Sièverificatounerrore:{0}",ex.ToString())

EndTry

Console.ReadLine()

EndSub

EndModule

Page 459: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

L’utilizzodelparametroTruenelmetodoDeleteciconsentediprocederecomunqueallacancellazione.Passando,invece,ilvaloreFalse,siottienel’outputdifigura19.3.

Figura19.3–L’outputdellaconsoleapplicationquandositentadieliminareunadirectorynonvuota.

In termini del risultato ottenuto, passare False al metodo Delete(recursive As

Boolean)èdeltuttoequivalentearichiamareilmetodoDelete().

Perquantoriguardaleoperazionidicreazioneedeliminazionevistefinora,èpiuttostoindifferente utilizzare la classe Directory o DirectoryInfo. Nelle prossime paginevedremo invece che, per compiere operazioni più complesse quali lo spostamento o lacopia,ènecessarioutilizzarleentrambesecondolenecessità.

SpostareunadirectoryPossiamospostareunadirectorymedianteilmetodoMove,espostodallaclasseDirectoryo il metodo MoveTo (destDirName As String), esposto dalla classe DirectoryInfo.Nell’esempio 19.6, dopo aver creato la directory ne indichiamo il nuovo percorsomediante ilmetodoMoveTo.È importanteche,all’internodiquest’ultimo,nonesistagiàunadirectory con il nome chevogliamoutilizzare; in caso contrario, verrà sollevata uneccezioneel’operazionesaràabortita.

Esempio19.6ModuleModule1

SubMain()

Dim dInfo As DirectoryInfo = New

DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments),"Capitolo19"))

Try

dInfo.Create()

Console.WriteLine("Directorycreatacorrettamente,premiuntasto

perspostarla")

Page 460: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Console.ReadLine()

dInfo.MoveTo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonPictures),

"Capitolo19"))

Console.WriteLine("Directoryspostatacorrettamente")

CatchexAsException

Console.WriteLine("Sièverificatounerrore:{0}",ex.ToString())

EndTry

Console.ReadLine()

EndSub

EndModule

L’esempio 19.7 mostra il medesimo codice dell’esempio precedente, controllandopreventivamente l’esistenza della cartella destinazione ed annullando, eventualmente,l’operazione.

Esempio19.7ModuleModule1

SubMain()

Dim dInfo As DirectoryInfo = New

DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments),"Capitolo20"))

Try

dInfo.Create()

Console.WriteLine("Directory creata correttamente, premi un tasto

perspostarla")

Console.ReadLine()

IfNotDirectory.Exists(Path.Combine(Environment.

GetFolderPath(Environment.

SpecialFolder.CommonPictures),"Capitolo20"))Then

dInfo.MoveTo(Path.Combine(Environment.GetFolderPath(Environment.

SpecialFolder.

CommonPictures),"Capitolo19"))

Console.WriteLine("Directoryspostatacorrettamente")

Else

Console.WriteLine("Directorygiàesistente")

EndIf

CatchexAsException

Console.WriteLine("Sièverificatounerrore:{0}",ex.ToString())

Page 461: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndTry

Console.ReadLine()

EndSub

EndModule

Possiamo verificare l’esistenza di una directorymediante l’utilizzo delmetodo Exists,espostodallaclasseDirectory.EssoaccettaunparametroditipoString,cherappresentailpercorsodelladirectorydicuiverificarel’esistenza.

CopiareunadirectoryComepossiamovederenell’esempioseguente,copiareunadirectoryrichiedequalcherigadicodiceinpiù,poichénonesisteunmetodospecifico.

Nell’esempio 19.8, come prima cosa recuperiamo tutte le directory presenti nelladirectory; a questo scopo utilizziamo il metodo GetDirectories, esposto dalla classeDirectoryInfo.

Esempio19.8ModuleModule1

SubMain()

Dimdirectories()AsDirectoryInfo=NewDirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments)).GetDirectories()

Try

DimdirectoryInfoAsDirectoryInfo

ForEachdirectoryInfoIndirectories

If Not directoryInfo.GetAccessControl().AreAccessRulesProtected

Then

DimcopyPathAsString=Path.Combine(Environment.

GetFolderPath(Environment.SpecialFolder.CommonDocuments), String.Format("{0} copia",

directoryInfo.Name))

Directory.CreateDirectory(copyPath)

Console.WriteLine(String.Format("Directory{0}copiata

correttamente",directoryInfo.Name))

DimfileInfoAsFileInfo

Dimfiles()AsFileInfo=directoryInfo.GetFiles()

ForEachfileInfoInfiles

fileInfo.CopyTo(Path.Combine(copyPath,String.Format("{0}

copia{1}",Path.GetFileNameWithoutExtension(fileInfo.Name),Path.

Page 462: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

GetExtension(fileInfo.Name))))

Console.WriteLine(String.Format("File {0} copiato

correttamente",fileInfo.Name))

NextfileInfo

Else

Console.WriteLine(String.Format("Impossibile copiare la

directory

{0}",directoryInfo.Name))

EndIf

NextdirectoryInfo

CatchexAsException

Console.WriteLine("Sièverificatounerrore:{0}",ex.ToString())

EndTry

Console.ReadLine()

EndSub

EndModule

Proseguiamo iterando la collezione di oggetti DirectoryInfo, restituita dal metodoGetDirectories. Per ognuno di essi, mediante il metodo GetAccessControl,verifichiamo,attraversoilvaloredellaproprietàAreAccessRulesProtected,dipossederei requisiti necessari per compiere le operazioni successive. Se possiamo accedere alladirectory, ne creiamo una nuova con ilmetodo CreateDirectory, al quale passiamo ilnomedelladirectorycorrente.Sempresull’oggettoDirectoryInfocorrente,utilizziamoilmetodo GetFiles per recuperare i file presenti nella directory. Il metodo GetFilesrestituisceunacollezionedioggettiFileInfo;suognunodiessirichiamiamoilmetodoCopyTopereseguirelacopia.

Page 463: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura19.4–L’outputdellaconsoledopolacopiadelladirectory.

Lafigura19.4,mostral’outputprodottodallaconsoleapplicationcheabbiamorealizzatonell’esempio19.8; possiamo vedere come sia stato impossibile copiare la directoryMyMusic,MyPictureseMyVideo,inaccessibiliperlanostraconsoleApplication.

Nell’esempio 19.8, per eseguire la copia del file, abbiamo utilizzato un’istanza dellaclasseFileInfo,cheesponemetodieproprietàperlagestionedeifile.AlmetodoCopyToabbiamo passato una stringa, che è il risultato della concatenazione del percorso dellacopia della directory, più il nome del file corrente ma sprovvisto di estensione, cheabbiamo rimosso mediante l’utilizzo del metodo Path.GetFileNameWithoutExtension,seguitodallaparola“copia”einfinel’estensioneoriginaledelfile,recuperatamedianteilmetodoPath.GetExtension.

Negliesempiprecedenti,abbiamopiùvolteincontratolaclassePathquandoilcodicerichiedeva lamanipolazionedelpercorsodi fileedirectory.Maqualisono ivantaggidiutilizzarelaclassePathquandopossiamoutilizzareinumerosimetodiespostidallaclasseString per ottenere gli stessi risultati? Essa rappresenta un modo sicuro e testato dimanipolare i percorsi, un’operazione delicata che, se non eseguita correttamente, puòesporrelanostraapplicazioneaproblemididicurezzacome,adesempio,problemidipathcanonicalization. La tabella 19.2 riepiloga i metodi più frequentemente utilizzati dellaclassePath.

Tabella19.2–MembripiùcomunementeutilizzatidellaclassePath.Nome Significato

Combine(eoverload) Permettedicombinaredueopiùpartidiunpercorso,aggiungendo,senecessario,ilsimbolo/

GetExtension Recuperal’estensionedelfile,datoilpercorso

GetFileName Recuperailnomedelfileconl’estensione,datoilpercorso

GetFileNameWithoutExtension Recuperailnomedelfileprimadell’estensione

GetInvalidFileNameCharsOttieneun’arraydeicaratterinonconsentitineinomideifile,utilepercontrollarecheilnomediunfilenonlicontenga

GetRandomFileName Creainmodorandomilnomediunfileodiunadirectory

GetDirectoryName Recuperailnomedelladirectorydatoilpercorso

Lacreazione,l’eliminazione,lospostamentoelacopianonsonoleunicheoperazionicheè possibile effettuare sul file system. Nel prossimo paragrafo vedremo come eseguirericercheefiltrareilcontenutodiunadirectory.

Nelcasoincuisianecessariomonitorareeventualimodificheapportatealfilesystemdaaltreapplicazioniinesecuzionenelsistema,il.NETFrameworkmettea disposizione la classe FileSystemWatcher, che abbiamo avuto modo diillustrarenelcapitolo16.

EseguirericerchesulfilesystemUnanecessitàpiuttostocomuneperleapplicazionichelavoranoconfileecartelleèquelladieffettuare ricerche.LeclassiDirectoryeDirectoryInfo espongono,allo scopo,una

Page 464: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

seriedimetodi,chepossiamoutilizzarecomenell’esempio19.9.

Esempio19.9ModuleModule1

SubMain()

DimdInfoAsDirectoryInfo=NewDirectoryInfo(

Environment.GetFolderPath(

Environment.SpecialFolder.CommonDocuments))

Try

Dimdirectories()AsDirectoryInfo=

dInfo.GetDirectories("*",SearchOption.TopDirectoryOnly)

DimdirectoryAsDirectoryInfo

ForEachdirectoryIndirectories

Console.WriteLine(

"{0}{1}",directory.FullName,directory.LastAccessTime)

Nextdirectory

CatchexAsException

Console.WriteLine(

"Sièverificatounerrore:{0}",ex.ToString())

EndTry

Console.ReadLine()

EndSub

EndModule

L’esempio19.9èmoltosimileaiprecedenti:periniziare,creiamoun’istanzadellaclasseDirectoryInfo. In seguito, per ottenere una lista delle directory, utilizziamo il metodoGetDirectory,alqualepassiamodueargomenti:ilprimo,deltipoString, rappresenta icriteridiricerca,ilsecondo,deltipoSearchOption,indicadinonpropagarelaricercaallesottodirectory.Possiamovedereilrisultatodellaricercanellafigura19.5.

Figura19.5–L’outputdellaconsoledopolaricerca.

Page 465: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Nell’esempio19.8cisiamolimitatiaenumeraresolamenteledirectory.Lemodifichedaapportarealcodiceperrecuperareifilesonosemplicissimeeconsistononell’utilizzareilmetodoGetFiles.Una delle operazioni più comuni sui file, oltre allo spostamento e lacopia, è la creazione e la successiva modifica del suo contenuto. Questi saranno gliargomentidelprossimoparagrafo.

CreareemodificareunfileLagestionedeifile,lalorocreazione,illorospostamentooeliminazione,comeabbiamoavuto modo di vedere negli esempi precedenti, avvengono mediante il tipo File oFileInfo.Nell’esempio19.10 abbiamo utilizzato ilmetodo File.Create per creare unfiledalnome“myFile.txt”.

Esempio19.10ModuleModule1

SubMain()

Try

DimmyfileStreamAsFileStream

DimmyPathAsString=Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments),"myfile.txt")

myfileStream=File.Create(myPath)

DiminfoAsByte()=NewUTF8Encoding(True).GetBytes("Unsaluto

dall'autorediquestocapitolo.")

myfileStream.Write(info,0,info.Length)

myfileStream.Close()

DimmySteamiReaderAsStreamReader=File.OpenText(myPath)

DoWhilemySteamiReader.Peek()>=0

Console.WriteLine("il file contiene: {0}",

mySteamiReader.ReadLine())

Loop

mySteamiReader.Close()

CatchexAsException

Console.WriteLine("Sièverificatounerrore:{0}",ex.ToString())

EndTry

Console.ReadLine()

EndSub

EndModule

Ilmetodo File.Create restituisce un’istanza della classe FileStream. Questa classe ci

Page 466: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

consentedimanipolarneilcontenuto,accodandodel testotramiteilmetodoWrite,dopoaverlocodificatoinformatoUTF8.

Figura19.6–Ilcontenutodelfile,visualizzatonellaconsoleapplication.

L’immagine19.6mostra il risultato della creazionedel file e dell’inserimentodel testo.Bisognaprestareattenzionealfattoche,nelcasoincuiilfilesiagiàpresente,l’esecuzionedel metodo File.Create ne comporta la sovrascrittura. Pertanto, è sempre meglioverificarnepreventivamentel’esistenzatramiteilmetodoFile.Exists.

Nell’esempio19.10abbiamoutilizzatoiltipoFileStream.Piùingenerale,unostream è un’astrazione che produce o consuma informazioni. Tutti i tipi distream presentano un medesimo comportamento, ereditato dalla classe baseStream.Ciò permette di utilizzare tutti gli stream allo stessomodo, anche seprovenientidafontidifferenti.

Al livello più basso, tutti gli stream operano sui byte; noi esseri umani nonsiamo abituati a lavorare direttamente sui byte e, per questo motivo, il .NetFrameworkdefiniscediverseclassichesonoingradodiconvertireunflussodibyteinunflussodicaratteri,permettendocidileggereescrivere,peresempio,leinformazionicontenuteinunfile.Vedremoaltritipidistreamnelcapitolo19.

È importante porre attenzione alla scelta della directory nella quale salvare i dati dellanostra applicazione: esistono cartelle, come Programmi o System, per il cui accesso inscritturaWindows richiede di impersonare un utente con privilegi amministrativi. Unapossibile alternativa, allora, può essere quella di utilizzare l’IsolatedStorage, ossia unaporzionedidiscocheWindowsriservaalleapplicazioni.

IsolatedStorageQuando scegliamo un percorso permemorizzare i dati della nostra applicazione, senzasaperlo,stiamoprendendounadecisionedelicata.Infatti,nonpossiamoescludereapriorichequelpercorsosiagiàutilizzatoochesaràutilizzatoinfuturo.Questasituazionepuòportare conseguenze difficilmente calcolabili, specialmente se la congruenza delleinformazionièunrequisitofondamentale.

PerovviareaquestoinconvenientepossiamoutilizzarelaclasseIsolatedStorageFile.Tale classe rappresenta un compartimento stagno, basato sull’identità dell’Assembly edell’utente e perciò non esposto all’interferenza di altre applicazioni. Naturalmentel’IsolatedStoragenonèmagica:ilsupportodimemorizzazioneèsempreildiscodelnostrocomputer, più precisamente <SYSTEMDRIVE>\ Users\<user>\AppData\Local.

Page 467: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Semplificando,quellochefal’IsolatedStorageèimpedirecheleinformazionidellanostraapplicazione sianodistruttedaaltre.Nell’esempio seguentevedremocomeottenereunostore,creareunadirectoryeaggiungereunnuovofile.

L’esempio 19.11 prende spunto dal precedente 19.10, ma è stato modificato perutilizzare la classe IsolatedStorageFile. Questa classe non può essere istanziatadirettamenteeperottenereunriferimentovalidoènecessarioutilizzareilmetodostaticoGetStore; in seguito, controlliamo che lo storage contenga o meno una directory dalnome“Documenti”e,incasonegativo,procediamoallasuacreazionemedianteilmetodoCreateDirectory.

Esempio19.11ModuleModule1

SubMain()

Try

DimisoFileAsIsolatedStorageFile=IsolatedStorageFile.GetStore(IsolatedStorageScope.UserOrIsolatedStorageScope.AssemblyOr

IsolatedStorageScope.Domain,GetType(System.Security.Policy.Url),GetType(System.Security.Policy.Url))

IfNotisoFile.DirectoryExists("Documenti")Then

isoFile.CreateDirectory("Documenti")

EndIf

Dim isoStream As IsolatedStorageFileStream =

isoFile.CreateFile("myFile.

txt")

DiminfoAsByte()=NewUTF8Encoding(True).GetBytes("Unsaluto

dall'autorediquestocapitolo.")

isoStream.Write(info,0,info.Length)

isoStream.Close()

DimmySteamiReaderAsStreamReader=NewStreamReader(isoFile.

OpenFile("myFile.txt",FileMode.Open))

DoWhilemySteamiReader.Peek()>=0

Console.WriteLine("il file contiene: {0}",

mySteamiReader.ReadLine())

Loop

mySteamiReader.Close()

CatchexAsException

Console.WriteLine("Sièverificatounerrore:{0}",ex.ToString())

Page 468: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndTry

Console.ReadLine()

EndSub

EndModule

Quest’ultimopassonondifferiscemoltodaquantofattoinprecedenza.Lostessovaleperil file, che possiamo creare mediante l’utilizzo del metodo CreateFile, esposto dallaclasseIsolatedStorageFile.

La lettura avviene inmanieradel tutto analogaall’esempioprecedente,utilizzando laclasse StreamReader. Come possiamo notare, però, in questo caso abbiamo costruitosfruttando un particolare tipo di stream, IsolatedStorageFileStream, che rappresenta unflussodibytediunfilecontenutonell’isolatedstorageechepossiamoottenereinvocandoilmetodoIsolatedStorageFile.OpenFile.

L’output dell’applicazione è il medesimo di figura 19.7, ma il comportamento èsensibilmente differente, perché siamo riusciti a scrivere su una porzione del discoappositamente dedicata da Windows per la memorizzazione di dati specificidell’applicazione.

IlRegistryIlRegistry è il cuorepulsantediWindows, in esso sonomantenute, sotto formadi unastrutturagerarchica,leinformazionivitaliperilfunzionamentodelsistemaoperativoeperleapplicazionichevisonoinstallate.

La sua introduzione risale alla versione 3.0 diWindows e vi sonomantenuti profiloutente,hardwareequantoaltroprimavenivamemorizzatoneifile*.INI.

Lavorare con le informazioni contenute nel Registry è un’operazione delicata.L’eliminazioneaccidentalediunachiaveounamodificainopportuna,puòcompromettereilcorrettofunzionamentodelsistema,finoacausarneilblocco.Èperquestomotivoche,prima di qualsiasi modifica al Registry, è consigliabile fare una copia dello stesso,operazionechepossiamocompiereutilizzandol’applicazioneRegEdit.exe.

Prima di interagire con il registro è indispensabile conoscerne alcuni aspetti. Comeabbiamo detto, le informazioni in esso contenute sono organizzare in forma gerarchica;ognielementodellagerarchiaèchiamatochiave(key)eognichiavecontieneunaseriedivalori(values).

Page 469: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura19.7–L’applicazioneRegEditor.

Nell’immagine 19.7 possiamo vedere l’interfaccia dell’applicazione RegEdit. Sullasinistra troviamolastrutturagerarchicamediante laqualeèorganizzato ilRegitry.Sulladestraidettaglidellachiaveselezionata.

Lagerarchiasicomponediunnodoprincipale,ilqualerappresentailnostrocomputeredacinquesottochiavi:

HKEY_CLASSES_ROOT contiene le informazioni memorizzate circa leapplicazioniregistrateeleassociazioniconleestensionideifile;

HKEY_CURRENT_USER contiene le informazioni relative al profilo utentecorrente,linkandoledallachiaveHKEY_USERS;

HKEY_LOCAL_MACHINE contiene le informazioni comuni a tutti gli utenticome,adesempio,leconfigurazionihardwaredelcomputer;

HKEY_USERScontienegliutentiregistratinelsistema;

HKEY_CURRENT_CONFIG contiene informazioni relative al runtime, nonpersistitesudiscoeottenuteduranteilbootdellamacchina.

PossiamoeseguireunbackupcompletodelRegistryattraversolavoceExport,chetroviamosottoilmenuFile.

In ambiente .NET possiamo, leggere, aggiornare e creare nuove chiavi del RegistrymediantelaclasseRegistryKey,chetroviamonelnamespaceMicrosoft.Win32.

Lo scopo dell’esempio 19.12 è quello di leggere la chiave di registro evidenziatanell’immagine19.8.IlpuntodipartenzaèlachiaveLOCAL_MACHINE,acuièpossibileaccedereutilizzandoilcorrispondentefieldstaticoLocalMachine.

Page 470: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio19.12ModuleModule1

SubMain()

DimregistrykeyAsRegistryKey=Registry.LocalMachine

registrykey =

registrykey.OpenSubKey("HARDWARE\\DESCRIPTION\\System\\

CentralProcessor\\0")

DimvalueAsObject=registrykey.GetValue("ProcessorNameString")

Console.WriteLine("Iltuòprocessoreè:"+value)

Console.ReadLine()

EndSub

EndModule

Successivamente,tramiteilmetodoOpenSubKeyèpossibileaddentrarcineidettagli,finoarecuperareilvaloredellachiaveProcessorNameString,chepossiamomostrareavideo.

L’immagine19.8mostrailrisultatodell’esempio19.11,tramiteilqualesiamoriuscitiadeterminarelatipologiadelprocessoreinstallato.

Possiamo inoltre aggiungere e rimuovereunachiavenel registroutilizzando imetodiCreateSubKeyeDeleteSubKey,ponendomoltoattenzioneacosaandiamoaeliminareconquest’ultimo; si tratta infatti dimodifiche irreversibili epertanto, soprattuttoutilizzandoDeleteSubKey,bisognaesseremoltoaccorti.

Figura19.8–Iltipodiprocessoreinstallato,visualizzatonellaConsoleApplication.

Lacreazionediunachiaveèsemplicecomelasualettura:l’esempio19.13mostracomecreareunanuovachiaveeaggiungereilvalorealsuointerno.

Esempio19.13ModuleModule1

SubMain()

Dimchapter20AsRegistryKey=Registry.CurrentUser.CreateSubKey("Capitolo20")

DimautorAsRegistryKey=chapter19.CreateSubKey("Autore")

autor.SetValue("Name","Marco")

Page 471: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Console.WriteLine("Chiavecreataconsuccesso")

Console.ReadLine()

EndSub

EndModule

Analogamente agli esempiprecedenti, tramite il field staticoCurrentUser espostodallaclasseRegistry,possiamoottenereunriferimentoallachiaveHKEY_CURRENT_USER,all’interno della quale abbiamo creato le due nuove chiavi “Capitolo20” e “Autore”,utilizzandoilmetodoCreateSubKey.InfineconilmetodoSetValue,abbiamoinseritounnuovovalore,identificatodallaparola“Name”econilvalore“Marco”.

Figura19.9–Ilrisultatodell’esempio19.12.

L’immagine 19.9 mostra la chiave e il valore aggiunti al Registry dopo l’esecuzionedell’esempio19.12Ilregistrypuòessereutilizzatodallenostreapplicazionipersalvareerecuperare le informazioni di configurazione e ha il vantaggio dimantenere degli storeseparatiperutente,oltreaunostoreglobale.Attenzioneperòal fattoche idatichepuòcontenerehannodimensione limitataeche il contenutodeveessereespresso in formatostringa o binario (e in quest’ultimo caso, quindi, non leggibile se non con un appositotool).

Finoracisiamolimitatiautilizzarerisorselocaliallamacchinaincuièinesecuzionelanostraapplicazione.Nelprossimoparagrafoelimineremoquestovincoloevedremocomeaccedereafileerisorseremote.

Principidicomunicazionedirete

Page 472: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Lanecessitàdimettere incomunicazionepiù sisteminascedall’esigenzadicondividereinformazionitrapiùapplicazioni,ancheeterogeneeodistantigeograficamente.Negliannisettanta, questa esigenza ha portato i ricercatori del Massachusetts Institute ofTechnology (il famosoMIT) a sviluppare unmodello di inter-connessione “a rete”, diefficienzasuperiorerispettoaunaconnessionelineare.Inquestomodelloleinformazionipotevano transitare in più percorsi diversi, senza che fosse necessaria la presenza di unsistemaspecifico.

Le fondamenta di tale architettura si basano sul protocollo di rete IP (InternetProtocol), cheprevede la frammentazionedeidati inpiùpacchetti, al finedi transitareall’internodellareteinmodoframmentatoedautonomo,conilvantaggiodipoteressererichiestinuovamente,incasodicorruzioneoperdita.

Nonostante il modello “a rete”, è indispensabile che ogni sistema connesso siaidentificabileinmanieraunivocarispettoaglialtri.Perquestomotivo,aciascunodiessiviene assegnato un indirizzo IP, generalmente composto da quattro numeri a tre cifre,separatidaunpunto.

Per conoscere il proprio indirizzo è sufficiente visualizzare le proprietà di rete,seguendo le procedure del proprio sistema operativo, oppure richiamare “IpConfig” inconsole,darigadicomando.

Quandouncomputernonèconnessoadalcunarete,hal’indirizzoIP127.0.0.1.Questovieneutilizzatodalsistemaoperativoproprioperriferirsiasestesso,inassenzadiconnessionedirete.Esisteancheunalias,conilnomedilocalhost.

L’indirizzodelnostrocomputerall’internodiunareteèunivoco,masolorispettoaglialtrisistemi connessi a tale rete; quando siamo connessi a Internet, il nostro indirizzo nonidentificadirettamentealcuncomputer,mailrouterchefadagatewayperlaconnessione.

Architetturaalivelli:ilmodelloditrasportoPossiamosemplificarel’architetturadiretecomeunmodelloaquattro“livelli”principali:oltreallivello“fisico”,definitodall’hardware,abbiamogiàaccennatoalprotocollodireteIP, il quale costituisce il fondamento, definendo le modalità con cui devono essereorganizzatiidati,perrispettareunodeiparadigmidell’architettura.Illivellosovrastantesioccupadidefinirelatipologiadiscambiodeidati;neglianni,sisonoaffermatiiprotocolliTCPeUDP,deiqualiparleremoinseguito.Taliprotocollisonospecializzatineldefinirecomeipacchettidebbanoessereveicolatiegestitinellevarierichiesteepertantopossonoessereclassificatiall’internodeiprotocolliditrasporto.

Infine, ilmacro-livellosovrastanteècostituitodaibenpiùnotiprotocolliapplicativi,comel’HTTPel’FTP,iqualidefinisconoleinterfacceconleapplicazioni,epossiedonocaratteristichespecificheperitipididatieserviziaiqualisirapportano.

IlprotocolloHTTP(HypertextTransfertProtocol),adesempio,sibasasulprincipiodi “richiestae risposta”, tipicodellearchitettureclient/server.Sviluppato inambitowebperladivulgazionedidocumentiipertestuali,ilclientèrappresentatodalbrowser,ilquale

Page 473: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

invia in messaggio di “richiesta” al server (web), che restituisce i dati attraverso unmessaggio di “risposta”. Al termine dell’interazione, la connessione viene chiusaautomaticamente,senzaalcunagestionedellostato:ilprotocolloHTTP,infatti,ènotoperessere “stateless” (senza stato) e la sua diffusione, accoppiata a Internet, ha spinto glisviluppatoriatrovaresoluzionialternative(neilinguaggistessi)perlagestionedellostato.

PorteeprotocolliapplicativistandardPerognispecificatipologiadiserviziesposti inrete,natiancheinparalleloconi tipididatidagestire,èstatasviluppataunamoltitudinediprotocolliapplicativi,spessocreandounaduplicazionedifunzionalità.Perriceverecontemporaneamentedatieterogenei tra lastessacoppiadihost,èstatosviluppatoilconcettodimultiplazionediporte,grazieallaquale ogni protocollo applicativo utilizza una specifica porta (un intero a 16 bit), perdistinguere,alivelloditrasporto,ipropripacchettiintransito.

Benché del tutto arbitrarie, negli anni si sono consolidate alcune coppie di porte ditrasmissioneeprotocolliapplicativi,divenendosuccessivamenteveriepropristandard.Nellatabella19.1possiamoleggereunelencodeiprotocollipiùnoti,conlecorrispondentiportedicomunicazione.

Tabella19.3-Principaliprotocollierelativeportedicomunicazione.Porta Protocollo Utilizzo

21 FTP Scambiodati

25 SMTP Inviomessaggie-mail

110 POP3 Ricezionemessaggie-mail

143 IMAP Ricezionemessaggie-mail

80 HTTP (HyperTextTransferProtocol)Pagineweb

119 NNTP Newsgroup

Taliprotocolli sono incostanteevoluzione, inparallelocon icambiamentie leesigenzetecnologichechesipresentano:lostessoIMAPrappresental’evoluzionedelPOP3perlaricezione di posta elettronica, in risposta alla necessità di una gestione più evoluta deimessaggi, anche sudispositivimobili.Trattandosidi standarddi comunicazione, la lorodiffusioneèmoltogradualeediluitaneltempo.

IprotocolliTCPeUDPDopounabreve introduzione alla comunicazionedi rete, parliamodei dueprotocolli ditrasporto maggiormente utilizzati nelle nostre applicazioni: il Transmission ControlProtocol(TCP)el’UserDatagramProtocol(UDP).Comepossiamointuiregiàdalloronome,laparticolaritàdelprotocolloTCPèilcontrollodeidatiintransito;nellospecifico,taleprotocolloprevedecheipacchettiarrivinoadestinazione,chenonsianocorrottiechearrivino anche nello stesso ordine in cui sono stati inviati. Com’è comprensibile, tale

Page 474: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

controllosottoponeaunonerepercettibile,soprattuttointerminiditempoditrasmissione;percontro,offreunanotevolegaranziainmateriadiqualitàdellacomunicazione.

LadifferenzaprincipaletrailTCPeUDPèproprioilcontrollosuidati intransito: inUDPabbiamounavelocitàmaggioredicomunicazione,proprioperl’assenzadicontrollo,eidativengonoinviatisottoformadidatagrammi,cheilriceventepuòomenoricevere.Taleprotocollotrovaimpiegonellecomunicazioniincuihapiùimportanzalavelocitàditrasmissione rispetto alla qualità come, ad esempio, nelle trasmissionibroadcast, nellequaliètrascurabileperderealcunibyte,nelcomplessodellacomunicazione.

Il TCP, invece, è molto più adatto nel trasferimento di file, per i quali l’attesa ègiustificatadaundatocompletamentevalidoeutilizzabiledall’applicazionerichiedente.IlprotocolloHTTPsiappoggiaaTCPproprioperlanecessitàcheunfileHTMLarrivialbrowserintegroeinterpretabile.

IsocketelacomunicazioneabassolivelloNella programmazione managed, poniamo la nostra attenzione sul livello più alto dicomunicazione,trascurandolemodalitàdiscambiodeipacchettieconcentrandocisuidatie sulla logica applicativa, mentre il resto delle operazioni a basso livello è gestito dalsistema operativo ed è del tutto trasparente per il programmatore e per l’applicazionestessa.

L’oggetto di livello inferiore, per la gestione delle comunicazioni, è Socket, delnamespaceSystem.Net.Sockets,attraversoilqualeabbiamoilcontrollocapillaredituttele impostazionidiconnessione.Qualoranonavessimo lanecessitàdi talecontrollo,checomporta alcuni oneri in termini di sviluppo, possiamo utilizzare le seguenti classispecializzate,chetroviamogiàimplementatenellaBCLdel.NETFramework:

UdpClient;

TcpClient;

TcpListener.

Neiparagrafisuccessivivedremocomeutilizzarequesteclassi.

InviareunsemplicetestoconunclientUDPLa classe UdpClient consente uno scambio di dati inmodalità socket, quindi di bassolivello, attraverso il protocollo UDP, senza stato e senza la necessità di attendere laconnessioneconunhostspecifico.

Nell’esempio 19.14, vediamo come inviare una semplice stringa di testo attraversoun’istanzadell’oggettoUdpClient.

Esempio19.14

Page 475: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

PrivateSubButton1_Click(ByValsenderAsSystem.Object,_

ByValeAsSystem.Windows.RoutedEventArgs)HandlesButton1.Click

DimclientAsNewUdpClient()

client.Connect("localhost",8080)

DimsendByteAsByte()=Encoding.ASCII.GetBytes(TextBox1.Text)

client.SendAsync(sendByte,sendByte.Length)

EndSub

Per iniziare la connessione, utilizziamo il metodo Connect e specifichiamo comeparametrisia l’hostacuivogliamoinviare imessaggisia laportadicomunicazionecheuseremo:inquestocasoinviamoimessaggiallastessamacchina(localhost)attraversolaporta8080.Questovaloredeveesseresuperiorea1024pernonandareinconflittoconleporte standard, di cui abbiamo parlato, e la porta non deve essere utilizzata da altreapplicazioni. L’effettivo invio dei dati avviene attraverso il metodo SendAsync, a cuipassiamo l’array di byte corrispondenti al testo che vogliamo trasmettere, oltre allalunghezzadell’arraystesso.

Per eseguire questo esempio abbiamo costruito un semplice client WPF, con unaTextBox in cuipossiamo immettere il testo, oltre aunButton,di cuigestiamo l’eventoClickconilcodicedell’esempio19.13.Nelcorsodelcapitoloutilizzeremoquestotipodiinterfacciapereseguireglialtriesempi.

RicevereimessaggiconunminiserverUDPPer ricevere i messaggi possiamo utilizzare la stessa classe UdpClient e il metodoReiceveAsync, non prima di essercimessi in ascolto su una combinazione specifica diindirizzo/porta.Comeabbiamospiegatoinprecedenza,ilprotocollononprevedechesiastabilitaunaconnessione,quindilaricezioneèdeltuttosvincolatadall’invioenecessita,pertanto, che sia eseguito in continuo. Nell’esempio 19.15, grazie al metodoReiceveAsyncilcicloWhilepuòcontinuaresenzachel’interfacciarimangabloccata.

Esempio19.15PublicDelegateSubPrintDataDelegate(ByValresultAsString)

PublicSubNew()

InitializeComponent()

ReiceveData()

EndSub

PrivateAsyncSubReiceveData()

DimserverAsNewUdpClient(8080)

While(True)

DimresultAsUdpReceiveResult=Awaitserver.ReceiveAsync()

Page 476: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DimreiceveByteAsByte()=result.Buffer

DimreiceveStringAsString=Encoding.ASCII.GetString(reiceveByte)

TextBox2.Text+=String.Format("{0}",reiceveString)

EndWhile

EndSub

Anche in questo caso abbiamo creato una sempliceWPFApplication, che chiameremo“Server”: nel costruttore dell’UserControl principale richiamiamo il metodoReiceveData. In tale metodo, in un ciclo sempre attivo, andiamo a ricevere i datiprovenienti da tutti gli host in comunicazione sulla porta 8080, dichiarando un oggettoIPEndPoint. Infine,nonci rimanecheconvertire in stringa ibyte ricevuti e stamparli avideo,nelTextBoxinseritoappositamente.Nellafigura19.10possiamovederel’usodelleapplicazioniclienteserverdiesempio.

Figura19.10–EsempiodiscambiodatitraapplicazioniconprotocolloUDP.

Con le dovute semplificazioni dettate dalla necessità di non complicare l’esempio, conpoche righe di codice abbiamo visto come sia semplice scambiare dati tra diverseapplicazioni.

InviareericeveredaticonlaclasseTcpClientCome abbiamo detto, la natura del protocollo TCP lo rende più indicato per iltrasferimentodifileedati,lacuiintegritàèpiùimportantedellavelocitàditrasmissione.Comeper l’UDP,nel .NETFrameworkesisteunaclasse socket specializzataperquestoprotocollo,laclasseTcpClient.

A differenza di UdpClient, per inizializzare un trasferimento con TcpClient ènecessario che sia preventivamente stabilita una connessione con un ricevente. Questaoperazione può essere eseguita attraverso la classe TcpListener, grazie alla qualepossiamoattendereegestireleconnessioniprovenientidapiùclient.

Per introdurre lemodalitàd’usodiquesteclassi,analizziamounsempliceesempioditrasferimentodati,inmodochepiùclientpossanovisualizzaresuunaapplicazioneserveralcune immagini selezionate dall’utente. Come per l’applicazione server dell’esempio19.14, procediamo alla creazione di una WPF Application e, nel costruttoredell’UserControl principale andiamo ad inizializzare l’oggetto TcpListener.L’implementazioneèvisibilenell’esempio19.16.

Page 477: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Esempio19.16Private Async Sub W_Loaded(sender As Object, e As RoutedEventArgs)

Handles

MainWind.Loaded

AwaitReiceveData()

EndSub

AsyncFunctionReiceveData()AsTask

Dim server As New TcpListener(New IPEndPoint(IPAddress.Any, 1234))

server.Start()

While(True)

DimlocalClientAsTcpClient=Awaitserver.AcceptTcpClientAsync()

DimnetStreamAsNetworkStream=localClient.GetStream()

IfnetStream.CanReadThen

DimdataStreamAsMemoryStream=NewMemoryStream()

DimdataByteAsByte()=NewByte(1023){}

DimiAsInteger=0

Do

i=AwaitnetStream.ReadAsync(dataByte,0,1024)

Ifi>0Then

dataStream.Write(dataByte,0,i)

EndIf

LoopWhilei>0

dataStream.Seek(0,SeekOrigin.Begin)

DimbmpImageAsBitmapImage=NewBitmapImage()

bmpImage.BeginInit()

bmpImage.StreamSource=dataStream

bmpImage.EndInit()

DimimgAsImage=NewImage()

img.Stretch=Stretch.Uniform

img.Source=bmpImage

StackPanel1.Children.Add(img)

EndIf

localClient.Close()

netStream.Close()

EndWhile

EndFunction

Page 478: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Conl’oggettoIPEndPointspecifichiamogliindirizzieleportedeglihostsucuil’oggettoTcpListener rimane in ascolto in attesa di possibili connessioni, mentre conIPAddress.Anyciapriamoatuttiipotenzialiclient.

All’interno di un ciclo attiviamo la comunicazione con AcceptTcpClientAsync, cherestituisce l’oggetto TcpClient, mediante il quale possiamo inviare e ricevere i dati.Nell’esempioprecedenterecuperiamolostreamdicomunicazione,ditipoNetworkStream,attraversoilmetodoGetStream.Trattandosidellaparteserverdelnostroesempio,quellain ricezione, procediamo alla lettura dei dati, salvandoli in unMemoryStream, al fine dipoterliutilizzarecomesorgentedell’oggettoBitmapImage,edimostrarliavideoconuncontrolloditipoImage.

Per realizzare l’esempio, andiamo a creare un’applicazione nella quale daremo lapossibilitàdiscegliereun’immagineconl’oggettoOpenFileDialog,eneinvieremoidatiin modo del tutto simile a quanto abbiamo fatto nell’applicazione server. Possiamovederneunaimplementazionenell’esempio19.17.

Esempio19.17Private Async Sub Button1_Click(ByVal sender As System.Object, ByVal e

As

System.Windows.RoutedEventArgs)HandlesButton1.Click

UsingfileStreamAsStream=File.OpenRead(TextBlock1.Tag.ToString())

DimclientAsNewTcpClient()

Awaitclient.ConnectAsync("localhost",1234)

DimnetStreamAsNetworkStream=client.GetStream()

DimsendBuffer(1023)AsByte

DimbytesReadAsInteger=0

Do

bytesRead=AwaitfileStream.ReadAsync(sendBuffer,0,1024)

IfbytesRead>0Then

netStream.Write(sendBuffer,0,bytesRead)

EndIf

LoopWhilebytesRead>0

netStream.Close()

EndUsing

EndSub

Dopo aver aperto lo stream dell’immagine presente sul file system, inizializziamol’oggettoTcpClient e apriamouna connessione all’host locale, sulla porta 1234, con ilmetodoConnectAsync.Proprioperlanaturadelprotocollo,èimportanteche,almomentodellachiamatadelmetodoConnect,ilserversiagiàattivoeinascolto.

Page 479: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Con GetStream apriamo il NetworkStream, con il quale inviamo i dati al server, eandiamoascrivereibytedell’immagineselezionata.

Nella figura 19.11 possiamo notare come più client possano inviare al server i bytecorrispondentialleimmaginiselezionate,senzalanecessitàditrasferireverieproprifile,un’operazioneper laqualeabbiamoadisposizionespecificioggetticheanalizzeremo inseguito.

Figura19.11–EsempiodiscambiodidatitraapplicazioniconprotocolloTCP.

Con queste classi abbiamo visto come sia semplice gestire le comunicazioni a livellobasso.Proseguiamooraconl’analisideglialtrioggettidel.NETFramework.

IlnamespaceSystem.NetNellasezioneprecedenteabbiamodescrittoleclassidelnamespaceSystem.Net.Sockets,chesonoclassidilivellobassoperlacomunicazionedidati.Oltreaqueste,nelnamespaceSystem.Net possiamo trovare una vasta serie di strumenti specializzati nellacomunicazione con i protocolli applicativi, come HTTP o FTP, che ci sollevanodall’oneredellagestionedirettadeibyte.

Iprincipalioggettid’usopiùfrequentesonorappresentatiinfigura19.12.

Page 480: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Figura19.12–GerarchiadeglioggettinamespaceSystem.Net.

Inaltrepartidelmanuale,analizzeremolecaratteristicheeimodid’usodiquesteclassi,cosìdacomprendernealmegliol’utilitàspecifica.

LaclasseWebClientNell’introduzionealprotocolloTCPeall’utilizzodell’oggettoTcpClient,abbiamovistolaperentorianecessitàdirealizzareunaspecificacontroparte,cosiddetta“server”,conlaquale instaurare una connessione per l’invio e la ricezione dei dati. Nel contesto delprotocolloapplicativoHTTP(maquestodiscorsovaleancheperFTPoSMTP), laparte“server”puòessereeseguitadaunadellenoteapplicazioniwebserver,comeMicrosoftInternetInformationServices(IIS),Apacheoaltreapplicazioni,asecondadelsistemaoperativocheabbiamoscelto.Lapresenzaditaliapplicazioni,benintegrateconisistemioperativistessi,rendemoltofacileladistribuzionediinformazionipubblicheattraversolareteinternet.

Unwebserveropportunamenteconfiguratoecollegatoallarete,infatti,èaccessibiledaogniclientcheneeseguaspecificherichieste,adesempio,attraversolaporta80,riservataproprio al protocollo HTTP. Con i browser abbiamo la possibilità di consultarevisivamente le informazioni presenti nei server attraverso il linguaggio HTML, mapossiamoancheutilizzareilprotocolloperloscambiodidati,cosìcomeabbiamovistoneiprecedenti paragrafi: per tali operazioni di base abbiamo a disposizione la classeWebClient.

Questa classe ci consente di effettuare le principali operazioni di comunicazione,usando i protocolli HTTP, FTP e File. Abbiamo un’interfaccia unica semplificata, condiversimetodi per gestire i dati di risorse esposte sia da unweb server sia da un FTP

Page 481: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

server,ma anchedirettamente da file system.Nell’esempio19.18 utilizziamo ilmetodoOpenReadTaskAsyncperaccedereaunarisorsapresenteinunsitowebditest,aprendounostreamdidatierecuperandoiltestocorrispondente.

Esempio19.18DimclientAsWebClient=NewWebClient()

DimdataStreamAsStream=Awaitclient.OpenReadTaskAsync(_

NewUriBuilder("http","localhost",1503,TextBox1.Text).Uri)

DimreaderAsStreamReader=NewStreamReader(dataStream)

DimdataAsString=Awaitreader.ReadToEndAsync()

TextBox2.Text=data

Nellafigura19.13vediamocomel’applicazioned’esempio legga ilcontenutodel fileditesto,inmodomoltosimileaunbrowser.

Figura19.13–EsempiodiaccessoarisorsaHTTPconbrowsereWebClient.

Nell’esempio19.17,abbiamorichiamatoconsuccessounfileTXT,poichésitrattadiuntipo di risorsa il cuiMIME èmappato e quindi gestito da IIS. Il registro dimappaturaprevedeunaconfigurazionepredefinitaperlaqualealcunerisorseentranonelprocessodigestionediASP.NET,mentrealtrevengonosemplicementerestituitedalwebserversottoformadirisposta.

Nell’esempio 19.17 e in tutti quelli che necessitano di un sito web, abbiamoutilizzatoun’applicazionewebinesecuzioneconASP.NETDevelopmentServer,preferito a IIS. La scelta è voluta, al fine di rendere gli esempi allegatifacilmenteeseguibili,senzadovereffettuareparticolariconfigurazioni.Pernonandareinconflittoconlaporta80gestitadaIIS,questowebserverintercettalerichieste HTTP su una porta configurata: nell’esempio 19.17 è la 1503.Pertanto, negli esempi andremo a specificare tale porta, oltre a “localhost”comehost.

OltreaOpenReadTaskAsync,possiamoleggereidaticoniseguentimetodi:

Page 482: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

DownloadData: restituisce direttamente l’array di byte di una risorsa;DownloadDataTaskAsyncèlacorrispondentemodalitàasincronadiDownloadData,cheeseguelarichiestaesvincolailthreaddall’attesadellaricezionedeidati;

DownloadFile: esegue il download di un file remoto su un file locale; conDownloadFileTaskAsync possiamo eseguire questa operazione, ma in modalitàasincrona;

DownloadString: restituisce direttamente il contenuto della risorsa, eseguendoautomaticamente l’encoding in stringacon lamodalità specificatanellaproprietàEncoding. Come nel caso degli altri metodi, abbiamo a disposizioneDownloadStringTaskAsync, per evitare che la richiesta sia bloccante perl’interfaccia.

InviaredatialserverLa classe WebClient dispone di alcuni metodi anche per l’invio di testi, dati e filecompleti,qualiadesempio:

OpenWrite: apre uno stream (nel quale possiamo scrivere i dati) con la risorsaremota;

UploadData:inviadirettamenteunarraydibyteaunarisorsaremota;

UploadFile:eseguel’uploaddiunfilelocale;

UploadString: invia una stringa a una risorsa remota, previo encoding dei byteconlamodalitàspecificatanellaproprietàEncoding;

UploadValues: invia una collezione nome/valore tipica degli scenari di invioPOSTdirichiesteHTTP.

Cosìcomeperildownload,ognunodeimetodiappenadescrittidisponedellacontroparteasincrona,conicorrispondentieventidi*ProgressChangede*ProgressCompleted,oltreaicorrispondentimetodiasincronicheusanoAsynceAwait.

Nell’esempio 19.19, usiamo un StreamWriter per inviare il testo presente in unaTextBoxallostreamapertoconOpenWriteTaskAsync.

Esempio19.19DimclientAsWebClient=NewWebClient()

DimdataStreamAsStream=Awaitclient.OpenWriteTaskAsync(_

String.Format("C:\{0}",TextBox1.Text))

DimstrAsStreamWriter=NewStreamWriter(dataStream)

Awaitstr.WriteAsync(TextBox2.Text)

str.Close()

Page 483: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

dataStream.Close()

È importante ricordare che l’accesso a risorse del file system è vincolato alleautorizzazionidell’utenteconcuisieseguel’applicazione.

La classe WebClient incapsula l’elaborazione con i protocolli applicativirelativial tipodi risorsaacui sihaaccesso. Inparticolare,nell’inviodidatiattraversoprotocolloHTTP,vieneautomaticamenteutilizzato ilmetodoPOST,qualora non sia specificato come parametro nei metodi che lo consentono.Nell’aggiornamentodeidatidiquesto tipodi risorse, ènecessarioche ilwebserverintercettitalirichieste,recuperilostreamedesegual’aggiornamentonelpropriocontestoapplicativo.

A fronte della semplicità d’uso, la classe WebClient non ci consente di entrare neldettagliodellacomunicazione;perleoperazionirelativeallecaratteristichedeiprotocolliapplicativiabbiamoadisposizioneoggettipiùspecializzati,cheanalizzeremoinseguito.

ComunicazioneconiwebserverattraversoHTTPCon WebClient abbiamo visto una modalità semplificata con cui possiamo accedere adiversi tipi di risorse remote. Mediante le classi astratte WebRequest e WebResponse,possiamoentrareneldettagliodelmodello richiesta/risposta tipicadeiprotocolliTCP;atal proposito, nel .NET Framework, troviamo diverse implementazioni di tali classi,ognuna specifica per il tipo di protocollo, così come rappresentato in precedenza nellafigura19.13.

Grazie alla classe HttpWebRequest abbiamo la possibilità di interagire con le risorseespostedaunwebserverconilprotocolloHTTP:conilmetodoGetResponsepossiamorecuperare ilmessaggio di risposta attraverso l’oggettoHttpWebResponse.Tale oggettodispone dimolte proprietà, utili per conoscere i dettagli della risorsa: conContentTypepossiamoconoscere le informazioni relative al tipo, conLastModified abbiamo ladatadell’ultimamodifica, da utilizzare insieme a IsFromCache per stabilire la validità dellarisorsa stessa. Con StatusCode possiamo conoscere il codice di stato HTTP(HttpStatusCode); molto interessante, in generale, è la possibilità di controllarecompletamente tutte le header delmessaggio di risposta, grazie alla proprietà Headers,collezioneditipoWebHeaderCollection.

Con laproprietàCookiespossiamoaccedereallacollezionedioggettiCookie relativialla risposta, che possiamo gestire anche in scrittura con la proprietà CookieContainerdell’oggettoHttpWebRequest.

Dall’oggettoHttpWebResponsepossiamorecuperarelostreamdirisposta,attraversoilmetodoGetResponseStream,epossiamoelaboraretalestreamnellenotemodalità,ancheinfunzionedeltipodiripostastessa.

In modo molto simile a quanto abbiamo già visto, con HttpWebRequest possiamoinviaredatiaprendounostream,sfruttandoilmetodoGetRequestStreamAsync.

Page 484: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

HttpWebRequest eHttpWebResponse sono oggettimolto ricchi di funzionalità, la cuianalisi dettagliata esula dagli obiettivi di questo capitolo. Nell’esempio 19.19riepiloghiamo uno scenario più complesso, illustrando come sia possibile inviare dati aunapaginaASP.NET,sfruttandoilmodelloasincronosupportatodaglioggetti.

Per l’esempio 19.19 possiamo creare un’applicazione WPF molto simile a quellarealizzata per l’esempio 19.16, in cui possiamo scegliere un’immagine da file system,visualizzarnel’anteprimaeinviarlaalwebserverconlapressionediunbottone,dicuiilcodice19.20èilgestoredell’evento.

Esempio19.20PrivateAsyncSubButton1_Click(ByValsenderAsSystem.Object,_

ByValeAsSystem.Windows.RoutedEventArgs)_

HandlesButton1.Click

fileStream=File.OpenRead(TextBlock1.Tag.ToString())

DimrequestAsHttpWebRequest=_

CType(WebRequest.Create(uploadUri),HttpWebRequest)

request.Method="POST"

DimpostStreamAsStream=Awaitrequest.GetRequestStreamAsync()

DimsendBuffer(1023)AsByte

DimbytesReadAsInteger=0

Do

bytesRead=fileStream.Read(sendBuffer,0,1024)

IfbytesRead>0Then

postStream.Write(sendBuffer,0,bytesRead)

EndIf

LoopWhilebytesRead>0

DimresponseAsWebResponse=Awaitrequest.GetResponseAsync()

DimstreamResponseAsStream=response.GetResponseStream()

DimstreamReadAsNewStreamReader(streamResponse)

DimresponseStringAsString=streamRead.ReadToEnd()

TextBlock1.Text=responseString

streamResponse.Close()

streamRead.Close()

response.Close()

fileStream.Close()

EndSub

IlmetodoCreatedellaclasseWebRequestcreal’oggettoHttpWebRequestconl’URIdella

Page 485: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

pagina ASP.NET. Apriamo quindi la richiesta dello stream in modo asincrono con ilmetodo GetRequestStreamAsync, in esso scriviamo i byte del file selezionato e litrasmettiamo con il metodo GetResponseAsync, con il quale restiamo in ascolto delmessaggiodirispostasempreinmodoasincrono.Infinevisualizziamoavideoilrisultatotrasmessodalwebserver.

Nell’esempio19.21possiamovedere ilcodicedellapaginaASP.NET,cherecupera lostream in ingresso con la proprietà InputStream dell’oggetto Request, di tipoHttpRequest,escrivesulfilesystemattraversoilmetodoOpenWritediFileStream.

Esempio19.21ProtectedAsyncSubPage_Load(ByValsenderAsObject,_

ByValeAsSystem.EventArgs)_

HandlesMe.Load

IfRequest.QueryString("path")IsNotNothingThen

Dim_physicalApplicationPathAsString=_

HttpContext.Current.Request.PhysicalApplicationPath

Dim_pathAsString=_

String.Format("{0}\{1}",_

_physicalApplicationPath,_

Convert.ToString(Request.QueryString("path")))

UsingstreamAsFileStream=File.OpenWrite(_path)

DimdataByteAsByte()=NewByte(1023){}

DimiAsInteger=0

Do

i = Await Me.Context.Request.InputStream.ReadAsync(dataByte,

0,1024)

Ifi>0Then

Awaitstream.WriteAsync(dataByte,0,i)

EndIf

LoopWhilei>0

EndUsing

Response.Clear()

Response.Write("ok")

Response.End()

Else

Response.Clear()

Response.Write("errore")

Page 486: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Response.End()

EndIf

EndSub

Con ilmetodoWritedell’oggettoResponse possiamo scrivere il testo delmessaggio diriposta, per recuperarlo nella nostra applicazione di esempio. Il codice riassume lemodalità di lavoro con ilmodello asincrono, nel quale è possibile trovare alcuni spuntiutiliperrisolvereabitualiproblematichediprogrammazione.

HttpClient:un’evolutainterfacciaHTTPperapplicazionimoderneOltrealleclassicheabbiamoappenavisto,nell’assemblySystem.Net.Http.dllabbiamoadisposizioneHttpClient, una classe che incapsula le funzionalità per consumarewebservices REST con grande produttività e soprattutto in modo portabile tra applicazionieterogenee.

HttpClientesponeunaseriedimetodiperlecomunioperazionidiGET,POST,PUT,DELETE:

GetAsync;

GetByteArrayAsync;

GetStreamAsync;

GetStringAsync;

PostAsync;

PutAsync;

SendAsync;

DeleteAsync.

Ciascunmetododisponedi diversi overload e, comepossiamovedere, talimetodi sonotutti asincroni e possono essere invocati con await. Nell’esempio 19.22 vediamo ilmetodoGetStringAsyncperrecuperaredatidiunservizioinsempliceformatotesto.

Esempio19.22Usingclient=NewHttpClient()

Try

client.BaseAddress=NewUri("http://localhost:18974/")

client.MaxResponseContentBufferSize=1024

DimdataAsString=Awaitclient.GetStringAsync("api/products/1")

Page 487: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

CatchexAsException

Finally

EndTry

EndUsing

HttpClient implementa IDisposable, quindi è buona pratica usarlo all’interno delcostruttousing.Ancheinquestocasopuòessereutileeseguiretalimetodiintry/catch.Nelcodicedell’esempio,possiamovedere laproprietàBaseAddressconcui impostiamol’Uri di base del servizio invocato; con MaxResponseContentBufferSize, invece,possiamo definire la grandezza del buffer in lettura, il cui valore predefinito è di duegibabyte.

Solitamente i web service REST si scambiano oggetti nei formati JSON e XML equindi, in questo caso, potremmo procedere manualmente alla deserializzazione dellastringanell’oggettonoto.

Quandoabbiamobisognodientrareneldettagliodellarispostadelservizio,possiamoinvocareilmetodoGetAsync,comenell’esempio19.23.

Esempio19.23Usingclient=NewHttpClient()

Try

client.BaseAddress=NewUri("http://localhost:18974/")

Using response As HttpResponseMessage = Await

client.GetAsync("api/products/1",cts.Token)

log.AppendLine(response.RequestMessage.ToString())

log.AppendLine(response.Version.ToString())

log.AppendLine(response.StatusCode.ToString())

Ifresponse.IsSuccessStatusCodeThen

Dimcontent=response.Content

ForEachitemAsvarIncontent.Headers

log.AppendLine(item.Key+""+item.Value.FirstOrDefault())

Next

DimdataAsString=Awaitcontent.ReadAsStringAsync()

log.AppendLine(data)

Else

log.AppendLine(response.ReasonPhrase)

response.EnsureSuccessStatusCode()

EndIf

EndUsing

Page 488: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

CatchgeneratedExceptionNameAsTaskCanceledException

CatchexAsException

Finally

log.AppendLine("------------")

TextBox2.Text=log.ToString()

EndTry

EndUsing

Il metodo GetAsync ci dà accesso all’oggetto HttpResponseMessage, che espone ilcontenutodellaresponseconlaproprietàContent,isuoiHeaderealtreinformazioni.

Content,ditipoHttpContent,puòesserelettoconilmetodoReadAsStringAsync,checirestituisceilcontenutodelmessaggioinformatostringa.

L’oggetto HttpResponseMessage, recuperato con questa modalità, permette maggiorecontrollo sulla response e ci consente di capire se il servizio ha risposto con unoStatusCode consono a un’elaborazione andata a buon fine (IsSuccessStatusCode), eanche di sollevare un’eccezione nel caso contrario, con il metodoEnsureSuccessStatusCode.

Nel codicedell’esempio 19.24, vediamo l’uso delmetodo PostAsync per inviare deidatiinPOSTalwebservice.

Esempio19.24Usingclient=NewHttpClient()

client.BaseAddress=NewUri("http://localhost:18974/")

DimnewDataAsString="{'Id':22,"&vbCr&vbLf&"

'Name':'Product22',"&vbCr&vbLf&"

'Price':22.0,"&vbCr&vbLf&"

'Category':'Category22'}"

DimcontentPostAsHttpContent=

NewStringContent(newData,Encoding.UTF8,"application/json")

UsingresponseAsHttpResponseMessage=

Awaitclient.PostAsync("api/products",contentPost)

Ifresponse.IsSuccessStatusCodeThen

DimproductAsProduct=

Awaitresponse.Content.ReadAsAsync(OfProduct)()

log.AppendLine(product.ToString())

EndIf

EndUsing

EndUsing

Page 489: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IlmetodoPostAsyncaccettacomeparametrol’Uridelservizioe,soprattutto,unoggettocheestendelaclasseastrattaHttpContent,comeoggettodainviare.Nell’esempioèstatousatoStringContent,conilqualeunoggettoProductèstatorappresentatoinstringaconformatoJSON.

L’utilizzo degli altri metodi non differisce molto da quanto abbiamo visto; asemplificareulteriormenteilcodicevieneinaiutounaseriediextensionmethod,chesonopresentinellalibreriaMicrosoft.AspNet.WebApi.Client,installabileattraversoNuGet.

In particolar modo, nell’assembly System.Net.Http.Formatting.dll, possiamotrovare ReadAsAsync, PostAsJsonAsync, PutAsJsonAsync e tutti i loro overload cheriducono gli oneri di serializzazione e deserializzazione dei dati in transito. L’esempio19.25 è ci consente di comprendere appieno la riduzione del codice grazie a due deisuddettimetodi.

Esempio19.25DimproductAsProduct=Awaitresponse.Content.ReadAsAsync(OfProduct)

()

'//

Await client.PostAsJsonAsync(Of Product)("api/products", product,

cts.Token)

QuasituttiimetodidiHttpClientprevedonounparametroditipoCancellationTokenconcuipossiamocontrollareitaskeannullarel’esecuzionedelcodicesuccessivo.Nelcodiceabbinatoallibrosonopresentialcuniesempi.

ScambiarefileconilprotocolloFTPQuanto detto nel caso diHTTP perHttpWebRequest, trova una controparte nelle classiFtpWebRequesteFtpWebResponse,pergestirelerisorseespostedaunserverFTP.

Anche FtpWebRequest eredita da WebRequest e, per questo motivo, troviamo icorrispondentimetodi,relativialprotocolloFTP,cheabbiamovistonelcasodell’accessoe l’aggiornamento dei dati. Una delle differenze più importanti è la funzionalità cheassumelaproprietàMethodnelcasovengautilizzataconilprotocolloFTP.Grazieaquestaproprietà,infatti,andiamoaspecificarelediverseoperazionichepossiamocompiere,siacon una singola risorsa remota, sia nell’intero contesto di una directory. PossiamodescriverequesteoperazioniconiseguentimembridellaclasseWebRequestMethods.Ftp:

AppendFile;

DeleteFile;

DownloadFile;

GetDateTimestamp;

Page 490: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

GetFileSize;

ListDirectory;

ListDirectoryDetails;

MakeDirectory;

PrintWorkingDirectory;

RemoveDirectory;

Renarne;

UploadFile;

UploadFileWithUniqueName.

I nomi sono auto esplicativi: nell’esempio 19.26 possiamo vedere come utilizzarel’oggettopereseguirel’uploaddiunfile.

Esempio19.26UsingfileStreamAsStream=File.OpenRead(TextBlock1.Tag.ToString())

DimuploadUriAsString=String.Format("ftp://xxx.xxx.xxx.xxx/{0}",TextBlock1.Text)

DimrequestAsFtpWebRequest=_

CType(WebRequest.Create(uploadUri),FtpWebRequest)

request.Method=WebRequestMethods.Ftp.UploadFile

request.Credentials = New NetworkCredential("username",

"password")

DimrequestStreamAsStream=Awaitrequest.GetRequestStreamAsync()

DimsendBuffer(1023)AsByte

DimbytesReadAsInteger=0

Do

bytesRead=AwaitfileStream.ReadAsync(sendBuffer,0,1024)

IfbytesRead>0Then

AwaitrequestStream.WriteAsync(sendBuffer,0,bytesRead)

EndIf

LoopWhilebytesRead>0

requestStream.Close()

Dim response As FtpWebResponse = CType(request.GetResponse(),

FtpWebResponse)

TextBlock1.Text=response.StatusDescription

EndUsing

Page 491: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

L’implementazionenondifferiscemoltodallemodalitàcheabbiamoanalizzatoperglialtriprotocolli.Unaparticolaritàd’usomoltofrequenteconilprotocolloFTPèlapossibilitàdispecificare le credenziali di accesso.Nell’esempio, usando la proprietà Credentials ditipo ICredential, abbiamo specificato username e password grazie all’oggettoNetworkCredential. In virtù di queste credenziali, il server FTP autorizzerà omeno leoperazionicheandremoadeseguire.

ConclusioniInquestocapitoloabbiamoinizialmentevistocomesvolgereleoperazionipiùcomunisufile e directory, quali spostamento, copia o eliminazione; successivamente abbiamomostrato come effettuare ricerche e come possiamo utilizzare la classe FileStream perinteragireconilcontenutodiunfile.

In seguito abbiamo introdotto il concetto di IsolatedStorage, ossia un’alternativavalidaesicurapermemorizzareinformazioniinunaporzionedidiscogiàpredispostaalloscopodalsistemaoperativo.

Successivamente abbiamo illustrato i principi di comunicazione di rete e lecaratteristichedeiprotocolli che si sonoevoluti,nel tempo, inparalleloallo sviluppodiInternet.Inseguito,abbiamoanalizzatoiprincipalistrumentidimediolivello,medianteiqualipossiamogestire lecomunicazionisocket, lavorandoconglioggetti specificiper iprotocolliTCPeUDP.

Dopoabbiamoaffrontatogliesempipiùcomunidigestionedellerisorseremote,comeHTTPeFTP, analizzando le classi principali disponibili nel namespaceSystem.Netdel.NETFramework.

Infine abbiamo introdotto le classi con le quali possiamo inviare messaggi di postaelettronica nelle nostre applicazioni. L’argomento è molto vasto e complesso, comedimostrano il numero di classi disponibili nella BCL. Il loro studio richiede un certotempoe,soprattutto,lacomprensionepropedeuticadeiprincipidelleinterazionialivellodiprotocollo.Sonostatiintrodottiiconcettiprincipaliesonostatianalizzatiinparticolarmodogliscenaripiùcomuni,chepossonorisponderealleesigenzequotidianedellenostreapplicazioni. Attraverso l’uso di questi strumenti diventa possibile implementare ilsupportoaqualsiasitipodiprotocollo,ancheaunototalmentecustom.

Conquestoultimocapitolo,ilnostroviaggioallascopertadiVBèterminato.All’internodel libro abbiamo affrontato diversi temi, cercando di coprire maggiormente quelli diinteressecomune,vi invitiamoadapprofondiregliaspettidivostro interesse,aiutandovicon le risorse che abbiamo segnalato e con la documentazione ufficiale. BuonaprogrammazioneconVisualStudio!

Page 492: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

AppendiceA

MicrosoftAzure

Unadelleproblematiche inassolutopiù sentitedapartedichi investenello sviluppodiapplicazioni software è quella di realizzare prodotti che garantiscano tempi di rispostaaccettabilianchequandoiltrafficoelaquantitàdidatielaboratiaumentano.Inunaparola,ciòchesirichiedealsoftwaredioggièchesiascalabile.

In generale, i primi traguardi nella corsa alla scalabilità si conquistano già in fase diprogettazione e realizzazione,ma sarebbe limitativo non considerare che, in una similesfida, anche l’hardware abbia unpesonon indifferente.Tuttavia, dotarsi d’infrastrutturehardwareingradodigestireungrandeonerecomputazionale,richiedeinvestimentispessononindifferentieavoltenongiustificatidaunarealenecessitànelmedio-lungoperiodo.Peresempio,possiamotrovarciadovergestireunasituazionedicaricotransitorialegataallanciodiunnuovoprodotto,dotandocidiunsistemapensatoperfarfronteadaltipicchiditraffico,maritrovandocisuccessivamenteconunimpiantosovradimensionatoquandogliaccessitorninonellanorma.

Larispostaaquestotipodiesigenzesichiamacloudcomputinge,tralevarierealtàaoggiesistenti, lapiattaformaMicrosoftAzure, senzadubbio, rappresentaunasceltachepuòrivelarsivincente,vistalapossibilitàdieseguireapplicazionibasatesullatecnologia.NETeall’ottimosupportodapartediVisualStudio2015.

IntroduzioneaMicrosoftAzureLapiattaformaMicrosoftAzureèbasata suun’infrastrutturahardwarepresenteneidatacenter di Microsoft. Chiunque voglia avvalersene, può acquistare una serie di unitàelaborative, sotto formadimacchinevirtuali,basatesuWindowsServer e, inbasealleproprienecessitàdelmomento,puòdeciderediallocareuncertonumerodiserver,cosìdaessereingradodiincrementareeadattarelacapacitàdirispostaaipicchidirichieste.

IservizioffertidaMicrosoftsonomolteplicievannodaiserviziIaaS(InfrastructureasaService)aiPaaS(PlatformasaService).Essiinteressanoormaitutteleareerelativealnetworking,ibigdata,lalororaccoltaetrasformazione,ilmachinelearningeiservizicheruotano attorno alla realizzazione di applicazioni web o app. Per quanto riguarda noisviluppatori,quindi,iservizicheingenerecipossonointeressaresono:

Page 493: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

CloudService: il supporto ingradodieseguire lenostreapplicazioni inmanierascalabile e affidabile, che ci consente il pieno controllo della macchina con unsistemaautomatizzato;

SQL Database: un database relazionale basato su SQL Server ma nel cloud,scalabileecompletamentegestito;

Appservice:laformapiùsempliceperospitareunnostrositointernet,delleAPI,ounbackendperappmobile,anchegratuitamente;

ServiceBus: servizi che permettono la veicolazione di messaggi, tramite relay,codeesottoscrizione;

Caching: CDN e servizi di memorizzazione ridondanti tra i server per unamigliorevelocitàdirisposta;

Application Insights: servizio per raccogliere la telemetria, monitorare ediagnosticareproblemirelativiallenostreapplicazioni,anchenonweb;

Media service: engine che permettono di automatizzare i processi di codifica etrasformazionedicontenutimultimediali.

Storage:unospaziodovepersistereinformazioniinunambientedelocalizzato,incuiilconcettodiFileSystemperdesignificato.Essoconsentedimemorizzaredatiintredifferentistrutture,Queue,BloboTable.

I costi per avvalersi diMicrosoft Azure sono legati al numero di processi utilizzati, altrafficoeallospazio,eciò rendequestapiattaformaadeguataalleesigenzediunavastagammadiaziende,dallepiccoleemedieimpreseallegrandisocietà.Itoolpersviluppareapplicazioni sono invece assolutamente gratuiti, dato che possiamo utilizzare qualsiasiversione diVisual Studio e il SoftwareDevelopmentKit (SDK)gratuito, che possiamoscaricareseguendoleistruzionipresentisulsitoufficialediMicrosoftAzure,all’indirizzohttps://azure.microsoft.com.

Nel prossimo paragrafo vedremo come realizzare una semplice applicazione diesempio,chesfruttigliAppService,inparticolareleWebApp.

HelloWorld,daMicrosoftAzureUna volta installato Microsoft Azure SDK, possiamo creare un nuovo progetto orecuperarne uno che abbiamo già sviluppato. LeWeb App, infatti, sono delle normaliapplicazioniASP.NETWebFormsoASP.NETMVCchelavoranoinunambientevirtualeeraggiungibileattraversoIIS,iltuttoinmanieratrasparentepernoisviluppatori.

Grazie all’SDK installato, sul progetto web ritroviamo le voci “Publish” e “AddApplicationInsightsTelemetry”,comevienemostratonellafiguraA.1.

PremendosullaprimavoceaccediamoaiservizidiWebDeploy,dovepossiamoconunclickaccedereallalistadelleWebAppchegiàdisponiamosuMicrosoftAzureocrearne

Page 494: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

unanuovaattraversol’appositopulsante.

Per poter pubblicare su Microsoft Azure è necessario disporre di unasottoscrizione che possiamo ottenere registrandoci gratuitamente sul sitohttps://azure.microsoft.com.

FiguraA.1–IntegrazionedeiservizidiMicrosoftAzureall’internodiVisualStudio.

Page 495: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

FiguraA.2–WizardperlapubblicazionedellaWebApp.

Ilwizard,visibilenellafiguraA.3,èpiuttostosemplicedaseguireenelcasodiunanuovaWebApp, ci chiede in quale sottoscrizionemetterla, la regione geografica (inmododaidentificare la farm, in genere la più vicina a dove ci interessa navigare) e, cosa piùimportante,ilnome,chedeterminapoil’indirizzofinaleconcuiraggiungereilsito,comeperesempiohttp://miosito.azurewebsites.net.

Page 496: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

FiguraA.3–PaginadicreazionedellaWebApp.

Almomentodellastesuradellibro,leWebApppossonoassumereunaconfigurazionefreeche,nell’ambitodicertilimiti,consentonodiaverefinoa10sitipubblicatigratuitamente.Creata la Web App proseguiamo il wizard, dando indicazioni sulla modalità dicompilazione e premiamo “Publish”. L’applicazione viene così compilata e tutti i filenecessari (view, dll e contenuti) vengono automaticamente copiati. Al termine dellaprocedura, il browser viene automaticamente aperto sul dominio da noi indicato, e laproceduraèconclusa.Possiamoripeterel’operazionedideploypiùvolte,conilvantaggiocheilmotoresadistinguerecosaècambiato,caricandosoloifilenecessari.

Page 497: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

AppendiceB

InteroperabilitàconDLLeCOM

Ilmondomanaged, offerto dal .NETFramework 4.6, cimette al riparo da problemi digestionedellamemoriaedavulnerabilitàdisicurezza,rendendoanchemoltopiùsempliceilversioningdeinostriassemblyelalorodistribuzione.

Esiste però ancora una nutrita schiera di applicazioni unmanaged, fatta da DLL(DynamicLinkLibrary),scritteconmolteplicilinguaggi,chesonotutt’altrochelegacyesarannocomponentifondamentaliancorapermoltianni.WindowsstessoèunmanagedetutteleAPI(ApplicationProgrammingInterface)cheoffreperl’accessoall’interfaccia,all’I/Ooalkernel,sonodisponibiliattraversoDLL,lequaliespongonofunzioniscritteinlinguaggio C. Attraverso il Platform SDK possiamo conoscere la loro firma, le lorofunzionalità e le costanti da utilizzare. Per noi sviluppatori che usiamo il .NETFramework, tuttoquestopuò sembrareunabanalità,manelmondounmanaged, invece,nonloè.Itipididatinonsonouniformitrailinguaggi,icompilatori,lepiattaformex86ox64eanche lapiù semplicedelle stringhepuòessereallocata inmemorianeimodipiùdisparati:ANSI,Unicode,comepuntatoreocomearraydicaratteri,tantoperfarealcuniesempi.

Tuttoquesto,purtroppo,èscomodoehaportato, inpassato,alladefinizionedialcunicontratti,confilecontenentimetainformazioniperdefinireunaDLLerendernepiùfacilel’utilizzo. Questa interfaccia, identificata con il nome di COM (Component ObjectModel) è un’altra parte fondamentale di Windows, sfruttata dalla maggior parte delleapplicazioni sviluppate per questa piattaforma, come la suite di Office o alcunicomponentidedicatiaInternet,conosciuticonilnomediActiveX.

Questa panoramica ci fa quindi capire che dialogare con il sistema operativo, o conelementiesternial.NETFramework,èunapraticatutt’altrocherara.Il.NETFrameworkstessomettegiàadisposizionealcuniclassilacuiimplementazionedipende,infondo,daquesti componenti esterni. Ne sono un esempio l’accesso al file, l’uso di socket, lerichiesteHTTP;però,nontutteleDLLoglioggettiCOMdicuipossiamoaverbisognohannolalorocontropartemanaged.

Vediamoquindi alcuni esempipiù comuni, per capirequali sianogli strumenti che il.NETFrameworkcimetteadisposizionepersuperarequestolimite.

CreareundocumentoExcel

Page 498: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

LasuitedistrumentiperillavorodiMicrosoft,dinomeOffice,èunodeicasipiùcomunicon cui ci possiamo trovare a dialogare, per esempio per la creazione di documenti oworksheet all’interno di un’applicazione Console, WPF o WinForm. Non possiamousufruiredelmondoCOM,invece,nelcasodiUniversalWindowsPlatformapp.

Tutto il modello a oggetti di Office è disponibile tramite COM, perciò ci è data lapossibilità di automatizzare i processi di creazione emanipolazione dei documenti. PercreareunfoglioExcel,popolarloesalvareilrelativofile,senzal’interazionedell’utente,dobbiamo, attraverso Visual Studio 2015, selezionare la voce “Add Reference" eposizionarci sulla tab di nome COM. In questa sezione vengono caricati tutti gli oggettiCOM installati e registrati sulla macchina: qualora non fosse presente nella lista,dobbiamoandareacercaremanualmenteilfile.dll,.exeo.tlb.

Nelnostrocaso,ilcomponentechecerchiamosichiama“MicrosoftExcel16.0ObjectLibrary”, come visibile nella figuraB.1, e lo referenziamo come se fosse un assembly.NET.

FiguraB.1–AggiuntadiunriferimentoauncomponenteCOM.

Referenziare un componente COM prevede la stessa procedura di un assembly, ma inrealtàcambianomoltepliciaspetti.Tralereferenze,unavoltapremutoOK,citroviamodueassembly.NET,cioèMicrosoft.Office.CoreeMicrosoft.Office.Interop.Excel.

SonoassemblygeneratidaVisualStudio2015,inbaseallemetainformazionidiCOM(in questo caso pre generati daMicrosoft stessa e inclusi nell’SDK) che contengono leinterfaccee lestruttureutilizzatedalcomponenteCOM,permettendocidiutilizzarlenel

Page 499: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

nostroapplicativocomesefosseronormalitipisviluppatiincodicemanaged.

Nell’esempioB.1 si può vedere come possiamo facilmente creare un file di Excel epopolare una cella. Il componente di Excel prevede che venga istanziato un suoriferimento con l’interfacciaApplication, la quale crea fisicamente un nuovo processoexcel.exe, perciò dobbiamo assicurarci sempre di chiamare il rispettivo metodo dichiusuraQuit.

EsempioB.1'CaricoExcel

DimappAsNewApplication()

Try

'Creoilfile

DimworkbookAsWorkbook=app.Workbooks.Add()

'Recuperoilfogliopredefinito

DimworksheetAsWorksheet=workbook.ActiveSheet

'Preparolaprimacella

DimrangeAsRange=worksheet.Cells(1,1)

range.Value="ASPItalia.com"

range.EntireColumn.AutoFit()

range.Font.Bold=True

'Salvoilfile

DimfilenameAsString=Path.Combine(Environment.CurrentDirectory,"test.xlsx")

workbook.SaveAs(filename)

Finally

'Chiudoexcel

app.Quit()

EndTry

ConoscendoExcel, ilcodiceèpiuttostoautoesplicativo,perchésimula leazionicheunnormaleutentefarebbe:

creareunworkbook;

posizionarsisullacella;

popolarelacellaformattandola;

salvareilfile.

Ladifficoltàdiutilizzosiriduceallaconoscenzadicomeilcomponentelavora,grazieamoltecaratteristichediVisualBasic,chenesemplificanol’utilizzo.MetodicomeSaveAs

Page 500: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

prevedonomolteplici parametri opzionali, chepossiamonon specificare grazie ai valoripredefiniti.

Come abbiamo anticipato, Application, Workbook e Worksheet, tra le altre, sonointerfaccericavatedalcomponenteepertantosonodettiproxy.Noncontengononessunaimplementazione,perchéognichiamatadiistanzachefacciamovieneinrealtàgestitadalRuntime CallableWrapper (RCW), che fa da interlocutore tra il mondo managed equellounmanaged.Questirestanoinfattidistintitraloroeirelativitypesystemnonsonocompatibili, perciò l’unica soluzionepossibile prevede cheogni volta in cui allochiamounastringain .NETe lapassiamoaunafunzioneunmanaged, lastringavienecopiataeconvertitainunspaziodimemorianongestitodalCLR,chel’ambienteunmanagedpuòliberamenteleggereemanipolare.

Questoprocesso,dettodimarshalling,purtroppocostadalpuntodivistaprestazionaleedèunodeimotivipercuidobbiamopropendereall’utilizzodiclassimanaged,quandopossibile,ascapitodiquelleunmanaged.

NonsempreperòabbiamoachefareconcomponentiCOM,mapiuttostoconAPIdiWindows:peressedobbiamoprocederemanualmentealladichiarazionedellafirmaedeltipodimarshaling.

ChiamareleAPIdiWindowsAbbiamodettocheil.NETFrameworkincludegiàclassilacuiimplementazionesibasasuchiamatealleAPIdiWindows.LeWinFormstessesonouninsiemediclassicheusanoWin32 (la parte diWindows dedicata alle finestre, ai bottoni), ma non sempre questecopronotutteleesigenzedicuipossiamoaverebisogno.

In questi casi, dobbiamo procedere manualmente all’uso delle API e, per farlo,dobbiamodichiararedellefunzionistatiche,marcate,però,conunospecialeattributo,dinomeDllImport,cheindicalaDLLcheesponetalefunzioneecipermettedispecificarecomechiamarla.

Supponiamo quindi di voler rimuovere il pulsante “X” di chiusura della finestra chetroviamoaogniconsoleapplicationowindowsapplication.Perfarlo,dobbiamoricorrereall’API di nome GetSystemMenu, per ottenere il riferimento al menu della finestra, e aquelladenominataRemoveMenu,perrimuoverelavoce.Nell’esempioB.2possiamovederecomedichiararequestefunzioni,marcandoleconl’appositoattributo.

EsempioB.2<DllImport("user32.dll")>

PrivateFunctionGetSystemMenu(ByValhWndAsIntPtr,ByValbRevertAsBoolean)AsIntPtr

EndFunction

Page 501: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

<DllImport("user32.dll")>

PrivateFunctionRemoveMenu(ByValhWndAsIntPtr,

ByValnPositionAsInteger,ByValwFlagsAsInteger)AsInteger

EndFunction

Possiamo notare, prima di tutto, la mancanza d’implementazione della funzione el’indicazionedellauser32.dllcomenomedellaDLLchecontienelafunzione.Lafirmadi quest’ultima dev’essere uguale a quella della corrispettiva funzione unmanged ed ènostro compito individuare il tipo .NET compatibile e convertibile nel tipo definito inlinguaggioC.

IltipoIntPtr rappresentaunpuntatoreche,asecondadellapiattaforma,vuoldireunpuntatore a 32 o a 64 bit. Tutti glihandle diWindows, infatti, sono rappresentati conquesto tipo:questocipermettediottenereun riferimentoalmenu,perpoipassarloallafunzioneRemoveMenu.

Nell’esempioB.3vediamo,infatti,cheotteniamol’handledellafinestradellaconsole,otteniamoilmenuelorimuoviamoinbaseallaposizione.

EsempioB.3'Recuperolafinestradellaconsole

DimhandleAsIntPtr=Process.GetCurrentProcess().MainWindowHandle

'Recuperoilmenu

DimhMenuAsIntPtr=GetSystemMenu(handle,False)

IfhMenu=IntPtr.ZeroThenThrowNewWin32Exception()

'RimuovolaXposizionatasempreall'indice6

RemoveMenu(hMenu,6,MF_BYPOSITION)

Questo semplice esempio ci permette di capire che, anche nell’ipotesi in cui il .NETFrameworknonfossecompleto,abbiamocomunqueadisposizioneunaseriedistrumentipersuperarequestilimitiegovernarel’interosistemaoperativo,attraversoleAPIesposte.

Visonoperòmoltepliciaspettidaprendereinconsiderazione,peresempiorelativiallagestione degli errori, alla gestione dei puntatori e al marshalling. Perciò, per maggioriinformazioni,consigliamodiconsultarelarelativadocumentazionepresenteall’indirizzohttp://aspit.co/agi.

Page 502: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

AppendiceC

SviluppareWindowsService

IWindowsService,notianchecomeserviziWindowsoNTService, sonoapplicazioniprogettateperessereeseguitesenzachevisiauncontrollodirettodapartediunutente.Nellamaggiorpartedeicasi,vengonoavviatiautomaticamentedaWindows,nonappenail sistema operativo ha completato la fase di boot. Possono comunque essere lanciati,fermatioriavviatimanualmente,anchesenonpresentanoalcuntipodiinterfacciautente,egiranoinbackgroundconun’identityindipendentedall’utenteeventualmentecollegatoalsistema.Questecaratteristiche li rendono idealiperessere impiegati inambitoserver,pereseguireazionidilungadurataodiunacertacomplessità,eperfornirefunzionalitàdisupportoallealtreapplicazioni.

Esempi significativi di Windows Service sono lo spooler di stampa, il sistema diloggingdeglieventi(EventLog), ilserviziodiaggiornamentoWindowsUpdate, ilTaskScheduler, il Windows Firewall, i programmi antivirus, i vari componenti dei DBMS,comeSQLServer,eInternetInformationServices(IIS).

SviluppodiunWindowsServiceUnWindows Service non è altro che una specializzazione del tipo base ServiceBase,contenutonelnamespaceSystem.ServiceProcessenell’assemblyomonimo,insiemeallealtre classi per la gestione dei servizi. In pratica, tutto quello che dobbiamo fare perimplementare unWindows Service consiste nel definire un tipo che derivi dalla classeappenamenzionata,configurarelesueproprietàeimplementarealcunimetodi,affinchéilcodice possa reagire in modo opportuno quando il servizio viene avviato, sospeso oarrestato.LapresenzainVisualStudiodiuntemplatediprogettospecificoperiWindowsService e il designer a esso associato ci permettono di saltare tutti i passaggiimplementativi iniziali, che vengono svolti in modo trasparente direttamente dallostrumentodisviluppo.

Per illustrare il procedimento di creazione di un servizioWindows, ricorriamo a unsemplice esempio, ovveroun serviziodenominatoDirectoryWatcher.QuestoWindowsService permette di monitorare una particolare directory del filesystem e di registrarenell’Event Log di Windows tutte le modifiche che riguardano i file contenuti in taledirectory.Perpoterfarequesto,useremoilcomponenteFileSystemWatcher.

Il primopassoda compiere per poter sviluppare un servizio consiste nel generare un

Page 503: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

progettoapartiredaltemplaterelativoaiWindowsService.Nelnostrocaso,assegniamoalprogettoilnomeDirectoryWatcher.

All’atto della creazione, il progetto è composto dal file Servicel.vb, che possiamorinominare comeDirectoryWatcher.vb.A questo file sono associati un designer e unasezione di codice. Il designer consente di inserire componenti, semplicementetrascinandoli dalla toolbox di Visual Studio. Nel nostro caso, per esempio, possiamoincludereilcomponenteFileSystemWatchermenzionatoinprecedenza.

Come abbiamo detto in precedenza, oltre al designer, al file relativo al servizio èassociataancheunasezionedicodice.InizialmentequestasezioneapparemoltosempliceedessenzialeecontieneunicamenteiduemetodiOnStarteOnStop,chevengonoeseguitiall’avvioeall’arrestodelservizio.Ilrestodelcodicevienegeneratodaldesignerinmodoautomatico,all’internodelfilenascostoDirectoryWatcher.Designer.vb.Inquestofileèpresenteladichiarazioneparzialedellaclasse,cherappresentailservizioveroeproprio.

Dal momento che gran parte del codice di base viene generato automaticamente daVisual Studio, ciò che siamo chiamati a fare consiste unicamente nell’implementare imetodichevengonoeseguitiduranteilciclodivitadelservizio,inparticolareall’avvio,prima dell’arresto, in occasione delle sospensioni o nelle altre circostanze per noisignificative.

IduemetodiprincipalisonoOnStarteOnStop.Essivengonoeseguiti rispettivamentequandoilservizioparteesifermaesonoinclusinellasezionedicodicedelserviziofindall’inizio.Inoltre,ilmetodoOnStartèingradodiaccettarealcuniparametridilancio,inmodosimilareaquantoavvieneperleapplicazioniConsole.

Oltre ai due metodi menzionati poc’anzi, esistono altri metodi come OnPause,OnContinueoOnShutdown,chesonodefiniticomevirtualinellaclasseServiceBase.Essinon presentano alcuna implementazione di base particolare e vanno implementati nelleclassi derivate solo se necessario. La tabella C.1 elenca i metodi principali diServiceBase,indicandoperciascunodiessilecircostanzeincuivengonoeseguiti.

TabellaC.1-IprincipalimetodidellaclasseServiceBase.

Metodo Descrizione

OnContinue Vieneeseguitoalriavviodelserviziodopounasospensione.

OnCustomCommandViene eseguito quando il Service Control Manager inoltra un comando personalizzato sotto forma dinumerointeroalservizio.

OnPause Vieneeseguitoquandoilserviziovienesospeso.

OnPowerEventVieneeseguitoalcambiodistatodell’alimentazionedelcomputer.Utilenelcasodeidispositiviportatili,inparticolarepergestirelesituazionidisospensionedellasessioneutente(sleep).

OnSessionChange VieneeseguitoinoccasionedellanotificadimodificaricevutadaunasessioneTerminalServer.

OnShutdown Vieneeseguitosubitoprimadellospegnimentodelsistema.

OnStart Vieneeseguitoall’avviodelservizio.

OnStop Vieneeseguitoquandoilserviziovienearrestato.

Nel caso del nostro esempio, dal momento che abbiamo scelto di poter sospendere il

Page 504: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

servizio e di gestire gli eventi legati allo spegnimento del sistema, possiamo fornireun’implementazione dei metodi OnPause, OnContinue e OnShutdown. Oltre a questo,ovviamente,dobbiamoanchescrivereilcodiceperimetodidiavvioearresto.

L’esempioC.1riporta l’implementazionecompletadelservizioDirectoryWatcher. Infasedicompilazione,questocodicevieneunitoaquellogeneratoinmodoautomaticodaldesigner, a formare un’unica classe, provvista di tutte le caratteristiche necessarie perpoterrappresentareunWindowsServiceveroeproprio.

EsempioC.1ImportsSystem.Configuration

ImportsSystem.Diagnostics

ImportsSystem.IO

PublicClassDirectoryWatcher

FriendPropertyPathAsString="C:\Temp\"

FriendFilterAsString="*.*"

FriendPropertyIsRecursiveAsBoolean=False

ProtectedOverridesSubOnStart(ByValargs()AsString)

Me.GetConfiguration()

FileWatcher.Path=Me.Path

FileWatcher.Filter=Me.Filter

FileWatcher.IncludeSubdirectories=Me.IsRecursive

FileWatcher.NotifyFilter=NotifyFilters.LastAccessOr_

NotifyFilters.LastWriteOrNotifyFilters.FileNameOr_

NotifyFilters.DirectoryName

FileWatcher.EnableRaisingEvents=True

EndSub

ProtectedOverridesSubOnStop()

FileWatcher.EnableRaisingEvents=False

EndSub

ProtectedOverridesSubOnPause()

FileWatcher.EnableRaisingEvents=False

EndSub

ProtectedOverridesSubOnContinue()

FileWatcher.NotifyFilter=NotifyFilters.LastAccessOr_

NotifyFilters.LastWriteOrNotifyFilters.FileNameOr_

NotifyFilters.DirectoryName

FileWatcher.EnableRaisingEvents=True

Page 505: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

EndSub

ProtectedOverridesSubOnShutdown()

FileWatcher.EnableRaisingEvents=False

EndSub

PrivateSubOnFileChanged(ByValsenderAsObject,ByVale_

AsFileSystemEventArgs)HandlesFileWatcher.Changed

DimmessageAsString="Item'"&e.Name&"'changed."

EventLog.WriteEntry(Me.ServiceName,message)

EndSub

PrivateSubOnFileCreated(ByValsenderAsObject,ByVale_

AsFileSystemEventArgs)HandlesFileWatcher.Created

DimmessageAsString="Item'"&e.Name&"'created."

EventLog.WriteEntry(Me.ServiceName,message)

EndSub

PrivateSubOnFileDeleted(ByValsenderAsObject,ByVale_

AsFileSystemEventArgs)HandlesFileWatcher.Deleted

DimmessageAsString="Item'"&e.Name&"'deleted."

EventLog.WriteEntry(Me.ServiceName,message)

EndSub

PrivateSubOnFileRenamed(ByValsenderAsObject,ByVale_

AsRenamedEventArgs)HandlesFileWatcher.Renamed

DimmessageAsString="Item'"&e.Name&"'renamed."

EventLog.WriteEntry(Me.ServiceName,message)

EndSub

PrivateSubGetConfiguration()

'…EndSub

EndClass

Come possiamo notare nell’esempioC.1, i metodi OnStart e OnContinue del servizioDirecoryWatcher attivano il monitoraggio del filesystem, valorizzando la proprietàEnableRaisingEvents del componenteFileSystemWatcher. Inmodo analogo, imetodiOnStop,OnPauseeOnShutdownusanolastessaproprietàperfermareilmonitoraggio.Lascritturanell’EventLogdiWindowsdellemodificheaifilevienefattaneglieventhandlerrelativiaglieventiscatenatidalcomponenteFileSystemWatcher.

Creazionedell’Installereconfigurazione

Page 506: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

IWindows Service non possono essere lanciati come normali applicazioni,ma devonoessere installati all’interno del sistema operativo, in modo che possano essere avviatitramitelaconsoleMMCdiWindowsoppuredaprompt,tramiteilcomandoNETSTART.

Perrendereunservizio installabile,dobbiamoinnanzituttocreareunInstaller,chevaaggiuntoallostessoprogettodisviluppo.AncoraunavoltaVisualStudiocivieneinaiuto,fornendo tutti gli strumenti necessari per poter eseguire questa operazione in modoautomatico.

PeravviarelaproceduraautomaticadicreazionediunInstaller,dobbiamorichiamareilmenù contestuale all’interno del designer del servizio e selezionare l’opzionecorrispondente. A questo punto Visual Studio aggiunge al progetto il fileProjectInstaller.vb (che possiamo rinominare col nomeDirectoryWatcherInstaller.vb).Ancheinquestocaso,alfileinquestioneèassociatoundesigner,attraversoilqualepossiamoconfigurareicomponentiinessocontenuti.

L’InstallerdiunserviziononèaltrocheunaclassechederivadaltipobaseInstaller,contenuto nel namespace System.Configuration.Install. Quest’ultimo include dueelementifondamentali:

un componente Service Installer, di tipo ServiceInstaller, che serve perdefinireilcomportamentodelservizioelesuedipendenze;

uncomponenteServiceProcessInstaller,ditipoServiceProcessInstaller,cheserveperconfigurareilcontestodisicurezzaperilservizio.

Questiduecomponentisonogeneratiautomaticamenteall’attodicreazionedell’Installer.Anche se non è obbligatorio farlo, è buona norma rinominarli con nomi che faccianoriferimentoalservizioassociatoall’Installer.

Sia il Service Installer sia il Service Process Installer possono essere configuratimediante un’apposita finestra di Visual Studio. Tra le altre cose, possiamo indicarel’identity con cui deve girare il servizio. Infatti, la proprietà Account diServiceProcessInstaller specifica il tipo di utente usato dal servizio e può assumerequattrodiversivalori:

User,ovverounutentediWindowspersonalizzato;

LocalSystem,ovverounutentebuilt-indiWindows,conprivilegiamministrativi;

NetworkService,ovverounutentebuilt-indiWindows,abassiprivilegi,chesullaretesipresentacomeutenteautenticatoconlecredenzialidelcomputerlocale;

LocalService, ovvero un’utente built-in di Windows, a bassi privilegi, chepresentacredenzialianonimesullarete.

Qualora volessimo associare al servizio un account che non sia tra quelli built-in diWindows,l’opzionedascegliereèUser,chetral’altrorappresentaanchel’impostazionepredefinita.Qualora le credenziali non siano indicate all’interno dell’Installer, verrannorichieste durante la fase di installazione.Dalmomento che,molto spesso, unWindowsServicesi trovaadovereseguireazionicherichiedonoprivilegiamministrativi, inmolti

Page 507: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

casi la scelta più indicata è rappresentata dall’opzione LocalSystem. In ogni caso, èsempre buona norma associare a un servizio le credenziali più restrittive tra quellepossibiliinrelazionealtipodioperazionisvoltedaquest’ultimo.

Una volta configurato l’Installer e i suoi componenti, il servizio è pronto per essereinstallatoall’internodiWindows.

InstallazionediunWindowsServiceUna volta compilato il progetto di sviluppo, al fine di produrre un file eseguibile (nelnostro casoDirectoryWatcher.exe) contenente il serviziovero e proprio, siamoprontiperusaredalineadicomandol’utilityInstallUtil.exe,inclusanelSoftwareDevelopmentKitdel.NETFrameworkeinstallatanelsistemainsiemeaVisualStudio.

Ilcomandodiinstallazioneprevedeunasintassimoltosemplice:InstallUtil"C:\DirectoryWatcher\DirectoryWatcher.exe"

Questo comando dev’essere eseguito con privilegi amministrativi. Se tutto procedecorrettamente,alterminevienemostratounmessaggiochecicomunicachel’installazioneè andata a buon fine. Dato che InstallUtil.exe opera in modalità transazionale, essocancellaogniazioneparzialesvoltadurante l’installazione, incasodierrori imprevistioqualoralecredenzialidell’utentenonsianovalide.Inquestesituazionicivienemostratounmessaggiodierroredettagliato.

PossiamousareInstallUtil.exeancheperdisinstallareunWindowsService.Lasintassièmoltosimileallaprecedente,occorresemplicementeaggiungerel’opzione/U:

InstallUtil"C:\DirectoryWatcher\DirectoryWatcher.exe"/U

Affinchéladisinstallazioneabbiaesitopositivo,ilserviziodev’essereprimaarrestato.

Unavolta installato,un serviziononèancora inesecuzione, indipendentementedallamodalità di avvio scelta, valida solamente durante il boot di sistema. Esso va quindiavviato manualmente. Un Windows Service può essere avviato, arrestato, sospeso eriavviatointremodi:

utilizzando la console MMC inclusa negli strumenti di amministrazione diWindows;

tramite i comandi NET START, NET STOP, NET PAUSE e NET CONTINUE,eseguibilidaprompt;

inmodoprogrammatico,attraversoilcomponenteServiceController.

LaconsoleMMC,dedicataaiservizi,mostral’interalistadeiWindowsServiceinstallatinel sistema. La console MMC permette anche di visualizzare il dettaglio di ciascunWindows Service e di modificare alcune delle sue impostazioni (quelle che abbiamodefinitoall’internodell’Installer).Inparticolare,possiamocambiarelamodalitàdiavvio,settareun’identitydiversaespecificareiparametridilanciopassatialmetodoOnStartdel

Page 508: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

servizio.

Page 509: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

AppendiceD

Distribuzionedelleapplicazioni

Il deployment rappresenta un passaggio obbligato per rendere operative le applicazionisviluppateconVisualStudio2015 inVisualBasic.Distribuireun’applicazione significaeseguire un insieme di attività atte a installare gli assembly generati durante la fase dicompilazione(eglieventualifileaccessori)inunambientediversodaquellodisviluppo.

Ovviamente, esistono diverse possibilità di distribuzione, legate inevitabilmente almodello di funzionamento dell’applicazione e al risultato del processo di compilazione.Per le applicazioni che, per essere distribuite, non necessitano di uno store (come ilWindows Store o il Marketplace di Windows Phone), rimangono validi alcuni deglistrumenti presenti all’interno di Visual Studio già nelle versioni precedenti a quellaattuale,conl’unicaeccezionediWindowsInstaller,nonpiùsupportato.

Per fare alcuni esempi, un’applicazioneWindows ha unmodello di funzionamento ed’interazionecompletamentedifferenterispettoaun’applicazioneweb.Allostessomodo,unalibreriaDLLrappresentaunoutputdicompilazioneconcaratteristichediverserispettoaquellediunassemblydirettamenteeseguibile.IprogrammiperWindows,cosìcomeleapplicazioniconsole,vengonoeseguitiall’internodelsistemaoperativoeconessodevonopoter interagire in modo completo, in base al contesto di sicurezza utilizzato.Diversamente,perpoteressereinvocabiledaremototramiteHTTP,un’applicazionewebnecessita di un ambiente di hosting che la ospiti, mentre una libreria ha, piùsemplicemente, bisogno di un’applicazione per poter essere caricata in memoria edeseguita.

Questediversità sostanziali si riflettonodirettamente sulmodoconcuiunprogettodisviluppo può essere distribuito nel suo ambiente di esecuzione. Pertanto le diversetipologie di progetto in Visual Studio 2015 presentano inevitabilmente procedure didistribuzionedifferenti,caratterizzatedastrumentispecifici,utilialloscopo.

Nelcorsodiquestaappendiceproveremoaillustrareletecnicheelesoluzioniprincipalipereffettuarel’installazionedilibrerieeapplicazioni,facendoriferimentoadalcunedellefunzionalitàoffertedaVisualStudio2015,pensateperagevolareleattivitàdideploymentneidiversicasi.

Assemblyprivatiepubblici

Page 510: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

Gliassemblyrappresentanol’outputdelprocessodicompilazione. Inbasealla tipologiadelprogettodisviluppo,essipossonoesseresolamentedeicomponenti,richiamabilidallealtre applicazioni, oppure direttamente eseguibili. Pertanto, una prima distinzione perpoter categorizzare gli assembly risiede proprio nella loro estensione, che ne denota lecaratteristichedicaricamento:

unalibreriaoclasslibrary(conestensione“.dll”)rappresentaunassemblyilcuiscopoèquellodicontenereleclassielefunzionalitàchepossonoessereutilizzateinaltreapplicazioniolibrerie;

unassembly eseguibile (con estensione “.exe”) rappresenta un programma chepuòesseredirettamenteavviatoeche,asuavolta,puòcaricaredinamicamenteinmemoriadiverselibrerieaccessorie.

I programmiperWindows, ovvero le applicazioniWPF,Console eWindowsForms e iWindows Service, vengono compilati come assembly eseguibili. In tutti gli altri casi,l’outputdicompilazioneèsempreunaclasslibrarye,cometale,aruntime,necessitadiunprocessohostchelacarichiinmemoria.

Oltreallasuddivisionedegliassembly inbaseall’estensione,possiamo introdurreunasecondacategorizzazioneinbaseallivellodivisibilità:

assembly privato: si tratta di un assembly visibile e accessibile unicamentenell’ambito di una particolare applicazione managed. Pertanto l’assembly vadistribuito unitamente all’applicazione che lo usa. Generalmente, gli assemblyprivati vengono inseriti nella directory dell’applicazione e, nel caso delleapplicazioniweb,nellasottodirectorybin,destinataaconteneretuttiicomponentiaccessori;

assembly pubblico o firmato: si tratta di un assembly richiamabile da tutte leapplicazionimanagedeseguiteall’internodiunsistemaoancheesternamentesullarete. In genere, un’assembly pubblico va installato localmente nella GlobalAssembly Cache (GAC) e necessita di essere contrassegnato con una firma ingradodiidentificarloinmodounivoco.

Le strutture di questi due tipi di assembly sono sostanzialmente identiche fra loro.Essiusano lo stesso formato interno, con header, metadati e manifest simili, e contengonoentrambicodiceMSIL.Aldilàdiquesto,possiamodirecheunassemblyècontraddistintodaquattroelementicaratteristici:

unnome: è il nome del file senza estensione e può essere specificato inVisualStudio2015,all’internodelleproprietàdiprogetto;

unaversione(Version):èunnumeroidentificativoconunformatocompostodaquattro cifre come, per esempio, 1.0.0.0. Questa informazione è inclusa neimetadatidelmanifestedèconfigurabileall’internodelleproprietàdiprogetto;

una cultura (Culture): definisce le caratteristiche di globalizzazione associateall’assembly.Anch’essa,comelaversione,èinclusaneimetadatidelmanifestedèdefinibileall’internodelleproprietàdiprogetto;

Page 511: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

un token pubblico (PublicKeyToken): è un valore che identifica l’autoredell’assemblyol’organizzazionechel’haprodotto.

Sebbene le prime tre informazioni siano sempre disponibili, al fine di identificare unassembly privato è sufficiente semplicemente il nome. Infatti, quando il CommonLanguageRuntimecaricainmemoriaunassemblyprivato,trascuralaversioneeiltokenpubblico,consideraunicamentelaCultureperlagestionedellaglobalizzazioneeutilizzailnomeperricercare,dentroladirectorydell’applicazione,ilfilerelativoall’assembly.

Nelcasodegliassemblypubblicilasituazioneèdiversa.Dalmomentocheiprimitreelementi non permettono di garantire l’univocità dell’assembly, il Common LanguageRuntime necessita di tutte e quattro le informazioni elencate in precedenza. Infatti, unassemblypubblicodeveesserefirmatoconunacoppiadichiavi(pubblicaeprivata)checonsentediidentificareinmodounivocoilsuoautoreaparitàdinome,versioneecultura,in modo tale da poterlo distribuire non solo localmente all’interno di un sistema, peresempio in GAC, ma anche esternamente sulla rete o in Internet. Nel suo complesso,l’insiemedeglielementimenzionaticomprendente lacoppiadichiaviprende ilnomedistrongname.

Sepiùapplicazioniaccedonoaunassemblyall’internodello stesso server,puòaveresenso considerare l’ipotesi di installarlo all’interno della GAC. Nel caso in cui perquell’assembly pubblico vengano rilasciate più versioni in tempi diversi, esse possonocomunque essere inserite nella Global Assembly Cache, senza che vi sia alcun tipo diinterferenza. Infatti, lo strong name permette di differenziare un assembly pubblicorispettoaunaltroegarantiscelasuaunivocità,ancheaparitàdinome.

DistribuzionedelleapplicazioniWindowstradizionaliCome detto nell’introduzione di questa appendice, in Visual Studio 2015 WindowsInstaller, utilizzato in passato per la generazione di file di installazione con estensione“.msi”, non è più supportato. Di conseguenza, per creare un programma di setup perapplicazioniWindowstradizionali,dobbiamonecessariamentericorrereauntoolprodottodaterzeparti.

In alternativa, possiamo comunque continuare a usare la tecnologia di deploymentClickOnce. Essa permette di distribuire applicazioni in grado di aggiornarsiautomaticamenteediessereeseguitedaremotoolocalmente,conun’interazioneminimada parte dell’utente finale. In più, fornisce un approccio centralizzato, per certi versisimilare a quello usato per le applicazioni web, che permette di semplificare in modoconsiderevole il processo di distribuzione delle applicazioni Windows. ClickOnce puòessereusatopereseguireildeploymentdiprogrammicomeleapplicazioniWPF,ConsoleeWindowsForms.

PerconfigurarelediverseopzionidipubblicazionediClickOnce,inVisualStudio2015

Page 512: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

abbiamoadisposizioneun tabspecificocontenutoall’internodelleproprietàdiprogetto(tab “Publish”). Attraverso questo tab, possiamo gestire gran parte degli aspetti cheriguardano ilprocessodipubblicazione.Abbiamo lapossibilitàdidefinire l’insiemedeifile che compongono l’applicazione e gli eventuali prerequisiti, nonchè il percorso dipubblicazione (un serverweb, un server FTPo un percorso su disco), l’eventualeURLd’installazioneelamodalitàdidistribuzione(onlineooffline).

All’interno del tab “Publish” possiamo inoltre configurare in modo semplice eimmediato anche il meccanismo di aggiornamento automatico. Infatti un’applicazioneClickOnceè ingradodiaggiornarsiautomaticamentenelmomento incuivieneavviata,datochepuòverificareladisponibilitàdiversionipiùrecentieprocedereallasostituzioneautomatica degli eventuali file modificati. Le modalità di aggiornamento sonoregolamentate da un numero di versione composto da quattro cifre. Tra le opzionidisponibili, possiamo scegliere che, a ogni pubblicazione, il contatore delle revisioni(corrispondente alla quarta cifra del numero di versione) debba essere incrementatoautomaticamente,inmodotaledaforzarel’aggiornamentodell’applicazioneClickOnce.

DistribuzionedelleapplicazioniwebDistribuireun’applicazionewebsviluppatainASP.NETeVisualBasicsignificainstallarlasu uno o più server appositamente preparati e configurati. La preparazione consiste nelcopiaree,inalcunicasi,installaretuttiicomponentinecessari.

Il deployment di un’applicazione ASP.NET dipende dal modello di sviluppo ecompilazione scelto per realizzarla. Esistono tre tipologie differenti, che caratterizzanoprofondamenteleattivitàdidistribuzione,dalmomentochenellediversesituazioniifiledatrasferiresulservervarianodiconseguenza.

DistribuzioneconcodeinlineIlmodello di compilazione di tipo “code inline” prevede che il codice server scritto inVisualBasiceilmarkupHTMLsianocontenutiall’internodellostessofilefisicoeche,infase di esecuzione dell’applicazione, essi vengano dinamicamente compilati. In questocaso, il deployment dei file sul server è immediato, in quanto consiste in una sempliceoperazione di copia dei file attraverso il comando XCOPY. Dal momento cheun’applicazione ASP.NET non è composta esclusivamente dal codice, con esso vannodistribuiti anche tutti i file presenti nelle cartelle App_*, i file di configurazione, leimmagini e gli assembly privati della directory /bin/. Questo approccio di sviluppo edeploymentprevedecheilcodicesorgentevengadistribuitoinchiarosulserver.

DistribuzioneconcodebehindIlmodellodisviluppodenominato“codebehind”sfruttalaprecompilazioneeprevedecheilcodicediunapaginasiasuddivisointrefile:unocontenenteilmarkupHTML,unocon

Page 513: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

il codice server scritto inVisual Basic e uno che include la dichiarazione dei controllipresentinelmarkup.

Perutilizzarequestomodellodisviluppo,inVisualStudio2012dobbiamosceglieredicreare un Web Project, ovvero sviluppare l’applicazione web a partire da uno deitemplatediprogettodiVisualStudio.Inquestocaso,all’attodellacompilazione,tuttoilcodiceserverdellepagineeledichiarazionideicontrollivengonounitiinsiemeaformareununicoassemblyprivato(conestensione“.dll”)cheprendeilnomedelprogetto.

Questamodalità di deployment si differenziadalla precedenteper il fatto che tutto ilcodicesorgentevienemessosulserversottoformadiassembly,ovveroquellogeneratoinfasedicompilazione.IfilescrittiinVisualBasicnondevonoesseredistribuiti,giacchélaloroversionecompilataègiàpresenteall’internodell’assembly.

DistribuzioneconcodefileIlterzoeultimomodellodisviluppoèdenominato“codefile”.Questoapprocciocercadiestrarreilmegliodalleduetecnicheprecedenti.Infatti,purmantenendolasuddivisionetrail markup HTML e il codice sorgente in Visual Basic, esso prevede che tutto vengacompilatoaruntime.

LastrutturadiunapaginaASP.NETèmoltosimileaquellavistainprecedenzaperilcode behind. Peraltro, la compilazione del codice sorgente torna a essere nuovamentedinamica e la distribuzione con code file segue praticamente le stesse regole viste inprecedenzaperilcodeinline,conlasoladifferenzachesulservervannotrasferitiancheifilecontenentiilcodicescrittoinVisualBasic.

Perutilizzarequestomodellodisviluppo,inVisualStudio2015dobbiamosceglieredicreareunWebSiteinvecediunprogetto.

One-ClickDeploymentLadistribuzionedi un’applicazioneASP.NETnon consiste solonella copia dei file,maanche nella creazione e configurazione dell’ambiente lato server, attraverso lamodificadei valori nel file web.config (per esempio, settaggi applicativi, percorsi sul disco,stringhe di connessione, aspetti di sicurezza ecc.) o impostando i parametri difunzionamentodiIIS.Lostessodiscorsovaleancheperlacreazionedeldatabase,poichéun’applicazione web, generalmente, utilizza un DBMS come sistema per gestire lapersistenzadeidati.

Spesso le attività descritte sono alquanto articolate. Usare il comando XCOPY oeseguiremanualmentegliscriptDDLpergenerareloschemarelazionalesonooperazioniche, se gestite in modo superficiale, possono portare a errori o mancanze anche graviduranteildeploymentdiun’applicazioneweb.

Alla luce di queste considerazioni, diventa utile poter disporre di uno strumento di

Page 514: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

automazionedelprocesso.Oltreaeliminareilrischiodierrori,unsistemaautomatizzatopermettedirendereripetibileilprocessodipubblicazionediun’applicazioneweb.

Per venire incontro a questa esigenza, Visual Studio 2015 include una funzionalitàchiamataOne-ClickDeployment, che consente di creare automaticamente un packaged’installazionecontenentetuttoquellocheserveall’applicazioneperpoteresseretrasferitanell’ambientelatoserver(pagineASP.NET,assemblyprivati,componenti,databaseecc.).Una volta che il package è stato portato sul server, possiamo utilizzarlo per crearel’applicazioneinIIS,generareildatabaseeinstallaretuttelerisorsenecessariealcorrettofunzionamentodell’applicazione.

ÈbenesottolinearecheOne-ClickDeploymentèdisponibilesoloperiprogettiwebenon per le applicazioni che puntano semplicemente a una directory (web site). Questosignificachesiamoobbligatia sviluppare l’applicazioneutilizzando ilmodellodelcodebehind. Una volta fatto questo, non vi sono altri accorgimenti da seguire e possiamopassare alla fase di creazione del package di deploy. Per una spiegazione esaustiva dicomefunzionaneldettaglioquesta tecnologiadideployment,vi rimandiamoall’articolodisponibileall’URL:http://aspitalia.com/ih.

Page 515: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

AppendiceE

IlnamespaceMy

Nello sviluppo di progetti per Windows, Visual Basic include implicitamente unnamespace speciale, chiamato My, che espone proprietà e metodi che semplificanol’accesso a funzionalità presenti nella BCL (BaseClass Library) del .NET Framework.L’obiettivo di questo namespace è quello di rendere diretto e immediato l’accesso afunzionalitàavanzateediusofrequente,conunaconseguentesemplificazionedelcodice.Sitrattainpraticadiunascorciatoia,chesipuòrivelaremoltoutileecomodaindiversicasi.Questo namespace è estendibile, così che possiamo aggiungere nuove funzionalitàchenepersonalizzinoilcomportamento,adattandosimeglioallenostreesigenze.

AccessoallerisorsedelcomputerUno degli ambiti in cui il namespace My è molto comodo è l’accesso al file system.Nell’esempioE.1possiamovederequantodiventifacileleggereilcontenutodiunfile.

EsempioE.1Dimcontentasstring=

My.Computer.FileSystem.ReadAllText("c:\path\file.txt")

In questo caso, possiamonotare come il namespaceMy espongauna classe, denominataComputer, all’interno della quale la proprietà FileSystem offre un metodo ad hoc perleggere file. Attraverso questa proprietà possiamo accedere a molte altre funzionalità,qualiperesempio:

CopyDirectory:copiadiunadirectory;

CopyFile:copiadiunfile;

CreateFile:creazionediunnuovofile;

CreateDirectory:creazionediunanuovadirectory;

DeleteDirectory:eliminazionediunanuovadirectory;

DeleteFile:eliminazionediunfile;

FileExists:indicazionedell’esistenzadiunfile;

Page 516: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

FindInFiles:ricercaall’internodiunfile;

GetDirectories:elencodelledirectoryinunpercorso;

GetFiles:elencodeifileinunpercorso;

MoveDirectory:spostamentodiunadirectory;

MoveFile:spostamentodiunfile;

WriteAllText:scritturaall’internodiunfileditesto.

InrealtàMy.Computerconsentel’accessodirettoaungrannumerodirisorsedelsistema.Possiamo accedere alla tastiera (proprietà Keyboard), al mouse (proprietà Mouse), allaclipboard(proprietàClipboard),alla rete (proprietàNetwork),allastampante (proprietàPrinter) e al registry di Windows (proprietà Registry). In genere, l’utilizzodell’Intellisense all’interno di Visual Studio è più che sufficiente per esplorare lepossibilitàoffertedaquestonamespaceedallerelativeclassi.

Accessoalleimpostazionidell’utenteUn’altraclasseinteressanteespostadalnamespaceMyèSettings,grazieallaqualesiamoingradodimanipolare,inletturaescrittura,leimpostazioniutentespecificateattraversolavoceSettings,postaall’internodelleproprietàdelprogetto.Ilcontenutodiquestaclasseviene generato dinamicamente, al fine di permettere l’accesso alle impostazionidell’applicazione inmodo facile e immediato.Aggiungendo, per esempio, un elementoApplicationTitleall’internodeisettaggidell’applicazione,possiamorileggerneilvaloreall’internodell’applicazionestessa,comemostratonell’esempioE.2.

EsempioE.2Dimtitleasstring=My.Settings.ApplicationTitle

Possiamo modificare il valore di un’impostazione semplicemente assegnandolo allacorrispondente proprietà. Le modifiche sono salvate alla chiusura dell’applicazione,oppurerichiamandoesplicitamenteilmetodoSave.

AltreinformazioniPer approfondire ulteriormente gli argomenti trattati in quest’appendice, consigliamo diconsultare la documentazione MSDN, disponibile all’indirizzo:http://msdn.microsoft.com/it-it/library/eht682b5(v=vs.110).aspx.

In buona sostanza, comunque, lo scopo ultimo del namespace My è quello diraggruppare e semplificare l’accesso a una serie di funzionalità che sono già presentiall’internodellaBCLdel.NETFramework,mailcuiutilizzopotrebberisultarecomplesso

Page 517: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

per uno sviluppatore alle prime armi. Per questa ragione, è abbastanza raro trovarnetraccianell’ambitodiprogetticomplessi.

Page 518: VISUAL BASIC 2015amici.cgel.me/libri/Daniele.Bochicchio.Visual.basic.2015.2016.pdf · ASP.NET, XAML, Windows 10 e servizi. Visual Basic 2015 Guida completa per lo sviluppatore è

InformazionisulLibroAggiornataa.NET2015eVisualStudio2015,questaguidacompletaaVisualBasic2015 è l’espressione corale di un gruppo di sviluppatori che, sin dalla sua primaversione,utilizzaquestolinguaggiopercostruireapplicazionidiogni tipo,daquellededicatealwebfinoacomplessisistemienterprise.

Illibro,cheincludeleultimenovitàintrodottedalframeworknellaversione2015,tratta le basi del linguaggio fi no ai concetti più avanzati, spiega l’usodell’OOP inVisual Basic, per poi passare alle tecnologie più attuali come LINQ, EntityFramework,WPF,Windows10,ASP.NETeWCF.Èiltestoidealesiaperchiiniziaaprogrammare sia per chi usa da tempo questo linguaggio e vuole scoprire tutte lenovitàdiVisualBasic2015.PUNTIDIFORZA

•Icomponentidelnuovo.NET2015

•VisualBasic2015:dallebasialleapplicazioniavanzate

•OOP:laprogrammazioneorientataaglioggetti

•CollectioneGenerics,DelegateedEventi

•EseguirequerynelcodiceconLINQ

•ADO.NETedEntityFramework

•XML,LINQtoXMLeXAML

•ApplicazioniASP.NETconVisualBasic

•ApplicazioniperWindows10