Di .NET e di altre amenita'

January 2006 Blog Posts

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: xedotnet.org è online!!!

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

 


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Quando leggere una property fa la differenza

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: Framework .NET 2.0: Convertire tipi con .NET 2.0, Generics e Reflection

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Un finder un po' generico...

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: ITextControl interface

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: Offerta di lavoro in provincia di Venezia

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Quei maledetti 5 pixels

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Migrare i profili anonimi

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

 


per leggere il post originale o inviare un commento visita il seguente indirizzo: Pubblico ringraziamento

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: User Group Triveneto: Ecco dove ci troviamo

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


per leggere il post originale o inviare un commento visita il seguente indirizzo: User Group Triveneto: Ultimo avviso

ASP.NET 2.0: Aggiungere WebPart a runtime

Quest'oggi mi sono scontrato con un problema che pareva di banale soluzione ma che si è rivelato essere decisamente subdolo. L'obbiettivo da raggiungere era di caricare le webparts di una pagina dinamicamente da un database invece che inserirle nel markup come di consueto. A prima vista può sembrare che il framework offra quanto necessario per compiere questo compito. Il WebPartManager ad esempio espone il metodo AddWebPart() che sembra fatto a posta per quello, ma dopo un po' di tentativi si intuisce che c'è qualcosa che non va.

Il problema non è che il metodo in questione non funzioni, ma anzi, che funziona troppo. Infatti il difetto che si evidenzia quasi subito è che ad ogni postback le webpart vengono nuovamente aggiunte causando una crescita smisurata e inarrestabile. Qualunque tentativo di gestire questo comportamento infausto non ha i risultati sperati. A partire dal consueto "IsPostBack", fino alla verifica controllo per controllo che non si stiano inserendo duplicati tutti i tentativi falliscono meramente.

Il fatto è che, quando si aggiungono le webpart queste vengono persistite nel database di personalizzazioni. Perciò la volta successiva che la pagina viene costruita le personalizzazioni salvate causano la duplicazione delle webpart. Naturalmente a questopunto verrà persistita anche la duplicazione, con l'ovvio risultato che la volta successiva ci si ritrova con una triplicazione... e così via.

L'unica soluzione a questo problema l'ho trovata spulciando tra le sessioni della PDC'05. Il trucco sta nel creare un WebPartManager derivato da quello consueto e gestire al suo interno l'aggiunta delle webparts dinamiche nell'OnInit della pagina. In questo modo sarà possibile sfruttare la classe WebPartManagerInternals esposta per mezzo della proprietà Internals per settare le proprietà delle webpart aggiunte e farle per così dire "rientrare" nel normale ciclo di vita delle webpart.

Ecco un breve spezzone di codice:

// metodo chiamato nel Page.OnInit()
private void AddExternalWebParts()
{
    
// legge le webpart dallo storage
     
List<WebPartData> parts = 
         WebPartProvider.GetWebParts(
this.Page);

    
// cicla le webpart
    
foreach (WebPartData data in parts) 
    {
        
// istanzia lo usercontrol
        
Control uc = 
            
this.Page.LoadControl(data.AscxVirtualPath);
        
        
// crea la webPart che incapsula lo usercontrol
        
GenericWebPart webPart = 
            WebPartManager.CreateWebPart(uc);

        
// setta le proprietà        
        
Internals.SetZoneID(webPart, data.ZoneID);
        Internals.SetZoneIndex(webPart, data.ZoneIndex);
        Internals.SetIsShared(webPart, 
true);

        
// Aggiunge una WebPart statica
        
Internals.AddWebPart(webPart);
    }
}

Nell'esempio che ho linkato, nel folder ExternalWebPart è presente anche il codice per creare le connessioni tra webpart automaticamente. Ma questa è un'altra storia.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Aggiungere WebPart a runtime

ANNUNCIO: Uno User Group per il triveneto

