RSS 2.0 Atom 1.0 CDF  
JASoft.org - ASP.NET
El blog de José Manuel Alarcón Aguín. Programación .NET y mucho más...
 

Hay veces que necesitaremos usar programáticamente un ScriptManager dentro de una página, por ejemplo para añadir dinámicamente referencias a Scripts o a servicios Web o WCF. Para ello deberemos automatizar el control ScriptManager que toda página AJAX debe tener, pero ¿qué pasa si no existe ese control?

Para asegurarnos de que el control está añadido a la página y que podemos utilizarlo podemos emplear el método estático GetCurrent de la clase ScriptManager para verificar su existencia, así:

public static bool IsScriptManagerPresent(Page p)
{
   ScriptManager Smgr = ScriptManager.GetCurrent(p);
   return (Smgr != null);
}

Con esta sencilla función podremos averiguar si hay un Scriptmanager presente o no.

Es interesante notar que este método funciona y devuelve el valor correcto incluso cuando el ScriptManager no está presente en la página actual sino en la página plantilla (Master Page) que la contiene. No obstante es importante darse cuenta de que en ese caso devovlerá true incluso si la Master Page tiene un ScriptManager aunque no tengamos un ScriptManagerProxy (SMP) en la nuestra, por lo que si obtuviésemos una referencia al ScriptManager estaríamos trabajando directamente con el de la MP aún sin un SMP.

Wednesday, August 06, 2008 8:54:58 PM (Hora de verano romance, UTC+02:00)  #    Comments [0]   AJAX | ASP.NET  |  Trackback

En mi anterior post comentaba los peligros de usar alegremente los controles UpdatePanel de AJAX y mostraba con la excelente herramienta Fiddler cómo eran las peticiones que se enviaban y recibían.

Alguien me ha preguntado cómo hago para poder utilizar Fiddler con el servidor Web de desarrollo que viene con Visual Studio (conocido comunmente como Cassini), ya que por mucho que actives Fiddler por defecto no captura las peticiones hechas a dicho servidor.

El servidor de desarrollo sólo admite peticiones locales y accedemos a ése a través de una URL del tipo:

http://locahost:3572/miapp

Eligiendo un puerto aleatorio de cada vez.

Cuando lanzas Fiddler éste se coloca como proxy de Internet Explorer interceptando todas las llamadas que hace éste a las páginas Web. Lo que ocurre es que IE cuando detecta que una llamada se va a hacer en local (contra localhost vamos) automáticamente hace caso omiso de los posibles proxy que hubiera y lanza la petición directamente, de ahí que Fiddler no funcione.

Podemos solucionar este problema de una manera sencilla usando el siguiente truco.

Modificación al vuelo de la URL en Fiddler

La herramienta Fiddler nos permite responder a diferentes eventos mientras realiza una petición, los cuales podemos interceptar con código de Script. Se puede ver el ´codigo por defecto de estos eventos usando el menú "Rules" de fiddler, así:

Uno de estos eventos se produce justo antes de lanzar la petición desde el proxy y se llama "OnBeforeRequest". Por lo tanto podemos modificar la URL local para que IE piense que es externa, y volver a modificarla en el evento mencionado antes de que el proxy lance la petición. La manera más fácil es añadir a la palabra 'localhost' un punto justo al final. Así IE no la reconocerá como la URL local y la petición pasará a través de Fiddler. En el evento OnBeforeRequest sólo tenemos que añadir los siguiente al principio:

        if (oSession.host.substr(0, 10)=="localhost.")
        {
                 oSession.host=oSession.host.replace("localhost.", "127.0.0.1");
        } 

Esto hace que cuando Fiddler detecta una petición a cualquier url que empiece por "localhost." la transforma en una llamada a la misma URL dentro de "127.0.0.1", que es equivalente.

Obviamente podríamos usar cualquier otro añadido a la URL local para cambiar la petición. Incluso en lugar de un simple punto añadir un subdominio especial del estilo ".local", para que fueran URLs del estilo "localhost.local" o algo así, cambiando por tanto el pequeño código de intercepción en el evento, pero el punto es el camino más rápido y va de maravilla.

Así que ya sabes, haz ese retoque en el evento, y a partir de entonces lanza tu aplicación y justo tras haber lanzado Fiddler añádele un punto a localhost al final para que Fiddler entre en acción y puedas analizar con detalle todo el trasiego de información entre cliente y servidor que produce tu aplicación, incluyendo peticiones AJAX encualquier puerto :-)

Tuesday, July 29, 2008 4:26:03 PM (Hora de verano romance, UTC+02:00)  #    Comments [0]   AJAX | ASP.NET  |  Trackback

Las tecnologías de Microsoft han adolecido tradicionalmente de un problema que es a la vez, paradójicamente, su mayor ventaja: la sencillez aparente de uso. Pienso que  la clave del éxito de Windows, Office y otros muchos productos de la casa de Redmond ha sido y es su sencillez de uso. Pero esta misma sencillez de uso se convierte también un arma de doble filo: hace que la gente se quede en la superficie de las cosas, sin comprender bien las consecuencias de lo que hacen. Ha pasado toda la vida con las versiones de servidor de Windows, y ha pasado y pasa con las herramientas de desarrollo. Al ser fáciles de configurar y utilizar la gente enseguida "controla" la tecnología correspondiente, lo cual es un error grave.

