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