Consentitemi un momento di solennita, per onorare gli eventi che mi stanno conducendo, con la collaborazione di alcune altre persone della mia regione a tentare di unire i nostri sforzi per un'impresa comune. L'impresa in questione è uno UserGroup focalizzato nel veneto, ma che vorrebbe catalizzare l'attenzione degli appassionati e dei curiosi di tutto il nord-est, possibilmente da Verona a Gorizia e da Bolzano a Rovigo, come mi sono spesso trovato a ripetere in questi giorni.

L'annuncio di oggi è che Venerdì 20 Gennaio, nella zona di Castelfranco Veneto - ancora non è stata decisa con precisione la località - si terrà un incontro esplorativo aperto a tutti coloro che vogliano approfondire la propria conoscenza del Framework .NET e che intendano apportare il proprio contributo alla nascita di una nuova community.

Tale community, occorre essere chiari, non ha l'intento di sottrarre attenzione e visibilità all'UgiDotNet, la cui fondamentale importanza come punto di aggregazione rimane invariata, ma ha l'intento di smuovere, se possibile, le persone che per motivi di tempo e di distanza tipicamente non se la sentono di partecipare attivamente a questo UserGroup (o ad altri...) e creare l'occasione un giorno, se saremo abbastanza bravi di gettare le basi di una collaborazione.

Venerdì perciò tutti coloro che si trovassero nei paraggi saranno i benvenuti a quello che negli intenti dovrebbe essere l'appuntamento in cui tale UserGroup verrà fondato, ne verrà deciso il nome e la direzione di lavoro verso la quale nei primi mesi di attività ci dovremmo dirigere. Prego chiunque intenda partecipare di contattarmi al più presto all'indirizzo  per darmi modo di riservare un tavolo di dimensioni adeguate alla partecipazione.

powered by IMHO 1.3

 


per leggere il post originale o inviare un commento visita il seguente indirizzo: ANNUNCIO: Uno User Group per il triveneto

ASP.NET 2.0: Impostare a runtime le proprietà di una GenericWebPart

L'esperienza con le WebParts di questi giorni è stata l'occasione per scrivere un breve articolo per UgiDotNet che unitamente ad un utile Tip per aggirare un comportamento che potrebbe sembrare anomalo, descrive il meccanismo per cui ogni WebControl o UserControl può diventare una WebPart.

Buona lettura a tutti.

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

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Impostare a runtime le proprietà di una GenericWebPart

ASP.NET 2.0: tagMapping

Il web.config di ASP.NET 2.0 si sta rivelando una vera e propria miniera. Stamane, per puro caso ho scoperto un'altra chicca che mi accingo a proporvi. Celata, nei meandri del file di configurazione si trova una nuova sezione tagMapping che consente di sostituire tag all'interno di un Templated Control quale può essere una pagina, uno usercontrol o un qualunque controllo che esponga un template.

Per chiarire il concetto provate a pensare di aver utilizzato un WebControl all'interno di una vostra applicazione. Dopo che avete effettuato il deploy dell'applicazione in produzione vi rendete conto che una versione successiva dello stesso controllo utilizzata nell'applicazione gli darebbe una serie di feature importanti. Senza dover modificare il codice sarà sufficiente andare nel web.config e scrivere la seguente linea:

<pages>
    <tagMapping>
        <add 
            
mappedTagType="MyApp.Controls.NewControl" 
            
tagType="MyApp.Controls.OldControl"/>
    <
/tagMapping>
<
/pages>

Come risultato otterrete che l'applicazione istanzierà il nuovo webcontrol al posto di quello vecchio. La sostituzione del controllo avviene durante la fase di parsing del template per cui non introduce alcun overhead al momento dell'esecuzione.
Unico limite di questa tecnica è che il controllo da sostituire deve derivare da quello di partenza. In effetti più che comprensibile.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: tagMapping

ASP.NET 2.0: Applicare uno skin ad una proprietà di tipo Url

