E' stato rilasciato un training kit relativo i futuri "enhancements" del Framework 3.5. Si tratta di un pacchetto di hands-on-lab che comprende le seguenti tecnologie:

  • ADO.NET Data Services
  • ADO.NET Entity Framework
  • ASP.NET AJAX History
  • ASP.NET Dynamic Data
  • ASP.NET MVC
  • ASP.NET Silverlight controls
  • Per maggiori dettagli leggete questo post:

    http://lostintangent.com/2008/04/16/net-35-enhancements-training-kit/

    Il download pubblico lo trovate qui:

    http://www.microsoft.com/downloads/details.aspx?FamilyID=355c80e9-fde0-4812-98b5-8a03f5874e96&displaylang=en


    Dal Tech-ed stamane è arrivata la notizia che il framework .NET 3.0 è stato rilasciato in versione RTM. Ora finalmente sono disponibile gli strumenti di cui da tempo si parla cioè Windows Presentation Foundation, Windows Communication Foundation e Workflow Foundation. Molti dicono che domani tocchi a Windows Vista. Stiamo a vedere.

    Links:


    Le schermate pubblicate da Miguel de Icaza parlano chiaro. Oramai Mono sta diventando una realtà che può consentire di lavorare con gli strumenti di .NET sulle piattaforme Linux. A chi ha sempre detto che su Mono girano bene solo le pagine ASP.NET, ecco la risposta di Miguel che è riuscito nell'intento di far girare nientemeno che Paint.NET, ben 70000 righe di codice C# in ambiente Windows Forms, e ci tiene a precisare "senza l'ausilio di Wine".

    Nel post linkato Miguel descrive nei dettagli le difficoltà che ha dovuto affrontare dallo scorso Ottobre  per compiere questa impresa a dir poco epica. Paint .NET in effetti è un'applicazione molto complessa che sfrutta molto a fondo le caratteristiche del sistema operativo. La speranza è che per il lavoro di tutti i giorni si riesca a fare tutto in modo più semplice...

    Link: http://tirania.org/blog/archive/2006/May-19.html

    powered by IMHO 1.3

    tags: - categories:

    Chi come me sviluppa in ambiente web, è abituato a fare uso, talvolta anche abuso della Cache che il runtime http integra nel framework ASP.NET. Non tutti sanno però che questa cache, può essere abbastanza facilmente essere usata anche in applicazioni Windows Forms. In soldoni è sufficiente creare un runtime http fittizio che supporti adeguatamente la cache e il gioco è fatto.

    In realtà si tratta di un trucco abbastanza vecchio e conosciuto, ma quest'oggi ho finalmente deciso di risolvere con problema in modo definitivo. Il fatto è che spesso è utile incapsulare il caching all'interno di classi che poi possono trovare utilità indifferentemente  in applicazioni WebForms o WindowsForms. Perciò sarebbe utile avere una cache che si adegui al contesto in cui viene istanziata in modo trasparente. Vi propongo perciò in allegato a questo post il codice che ho realizzato, accompagnato da uno schema tratto dal class diagram di Visual Studio 2005 per esporvi la soluzione.

    Le tre classi che potete vedere a fianco pur nella loro semplicità fanno uso di due Design Pattern. Il CacheManager si comporta da un lato come una Abstract Factory, consentendo di istanziare con il metodo statico Create() un'istanza concreta dedicata all'ambiente in cui il processo è in esecuzione. Il test è molto semplice: se è presente un HttpContext verrà istanziato l'HttpCacheManager, in caso contrario la scelta ricaderà sul WinFormsCacheManager. La classe CacheManager inoltre è un Singleton. Essa espone una proprietà Current la quale rende disponibile il CacheManager corretto istanziato per mezzo di Create(). Questa organizzazione consente di avere accesso alla cache adatta al contesto per mezzo di una sola riga di codice:

    object cached = CacheManager.Current["cachedObject"];

    La classe concreta che implementa il CacheManager espone una serie di proprietà e metodi molto comodi. Add() che consente di aggiungere un item in cache, e IsCached che data una chiave verifica se essa è già presenti in cache. Quest'ultimo metodo permete di scrivere qualcosa del genere:

    public List<Product> GetProduct(int sku)
    {
        
    if (!CacheManager.Current.IsCached(sku))
            CacheManager.Current.Add(
                sku, 
                GetProductFromDB(sku), 
                TimeSpan.FromSeconds(20));

        
    return CacheManager.Current[sku] as Product;
    }

    Download: Elite.Utilities.Caching.zip (42 KB)

    powered by IMHO 1.3


    Un esperienza pratica di lavoro con WebServices, applicazioni legacy, e Framework .NET mi ha suggerito l'argomento dell'articolo che questa settimana è apparso sulle "colonne" di UgiDotNet. L'articolo dimostra come, sfruttando gli strumenti del framework 2.0 - mi riferisco a reflection e generics - si possa abbattere notevolmente il tempo di sviluppo di una applicazione. Non solo, l'implementazione è anche un bell'esempio di design, che grazie ad alcuni accorgimenti ha reso flessibile ed adattabile a future esigenze il codice. 

    Tenete presente che questo lavoro ci ha consentito di evitare la realizzazione di una cinquantina di convertitori ad-hoc che avrebbero richiesto un tempo esponenzialmente più elevato. Un ringraziamento al mio collega Roberto che è stato il primo a sentire l'esigenza di rendere parametrico in qualche modo il lavoro che stava facendo, stimolandomi nel trovare la soluzione che ora potete leggere.

    Link: http://www.ugidotnet.org/articles/articles_read.aspx?ID=109

    powered by IMHO 1.3


    Dare Obasanjo nel post che riporto qui sotto, informa sull'intenzione di migrare il suo RSSBandit al framework 2.0 solo quando un tale framework avrà raggiunto una certa base di utenza. Questo a quanto pare non avverrà prima di 1 o 2 anni!!! Mi spiace molto leggere questa notizia, infatti l'adozione del nuovo framework dalle applicazioni di uso più comune avrebbe essa stessa la capacità di velocizzare la sua diffusione. Pur comprendendo in parte le motivazioni che spingono Dare a questa decisione, credo che in questo modo si perda una bella occasione per fare giungere il framework agli utenti finali molto più rapidamente. E non credo che questo potrebbe arrecare danno a RSSBandit, infatti grazie alla possibilità di unire il setup del framework a quello della propria applicazione il passaggio è praticamente indolore.

    Link: RSS Bandit & .NET Framework v2.0

    powered by IMHO 1.3


    Il primo articolo della categoria riguarda un argomento davvero interessante, cui probabilmente molti sapranno dare una risposta, ma che ritengo molto utile per chi si avvicina al framework .NET da un punto di vista produttivo. Nell'articolo che ho aggiunto alla categoria viene illustrato come creare un file ZIP in C# per mezzo della conosciuta SharpZipLib ed in seguito decomprimerlo.

    Articolo: http://www.boschin.it/blogs/radicalmente/articles/sharpziplib.aspx

    Keywords: .net c# creare uno zip

    powered by IMHO 1.2

    tags: - categories:

    Chiunque sviluppi software per professione si sarà almeno una volta trovato di fronte alla necessità di creare o viceversa di scompattare un file zip. Spesso la trasmissione di dati sulla rete richiede che si comprimano i file originali in un unico archivio sia per esigenze di spazio sia di semplice unitarietà come fa ad esempio SCORM, un formato di packaging per l'e-learning. Infatti zip è in grado oltre che di ridurre le dimensioni fisiche di un singolo file adottando un algoritmo di compressione, anche di memorizzare la struttura di directory che originariamente conteneva una serie di file. L'algoritmo ZIP, utilizzato per operare la compressione risale ormai al lontano 1989 ed è nato in seguito ad una disputa legale tra Phil Katz e la SEA sulla proprietà di un precedente e meno efficiente algoritmo. In seguito alla perdita della causa, Katz decise di realizzare un nuovo algoritmo più efficace. Fu così che vide la luce ZIP, adottato per la prima volta dall'ormai famoso PKZIP dell'azienda PKWARE di proprietà dello stesso Katz. Fu solo in seguito, durante gli anni '90 che venne creata l'interfaccia grafica cui tutti siamo ormai abituati e che va sotto il nome di Winzip.

    Accantonando il fascino della storia di questo algoritmo cerchiamo di capire in che modo si possa dotare una nostra applicazione .NET di una compressione/decompressione di file che usi ZIP. Pensare di scrivere del codice che ricalchi questo algoritmo, per se fattibile è davvero complesso e rischia di risolversi in uno spreco di tempo eccessivo. Per fortuna esistono in rete alcune librerie, create e soprattutto testate da appassionati che permettono di raggiungere lo scopo con semplicità, includendole nei nostri progetti. La libreria che personalmente ritengo più efficace va sotto il nome di SharpZipLib ed è liberamente scaricabile presso il sito di IcSharpCode, il gruppo che ha realizzato anche una apprezzata IDE per .NET.

    Una volta scaricato il file della distribuzione binaria dal sito, occorre innanzitutto scompattarlo in una directory per poter usufruire del contenuto. Nella cartella si troveranno un buon numero di directory contenenti tutto il codice sorgente della libreria. Inoltre, nella cartella principale si trovano anche dei file batch, che consentono di installare l'unico assembly nella GAC del proprio PC. Questa è un'operazione molto importante ma non indispensabile. Inserire nella GAC l'assembly consentirà ai vostri programmi di accedere ad esso più rapidamente perchè le operazioni di ricerca e validazione compiute da fusion, il componente di .NET che si occupa del caricamento degli assembly verranno notevolmente semplificate. Tuttavia esso è in grado di reperirlo e caricarlo correttamente anche se tale assembly è presente nella medesima cartella cui fa capo il vostro programma. Qualora desideriate installare la SharpZipLib nella GAC potrete farlo comodamente lanciando il batch InstallGac.bat. Viceversa sarà possibile disinstallarlo con l'altro file UninstallGac.bat. L'assembly ICSharpCode.SharpZipLib.dll, presente nel medesimo file è l'assembly che dovremmo utilizzare nelle nostre applicazioni qualora non desideriamo porlo nella GAC. Tale assembly inoltre dovrà essere referenziato da VisualStudio .NET se si usa tale IDE per sviluppare.

    Una volta referenziato l'assembly, arriva il momento di creare il codice necessario. Per questo articolo mi riferirò al codice di esempio che si può trovare nella distribuzione dei sorgenti della libreria. Fulcro principale della libreria sono gli Stream di input e output che dovranno essere usati per comprimere e decomprimere il flusso dei dati. Le classi corrispondenti sono la ZipOutputStream e ZipInputStream che chiaramente si occuperanno rispettivamente di comprimere e decomprimere il flusso. Il meccanismo di compressione prevede innanzitutto che si apra lo stream di output verso il file destinazione e lo stream di input dal file di origine. Quest'ultimo sarà un normale stream non compresso. Naturalmente la logica di funzionamento degli Stream di .NET consentirà non solo di aprire un file fisico, ma anche una connessione di rete, un'area di memoria, etc... Aperto lo stream di output quindi si scandiranno uno ad uno tutti i file da comprimere aprendo uno stream di input da ognuno, e creando così una ZipEntry che consentirà di specificare le informazioni del file in questione nell'indice dello zip. La ZipEntry in particolare raccoglierà il nome del file, la dimensioen ed il CRC. Il CRC, per esteso Cyclic Redundancy Code è una sorta di firma elettronica del file che lo rappresenta in modo quasi del tutto univoco. Il CRC verrà utilizzato in fase di decompressione per verificare che il file estratto sia uguale all'originale e non abbia subito corruzione dall'operazione di compressione/decompressione. Per il calcolo del CRC la libreria mette a disposizione una classe omonima che si incarica di tutti gli oneri.

    Inserita la entry nel nuovo Zip con il metodo PutNextEntry() si provvederà a scriverne il contenuto nello stream per mezzo di una semplice Write(). Infine i metodi Finish() e Close() al termine porranno fine all'operazione di compressione. Ecco un breve esempio di quanto finora spiegato:

    public static void Main(string[] args)
    {
        
    string[] filenames = Directory.GetFiles(args[0]);
        
        Crc32 crc = 
    new Crc32();
        ZipOutputStream s = 
    new ZipOutputStream(File.Create(args[1]));
        
        s.SetLevel(6); 

        
    foreach (string file in filenames)
        {
            FileStream fs = File.OpenRead(file);
            
            
    byte[] buffer = new byte[fs.Length];
            fs.Read(buffer, 0, buffer.Length);
            ZipEntry entry = 
    new ZipEntry(file);            
            entry.DateTime = DateTime.Now;
            entry.Size = fs.Length;
            fs.Close();
            
            crc.Reset();
            crc.Update(buffer);
            entry.Crc  = crc.Value;
            
            s.PutNextEntry(entry);            
            s.Write(buffer, 0, buffer.Length);
        }
        
        s.Finish();
        s.Close();
    }

    Esempio 1 - Creare il file ZIP
     
     
    Utile segnalare che per mezzo del metodo SetLevel() si può specificare con un numero da 0 a 9 il livello di compressione dove 0 disabilita del tutto la compressione ma si limita a mantenere la struttura delle directory.
     
    L'operazione inversa non è più complessa di quella appena illustrata. Richiede semplicemente che si tenga conto della struttura presente nel file zip e che sulla base di essa si ricreino le directory e i file di destinazione. Gli stream di input e output saranno questa volta invertiti e sarà quello di output ad essere ripetutamente aperto e chiuso per scrivere il contenuto decompresso. Ecco di seguito il codice relativo:
     
     
    public static void Main(string[] args)
    {
        ZipInputStream s = 
    new ZipInputStream(File.OpenRead(args[0]));
        ZipEntry theEntry;

        
    while ((theEntry = s.GetNextEntry()) != null)
        {
            
            Console.WriteLine(theEntry.Name);
            
            
    string directoryName = Path.GetDirectoryName(theEntry.Name);
            
    string fileName      = Path.GetFileName(theEntry.Name);
            
            Directory.CreateDirectory(directoryName);
            
            
    if (fileName != String.Empty)
            {
                FileStream streamWriter = File.Create(theEntry.Name);
                
    int size = 2048;
                
    byte[] data = new byte[2048];

                
    while (true
                {
                    size = s.Read(data, 0, data.Length);

                    
    if (size > 0)
                        streamWriter.Write(data, 0, size);
                    
    else 
                        break
    ;
                }
                
                streamWriter.Close();
            }
        }
        s.Close();
    }
     
    Esempio 2 - Decomprimere uno zip
     
    L'unica reale differenza la si può riscontrare nella necessità di verificare la presenza di directory nel file e di ricrearle nella directory di destinazione per mantenere la struttura oiginale. Chiudo questo lungo articolo suggerendo lo studio del progetto HtpCompressionModule presente tra i sorgenti. Esso implementa un modulo per ASP.NET che consente la compressione/decompressione zip dello stream di output/input da e verso il browser che la supporti. Utile potrà essere anche la lettura del mio articolo, scritto per UgiDotNet, "Inside HttpHandlers" che spiega come realizzare un handler che mostri la struttura web di un file zip come se si trattasse di unsa normale virtual directory.
     
    tags: - categories:

    Proseguendo l'indagine nella configurazione dell'applicazione del Framework 2.0, sono finalmente venuto a capo del SettingsProvider.

    Il SettingsProvider è una classe, che si occupa della serializzazione/deserializzazione delle informazioni di configurazione, di una classe derivata da ApplicationSettingsBase. Un SettingsProvider si compone di un metodo GetPropertyValues() che riceve in input l'elenco delle proprietà della classe da deserializzare che sono marcate con un attributo di scope come UserScopedSettings o ApplicationScopedSetting e di uno speculare metodo SetPropertyValues() che invece riceve i valori da serializzare, corrispondenti alle suddette proprietà.

    L'uso classico di un SettingsProvider potrebbe essere ad esempio quello di serializzare e deserializzare le informazioni di configurazione su un file crittato. Per fare questo si dovrà creare una classe che deriva da ApplicationSettingsBase che esponga tutte le informazioni di configurazione (vedi qui).

    A questo punto si potrà realizzare una classe, derivandola da LocalFileSettingsProvider e fare l'override delle proprietà e dei metodi che la compongono, facendo particolare attenzione ai sopracitati GetPropertyValues() e SetPropertyValues(). Al loro interno si andrà a decrittare le informazioni di configurazione e a comporre una collection di valori o viceversa a serializzare le informazioni e poi a crittare il file.

    Ecco un breve esempio:

    public class CryptoSettingsProvider : LocalFileSettingsProvider
    {
        
    private string mName;

        
    public override string ApplicationName
        {
            
    get return mName;  }
            
    set { mName = value; }
        }

        
    public override string Name
        {
            
    get return "CryptoSettingsProvider"; }
        }

        
    public override SettingsPropertyValueCollection GetPropertyValues SettingsContext context, SettingsPropertyCollection ppc)
        {
            
    // deserializzare il file crittato
        
    }

        
    public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection ppvc)
        {
            
    // serializzare il file critato
        
    }
    }

    Il collegamento tra il SettingsProvider e la classe di configurazione si ottiene per mezzo dell'attributo SettingsProviderAttribute nel cui costruttore andrà specificato come tipo da istanziare il provider appena creato. Ecco l'attributo

    [SettingsProvider("Elite.Test.CryptoSettingsProvider,Elite.Test")]

    Occorre fare importanza anche alle proprietà della classe, oltre ai metodi. Personalmente la proprietà "Name" ha dato parecchi problemi dato che non c'era scritto da nussuna parte che era obblogatorio farne l'override.

    powered by IMHO