di .NET e di altre amenità

xedotnet.org é online!!!

Dopo alcune serate di lavoro, e svariati test è finalmente pubblico il sito della community del triveneto XE.NET. Un ringraziamento anche ad Andrea Dottor e a Marco ".mark" Trova per avermi supportato nelle lunghe nottate passate a lottare contro CommunityServer.

Il sito espone un numero limitato di servizi. Abbiamo un paio di feeds che useremo per informare gli iscritti a proposito delle notizie sulla community e sulla tecnologia .NET e un utile Roller presso il quale abbiamo aggregato alcuni feed degni di nota. Al momento non sono previsti altri servizi, ma contiamo di potenziare quanto prima il sito aggiungendo una sezione tips, non appena se ne manifesterà la necessità.

Da ieri sera infine, il sito accetta iscritti; chiunque volesse può registrarsi.

powered by IMHO 1.3

ASP.NET 2.0: Quando leggere una property fa la differenza

Stamane ho fatto una scoperta che definirei sconcertante. La semplice lettura della proprietà Controls, in alcuni WebControl di ASP.NET causa notevoli malfunzionamenti al ciclo di vita della pagina. In particolare stavo utilizzando il metodo di cui ho parlato in un post precedente, per cercare dei controlli all'interno della gerarchia della pagina. Questa ricerca, se eseguita all'interno dell'OnInit, fa si che alcuni controlli non manifestino più gli eventi tipici. Ad esempio, un LinkButton non notificava più il "Click", e una FormView non era più in grado di gestire il postback correttamente.

Dopo una lunga estenuante ricerca, sono riuscito ad individuare la riga che era origine del problema, e con mio stupore mi sono reso contro che in quel punto non facevo altro che leggere la proprietà Controls per enumerare i controlli figlio. C'è voluta una breve indagine on il Reflector per arrivare ad una possibile spiegazione. La proprietà Controls non legge semplicemente il valore di un field, ma si occupa anche di inizializzare la collection nel caso in cui essa non sia già popolata; ecco il codice estratto da reflector:

public virtual ControlCollection Controls
{
      
get
      
{
            
if ((this._occasionalFields == null) || 
                (
this._occasionalFields.Controls == null))
            {
                  
this.EnsureOccasionalFields();
                  
this._occasionalFields.Controls = 
                      
this.CreateControlCollection();
            }
            
return this._occasionalFields.Controls;
      }
}

Come appare chiaro questo codice si occupa di istanziare una ControlCollection di default qualora essa non sia già presente. A quanto pare questa inizializzazione causa problemi se effettuata esternamente. Suppongo che da qualche parte, all'interno del ciclo di vita di un chiamata, esista una porzione di codice che verifica se tale proprietà è già inizializzata e si comporta di conseguenza in modi del tutto diversi. In effetti, a ben guardare la classe Control espone un metodo che compie questa verifica e che torna utile per aggirare questo malfunzionamento. Si tratta di HasControls(), un metodo che restituisce false se la proprietà non è inizializzata. Evidentemente in Microsoft il problema ho avevano previsto, e quindi hanno fornito un metodo per aggirarlo. Ecco quindi come dovrebbe essere modificato il codice dell'esempio precedente:

public static T FindControlRecursive<T>(Control root, string id)
    where T : Control
{
    
if (root.ID == id && root is T)
        
return root as T;

    
if (root.HasControls())
    {
        
foreach (Control child in root.Controls)
        {
            T foundControl = FindControlRecursive<T>(child, id);
    
            
if (foundControl != null)
                
return foundControl;
        }
    }

    
return default(T);
}

In questo modo non si modificherà lo stato del controllo. Rimane semplicemente da rilevare che si tratta di un comportamento decisamente subdolo, che andrebbe affrontato e corretto. Probabilmente sollevare un'eccezione sarebbe stato preferibile. A me è costato 3 ore di lavoro. Spero che a voi vada meglio.

powered by IMHO 1.3

 

Framework .NET 2.0: Convertire tipi con .NET 2.0, Generics e Reflection

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

ASP.NET 2.0: Un finder un po' generico...

Chi usa ASP.NET conosce il metodo FindControl() che consente di trovare un controllo all'interno del proprio genitore. Sa sicuramente anche che questo metodo non è ricorsivo, ma si limita al primo livello e di solito si usa scrivere un metodo apposito che implementa questa ricorsività. In rete se ne trovano parecchi esempi ma voglio proporvene uno che ho scritto stamane per eseguire ricerche mirate ad uno specifico tipo di controlli:

public static T FindControlRecursive<T>(Control root, string id)
    where T : Control
{
    
if (root.ID == id && root is T)
        
return root as T;

    
foreach (Control child in root.Controls)
    {
        T foundControl = FindControlRecursive<T>(child, id);

        
if (foundControl != null)
            
return foundControl;
    }

    
return default(T);
}

L'uso di un generics in questo caso consente di specificare il tipo di controllo da ricercare nella gerarchia, semplificando di molto la stesura del codice. Se poi avete l'ardire di togliere il constraint allora scoprirete che è possibile anche cercare un controllo che implementa una determinata interfaccia...