Se create un WebControl e poi decidete di applicare ad esso l'utilizzo dei temi è necessario avere un particolare accorgimento per le proprietà che questo espone se debbono contenere un url relativo alla root del tema.

Ad esempio, se create una proprietà del WebControl, che espone l'url di una immagine che utilizzate per il rendering (ButtonImageUrl) e poi impostate questa proprietà nel file .skin vi renderete immediatamente conto che l'url che viene passato a runtime al WebControl è relativo la root dell'applicazione e non a quella del tema. Per ottenere la trasformazione relativa al tema occorre applicare alla property un attributo di tipo UrlProperty:

[UrlProperty]
public string ButtonImageUrl
{
    
get return this.buttonImageUrl;  }
    
set this.buttonImageUrl = value; }
}

Interessante notare che tale attributo dispone anche di una proprietà Filter, che consente di discriminare il tipo di file che devono essere soggetti alla trasformazione. Ad esempio se scrivere l'attributo come segue, solo le immagini gif saranno ricalcolate sulla base della root del tema.

[UrlProperty(Filter="*.gif")]

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Applicare uno skin ad una proprietà di tipo Url

PicoPSU...

Presso XYZ Computing  è possibile vedere qualche foto del più piccolo alimentatore del mond.

Eroga ben 120 Watt. Da non crederci!

Fonte: http://hardware.slashdot.org/article.pl?sid=06/01/12/1727210&from=rss

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: PicoPSU...

Venduti gli ultimi 1000 pixel...

Netcraft annuncia che Alex Tew, è riuscito a vendere gli ultimi 1000 pixel della sua Million Dollar Homepage per la ragguardevole cifra di 38100$. La sua homepage però è stata afflitta da un lungo downtime.

The Million Dollar Homepage was unavailable for an extended period early today, as huge publicity accompanied the completion of Alex Tew's novel online advertising service. Tew, a 21-year-old UK college student, sold the final 1,000 pixels for $38,100 in an eBay auction that closed Wednesday, netting Tew a total of $1,037,100 in total ad sales. The winner of the auction has not yet been announced. Tew launched the site in September to pay his college expenses, offering 1 million pixels of ad space at $1 a pixel.

Stavo pensando di vendere spazi nel mio blog. 1€ a lettera. Ce qualcuno che sgancia? 

Source: Netcraft: Million Dollar Homepage Hit By Downtime

powered by IMHO 1.3

 


per leggere il post originale o inviare un commento visita il seguente indirizzo: Venduti gli ultimi 1000 pixel...

ASP.NET 2.0: Rendere Skinnabili gli UserControl

Se provare a creare uno UserControl con ASP.NET 2.0 e poi tentate di registrarlo nel file di skin e applicando ad esso uno SkinId di settare alcune proprietà, vi troverete di fronte al seguente errore che ieri mi ha fatto perdere ben mezza giornata di lavoro:

Error 1 The control type 'ASP.MyControl_ascx' cannot be themed. C:\DEV\Test\Portal\App_Themes\my_theme\my_theme.skin 42 

Per risolvere questo problema occorre applicare un attributo alla classe che rappresenta lo UserControl in questo modo:

[Themeable(true)]
public partial class MyControl : UserControl
{
}

Chissa poi perchè di default gli UserControl non dovrebbero essere skinnabili? Ma questo è un altro paio di maniche...

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Rendere Skinnabili gli UserControl

ASP.NET 2.0: Url Rewriting

Curiosamente stamane Simone mi ha preceduto di un soffio nel parlarvi di Url Rewriting. In questi giorni infatti mi sono trovato nella necessità di soddisfare una particolare esigenza di rewriting che mi ha fatto approfondire l'argomento e avevo in mente di scrivere questo post da un po'. Preso atto che la scelta di Simone è ricaduta sull'implementazine di un IHttpModule, è evidente che il mio post non è una ripetizione perchè in realtà il metodo che ho usato è basato su una tecnica che nell'articolo di MSDN che Simone ha citato viene appena sfiorata. Eccomi quindi a proporvi il metodo che ho recentemente utilizzato per il rewriting dell'url in una applicazione che vedeva le proprie pagine riportate parzialmente nel database e parzialmente sul filesystem.

