di .NET e di altre amenità

Tools per speakers: WiiKey

Trovato oggi per puro caso sfogliando i progetti di codeplex. WiiKey permette di comandare powerpoint per mezzo di wiimote, l'innovativo "joystick" introdotto da Nintendo per la sua console. Interessante che supporta anche ZoomIt.

Codeplex: http://www.codeplex.com/WiiKey

Project home: http://www.indyproject.org/WiiKey/index.en.aspx

Jana Server also rocks!

E con questo facciamo tre post su prodotti. Questa volta però si tratta di un freeware che tengo sempre da parte nel mio cappellino da sistemista. Il post serva da tributo per la completezza e l'affidabilità di questo proxy server freeware made in germany che anche oggi come spesso è accaduto nella mia vista lavorativa si è rivelato di un aiuto strepitoso.

Ricordo ancora nella notte dei tempi quando riuscii a far uscire su internet tutta l'amministrazione dell'azienda presso cui lavoravo solo grazie a questo software. Parlo ormai di 5 anni fa, un tempo enorme in termini informatici. Jana server però è sempre presente e sempre uguale, un po' ostico da capire all'inizio ma poi impareggiabile.

Oggi abbiamo fatto qualche operazione non troppo ortodossa per superare dei problemi alla rete aziendale che naturalmente si propongono sempre e solo quando la data della consegna si profila all'orizzonte. Grazie JANA!

Link: http://www.janaserver.de/

ASP.NET 2.0: Filtrare gli utenti per le proprietà del profile

Stamane nel newsgroup di asp.net è apparsa una domanda interessante che mi ha fatto pensare un po' a proposito delle potenzialità di Membership e di ProfileProvider. Ho colto così l'occasione per scrivere due righe di codice per risolvere un problema che effettivamente potrebbe essere limitante nell'uso di questi strumenti. Il problema in questione è che così come le informazioni del profilo vengono persistite nella relativa tabella è praticamente impossibile se non molto difficile accedere ad esse per filtrare gli utenti in base ad esse.

Le informazioni di profilo vengono memorizzate tutte in due campi nella tabella aspnet_Profile con un formato particolare che consente al runtime di recuperarle velocemente ma che d'altro canto impedisce di accedervi per mezzo di una semplice query. Ecco come:

   1: PropertyNames: Age:S:0:2:Province:S:2:2:Town:S:4:7:
   2: PropertyValues: 38TVTreviso

In sostanza il campo PropertyNames oltre al nome delle proprietà contiene il tipo, il punto di inizio e la lunghezza della frazione del campo PropertyValues. Nel riquadro è riportato il formato di tre proprieta: Age, Province e Town.

Ora è del tutto evidente che sperare di scrivere una query SQL che consenta di raggiungere ad esempio tutti gli utenti che abitano in provincia di Treviso è pura utopia. Inoltre se andiamo a vedere i metodi del ProfileProvider in breve ci renderemo conto che estrarre questa informazione è piuttosto complicato e rischia di costringerci a leggere i campi uno per uno decodificandoli.

Oggi qualcuno naturalmente aveva bisogno di ottenere proprio questo risultato e quindi mi sono dovuto inventare un workaround. Di per se non sarebbe complesso trovare gli utenti di Treviso se i dati fossero spalmati correttamente in una tabella, perciò ho pensato di salvare una copia dei dati di interesse in una tabella di appoggio da usare per questi scopi.

L'idea è quella di inserirsi al punto giusto ed operare inserimenti e update all'unisono con il provider stesso in modo da tenere allineata questa tabella senza però perdere le funzionalità comode del provider che deve rimanere l'unico gestore in lettura e scrittura. Quindi ho deciso di estendere il provider e fare l'override del metodo SetPropertyValues().

   1: public override void SetPropertyValues(
   2:     SettingsContext sc, 
   3:     SettingsPropertyValueCollection properties)
   4: {
   5:     base.SetPropertyValues(sc, properties);
   6:  
   7:     using (SqlConnection conn = new SqlConnection(this.ConnectionString))
   8:     {
   9:         conn.Open();
  10:  
  11:         using (SqlCommand command = new SqlCommand("spx_UpdateProfileIndex", conn))
  12:         {
  13:             command.CommandType = CommandType.StoredProcedure;
  14:             command.Parameters.AddWithValue("@username", sc["UserName"]);
  15:             command.Parameters.AddWithValue("@province", properties["Province"].PropertyValue);
  16:             command.ExecuteNonQuery();
  17:         }
  18:     }
  19: }