En este caso me estoy refiriendo en concreto a la tecnología ASP.NET AJAX que tanto facilita el desarrollo de aplicaciones de interfaz avanzada para la Web. Desde mi punto de vista el Update Panel es una obra de arte que debería llevar un premio al diseño de componentes y arquitecturas. Antes de su existencia la creación de aplicaciones AJAX era compleja, a pesar de los diversos frameworks para ello que existían. El uso de los Update Panel convierte en algo realmente sencillo el crear aplicaciones Web con capacidad de respuesta rápida y sin refresco de página. Una maravilla vamos.

Lo cierto es que su sencillez ha hecho que la gran mayoría de los que los utilizan lo hagan sin un buen criterio. Todo el mundo "sabe" hacer aplicaciones AJAX hoy en día. Los lamentos vienen después cuando las aplicaciones deben escalar y ser eficientes, como en casi todos los casos en los que se ve a diferencia entre un buen y un mal programador.

Veamos qué pasa cuando colocas un Update Panel en una página ASPX para hacer algo tan tonto como actualizar la hora actual en una etiqueta. En una página vacía colocas un ScriptManager, un Update Panel y dentro de éste una etiqueta y un botón. al pulsar el botón asignas en un evento de servidor la hora actual a la etiqueta, así:

    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToShortTimeString();
    }

Una chorrada total. Vale ahora ejecutas y voilá!, mágicamente el Update Panel hace su trabajo y ves aparecer la hora en la eiqueta sin hacer un postback tradicional al servidor ysin que la página ni siquiere parpadee.

Estupendo. Pero vamos a analizar qué pasa entre bambalinas y más en concreto qué información se envía y se recibe a y desde el servidor. Para ello he utilizado a mi fiel amigo Fiddler, el analizador de tráfico que más me gusta. El resultado de la petición de ida y vuelta del Update Panel es el que se puede ver en esta figura:

En la parte de arriba podemos ver la petición que se envía y en la de abajo la respuesta recibida. ¡En total 889 caracteres (casi 1 KB) para realmente obtener una información (la hora) que ocupa solamente 8 caracteres!

Impresionante. Ahora imagínate esta situación en una página compleja en la que el avezado programador se ha dedicado a dejar caer UpdatePanels por doquier (cosa muy común y una mala práctica). Ahí es nada.

Existen formas mucho más eficientes de conseguir lo mismo eficientemente usando el mucho más amplio framework de ASP.NET AJAX, tal y como se explica en nuestro curso de ASP.NET AJAX.

La conclusión es que hay que utilizar las tecnologías con cabeza y comprendiendo lo que se hace. Lo fácil de usar es un arma de doble filo.

Sunday, July 27, 2008 1:37:20 PM (Hora de verano romance, UTC+02:00)  #    Comments [1]   AJAX | ASP.NET  |  Trackback

El próximo día 1 de Julio tengo el gusto de participar como ponente en este interesante evento on-line de SecondNUG, el grupo de usuarios de .NET en Español que cada vez está teniendo más tirón:

En este evento Luis Miguel Blanco se encargará de desvelar los secretos y dudas más comunes de las rejillas en programas de escritorio (Windows Forms), mientras que yo me encargaré de hacer lo propio con el control GridView de ASP.NET para desarrollo Web. Será una hora para cada control con contenidos eminentemente prácticos (mucha demo) y trataremos de resolver las dudas más comunes que se suscitan en los foros de MSDN.

Apúntate pulsando sobre la imagen de más arriba.

Wednesday, June 18, 2008 7:24:34 AM (Hora de verano romance, UTC+02:00)  #    Comments [5]   ASP.NET  |  Trackback

Siguiendo con esta mini-serie (parte I y parte II) sobre el mantenimiento de las sesiones en ASP.NET, en esta ocasión me voy a centrar en cómo evitar que una sesión caduque por inactividad mientras el usuario tenga el navegador abierto. Esta situación puede ser deseable en muchas ocasiones.

Por ejemplo, nada fastidia más que estar redactando en el navegador directamente un artículo para un boletín o un blog (como es el caso) y que cuando vas a enviarlo y pulsas el botón "Publicar" te salga un mensaje diciéndote que la sesión ha caducado (y por supuesto has perdido todo lo que escribiste). En este caso es interesante que la página de edición mantenga la sesión viva mientras tú estás trabajando en ella, aunque te vayas a comer y vuelvas dos horas más tarde. Este caso se da por ejemplo en aplicaciones como nuestro servicio MAILCast®, en el que hemos implementado una solución similar a la que describiré ahora.

