Di .NET e di altre amenita'

aprile 2006 Entries

Un anno e mezzo... ma non è cambiato nulla

Ho letto, ma solo fino ad un certo punto la polemica che si sta trascinando nel mainfeed di ugidotnet. Non potevo mancare di dire la mia dato che ormai un anno e mezzo fa sono stato io l'oggetto di un simile flame. Davvero credetemi se vi dico che oggi più di allora credo che l'errore fondamentale sia proprio quello di voler espungere qualcosa da questo feed. Post sulle certificazioni, post off-topic, post troppo lunghi, post politici, post letterari, post "diversi", di volta in volta sono di disturbo per qualcuno e si dovrebbe operare su di essi una sorta di autocensura. Il fatto è che così facendo si arriva a cancellare qualunque voce che sia almeno un po' fuori da coro. La mia opinione è che in un feed non si sia in diritto di cancellare alcunchè e tantomeno di marcarlo con un ot-scarlatto.

Non vi dirò cosa mi piace leggere e cosa non mi piace leggere. Vi dirò che mi piace poter scegliere e quindi selezionare i miei post preferiti tra tutti quelli che i blogger di ugidotnet vorranno scrivere e che non mi piace l'idea che sia qualcun'altro ad operare questa scelta per me. E se non bastasse sono convinto che la maggioranza dei lettori di ugidotnet la pensa come me, altrimenti non si spiegherebbe perchè i post che hanno più commenti nel mio weblog sono proprio quelli che vengono considerati ot.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Un anno e mezzo... ma non è cambiato nulla

Come sono ridotto...

Sto lavorando alle slide per Venerdì...

UPDATE: Pattern come se piovesse...

Mi è stato segnalato che il sito xedotnet ha avuto qualche problema nelle ultime ore. Si è trattato di un problema sistemistico che ora è stato risolto.

Rinnovo perciò l'invito ad iscriversi al seguente url:

http://www.xedotnet.org/subscriptions.aspx

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: UPDATE: Pattern come se piovesse...

Design Pattern come se piovesse...

Stamane è stata una giornata interessante in ufficio. L'analisi un po' meglio approfondita di una funzionalità mi ha portato a ideare una collaborazione di un bel numero di design pattern che a mio parere darà una bella flessibilità all'applicazione cui il mio team sta lavorando. Dico "darà" perchè in effetti toccherà al buon Roberto implementare le modifiche necessarie, con un po' di refactoring.

Ma tornando alla soluzione, posso dire che non capita spesso di veder lavorare assieme una CHAIN OF RESPONSABILITY, un COMMAND, un COMPOSITE e una FACTORY. Sarà che in vista della sessione che dovrò tenere il prossimo 5 maggio, ho accentuato la mia sensibilità nell'individuare queste soluzioni, ma comunque sia la soddisfazione e molta. Sapete com'è, nonostante il codice che è passato sotto le mie dita probabilmente si potrà oramai misurare in gigabytes, non tutti purtroppo di cui andare orgoglioso, ho ancora la fortuna di potermi emozionare quando riesco a scolpire un bel design, ad eliminare un po' di code smells e sento - questa è la parola giusta - che tutte le le cose sono al loro posto.

Ok, venendo al dunque dopo tutto questo grondare di autocompiacimento, sappiate che in questo clima favorevole mi sono messo a lavorare sulla sessione del 5 maggio. L'idea è quella di implementare un layer di provider per l'accesso ai dati facendo uso di un bel po' di patterns. Si parlerà di ABSTRACT FACTORY, di SINGLETON, di BRIDGE, di PROTOTYPE e di DECORATOR. Il tutto per realizzare in 45 minuti uno strato di astrazione del database che sia estensibile e flessibile a sufficienza da potersi utilizzare in qualunque contesto.

Non dico altro. Se considerate che nella sessione che segue la mia ci sarà nientepopoimeno che Luca Minudel, spero di aver stuzzicato a sufficienza la vostra curiosità da spingervi ad iscrivervi e a venire a trovarci. Il luogo è lo stesso dell'altra volta, l'ora anche... non vi resta che accaparrarvi una seggiola.

http://www.xedotnet.org/subscriptions.aspx