Nel metodo dapprima si chiama la base che provvede ad inserire i dati al loro posto come consueto. Poi il controllo passa alla stored procedure nella quale dati che vengono salvati nella tabella di appoggio. La tabella in questione ha un campo per ogni proprietà. La stored procedure è abbastanza furba da sapere se deve fare una insert o un update.

Con questo sistema si riesce a creare quindi una tabellina semplice che ci aiuti a fare delle query per trovare il riferimento agli utenti che hanno un dato valore in una proprietà. L'importante è non abusarne. Non si deve nemmeno per un momento pensare che modificando un valore in essa si modificheranno in accordo anche il valore della proprietà di profile, altrimenti ci troveremmo nella condizione in cui rifare il provider è più conveniente. Ovviamente poi sarà nostro onere tenere il numero di colonne appropriato per proprietà che vengano aggiunte in futuro.

Tuttavia lasciatemi fare una considerazione: la palese inadeguateza del ProfileProvider in casi come questo mi suggerisce che sia preferibile adottare un sistema custom per la persistenza di proprietà che poi servano per catalogare gli utenti, mentre il ProfileProvider dovrebbe essere usato per dati meno sensibili come ad esempio le personalizzazione dell'interfaccia o comunque dei dati che devono solamente essere persistiti tra diverse sessioni.

Codice di esempio completo: (6,8 KB)

Windows Vista - 6 Month Vulnerability Report

A quanto pare la "durezza" ormai proverbiale di Windows Vista in quanto a sicurezza sta pagando. Da un rapporto uscito in questi giorni pare che Windows Vista sia in assoluto il S.O. sul quale si riscontra il minor numero di vulnerabilità critiche negli ultimi sei mesi. Sinceramente non so dire se questo dipende dal diffusione ancora non ampia, ma mi pare comunque un buon risultato soprattutto tenendo in considerazione la quantità di persone che darebbe un dito pur di scovarne una... :)

Dallo stesso rapporto, il cui grafico parla chiaro, indovinate qual'è il S.O. più buggato?

Link:

Silverlight: Nibbles Tutorials

Segnalo la comparsa di un nuovo sito di tutorial su Silverlight e WPF. Si tratta di Nibbles Tutorials. Il sito è anche un bell'esempio di cosa si può ottenere con Siverlight dato che è sviluppato completamente con esso (Attenzione però che un sito realizzato in questo modo non sarà mai indicizzato dai motori di ricerca). Nel sito segnalato da ci sono già dei contenuti su Silverlight mentre sono ancora in preparazione quelli su WPF.

Link: http://www.nibblestutorials.net/

Technorati tags: , ,

Resharper 3.0

Non è la prima volta che parlo di questo prodotto. Confesso di avere avuto qualche delusione tempo fa quando dopo una installazione della versione 2.5 ho riscontrato parecchi problemi. Da ieri sto provando la versione 3.0 di Resharper che è uscita qualche giorno fa e devo dire che sono davvero impressionato. A parte la completezza e la estensività dello strumento devo rilevare che quelli che un tempo erano i maggiori problemi dovuti all'esagerata esigenza di memoria ram, ora sono stati del tutto risolti. Di tutto ciò che sono riuscito a provare, ho trovato solamente una cosa ancora un po' lenta: mi riferisco all'analisi che resharper può compiere ad ogni apertura di un file in Visual Studio che pare aver bisogno ancora di qualche miglioramento. Una volta disattivata questa opzione (che tra l'altro è marginale) resharper diventa un vero "missile" e l'indicatore delle risorse utilizzate rimane sempre sotto i 45 MB.

Non ho intenzione di fare una recensione completa del prodotto percò non posso non segnalare alcune chicche:

1) Find Usage è di gran lunga la funzione che mi piace di più. Io ho difficoltà a ricordare con esattezza tutti gli usi che ho fatto di una particolare classe o di un metodo e perciò questa caratteristica mi fa risparmiare un sacco di tempo