La mia implementazione di rewrite è basata sulla creazione di un HttpHandlerFactory. Se consideriamo un HttpModule come un filtro che intercetta tutte le chiamate alle pagine di una applicazione, e un HttpHandler un gestore per particolari tipi di chiamate che si sostituisce a quello delle normali pagine, la HttpHandlerFactory invece è una classe che viene usata dal runtime per istanziare un HttpHandler specifico in base alla chiamata che esso riceve. Implementando l'interfaccia IHttpHandlerFactory, in sostanza ci si pone nella HttpPipeline al livello più alto possibile e si è in grado di decidere quale handler istanziare in base all'url che si riceve ed in seguito passare ad esso la chiamata.

Questa condizione nel mio caso era davvero esemplificativa. Si trattava infatti di effettuare una semplice query nel database - query che con l'implementazione di un meccanismo di caching è diventata unica in tutta la vita dell'applicazione - e in base al risultato decidere se istanziare l'handler delle pagine aspx normalmente oppure variando leggermente l'input per ottenere oltre al rewrite, il caricamento di una specifica pagina in base a quanto specificato nel database. Vedo di spiegarmi meglio; tanto per cominciare vediamo come fa il runtime ad istanziare l'handler per le pagine aspx.

IhttpHandler page = PageParser.GetCompiledPageInstance(url, pathTranslated, context);

Per mezzo di questa semplice riga, è possibile indicare al runtime di produrre una istanza di IHttpHandler del tutto uguale a quella che produce esso stesso in condizioni normali. I parametri indicano il path virtuale, il path fisico della pagina e l'HttpContext della chiamata. Ecco quindi che in realtà utilizzando tale metodo si può "imbrogliare" il runtime facendo caricare ad esso un file che si trovi in un percorso diverso da quello reale che esso ha calcolato sulla base della chiamata. Il trucco per fare il rewriting in questo caso è di avere una singola pagina "dbpage.aspx", nella root dell'applicazione cui redirigere tutte le chiamate che fanno riferimento al database e - nel mio caso - rifilare al runtime una pagina "fisica" scelta fra una rosa di possibili layout per mezzo di un campo nel database stesso. Ecco il codice:

public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
    PortalPage page = 
this.Indexer.FindPage(url);

    
if (page != null)
    {
        context.Items["CurrentPage"] = page;
        
return PageParser.GetCompiledPageInstance("~/dbpage.aspx", this.MapLayout(page.Layout), context);
    }

    
return PageParser.GetCompiledPageInstance(url, pathTranslated, context);
}

public string MapLayout(string layoutName)
{
    
return string.Format("~/layouts/{0}.aspx", layoutName);
}

Il codice parla da solo, ma vediamo lo stesso di spendere due parole. La prima riga reperisce l'istanza della PortalPage da un oggetto tenuto in cache, che rappresenta la struttura caricata dal database una volta per tutte. A questo punto, se la pagina viene trovata essa viene inserita nel contesto della chiamata e poi viene effettuato il rewrite modificando l'url in ~/dbpage.aspx e passando come path fisico una diversa pagina aspx - che per inciso contiene una serie di WebPartZones in un ContentPlaceHolder. Nel caso in cui la pagina non esista nel database, i parametri vengono passati così come sono ricevuti al PageParser che quindi costruirà l'IHttpHandler consueto.

Risultato di questo giochetto è che parte delle pagine dell'applicazione sono definite in una tabella del database e l'utente potrà navigare tale struttura come se fosse fusa con quella sul filesystem stesso.

Non mi rimane di segnalarvi che questa tecnica è utilizzabile anche con il framework 1.1, praticamente senza alcuna modifica.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Url Rewriting