Ah.. dimenticavo: a dispetto di quello che riporta la pagina di iscrizione, visto che abbiamo quasi esaurito i posti l'iscrizione non è più facoltativa. Perciò pensateci ora...

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Design Pattern come se piovesse...

ASP.NET 2.0: Postback in a popup

Ormai sono abituato ad evitare a tutti i costi i popup nelle applicazioni web. Tuttavia mi rendo conto che c'è ancora qualcuno che non riesce a farne a meno, a torto o a ragione non mi interessa sapere. Durante la track web dei CommunityDays sono stato molto incuriosito da una domanda che è venuta dal pubblico e che recitava più o meno così: "è possibile effettuare il cross-page postback in un popup impostando il PostBackUrl?". La risposta naturale è no, ma quest'oggi, per puro diletto ho provato a capire se questo è proprio vero. In effetti se ragioniamo bene sul problema è evidente che esiste almeno un modo di effettuare il postback in una nuova finestra del browser, cioè impostando l'attributo "target" della form. Però impostare questo attributo a runtime mediante javascript è fattibile ma espone ad un fastidioso problema. Il mio primo tentativo è stato quello "semplice" di usare l'evento "OnClientClick" come segue:

btnPopup.OnClientClick = "document.forms[0].target = '_blank';";

Impostare l target in questo modo funziona perfettamente, ma lascia la form in uno stato inconsistente che fa si che tutti i controlli presenti effettuino il postback nella nuova finestra dopo che il pulsante è stato azionato per la prima volta. In effetti la cosa migliore sarebbe quella di ripristinare il target originale dopo il postback, ma in questo l'evento OnClientClick non ci può essere di aiuto perchè il runtime quando fa il merge degli script aggiunge il codice per il postback subito dopo quello immesso in questo attributo. La soluzione perciò è solamente quella di estendere il controllo Button per modificarne il rendering:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Text.RegularExpressions;

namespace Elite.Web.UI.WebControls
{
    
/// <summary>
    /// 
Summary description for ButtonEx
    
/// </summary>
    
public class ButtonEx : Button
    {
        
private string postBackTarget;

        
public ButtonEx()
        { }

        
protected override void Render(HtmlTextWriter writer)
        {
            
if (!string.IsNullOrEmpty(this.PostBackUrl) && 
                !
string.IsNullOrEmpty(this.PostBackTarget))
            {
                
using (StringWriter tempWriter = new StringWriter())
                {
                    
using (HtmlTextWriter htmlWriter = new HtmlTextWriter(tempWriter))
                    {
                        
base.Render(htmlWriter);
                        
                        Regex rx = 
new Regex(
                            @"onclick=""javascript:(?<code>[^""]*)""", 
                            RegexOptions.IgnoreCase);

                        writer.Write(
                            rx.Replace(
                                tempWriter.ToString(), 
                                
new MatchEvaluator(Evaluator)));
                    }
                }
            }
            
else
                base
.Render(writer);
        }

        
private string Evaluator(Match match)
        {
            
return string.Format(
                @"onclick=""javascript:document.forms[0].target='{0}';{1};" + 
                 "setTimeout(&quot;document.forms[0].target=''&quot;, 100);""",
                
this.PostBackTarget, 
                match.Groups["code"].Value);
        }

        
public string PostBackTarget
        {
            
get return postBackTarget; }
            
set { postBackTarget = value; }
        }
    }
}

Il codice è in effetti un po' tirato, lo confesso, ma è davvero l'unico modo che sono riuscito a trovare, dopo aver analizzato la classe Button del framework, per iniettare il codice prima e dopo la generazione del postback. in sostanza nel metodo render viene fatto generare il codice del pulsante in una stringa, e tramite una regular expression si effettua la sostituzione all'interno dell'evento onclick. Questo codice viene poi immesso nuovamente nel flusso del rendering. In questo modo impostando la proprietò PostBackTarget del ButtonEx si otterrà il sospirato postback in popup. L'unica curiosità che rimane è il fatto che ho dovuto usare un timeout di 100 millisecondi per reimpostare il target. Infatti semplicemente impostando la proprietà subito dopo WebForm_DoPostBackWithOptions non si ottiene l'effetto desiderato.

powered by IMHO 1.3

 


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Postback in a popup

System.Web.Hosting.CommunityDays