2) Potenziamento degli snippet. E' quasi incredibile. provate a scrivere "foreach" e Resharper automaticamente è in grado di completare il costrutto alla perfezione indovinando il più delle volte anche qual'è l'IEnumerable che intendete utilizzare. Non contento vi posiziona immediatamente tra le parentesi graffe... impagabile.

3) Ora supporta anche XML e XAML. Mano a mano che si scrive Resharper sistema l'XML alla perfezione. Bellissimo per i maniaci come me "Make Empty Tag" che si applica ovviamente solo ai possibili candidati.

Provatelo perchè ne vale la pena.

ANTS Profiler Rocks!

Ho l'obbligo morale di scrivere queste poche righe per elogiare un prodotto che mi ha appena tolto da un grosso problema. Ho trovato tale strumento di una semplicità e potenza davvero impareggiabili. Avevo un collo di bottiglia nell'esecuzione di una pagina web che nonostante tutti i tentativi di debug e logging non ero riuscito ad individuare. Grazie ad e alla sua capacità di loggare i tempi di esecuzione di tutti i metodi (della propria applicazione o del framework, pubblici o privati che siano), ho potuto ripercorrerre il tracciato di esecuzione della richiesta passo-passo individuando il metodo incriminato per poi "debellarlo" in un tempo più che accettabile se si considerano gli estremi benefici ottenuti.

Davvero un grande strumento che consiglio a chiunque intenda scrivere applicazioni "serie"... come devo dire molti altri prodotti di .

Technorati tags: , ,

Appunti di WPF: Un po' di link alla rinfusa #2

E' un po' di tempo che non pubblico molto su WPF, a causa di un lavoro che sto portando avanti che per ora mi assorbe fino all'ultimo minuto. Per oggi pubblico una serie di link che ho trovato nel web... 

 

: Robert Relyea spiega per quale motivo XAML è case-sensitive

: Un utile elenco delle braking changes tra la versione del Mix e la prossima release.

: E' stato pubblicato in versione stand-alone WPFPerf, il tool per le performance in WPF. Qualcosa anche .

: un nuovo sito sulle tecnologie WPF con anche una bella di applicazioni.

: Un'immagine PNG che riassume le feature di Silverlight.

 

ASP.NET 2.0: UserControls e Navigazione

Gli UserControl sono indubbiamente una gran bella invenzione in ASP.NET, per qualche verso anche meglio dei WebControl per i progetti low-end, perchè consentono di creare delle componenti riutilizzabili con molta più facilità risparmiando molto tempo. Con l'introduzione delle webparts poi il loro utilizzo si è moltiplicato a dismisura. Tuttavia non è la prima volta che mi trovo ad avere degli UserControl che pur essendo riutilizzabili come auspicabile talvolta soffrono di alcuni fastidiosi vincoli imposti ad esempio dalla navigazione del website.

Se ad esempio pensiamo ad un controllo che rappresenti la form di creazione/modifica di una entità del nostro sistema, non è sempre detto che alla pressione del tasto salva il comportamento debba essere il medesimo. Poniamo che il controllo sia usato una volta come "inserimento rapido" - posizionato immediatamente sotto ad una gridview - mentre un'altra volta verrà inserito in una pagina autonoma per l'edit dell'entità stessa. Se nel primo caso alla pressione del tasto Salva ci dovremmo aspettare di rimanere nella stessa pagina per consentire l'inserimento di un'altro record, nel secondo potremmo attenderci di tornare alla pagina da cui siamo arrivati. Se inseriamo questo comportamento hard-coded nello UserControl stiamo indubbiamente limitando la riutilizzabilità del controllo stesso. Dovremmo perciò gestire una serie di eventi per fare in modo che la navigazione non abbia impatto sulla riutilizzabilità del controllo.