Lo confesso, mi sto innamorando. Un amore un po' generics, ma sempre di amore si tratta...

powered by IMHO 1.3

ASP.NET 2.0: ITextControl interface

Nel framework 2.0 è presente una nuova interfaccia ITextControl, il cui compito è molto semplice, almeno quanto utile per chi sviluppa webcontrols. ITextControl identifica i controlli che espongono una proprietà Text e che quindi sono utilizzabili per "mostrare un output all'utente".

Implementano quindi ITextControl tutti quei controlli che avendo una proprietà Text possono consentire di mostrare qualcosa all'utente. Literal, Label, TextBox sono tutti controlli ITextControl. Tuttavia vorrei che qualcuno mi spiegasse perchè LinkButton e Button non implementano questa interfaccia. Questi ultimi implementano IButtonControl, che a sua volta espone la proprietà Text, ma era cos' difficile fare in modo che IButtonControl derivasse da ITextControl?

Pare una stupidaggine, ma forse non avete idea della quantità e qualità di codice che questo avrebbe consentito:

Control textControl = 
    FindTextControl(container, "HeaderText");

if (textControl is ITextControl)
    ((ITextControl)textControl).Text = 
this.Columns[i].HeaderText;
else if (textControl is IButtonControl)
    ((IButtonControl)textControl).Text = 
this.Columns[i].HeaderText;
else
    throw new 
InvalidOperationException("...");

sarebbe diventato:

ITextControl textControl = 
    FindTextControl(container, "HeaderText");

if (textControl != null)
    textControl).Text = 
this.Columns[i].HeaderText;
else
    throw new 
InvalidOperationException("...");

A volte basta talmente poco.

powered by IMHO 1.3

Offerta di lavoro in provincia di Venezia

L'azienda presso cui lavoro ha la necessità di assumere una nuova risorsa senior, con il seguente profilo:

  • Programmazione ad oggetti
  • ASP.NET 1.1
    • In particolare
      • Pagina aspx
      • Web User Control
      • Web Custom Control
      • Autenticazione/Autorizzazione
      • Localizzazione di applicazioni Web
  • C# 1.1
  • .NET Web Services
  • Microsoft SQL Server 2000
  • T-SQL
Rappresenta titolo preferenziale la conoscenza di:
  • ASP.NET 2.0
  • C# 2.0
  • Microsoft SQL Server 2005
e le seguenti certificazioni Microsoft:
  • MCSD - Microsoft Certified Solution Developer
  • MCAD - Microsoft Certified Application Developer

Chi fosse interessato non ha che da contattarmi all'indirizzo riportato nel mio blog.

powered by IMHO 1.3

ASP.NET 2.0: Quei maledetti 5 pixels

Se si prova a dare alle webparts un aspetto un po' più accattivante rispetto a quello che hanno di default ci si scontra con un piccolo ma fastidioso bug, riconosciuto da Microsoft come tale.  Le webpart, volenti o nolenti hanno sempre un padding di 5 pixel attorno al contenuto e di 2 pixel attorno al titolo. Tale padding non è impostabile in alcun modo, ma per stessa ammissione del team di ASP.NET 2.0 è hard-coded all'interno del framework.

Esistono un paio di workaround suggeriti da Microsoft in ladybug, ma la loro applicazione è del tutto limitata e difficoltosa. L'unico modo veramente valido che ho trovato - suggerito da un utente - per superare questo problema è lo sfruttare la natura dei css. Chiunque usi i css sa che in cascata vengono applicati prima i fogli di style .css, poi il contenuto di <style> e infine il valore dell'attributo style di ogni tag con il risultato che quest'ultimo ha la precedenza sugli altri e risulta insuperabile. Detto questo è evidente che l'attributo style="padding:5px" che si trova sul <td> che incapsula il contenuto della webpart è pressochè impossibile da aggirare.

Esiste però una clausola nei fogli di stile che consente di sovrascrivere questo comportamento di default. Si tratta dello switch !important che se fatto seguire ad uno stile fa si che esso diventi preponderante rispetto a quelli di livello superiore.

.webPart
{
   padding: 0px !important;
}

Questo breve pezzetto di stile risolverà definitivamente il problema. Speriamo però che Microsoft ci metta una pezza al più presto.

powered by IMHO 1.3

ASP.NET 2.0: Migrare i profili anonimi

Le nuove capacità di Profiling di ASP.NET 2.0 sono una feature molto apprezzabile anche in considerazione del fatto che sono in grado di gestire anche i profili anonimi, cioè consentono di persistere le impostazioni di profilazione anche per gli utenti che ancora non sono autenticati. Questo ad esempio torna utile nel momento in cui è necessario consentire la selezione della lingua anche ad un navigatore che non si è ancora registrato. Esiste però un piccolo problema per capire il quale vi farò un semplice esempio: immaginate di utilizzare il profilo anonimo appunto per persistere la lingua selezionata in un portale. Ora è evidente che qualora un utente anonimo imposti la lingua e in seguito si autentichi al portale, l'impostazione selezionata dovrà essere trasportata verso il profile autenticato. Per compiere questa migrazione esiste un evento apposito, gestibile nel global.asax in questo modo:

public void Profile_OnMigrateAnonymous(
    
object sender, 
    ProfileMigrateEventArgs args)
{
    ProfileCommon anonymousProfile = 
        Profile.GetProfile(args.AnonymousID);
        
    Profile.Culture = anonymousProfile.Culture;
    
    ProfileManager.DeleteProfile(args.AnonymousID);
    AnonymousIdentificationModule.ClearAnonymousIdentifier(); 
}

L'esempio è reperibile anche nella documentazione MSDN ma non è del tutto evidente.

powered by IMHO 1.3

Lo user group ghe xe!

Sono davvero lieto di potervi comunicare la bella novella. Stasera, alla cena indetta per fondare lo user group .NET del triveneto sono convenute ben 12 persone, molto più di quanto mi aspettassi per un incontro tutto sommato tra perfetti sconosciuti. Invece sono stato favorevolmente sorpreso della serietà dimostrata nell'affrontare gli argomenti via via proposti, nell'esporre cosa ognuno di noi si aspetti da questo user group, dagli obbiettivi che ci uniscono fortemente.

Il primo meeting dello user group del triveneto, ha deciso. Ha deciso innanzitutto di provare a costruire qualcosa gradualmente, stabilendo quelli che sono gli obbiettivi primari da raggiungere perchè si possa dire che la sua attività è iniziata.

1) mettere online un sito web, basato su community server, che serva da centro di aggregazione per distribuire le notizie che ci riguardano. Nulla di eccessivo, un feed rss dove chi vorrà potrà leggere le news e registrarsi per farci conoscere la propria presenza. Con il tempo poi magari sfrutteremo i forum per creare dei gruppi di lavoro.

2) organizzare il primo meeting ufficiale, da tenersi entro la fine del mese di febbraio. Il lavoro da fare è parecchio; stabilire dove tenerlo, organizzare una o due sessioni, deciderne l'argomento.

Il gruppo si è anche dato un nome davvero splendido: xedotnet giusto per non tradire le nostre origini. La decisione non è stata così difficile come pensavo. Una battuta ha suggerito questo nome il cui significato naturalmente è Xpert Enthusiast .NET

Infine, i convenuti hanno incaricato me, Alejandro Gonzalez e Andrea Dottor di portare il nuovo gruppo verso i primi due obbiettivi. Il gruppo quindi è nato e ha emesso il suo primo vagito. Sta a noi ora concretizzare queste decisioni e aiutarlo a sbocciare.

Fateci gli auguri.

powered by IMHO 1.3

Pubblico ringraziamento

Stamane ho ricevuto un inatteso ma graditissimo dono per cui ora mi sento di ringraziare pubblicamente. Si tratta nientemeno che della licenza Visual Studio Team Suite con MSDN premium Subscription che Davide Vernole mi ha consegnato incartata in una velina con impresso il logo degli MVP (che il mio feticismo mi porterà a conservare gelosamente) sotto forma di una placca metallica del formato di una carta di credito, con inciso il classico codice alfanumerico che apre le porte del paradiso.

Credo che non esistano parole sufficienti per esprimere la mia gioia e gratitudine, perciò posso solo prendere l'impegno di sfruttare il suo generoso gesto nel modo migliore, per supportare lo sviluppo del mio progetto open source IMHO 2.0 e per migliorare la mia conoscenza del Framework .NET da condividere con la community degli sviluppatori .NET.

Un grazie di dimensioni astronomiche, all'amico Davide che con questo gesto mi ha dimostrato una stima e considerazione che mi onora, ancor più dell'opportunità già importantissima di lavorare nel team guidato da lui.

powered by IMHO 1.3

 

User Group Triveneto: Ecco dove ci troviamo

Per tutti coloro abbiano ancora dubbi su dove sia il punto di incontro, ecco una foto della famosa "I" a fianco della quale ci troveremo domani sera alle 20:20. Dato che questa letterona è nel bel mezzo di una mini rotatoria vi sconsiglio di attendere la sotto. Sulla sinistra, giusto fuori dell'inquadratura troverete un edificio con un bancomat. Ci troviamo proprio li davanti.

A presto!

powered by IMHO 1.3

User Group Triveneto: Ultimo avviso

Invito chi volesse partecipare alla riunione di fondazione dello User Group Triveneto di inviarmi al più presto la sua adesione. Nel frattempo ho prenotato il tavolo presso la Pizzeria da Gennaro a Treville di Castelfranco Veneto. L'appuntamento è per le 20:20 presso il piazzale del centro commerciale I Giardini del Sole, nei paraggi della proverbiale "I" che ne fa da insegna. I convenuti poi muoveranno verso Treville dove il tavolo è prenotato per le 20:45.

powered by IMHO 1.3