Anlan Blog

Un posto per scrivere quello che sento
Options:

Archivio categoria ‘Programmazione’

Molto spesso nelle applicazioni Web il codice che scriviamo gestisce tutta una serie di directory siano esse temporanee oppure organiche all’applicazione (come ad esempio la creazione di cartelle specifiche per contenere le immagini di un articolo) dipendenti dalla radice principale dell’applicazione.  Quando queste cartelle non servono più (ad esempio l’articolo è stato eliminato) si cancellano e basta.

E qui si pone un problema : quando il codice ASP.NET (sia esso VB, C# o qualsiasi altro) cancella una sottodirectory della radice principale della applicazione, succede che l’intera sessione viene invalidata. Mi è successo proprio perchè ogni volta che, tramite codice, effettuavo una cancellazione, dovevo riautenticarmi. Il motivo di questo comportamento è dovuto a due fattori:

  1. La cancellazione di una directory dipendente dalla radice dell’applicazione causa il restart dell’intera applicazione (AppDomain restart)
  2. La gestione dello stato di sessione in modalità InProcess è legata allo stato dell’applicazione : se questa si riavvia, si perde anche lo stato della sessione.

Come ovviare quindi al problema ? Semplice … o non si cancellano le directory (naaahhhh) … oppure si attiva lo stato di session out-of-process tramite StateServer o un provider a vostra scelta: sqlServer oppure uno custom. In questo modo non incorrete nel rischio di spaccarvi la testa per due ore perse a capire come mai la sessione scade in continuazione.

Alla prossima.

PowerShell ti fa il Backup dei file con 7-zip

In questo mio precedente articolo mi sono già cimentato nell’implementazione di un sistema di backup utilizzando 7-zip come archiviatore. Purtroppo lo script batch che ne è uscito fuori, per quanto funzionante, è soggetto a molte, troppe limitazioni: una su tutte, la pratica impossibilità di maneggiare correttamente in un file batch nomi di file o cartelle che contengano caratteri speciali come “&” (ampersand).

Da non trascurare nemmeno le non eccellenti performance generali dello script che, non potendo gestire delle vere e proprie variabili, è costretto ad impostare continuamente variabili di ambiente. Insomma … la cara vecchia shell DOS è alla frusta da un bel pezzo, specialmente se paragonata alle estese e flessibilissime shell di comando Linux.

Forse proprio per quest’ultimo motivo (l’arretratezza delle shell di comando), Microsoft ha, ormai da un pezzo, la sua PowerShell. In pochissime parole : “Una eccellente implementazione del framework .Net in una console a riga di comando“. Troppo complicato ? Nahhhh.

PowerShell è forse uno dei maggiori balzi in avanti registrati nelle tecniche di scripting per Windows, nonchè la chiave di volta per la risoluzione dei problemi del mio script di backup con 7-zip.

E’ così nato il nuovo script : 7zBackup.ps1 . L’intero progetto è ospitato su Codeplex (la piattaforma Microsoft per la condivisione di progetti open) e non me ne vogliano gli amici italiani se è tutto in inglese. La soluzione offerta da questo script è, per me, molto interessante e con l’inglese è più facile trovare dei contributors o dei tester.

>> Backup dei file con 7-zip e PowerShell <<

Backup dei file con 7-zip

Le procedure di backup sono sempre una bella gatta da pelare. Personalmente non amo sistemi di backup “proprietari” che utilizzano codifiche esclusive perchè gli archivi generati (indipendentemente dal fatto che si tratti di copie su nastro o su disco) non sono facilmente portabili. A parte sistemi di classe enterprise che consentono procedure di disaster recovery, quello che mi aspetto da un archivio di backup è la semplice possibilità di portarlo, all’occorrenza, su un’altra macchina e di ripristinare i file senza dover installare pesanti software specifici. Insomma … che l’archivio di backup generato sia leggibile facilmente e ovunque con minime installazioni.

Il diminuito costo dello storage rende sempre più frequente l’utilizzo di backup su file (utilizzando SAN, NAS o gli stessi dischi dei server) relegando le copie su tape library ad ambiti sempre più ristretti e specializzati. In questo contesto ho sempre preferito, per il backup dei dati su server Windows, l’utilizzo dell’utilità di backup Microsoft (NTBackup) per i motivi che ho descritto sopra soprattutto la portabilità (leggo lo stesso archivio su un altro server Windows senza dover installare praticamente nulla).

L’utilizzo di NTBackup porta vantaggi ma anche svantaggi:

  • I file di backup sono molto grandi: NTBackup copia e archivia i file senza comprimerli
  • Creare una procedura per il backup automatico è piuttosto semplice ma non è altrettanto facile controllare l’esito: NTBackup non riporta ERRORLEVEL corretti (esce sempre con zero se si backuppa su disco) anche quando vi sono rilevanti errori.

Ho deciso allora di “cimentarmi” nella creazione di un batch di automazione per il backup che rispondesse ai seguenti requisiti:

  • Minime installazioni richieste sul computer e soprattuto che i software necessari siano disponibili gratuitamente
  • Possibilità di selezione di backup “Complete”, “Incrementali”, “Differenziali”
  • Compressione degli archivi salvati
  • Controllo dei codici di ERRORLEVEL
  • Gestione della rotazione dei file
  • Portabilità su sistemi diversi e, perchè no, anche su Linux

Il risultato è 7backup.bat : un singolo script batch (.bat) la cui esecuzione è facilmente schedulabile con minimi ed intuitivi switch da riga di comando.

Clicca qui per il download 7Backup.bat

Attenzione !! Questo script utilizza i junction points come caratteristica del file system NTFS. I Junction points vengono rappresentati da Windows Explorer come normali cartelle. MAI e ripeto MAI cancellare un junction point utlizzando Windows Explorer perchè questo porta alla cancellazione anche dei dati nella cartella di destinazione (ovvero quella oggetto del puntamento junction).

Disclaimer : questo script è stato testato con cura tuttavia può non essere esente da errori. Non utilizzatelo in ambienti ad alta criticità senza prima averlo testato adeguatamente su computer di prova. L’utilizzo del software è a vostra completa discrezione e rischio. Non rispondo di perdite di dati e non fornisco supporto diretto se non per il tramite, secondo tempo e disponibilità, di questo sito web.

I requisiti per il funzionamento sono :

  • Aver installato 7-zip che viene utilizzato per la generazione degli archivi compressi. Download 7-Zip.
  • Disporre di un filesystem NTFS
  • Aver installato l’utilità Junction di Sysinternals per la creazione di link simbolici alle directory

Lo script batch è interamente documentato (in inglese) e tutte le impostazioni rilevanti possono essere codificate come costanti o passate da riga di comando. Solo due valori devono essere impostati a mano. Per fare questo potete editare il file 7backup.bat con un normale editor di testo come notepad (vi consiglio comunque di dotarvi di Notepad++). I valori rilevanti sono :

:: 7-zip executable path.
:: If you have installed 7zip using standard path, then you do not need to
:: change this
SET BK-7ZBIN=%ProgramFiles%\7-zip\7z.exe

In questa variabile dovrete inserire il percorso completo che punta all’applicazione 7-zip. Se avete installato 7-zip con le impostazioni standard non dovreste avere bisogno di modificare nulla.

L’altra variabile rilevante è la seguente:

:: Junction executable path.
:: Find where Junction.exe is and set it here. If Junction.exe is in
:: a directory within the PATH variable you can simply indicate
:: junction.exe
SET BK-JUNCTION=%ProgramFiles%\SysInternalsSuite\Junction.exe

Le applicazioni di SysInternals non prevedono una procedura di setup e quindi possono essere inserite in qualsiasi percorso. Prendetevi un momento per individuare Junction.exe all’interno del computer ed indicate quindi il percorso in cui si trova. Se il percorso prevede directory con spazi NON mettete le virgolette. Verranno aggiunte automaticamente dallo script quando serviranno.

A questo punto potete provare ad eseguire il batch senza nessun parametro. Viene emessa la schermata di aiuto come segue:

7Backup-ScreenShot 

Tutti gli switch di comando sono spiegati e documentati.

Non resta altro che creare una “lista” di directory che vorrete backuppare. Con un normale editor scrivete l’elenco delle directory da backuppare, una per riga, indicandone il percorso completo inclusa la lettera di unità. Ad esempio:

C:\Dir1\Dati
C:\Dir3
D:\Archivi

Salvate il file in formato testo e annotatevi la posizione.
Attenzione. Non è ammessa l’indicazione di una Directory e di una sua Sottodirectory. Per esempio non è possibile indicare:
C:\Dir1\Dati
C:\Dir1\Dati\Commerciale
Questo perchè la procedura crea, per ogni directory elencata, un junction point nell’area di lavoro, includendo automaticamente tutte le sottodirectory. Il mancato rispetto di questa regola può portare a risultati imprevedibili e loop infiniti.

Potete ora lanciare il backup come ad esempio seguente:

7backup.bat --dirlist "C:\Mie Selezioni\Lista.txt" --type full --destdir "F:\MieiBackup" --rotation 3

Questo produrrà la generazione di un archivio di backup completo (ovvero di tutti i file contenuti nelle directory indicate nel file c:\Mie Selezioni\Lista.txt). Il file archivio verrà depositato nella directory F:\MieiBackup dove verranno mantenuti solo i 3 più recenti backup dello stesso tipo.

Alcune cose da considerare:

  • Lo script utilizza come directory di lavoro predefinita il percorso indicato nella variabile %temp% del sistema operativo. Questa impostazione può essere di disturbo nel momento in cui si desidera effettuare il backup di directory che stanno al di sopra della directory %temp%. Per ovviare al problema è sufficiente indicare una directory di lavoro (tramite lo switch –workdir) che sia al di fuori dei percorsi da backuppare.
  • La directory di destinazione degli archivi di backup deve essere in un’area di storage sufficientemente capiente
  • E’ possibile indicare nell’elenco delle directory da salvare un intero disco (Es. C:\). In questo caso non dovranno essere presenti, nell’elenco di selezione, altre directory appartenenti allo stesso disco e la directory di destinazione e di lavoro dovranno essere al di fuori del disco da backuppare
  • Le impostazioni di default codificate all’interno dello script abilitano il multithreading per 7-zip: questa impostazione riduce i tempi di archiviazione/compressione ma come effetto secondario occupa la/le cpu al massimo delle prestazioni per periodi di tempo anche prolungati. In caso di utilizzo su macchine virtuali con monitoraggio delle risorse attive, o nel caso in cui si debba prevedere l’esecuzione di altre procedure batch (per esempio in notturna) questa impostazione può generare warning o errori. Modificate nello script la sezione dedicata agli switch di 7-zip secondo le necessità più consone all’ambiente in cui eseguirete lo script.
  • La presenza di antivirus la cui protezione residente sia attiva può essere motivo di sensibili rallentamenti durante il processo di archiviazione/compressione. Se possibile inserite tra le esclusioni della protezione permanente dell’antivirus almeno il percorso di destinazione dell’archivio di backup.
  • All’interno del file di selezione non è attualmente possibile indicare cartelle con percorso UNC (es. \\nomeserver\nomecartella). Questa possibilità verrà inserita in una prossima release.
  • Durante la fase di selezione dei file da archiviare è noto un problema che impedisce la corretta selezione nel caso in cui nel nome del file (o della directory che lo contiene) è presente il carattere “&”. Al momento e finchè l’intera procedura viene eseguita in un solo file batch (senza l’aiuto di componenti di scripting esterni) non sono riuscito a trovare una valida soluzione al problema.
  • Il file archivio generato alla fine della procedura di backup contiene, oltre ai dati archiviati, copia del file di selezione delle directory ed il log completo delle operazioni effettuate (anche leggendo l’archivio da un’altra postazione potrete sapere come e quando è stato creato).

Ogni commento o integrazione è bene accetto.

Sono diventato matto per un paio di giorni alla ricerca del perchè, senza apparente motivo, utilizzando il connettore .NET di MySql, per certe Stored Procedures non riuscivo ad ottenere il valore dei parametri di Output. In realtà il motivo c’era ed era documentato qui.

In pratica succede che se il comando viene eseguito per restituire un reader la collezione dei parametri associati al comando non viene sincronizzata.

Per esempio

Dim myCmd as New MySqlCommand("nome_procedura", Connection)
myCmd.CommandType = CommandType.StoredProcedure
Dim myOutParam as New MySqlParameter("nomeparametro", MySqlDbType.Int32)
myOutParam.Direction = ParameterDirection.Output
myCmd.Parameters.Add(myOutParam)
Dim myReader as MySqlDataReader = myCmd.ExecuteReader()

If Not myCmd.Parameters(myOutParam).Value Is Nothing Then
' Qui i parametri di output non hanno ancora il valore di ritorno
...
...
End If

myReader.Close

If Not myCmd.Parameters(myOutParam).Value Is Nothing Then
' Qui i parametri di output hanno il valore di ritorno
...
...
End If

Se invece il comando viene eseguito con il metodo ExecuteNonQuery … non ci sono problemi.

ASP Classico o ASP.NET ?

Quasi tutti i programmatori che abbiano basato le loro applicazioni web su ASP (VBScript) arrivano prima o poi a porsi seriamente questa domanda nel momento in cui devono partire con un nuovo progetto. La risposta, almeno nel mio caso (o meglio per l’azienda per cui lavoro), non è proprio facile e merita un qualche approfondimento.

Innanzitutto è bene sgombrare il campo da inutili allarmismi riguardanti la prevista morte futura del supporto ASP Classico sulle piattaforme Microsoft. Dal momento che IIS 7.0 supporta ASP classico perfettamente (con qualche accorgimento come spiegato in questo Tips and Tricks for Classic Asp Developers on IIS 7) è lecito pensare che la deadline di ASP classico sarà portata in avanti almeno fino al 2017 il che, rispetto alla data attuale, mette a disposizione un’ulteriore finestra di 10 anni per prendere una decisione.

Il problema quindi si sposta automaticamente sulle differenze di contenuto tecnologico offerte dai due linguaggi, anche se, è bene dirlo, è assolutamente improprio tentare di mettere sullo stesso piano di “linguaggio” le due modalità. Sono infatti profondissime le differenze tra i due e lontanissimi i presupposti su cui si basano.

ASP classico è un linguaggio di scripting: ovvero una sequenza di istruzioni scritte su normalissimi file di testo (modificabili con un qualsiasi editor – a me piace moltissimo Crimson Editor) che vengono interpretati al volo (on-the-fly) da una dll di sistema, la ASP.dll. In quanto tale la sintassi prevista per le pagine ASP (Active Server Pages) è una qualsiasi tra quelle supportate da Microsoft ovvero VBScript, JScript e PHPScript anche se la stragrande maggioranza dei casi di utilizzo prevede l’impiego di VBScript

ASP.NET (aspx), al contrario, è una completa riprogettazione del modello Active Server Pages basato sull’utilizzo del Framework .NET (versione 1 oppure 2): il codice scritto (che può essere implementato nel linguaggio che si ritiene più consono : VB, C#, C++, J#) non è più interpretato ma “tradotto” in un linguaggio intermedio (MSIL – Microsoft Intermediate Language) le cui istruzioni vengono direttamente elaborate dal framework .NET. Molti credono che le pagine ASP.NET siano pagine compilate (ovvero dei binari in linguaggio macchina) ma ciò non è vero e può indurre a conclusioni errate. Il prodotto di compilazione di un codice .NET è, come detto, di fatto una traduzione che ha bisogno comunque di un ambiente di run-time per poter funzionare: il framework .NET appunto. Per i programmatori VB (pre .NET) è immediata l’analogia con lo pseudo-code di VB che necessitava delle librerire VBRun per poter funzionare.

Ma la vera rivoluzione copernicana, di fatto quella che crea i maggiori problemi di approccio ad ASP.NET per i vecchi programmatori ASP, sta nella completa rivisitazione della sintassi e della struttura del codice. Mentre con ASP classico si è abituati a pensare al normale flusso di programma top-down, con ASP.NET bisogna cambiare completamente il proprio approccio alla progettazione ed allo sviluppo: le classi diventano l’oggetto atomico del codice.

In aggiunta a ciò è anche utile osservare che mentre VBScript è una versione light del supporto Visual Basic con un numero molto limitato di funzioni e quasi nessun oggetto nativo (per algoritmi complessi infatti i programmatori devono spesso riferirsi ad oggetti COM esterni), ASP.NET è un VB pieno (oppure un C# pieno ecc) con tutte i modelli di oggetto (e relativi metodi e proprietà) offerti dal framework .NET: in altre parole, e semplificando all’estremo, con i linguaggi .NET praticamente non si ha bisogno d’altro. Per rendere l’idea è un po’ come avere un coltellino svizzero con solo una lama ed un paio di forbici (VBScript) contro un utensile con 5 lame diverse, forbici per la carta e per la plastica, un set completo di brugole, cacciaviti di varia natura, chiavi inglesi e chiavi tubolari, seghe, martelli e chi più ne ha più ne metta ( .NET ). Tutto questo, ovviamente, rende più difficoltoso l’approccio al linguaggio quanto meno sotto il profilo dell’apprendimento mnemonico di tutti gli spazi dei nomi. Come se ciò non bastasse ogni singolo metodo può disporre di diversi override (ovvero modi di invocare il metodo con sequenze di parametri diverse) il che ha reso, nel mio personalissimo caso, praticamente impossibile avvicinarsi alla programmazione .NET senza l’ausilio di un IDE Microsoft con tanto di intellisense: per fortuna Microsoft ha reso pubblicamente disponibili e gratuite le versioni “light” del suo celeberrimo Visual Studio grazie alle versioni Visual Studio Express.

Fatte queste debite e stringatissime premesse, è forse ora di cominciare ad analizzare i perchè di una scelta a favore di ASP Classico o di ASP.NET per l’avvio di un nuovo progetto. Ci tengo però a sottolineare che le domande e risposte che sto per proporvi si basano sull’assunto di un approccio ad un progetto di sviluppo di medio piccole dimensioni: l’analisi di un progetto di grandi dimensioni che abbia tempi di sviluppo e manutenzione molto lunghi, elevate complessità e necessità di integrazione particolarmente articolate, potrebbe (anzi sicuramente richiede) un’analisi completamente diversa.

  • ASP non sarà più supportato molto presto: come visto questa affermazione non è vera e anche se non è realistico pensare che una nuova applicazione ASP potrà vivere in eterno, è sicuramente verosimile affermare che il problema, al momento, non si pone.
  • ASP.NET è più potente di ASP: in linea di massima ed in via assoluta di principio questo è vero ma nello sviluppo di un progetto conta anche (forse soprattutto) la potenza del team di programmatori. Una squadra ASP già rodata e con diversi progetti alle spalle disporrà certamente di un repository di codice già bello che pronto, testato e rivisto più volte, conosciuto a menadito che li renderà molto spediti nello sviluppo. Al contrario se il team si trova alla sua prima esperienza di sviluppo allora perchè non spendere un po’ di tempo in formazione su .NET ?
  • ASP.NET consente uno sviluppo visuale: questo è completamente falso. E’ possibile scrivere applicazioni ASP.NET con un semplice editor di testo anche se si potrebbero incontrare le difficoltà di cui ho detto sopra. Ciò che rende possibile lo sviluppo visuale è Visual Studio (appunto) e nel caso in cui (come vedremo oltre) non sia possibile affidarsi alle versioni Express è necessario prepararsi ad un discreto esborso di denaro per acquisire la versione full. Tra l’altro lo sviluppo visuale non è sempre un bene: il codice generato automaticamente da VS per, ad esempio, un posizionamento assoluto degli oggetti su un form non è proprio il massimo. Preferisco ancora avere il controllo dell’HTML prodotto … anzi dell’intero codice senza routine nascoste.
  • ASP.NET è più veloce perchè è compilato: si e no. Innanzitutto abbiamo visto sopra come il prodotto di una compilazione ASP.NET non generi propriamente un binario eseguibile. D’altro canto è anche vero che la velocità di esecuzione di diverse routine è assai più veloce (basti pensare alla concatenazione di stringhe). Eppure mi chiedo … la velocità di una applicazione da cosa è data ? Sono molti i fattori che concorrono. Se pensiamo all’esecuzione del codice server dobbiamo anche pensare al numero di istanze da sopportare ognuna delle quali occupa memoria: un’occupazione di memoria minore (ASP) permette un maggior numero di thread prima che, ad esempio, il sistema inizi a far largo uso della memoria SWAP e quindi a far degradare in generale le performance. Con ASP.NET i processi server che sottendono alla esecuzione del codice .NET sono molto più dispendiosi e quindi raggiungono una massa critica molto prima. Inoltre è bene notare che quasi sempre i punti di criticità maggiore stanno nelle pesanti query sui database che nulla hanno a che vedere con l’adozione di un linguaggio basato su .NET o di scripting.
  • Con ASP.NET si usano interfacce AJAX di ultima generazione: vero ma questo si può fare anche con ASP Classico. AJAX è una tecnica mista di codice client e di processi server che dialogano attraverso flussi XML. AJAX non è legato a doppio filo con .NET. E’ vero invece che esistono moltissimi componenti di interfaccia utente (griglie, tabs, combo ecc) implementabili dall’interno di Visual Studio con dei semplici drag-and-drop ma la quantità di codice autogenerato mi piace sempre meno e non sono sicuro che sia ottimizzato per tutte le situazioni.
  • Le applicazioni ASP.NET sono compilate e quindi non manipolabili dai clienti: solo parzialmente vero. Programmatori esperti potranno sempre decompilare gli assembly generati. Anche se il vostro cliente non lo farà non è detto che il vostro codice sia al sicuro come in una cassaforte. Inoltre la “compilazione” (e relativo deploy dei soli assembly) comporta, quale rovescio della medaglia, che per fare modifiche anche infinitesimali dovrete sempre avere a disposizione l’intero codice (in ufficio), compilare il tutto, e mandare l’applicazione compilata al cliente. Con ASP classico vi basta notepad dal cliente e … voilà.
  • Con ASP.NET si mantiene il controllo di stato: anche con ASP Classico. ASP.NET è solo un modo di produrre codice HTML che verrà interpretato dal browser client. Le comunicazioni HTTP non hanno cognizione di stato. Il solo “valore aggiunto” di ASP.NET in questo ambito è la memorizzazione delle informazioni di stato nel campo nascosto _VIEWSTATE: ad ogni post del form, l’intero contenuto di _VIEWSTATE viene ritrasmesso al server il quale ricreerà la situazione di stato antecedente la richiesta e quindi elaborerà i nuovi dati inviati. E’ un giochino che si può implemetare tranquillamente anche con ASP Classico (ecco qui un bel Framework per ASP Classico).
  • ASP.NET fa più scena: parrebbe una considerazione inconsistente ma nella realtà dei fatti è spesso (non sempre) talmente vera da annullare tutti i “contro” elencati fino ad ora.  Un nuovo cliente (poco esperto) sarà sempre benevolmente impressionato dall’adozione di tecnologie di ultima generazione per il solo fatto che … sono di ultima generazione. Fa figo (perdonate l’espressione) sbrodolare che si sviluppa in ASP.NET anzichè in ASP Classico (magari diffamando il caro vecchio ASP che ci ha dato da mangiare per tanti anni): e questo in genere accade ogni volta che non si hanno argomenti a sostegno della bontà della propria applicazione in termini di efficacia e funzionalità.  L’esaltazione della tecnologia adottata mettendo in secondo piano le peculiarità del prodotto è sempre una pessima tecnica commerciale.

Per ora mi fermo qui … ogni commento è bene accetto.