Finalmente ho trovato qualche minuto per scrivere le mie riflessioni a proposito della mia recente partecipazione ai CommunityDays del 12 aprile scorso. Il mio primo pensierino, deve giocoforza andare ad Andrea, che ha dimostrato appieno il significato del termine ospitalità, nel mio caso non solo con una sessione splendidamente snocciolata con la chiarezza che lo contraddistingue, ma anche avendo invitato i presenti del nord-est a venire a conoscere XE.NET. Un grazie anche perchè questo mi/ci ha fatto sentire un po' più parte di questi CommunityDays splendidamente riusciti.

Inutile disquisire sulla qualità delle sessioni. In effetti si trattava di argomenti con cui ho a che fare tutti i giorni e - lo dico senza iattanza - grazie al tipo di progetto su cui sto lavorando non posso dire che mi fossero completamente sconosciuti. Tuttavia il sentire disquisire su questi argomenti ha il potere di chiarire i motivi di quello che normalmente a causa della fretta con cui tipicamente si lavora si tende a trascurare. Un po' come se i "mattoncini" che alla rinfusa si sono raccolti giorno per giorno alla fine siano condotti magistralmente al loro posto consentendo una visione d'insieme che illumina la ragione.

Un po' dovrei lamentarmi con il buon Cristian Civera, che muovendosi agilmente nella complessità degli argomenti della sua interessantissima sessione ha fatto tabula rasa di una serie di potenziali post che mi ero riservato di bloggare un po' per volta. Ehm, non sperate di cavarvela comunque, i post non li butto via. Devo dire però che l'efficacia dei suoi esempi è stata davvero disarmante. Nemmeno in un intero anno sarei riuscito a trovarne di così azzeccati. Ah, oltrettutto vorrei dire una cosa che so dovrebbe fare molto piacere a qualcuno che fa il mio mestiere: avete fatto caso alla pulizia del codice di Cristian? E' davvero raro vedere un codice così ben scritto...

Non sto a dilungarmi. Un complimento davvero a tutti per cortesia e bravura e interesse e, e, e... Uno degli obbiettivi che mi ero posto in questa giornata era non solo di imparare qualcosa al punto di vista tecnico, ma anche e soprattutto di osservare e assorbire qualche idea su come si conduce una sessione. Sapete probabilmente tutti che a breve dovrò provarci anche io e vedere Daniele, Andrea e Cristian per me è stato doppiamente utile.

La giornata ha avuto un epilogo inatteso: le chiacchiere con Andrea, Lorenzo, Emanuele, Mr.kino, Riccardo, Daniele e altri della truppa di UgiDotNet (chiedo perdono a chi non ho nominato) - di gran lunga la parte più piacevoledi tutto il workshop - mi hanno portato ad andarmene dall'incontro con un notevole ritardo sulla tabella di marcia che mi ero imposto. Un grazie anche per questo, per avermi accolto così spontaneamente nonostante tutto sommato fossi un perfetto sconosciuto.

Chiudo ringraziando per la splendida organizzazione, ma anche per la pazienza dimostrata Sara, che ho "tampinato" per un bel po' di tempo quando mi sono improvvisamente calato nel mio ruolo di "inviato speciale di XE.NET". Sara è stata davvero gentile e professionale rispondendo instancabilmente alle mie innumerevoli domande.

A presto e... buona Pasqua a tutti!

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: System.Web.Hosting.CommunityDays

E dopo più di un anno... Community Days!!!

Sono lieto di comunicarvi che domani sarò anche io ai community Days. E' probabile che mi vediate in giro, ma dubito che molti di voi si ricordino di me. Sarò alla track web, probabilmente tra le prime file, se non arrivo troppo in ritardo. Eppoi come voi ronzerò un po' in giro, a mietere qualche buona chiacchierata con gli amici che non vedo da tempo. Se mi cercate chiedete un po' in giro, e di certo troverete qualcuno che vi indicherà la persona che state cercando.

Ah, non ho una foto, ma se mi avete visto un po' di tempo fa tenete a mente che nel frattempo ho perso 15kg...

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: E dopo più di un anno... Community Days!!!

ASP.NET: AdvancedHyperLinkField