Recentemente ho adottato un sistema interessante che mi aiuta a gestire in modo più rapido questa problematica. Il primo passo è quello di creare uno UserControl base per tutti i controlli che dovranno implementare questo tipo di navigazione:

   1: public class CoreUserControl : UserControl
   2: {
   3:     /// <summary>
   4:     /// Gets or sets the navigations.
   5:     /// </summary>
   6:     /// <value>The navigations.</value>
   7:     [PersistenceMode(PersistenceMode.InnerProperty)]
   8:     public NavigationCollection Navigations
   9:     {
  10:        get { return GetViewState<NavigationCollection>("navigations", new NavigationCollection()); }
  11:        set { SetViewState<NavigationCollection>("navigations", value); }
  12:     }
  13:     
  14:     /// <summary>
  15:     /// Navigates to.
  16:     /// </summary>
  17:     /// <param name="navigationName">Name of the navigation.</param>
  18:     protected void NavigateTo(string navigationName, params object [] args)
  19:     {
  20:        string navigation = this.Navigations.GetNavigationUrl(navigationName, args);
  21:     
  22:        if (!string.IsNullOrEmpty(navigation))
  23:            Response.Redirect(navigation);
  24:     }
  25: }

Come si vede il controllo espone una collection di oggetti di tipo Navigation che rappresentano appunto le possibili transizioni in base agli eventi generati dallo usercontrol. Nel caso del controllo di cui sopra potrebbero essere OnSaved e OnCancel per rappresentare appunto la navigazione successiva al salvataggio dell'entità e quella causata dalla pressione di Cancel. L'oggetto Navigation espone solamente due proprietà: Name e NavigationUrlFormat. Il primo è il nome che daremo all'evento che causa la transizione mentre il secondo è l'url di destinazione comprensivo di eventuali marcatori per parametri che siano inseriti a runtime. Ecco un esempio di configurazione:

   1: <uc:PropertyForm runat="server" id="editProperty" Title="<%$ Resources:common,EditProperty_Title %>">
   2:     <Navigations>
   3:         <uc:Navigation Name="OnSaved" NavigationUrlFormat="~/list.aspx?id={0}" />
   4:         <uc:Navigation Name="OnCancel" NavigationUrlFormat="~/home.aspx" />
   5:     </Navigations>
   6: </uc:PropertyForm>

Lo usercontrol, perciò al termine di ogni operazioe dovrà comportarsi come segue:

1) Verifica che sia presente una Transizione con il nome richiesto

2) Se la transizione esiste attiva la navigazione verso la destinazione

3) Se la transizione non esiste rimane sulla pagina stessa

Questa verifica è fatta dal metodo NavigateTo(), esposto dallo UserControl base. Grazie ad esso, all'interno del codice del controllo sarà sufficiente scrivere il seguente codice per gestire la navigazione:

   1: protected void thisForm_ItemInserted(object sender, FormViewInsertedEventArgs e)
   2: {
   3:     if (e.Exception != null)
   4:         e.ExceptionHandled = HandleException(e.Exception);
   5:     else
   6:     {
   7:         NavigateTo("OnSaved", this.CurrentClass);
   8:     }
   9:  
  10:     e.KeepInInsertMode = true;
  11: }

Naturalmente non è l'unico modo: ad esempio potremmo usare l'url prodotto da GetNavigationUrl() per alimentare un link in una gridview e fare così in modo che si apra la form relativa ad una riga presenti in essa.

Personalmente ho trovato il sistema da un lato abbastanza flessibile e dall'altro sufficientemente semplice da non richiedere complesse infrastrutture che alla fine complicano le cose molto più di quello che semplificano.

Technorati tags: , ,

ASP.NET 2.0: Spostare la ViewState in Session

Quest'oggi nei newsgroup qualcuno mi ha chiesto come fare a spostare la ViewState (che ha la spiacevole tendenza a diventare colossale) in Session. Ho mostrato questa tecnica durante un recente webcast che trovate a questo indirizzo il codice sorgente da cui attigere http://www.xedotnet.org/40/section.aspx/376.

Comunque ripeto qui l'esempio, che peraltro è di una semplicità disarmante per completezza:

   1: protected override PageStatePersister PageStatePersister
   2: {
   3:     get
   4:     {
   5:         return new SessionPageStatePersister(this);
   6:     }
   7: } 

Il PageStatePersister è un componente di recente acquisizione per ASP.NET che ha l'onere appunto di persistere la viewstate. Tipicamente in questo campo si trova un HiddenFieldPageStatePersister, ma possiamo semplicemente cambiarlo con un'altro fornito dal framework stesso che si chiama SessionPageStatePersister e il gioco è fatto.

