Una de las principales ventajas de los controles de usuario de ASP.NET (User Controls) es que, al igual que las páginas ASPX, mediante el simple uso de unos atributos de directiva podemos hacer que se haga caché automática de su salida. De este modo podemos guardar en caché por un tiempo determinado una versión del control por cada valor que tome un parámetro, una cabecera del navegador, el valor de un control, etc... Ya he hablado repetidas veces sobre esto en este blog.

Hoy voy a comentar una técnica que nos permite saber si la instancia actual de un User Control en nuestra página es realmente resultado de haber ejecutado el control o, por el contrario, se ha obtenido directamente de la caché, sin procesamiento.

La utilidad de esto es, aparte de las cosas raras que puedan surgir por ahí que lo lleguen a requerir, para poder trabajar con él directamente cuando se instancia de manera dinámica en una página (con el método LoadControl de la clase Page). Normalmente el código que usamos es similar a éste:

MicontrolUsuario mcu = (MicontrolUsuario) LoadControl("MicontrolUsuario.ascx");
this.Controls.Add(mcu);
//Ahora hacer algo con él (normalmente asignarle un ID, texto, otras propiedades, etc...

Esto funciona de maravilla hasta que decidimos incluir en el control unos atributos de caché para no tener que procesarlo de cada vez. A partir de ese momento el código anterior "casca" y se produce un error en tiempo de ejecución.

El motivo es que cuando un control está en caché en lugar de instanciarse a través de su verdadera clase, se instancia un objeto de la clase PartialCachingControl que se usa para devolver únicamente los contenidos de la salida del verdadero control. Por ello al intentar convertirlo en un objeto de la clase original (como en el fragmento anterior), es cuando se produce un error, porque no lo es...

Por lo tanto, el código que nos permite detectar si un control de usuario está siendo usado desde la caché es tan simple como comprobar si es un objeto de la clase mencionada, así:

MicontrolUsuario mcu = (MicontrolUsuario) LoadControl("MicontrolUsuario.ascx");
this.Controls.Add(mcu);
if (mcu is MicontrolUsuario)
{
  //Ha sido procesado (no caché)
}
else if ( (mcu is PartialcachingControl) && 
          ((PartialCachedControl)mcu).CachedControl != null))
{
    //El control está en caché y se almacena dentro de esa propiedad
    MicontrolUsuario cacheado = (MicontrolUsuario)((PartialCachedControl)mcu).CachedControl;
    //ahora se hace lo que haga falta con él
}

Como vemos es relativamente sencillo, pero hay que controlar este truco para poder hacerlo como es debido.

Espero que te resulte útil :-)

Escrito por un humano, no por una IA