Mi è capitato di avere la necessità di creare all'interno di una colonna di gridview del codice javascript il quale potesse in qualche modo ottenere alcuni dei dati in corso di visualizzazione nella gridview stessa. Ad esempio, in riferimento alle popup di tipo subModal, di cui vi ho parlato in precedenza mi è stato necessario comporre dinamicamente l'url da passare alla chiamata Javascript che ne causa la comparsa.

La gridview, a meno che non abbia preso un abbaglio, non dispone di una campo che permetta la formattazione di codice lato client, a meno che non si voglia utilizzare un TemplateField. Inutile anche tentae di introdurre il prefisso "javascript:" l'url formattato infatti il runtime di ASP.NET per questioni di sicurezza lo sopprime senza colpo ferire. Ho perciò deciso di indagare un po' sul funzionamento della gridview per capire se era possibile estendere l'HyperLinkField in modo da gestire anche la formattazione di un ClientLink al pari di quello che si può fare con il NavigateUrl. Ecco il codice che ne ho tirato fuori:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.ComponentModel;

namespace Elite.Web.DataSources
{
    
/// <summary>
    /// 
Classe che implementa AdvHyperLinkField
    
/// </summary>
    
public class AdvHyperLinkField : HyperLinkField
    {
        
/// <summary>
        /// 
ctor
        
/// </summary>
        
public AdvHyperLinkField()
        { }

        
/// <summary>
        /// 
Inizializza una cella della GridView
        
/// </summary>
        /// <param name="cell">
cella</param>
        /// <param name="cellType">
tipo di cella</param>
        /// <param name="rowState">
stato della riga</param>
        /// <param name="rowIndex">
indica della riga</param>
        
public override void InitializeCell(
            DataControlFieldCell cell,
            DataControlCellType cellType,
            DataControlRowState rowState,
            
int rowIndex)
        {
            
// dapprima chiama il metodo base
            
base.InitializeCell(cell, cellType, rowState, rowIndex);

            
// se si tratta di una DataCell
            
if (cellType == DataControlCellType.DataCell &&
                cell.Controls.Count > 0)
            {
                
// trova l'hyperlink
                
HyperLink link = cell.Controls[0] as HyperLink;

                
// e aggancia l'evento DataBinding
                
if (link != null)
                    link.DataBinding += 
new EventHandler(link_DataBinding);
            }
        }

        
/// <summary>
        /// 
Gesisce l'evento che viene sollevato durante il DataBinding
        
/// </summary>
        /// <param name="sender">
il link che ha generato l'evento</param>
        /// <param name="e">
i dati dell'evento</param>
        
void link_DataBinding(object sender, EventArgs e)
        {
            
// trova il link che ha generato l'evento
            
HyperLink link = sender as HyperLink;
            
// preleva il controllo container
            
Control container = link.NamingContainer;

            
if (container != null)
            {
                
bool found;

                
// trova il DataItem corrente nel Container
                
object dataItem = DataBinder.GetDataItem(container, out found);

                
if (found)
                {
                    
// se lo ha trovato crea una list con le traduzioni
                    
List<string> paramList = new List<string>();

                    
// traduce ogni campo richiesto nel dato corrispondente
                    
foreach (string name in this.DataNavigateUrlFields)
                        paramList.Add(
                            DataBinder.GetPropertyValue(
                                dataItem, 
                                name) 
as string);

                    
// formatta l'url clent
                    
link.Attributes["onclick"] = 
                        
string.Format(
                            
this.DataClientNavigateUrlFormatString, 
                            paramList.ToArray());

                    
// assegna un url fittizio se non è giù stato 
                    // assegnato (altrimenti l'hypelink non appare)
                    
if (!string.IsNullOrEmpty(link.NavigateUrl))
                        link.NavigateUrl = "~/";
                }
            }
        }

        
/// <summary>
        /// 
proprietà contente i campi da utilizzare nella formattazione
        
/// </summary>
        
public string[] DataClientNavigateUrlFields
        {
            
get
            
{
                
if (ViewState["DataNavigateUrlFields"] == null)
                    ViewState["DataNavigateUrlFields"] = 
new string[0];

                
return (string[])ViewState["DataNavigateUrlFields"];
            }
            
set { ViewState["DataNavigateUrlFields"] = value; }
        }

        
// stringa da formattare
        
public string DataClientNavigateUrlFormatString
        {
            
get
            
{
                
if (ViewState["DataClientNavigateUrlFormatString"] == null)
                    ViewState["DataClientNavigateUrlFormatString"] = 
string.Empty;

                
return (string)ViewState["DataClientNavigateUrlFormatString"];
            }
            
set { ViewState["DataClientNavigateUrlFormatString"] = value; }
        }
    }
}

 