Comunque nel caso in cui la viewstate assumesse dimensioni bibliche vi consiglio di controllare quello che state facendo perchè il più delle volte basta impostare EnableViewState="false" su alcuni controlli chiave e si ottengono dei benefici notevoli. Non dimenticate infatti che occupare la Session può portare comunque ad un degrado delle prestazioni che avrà un impatto su tutti gli utenti collegati. Quindi occhio...

ASP.NET 2.0: Accedere correttamente alla cache

Recentemente mi è capitato di incorrere in acuni problemi relativi l'accesso alla Cache di ASP.NET in situazioni di scarsità di risorse e quindi in quei momenti particolari in cui entra in gioco la scadenza dei contenuti per i quali si usa la cache. Il codice che tempo fa avevo scritto pur se a prima vista dovrebbe essere funzionante, ad una analisi più meditata si è rivelato errato. Il codice, ridotto all'osso per renderlo meglio comprensibile è il seguente:

   1: public string GetCachedValue()
   2: {
   3:     if (Cache["cachedValue"] == null)
   4:         Cache["cachedValue"] = GetData();
   5:  
   6:     return Cache["cachedValue"] as string;
   7: }

Come dicevo il codice a prima vista non ha motivo di non funzionare, ma analizzando bene quello che può accadere durante il ciclo di vita dell'applicazione ci si rende conto che tra l'esecuzione della riga 3 e l'esecuzione della riga 6, può incorrere uno switch di contesto del thread in esecuzione e di conseguenza la cache potrebbe scadere ed essere rilasciato. Perciò se alla riga 3 il risultato dell'if determina che nella cache c'è qualcosa potremmo arrivare che alla riga 6 invece la cache è vuota. Vi assicuro che anche se ciò possa sembrare una eventualità remota, in un contesto in cui le risorse scarseggiano e in cui le chiamate sono molte essa non mancherà di verificarsi. Ecco quindi il corretto approccio alla cache per evitare questo tipo di problematiche:

   1: public string GetCachedValue()
   2: {
   3:     object cachedValue = Cache["cachedValue"];
   4:  
   5:     if (cachedValue == null)
   6:     {
   7:         cachedValue = GetData();
   8:         Cache["cachedValue"] = cachedValue;
   9:     }
  10:  
  11:     return cachedValue as string;
  12: }

Cosa cambia in questo approccio? Questo sistema, del tutto analogo ad esempio a quello che si usa per i singleton è thread-safe. Semplicemente il thread corrente prende un riferimento all'oggetto in cache nella variabile cachedValue. Questo comporta che anche se la cache dovesse essere liberata, il riferimento all'oggetto rimane valido e di conseguenza può essere ritornato in tutta tranquillità senza il rischio che i chiamanti incorrano in NullReferenceException. Per capire questa soluzione bisogna tenere bene a mente il fatto che nella cache sono presenti istanze di "object" e quindi o dei ReferenceType o dei ValueType boxed. Prenderne un riferimento eviterà innanzitutto che valutando la cache due volte si trovi una situazione differente ma eviterà anche che l'oggetto liberato sia mandato in coda per la collection da parte del Garbage Collector.

Technorati tags: , ,

Alla scoperta del VirtualPathProvider: un intero sito dentro un assembly

E' passato un po' di tempo dall'uscita del mio ultimo articolo sul sito di XeDotNet. Questo weekend ho deciso di investire un po' di tempo per scrivere un piccolo ma interessante esempio di come funziona a il VirtualPathProvider, un componente vitale di ASP.NET che nei mesi scorsi ho avuto modo di approfondire grazie ad un lavoro particolare che ho svolto in ufficio. L'articolo che ne è uscito illustra le potenzialità di questo particolare provider e descrive l'esempio nel quale un intero sito web composto da pagine, immagini, masterpage e css viene racchiuso all'interno di un assembly come Embedded Resource. Si tratta ovviamente di un esercizio che però oltre a dimostrare ampiamente le magie che si possono ottenere con il VirtualPathProvider, è anche in grado di rivelarne abbastanza in profondità limiti, problematiche e caratteristiche.

Link: