2006-01-31T15:22:00+01:00
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
2006-01-31T14:06:00+01:00
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
2006-01-29T01:19:00+01:00
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
2006-01-25T04:32:00+01:00
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
2006-01-25T03:43:00+01:00
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
2006-01-25T00:19:00+01:00
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
2006-01-23T05:35:00+01:00
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
2006-01-23T03:33:00+01:00
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
2006-01-20T16:05:00+01:00
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
2006-01-20T07:14:00+01:00
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
2006-01-19T05:30:00+01:00

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
2006-01-17T23:42:00+01:00
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