Questo nuovo tipo di campo, derivato direttamente da HyperLinkField, aggiunge due proprietà che consentono di decidere come formattare il codice eseguito in corrispondenza dell'evento javascript "onClick". DataClientNavigateUrlFields e DataClientNavigateUrlFormatString si comportano esattamente come le proprietà esposte da HyperLinkField e dedicate all'url. Vediamo un attimo di sottolinearne il funzionamento: La classe fa innanzitutto l'override del metodo InitializeCell. Questo metodo viene chiamato in corrispondenza di ogni cella della gridview e consente di aggiungere elementi al contenuto. Nel nostro caso dapprima viene richiamato il metodo base che si occupa di creare l'HyperLink nella cella, in seguito nel viene cercato tale link e ad esso si aggancia l'evento DataBinding solo nel caso di celle di tipo DataCell (escludendo quindi header e footer). In questo modo, ad ogni evento di bind dell'HyperLink di ogni cella verrà chiamato il metodo link_DataBinding() che estrae il DataItem dal contesto della GridView ed effettua il binding delle due nuove proprietà.

Nello stesso metodo c'è anche un piccolo stratagemma da evidenziare. Qualora il campo NavigareUrl sia vuoto, si inserisce un url fittizio (~/) sempre valido, in modo da provocare la comparsa dell'hyperlink che in caso contrario non verrebbe mostrato.

powered by IMHO 1.3


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

[XEDOTNET] 2° Meeting della community

Dopo circa due mesi dal primo meeting, finalmente è stato indetto il prossimo appuntamento che per quanto mi riguarda segnerà una data storica non solo per la community ma anche per me personalmente. Il prossimo 5 maggio infatti mi dovrò cimentare nella mia prima sessione pubblica e lo farò su un argomento nemmeno troppo semplice. Il meeting infatti darà incentrato sui Design Patterns e a me spetterà il compito di introdurre l'argomento con una prima sessione che ne affronterà i fondamenti. Ho iniziato perciò a ripassarmi il GoF, che naturalmente dovrà essere la linea guida sul quale incernierare una sessione, il cui scopo fondamentale è di consentire a chi ancora non ha una conoscenza di queste tecniche di iniziare a prenderne contatto. La sessione successiva alla mia invece, sarà tenuta da Luca Minudel, che si occuperà di accontentare anche i palati più esigenti affrontando gli aspetti avanzati e le applicazioni dei pattern più complessi.

Siete tutti invitati ad iscrivervi e a partecipare a questo evento che spero sia in linea con le ripetute richieste che mi sono arrivate da molti dei partecipanti al meeting precedente.

Link: http://www.xedotnet.org/subscriptions.aspx

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: [XEDOTNET] 2° Meeting della community

SubModal: La soluzione giusta per i popup

La discussione in merito all'uso di popup nelle applicazioni web infiamma sempre gli animi. Personalmente sono dalla parte di chi cerca di evitarli a tutti i costi perchè il loro utilizzo va contro quello che è il normale funzionamento di una pagina web. Riconosco però che l'uso di popup, specialmente in quelle che io definisco "applicazioni web" in contrapposizione ai "siti web", è spesso necessario per abbreviare la navigazione e migliorare l'interazione dell'utente.

In questi giorni ho scovato nella rete un libraria javascript, denominata subModal, che permette di risolvere questo problema con una eleganza impareggiabile. Si tratta di un tool che è in grado di realizzare facilmente popup implementate come dei semplici DIV/IFRAME, all'interno della stessa pagina, eliminando così la necessità di aprire finestre aggiuntive del browser. In questo modo si risolve anche il problema del blocco popup.

La libreria è completamente free, ed è compatibile con Internet Explorer, Firefox, Safari e Opera. Vi invito a vedere la demo che ne chiarisce molto le potenzialità.

Link: http://www.subimage.com/sublog/subModal

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: SubModal: La soluzione giusta per i popup