Otro ejemplo lo tenemos en servicios como nuestra plataforma de teleformación SELF, con la que impartimos los cursos de campusMVP. Si un alumno está parado en una lección que contiene por ejemplo un vídeo cuya duración es de media hora (la sesión normal dura 20 minutos) o que tiene un laboratorio que va siguiendo paso a paso y tarda una hora en hacerlo, cuando finalmente quiera pasar al siguiente punto del índice se encontraría con la desagradable sorpresa de que la sesión ha caducado y que por lo tanto debería volver a autenticarse en el sistema. Esto no es aceptable claramente, así que tenemos que buscar una solución para evitarlo.

Lo primero que se le suele ocurrir a todo el mundo es aumentar el tiempo de caducidad de sesión bien tocando la configuración de IIS (mala cosa pues afecta a toda la aplicación) o bien aumentándolo para una página específica. El probvlema que tiene esto es que nunca sabes cuánto es un tiempo razonable y que además en muchas ocasiones variará enormemente de unas páginas a otras al ofrecer éstas contenido dinámico. Además si luego realmente el usuario no permanece en la página y se limita a cerrar el navegador, la sesión se quedará ocupando memoria y recursos del servidor durante mucho rato sin necesidad alguna. Así que alguna forma mejor tiene que haber...

Lo cierto es que conseguirlo es muy fácil. ¿Cómo se consigue de manera natural que una sesión se mantenga activa?, pues como sabemos recibiendo peticiones del usuario en el servidor, las cuales renuevan el periodo de caducidad en cada petición.

Pues entonces la solución está clara: vamos a lanzar peticiones al servidor en segundo plano usando JavaScript, de forma que se reciban en el servidor y mantengan la sesión activa. Ni más ni menos.

Para ello una forma habitual de hacerlo sería usar el objeto XmlHttpRequest en el que se basan las aplicaciones AJAX, si bien como veremos enseguida ni siquiera hace falta complicarse tanto.

El "truco" es que el recurso que llamemos en el servidor no puede ser cualquiera, sino que tiene que ser alguno que pase por el "pipeline" de ASP.NET que incluya gestión de sesiones. Lo mejor, por tanto, es llamar a una página .ASPX o a un manejador .ASHX.

La llamada la podemos hacer usando un simple script que solicite más script al servidor, con un código similar a este:

//Ejecuta el script en segundo plano evitando así que caduque la sesión de esta página
function MantenSesion() 
{                
    var CONTROLADOR = "refresh_session.ashx";
    var head = document.getElementsByTagName('head').item(0);            
    script = document.createElement('script');            
    script.src = CONTROLADOR ;
    script.setAttribute('type', 'text/javascript');
    script.defer = true;
    head.appendChild(script);
} 

Con esto lo que hacemos es crear un nuevo script en la cabecera de la página y añadirlo al DOM del navegador, momento en el cual se solicitará al servidor. El origen del script en este caso es un simple manejador ASHX (que debe implementar la interfaz IRequiresSessionState para que se tenga acceso a la sesión y por lo tanto entre en el proceso el proveedor de sesiones) y que devuelve en este caso un simple comentario de script, ya que lo único que buscamos es que se mantenga activa la sesión gracias a la petición.

Podemos conseguir algo similar usando un iframe oculto al que mediante script le cambiamos la propiedad "src" para que pida una página ASPX del servidor la cual se devuelve vacía pero nos sirve para el mismo propósito. Es decir, no es necesario recurrir a técnicas más sofisticadas como la de XmlHttpRequest y nos aseguramos que funcionará hasta en navegadores bastante antiguos.

La otra cosa que hay que considerar es el intervalo de tiempo que usaremos para llamar a esta función de JavaScript que mantendrá la sesión viva. Si la sesión dura 20 minutos podemos llamar cada 18 minutos o así (para asegurar) y así no impactará demasiado en el servidor que mandemos estas peticiones extra pues son muy escasas. Por lo tanto la mejor forma de proceder es establecer un temporizador que llame a dicha función por ejemplo cada el 90% de la duración de la sesión de ASP.NET. Se consigue de forma muy sencilla simplemente añadiendo un código como este al final de nuestra página ASPX:

<script language="javascript" type="text/javascript">
    setInterval('MantenSesion()', <%= (int) (0.9 * (Session.Timeout * 60000)) %>);
</script>

Así lo que conseguimos es crear un temporizador que se repetirá cada 'x' milisegundos y que llamará a la anterior función para mantener la sesión abierta. Se multiplica por 60.000 el tiempo de sesión porque éste está expresado en segundos y el intervalo del temporizador debe ir en milisegundos. En el caso del tiepo de sesión por defecto (20 minutos) este código generaría un temporizador que renovaría la sesión cada 1.080.000 milisegundos, o sea, cada 18 minutos.

Como vemos es muy fácil de conseguir y puede resultar muy útil en ocasiones.

¡Espero que te sirva!

Wednesday, June 11, 2008 10:00:35 PM (Hora de verano romance, UTC+02:00)  #    Comments [7]   ASP.NET  |  Trackback
Copyright © 2008 José Manuel Alarcón Aguín. All rights reserved.