Ragazzi che monitor!

Dell ha messo in vendita il monitor dei miei sogni... peccato che costi 2200$.

So che Apple ci era già arrivata, ma io non uso Mac.

Link: Dell 3007WFP

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Ragazzi che monitor!

Vi siete mai chiesti se si può fare meglio di Google?

Per noi che ormai viviamo di googling, è abbastanza semplice forgiare delle sequenze di keyword che riescano a produrre il risultato voluto. Personalmente posso dire che ormai riesco a "parlare" con Google abbastanza facilmente, ma spesso mi sono chiesto, di fronte magari all'impaccio di qualche conoscente davanti alla casella di ricerca, se non fosse possibile migliorare ancora l'imbattibile motore di ricerca. Oggi ho scoperto che qualcuno ci sta provando. Si tratta di lexxe, un engine che è in grado di interpretare le domande poste da un utente trovando dei risultati molto più vicini alla richiesta di quello che fa Google con il medesimo input.

Source: http://google.blognewschannel.com/index.php/archives/2006/01/07/lexxe-search-engine/

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Vi siete mai chiesti se si può fare meglio di Google?

IMHO 2.0: Aggiornata la roadmap.

Ho provveduto ad aggiornare la roadmap di IMHO 2.0 per rispecchiare l'andamento del progetto. Le modifiche più significative sono il termine della lavorazione del Preview Panel, l'anticipazione di alcuni dei servizi della Media Library alla prima versione, e l'inizio dello sviluppo dell'editor.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: IMHO 2.0: Aggiornata la roadmap.

Ho fatto 1000... ma non me ne sono accorto!

Ricordo ancora la pompa con cui ho annunciato il mio 100esimo post sul blog di UgiDotNet. Per l'occasione ho addirittura postato una chicca di codice per Terminal Server. Stamane mi è capitato di scrivere il millesimo post, a distanza di 1 anno e 3 mesi da quel giorno e credetemi se vi dico che ci ho messo un po' ad accorgermene. Ma non si tratta di disattenzione, anzi se permettete si tratta di maggiore attenzione a quello che scrivo che alla quantità di post.

Beh, fatemi gli auguri... ci risentiamo a 10000... sempre che mi sopportiate tanto. 

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Ho fatto 1000... ma non me ne sono accorto!

Attenti a quell'F5!

La lotta agli hacker negli USA sta raggiungendo dei risultati grotteschi. Ecco cosa è successo a un tizio che ha incoraggiato i suoi compagni a premere ripetutamente F5 nella home page del sito della scuola.

link: http://www.cantonrep.com/index.php?ID=261925&Category=15&fromSearch=yes

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Attenti a quell'F5!

Robert Fripp compone la colonna sonora di Windows Vista

Su Channel 9 trovate un video che mostra il chitarrista Robert Fripp, fondatore dei King Crimson, impegnato in una sessione presso il campus Microsoft per realizzare la colonna sonora del nuovo Sistema Operativo Windows Vista.

Tags: Robert+Fripp, Windows+Vista

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Robert Fripp compone la colonna sonora di Windows Vista

Flight Simulator X...

Date un'occhiata a questi screenshots che mostrano cosa ci dovremmo attendere dalla prossima versione dell'inimitabile Flight Simulator. L'unico gioco che valga la pena di essere giocato... IMHO naturalmente.

Link: http://www.fsplanet.com/fsplanet_com_fsx.htm

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Flight Simulator X...

ASP.NET 2.0: I ResourceProvider

Prosegue con questo post la saga, iniziata quando ho parlato degli ExpressionBuilders, dedicata alle risorse tipicamente utilizzate nelle applicazioni ASP.NET per depositare stringhe, e in genere proprietà da utilizzare nel rendering dell'interfaccia. In quel post spiegavo come realizzare un ExpressionBuilder che permettesse facilmente dei leggere le risorse da un database anziche da un più consueto file resx. Esiste tuttavia un altro metodo, per fare la medesima cosa, che in realtà è quello che il framework indica come quello corretto. Chi avesse provato a realizzare l'ExpressionBuilder forse si sarà reso conto che pur funzionando egregiamente esso ha delle limitazioni fastidiose. Giusto per indicarne una per tutte, quella che a me ha fatto approfondire ulteriormente l'argomento, qualora vi trovaste a localizzare un SiteMap ben presto vi renderete conto che in questo l'ExpressionBuilder non vi è di alcun aiuto. Il motivo è presto detto: la funzione degli ExpressionBuilder non è quella di leggere risorse, ma semplicemente quello che tipicamente viene usato per questa operazione, il ResourceExpressionBuilder è solo una minima sfaccettatura all'interno dell'architettura del framework dedicata all'argomento.

Se come ho fatto io imbracciate il vostro reflector, e lo puntate sulla classe System.Web.SiteMapNode, vi accorgerete che la proprietà Title (una di quelle che è passibile di localizzazione), racchiude al suo interno molta più logica di quella che ragionevolmente ci si potrebbe aspettare. Ecco un estratto da Reflector:

public virtual string Title
{
  
get
  
{
    
if (this._provider.EnableLocalization)
    {
      
string text1 = this.GetImplicitResourceString("title");
                 
      
if (text1 != null)
        
return text1;

      text1 = 
this.GetExplicitResourceString("title", this._title, true);

      
if (text1 != null)
        
return text1;
    }

    
if (this._title != null)
        
return this._title;

    
return string.Empty;
  }
}

Procedendo ulteriormente nell'esplorazione in breve si scoprira che il codice porta ad istanziare il medesimo ResourceExpressionBuilder e quindi in definitiva tentare di localizzare una proprietà della SiteMap corrisponde ad usare l'ExpressionBuilder "Resources". Di primo acchito questo mi è parso davvero strano. L'idea che mi ero fatto era che a quel punto si potessero usare esclusivamente i consueti file resx per localizzare una SiteMap.

In realtà nel framework esiste una interfaccia IResourceProvider, che è il punto giusto cui agganciarsi per spostare la fonte delle risorse dai normali file al database. Un po' celato all'interno del DOM del web.config si trova un attributo dell'elemento <globalization> denominato resourceProviderFactoryType. In tale attributo si dovrà immettere il tipo, derivato da ResourceProviderFactory, che ha il compito di creare il ResourceProvider deputato a recuperare le risorse. Mi rendo conto che detto così pare un po' complesso, ma questo meccanismo è molto efficace perchè consente di avere diversi ResourceProvider che lavorano assieme, istanziati alla bisogna in base al tipo di risorse che si desidera prelevare. In particolare il ResourceProviderFactory dispone di due metodi, uno per le risorse cosidette "locali" e uno per quelle "globali". Per comprendere la distinzione si dovra pensare alle risorse locali come quelle dedicate ad una singola pagina, infatti il relativo metodo richiede in ingresso il path della pagina, mentre per globali si intendono quello usate da tutte le pagine dell'applicazione. In quest'ultimo caso il metodo richiede una "classKey" cioè un qualificatore che permette di distinguere dei gruppi di risorse.

Non è finita però. Dopo aver implementato il ResourceProviderFactory dovremmo procedere all'implementazione di IResourceProvider che richiede la realizzazione di due metodi. Il primo per la lettura di una singola risorsa, e il secondo che restituisce un IResourceReader, che serve al runtime per enumerare le risorse presenti. La classe che implementa IResourceReader sarà lanostra terza ed ultima fatica. Ecco di seguito il codice di entrambe le classi:

public class SqlResourceProvider : IResourceProvider
{
    
public object GetObject(string key, CultureInfo culture)
    {
        
// leggi una singola risorsa 
        return
GetResourceFromDB(key, culture);
    }

    
public System.Resources.IResourceReader ResourceReader
    {
        
get
        
{
            
// leggi un set di risorse
            
return new SqlResourceReader(
                GetResourcesFromDB(CultureInfo.CurrentUICulture));
        }
    }
}
        
public class SqlResourceReader : IResourceReader
{
    
private Dictionary<stringobject> resources;

    
public SqlResourceReader(Dictionary<stringobject> resources)
    {
        
this.resources = resources;
    }

    
public IDictionaryEnumerator GetEnumerator()
    {
        
return resources.GetEnumerator();
    }

    
public void Close()
    { }
        
    
public IEnumerator IEnumerable.GetEnumerator()
    {
        
return resources.GetEnumerator();
    }

    
public void Dispose()
    {
        Close();
    }
}

L'istanza del ResourceProvider andrà creata nel ResourceProviderFactory che registreremo in configurazione. In questo modo avremo interposto il nostro provider a tutti i tentativi di lettura di risorse di localizzazione effettuati da parte dei componenti del framework, ed in questo modo potremmo facilmente localizzarli. Anche la SiteMap di cui ho detto poco fa.
 

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: I ResourceProvider

Web Services: Usare tipi condivisi tra diversi Web Services

Chiunque abbia sviluppto un'applicazione che si appoggia a diversi web-services si sarà trovato nella condizione di avere una moltitudine di proxy generati che fanno capo a diversi oggetti del dominio applicativo. Molto spesso ci si trova nella condizione di avere dei duplicati in questi oggetti che per il fatto stesso di essere classi diverse, pur avendo le medesime proprietà non sono "compatibili". Perciò, ad esempio avendo un webservice che restituisce un Ordine ed un secondo webservice che lo richiede in input non è possibile passare al secondo direttamente l'oggetto restituito dal primo.

Nel framework 2.0 esiste una soluzione a questo problema che però comporta la generazione "manuale" dei proxy richiamando direttamente l'eseguibile wsdl.exe con lo switch /sharedtypes e passando a quest'ultimo gli url dei webservices che condividono i tipi. In questo modo verranno generati i proxy facendo capo ad una gerarchia di oggetti unica.

Source: http://weblogs.asp.net/israelio/archive/2005/01/04/346337.aspx


per leggere il post originale o inviare un commento visita il seguente indirizzo: Web Services: Usare tipi condivisi tra diversi Web Services

ASP.NET 2.0: Sitemap again

Chi volesse creare un provider custom per sitemap, non avrà che da implementare i due metodi astratti della classe StaticSiteMapProvider, da cui già eredita la consueta XmlSiteMapProvider. In questo articoletto di Jeff Prosise, in breve viene spiegato come fare, con un piccolo esempio di codice nel quale viene realizzato un SiteMapProvider per Access.

Link: http://msdn.microsoft.com/msdnmag/issues/05/06/WickedCode/


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Sitemap again

ASP.NET 2.0: Sitemap a go-go

Ecco un paio di simpatici tools per generare Sitemap. La prima (http://odetocode.com/Blogs/scott/archive/2005/11/29/2537.aspx) è una macro che genera il file web.sitemap dalla struttura del sito web ricavata da visual studio. Il secondo (http://weblogs.asp.net/bleroy/archive/2005/12/02/432188.aspx) scandisce la struttura del sito ASP.NET e genera un file xml adatto a Google Sitemaps.


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Sitemap a go-go

Sapete cos'è web 2.0?

Dimostratelo con un quiz...

link: http://blog.f4l.be/web2quiz/index.php


per leggere il post originale o inviare un commento visita il seguente indirizzo: Sapete cos'è web 2.0?

C'è chi di mac non vive...

Ecco qualcuno che ha deciso, a ragion veduta, che il mac non è il suo sistema operativo...

Link: http://www.russellbeattie.com/notebook/1008724.html


per leggere il post originale o inviare un commento visita il seguente indirizzo: C'è chi di mac non vive...

BUON ANNO!!!

Buon 2006 a tutti... pigroni!!!