martes, septiembre 15, 2009

Mantener viva una aplicación .NET en IIS con Web Scheduler Tasks

Web Scheduled Tasks en ASP.NET nos sirve para ejecutar tareas programadas cada determinado intervalo de tiempo. Está pensado para Aplicaciones Web alojadas en Hostings que no nos permiten acceder al servidor.

Pero para asegurarnos de que las tareas se ejecuten, debemos mantener “viva” la aplicación. Este se convierte entonces en la primer tarea a configurar en Web Scheduled Tasks.

WebRequestTask para Web Scheduled Tasks

Actualicé el sitio demo de Web Scheduled Tasks para incorporar un objeto IScheduleable cuya misión es mantener viva una aplicación a través de un WebRequest.

El código es muy sencillo y es el siguiente:

WebRequestTask

Lo que hace es tomar todas las entradas del Web.config cuyo “name” comience con “webRequest” y hace un request a la URL indicada en “value”. El sitio demo tiene la siguiente entrada en el Web.config:

<add key="webRequest01" value="http://localhost:38652/DemoScheduler/Default.aspx" />

Deberán modificar la URL. En mi PC, el sitio está en el puerto 38652, si el puerto es 80 no hay necesidad de indicarlo.

lunes, septiembre 14, 2009

Web Scheduled Tasks en ASP.NET 2.0, 3.0, 3.5 y MVC

¿Cómo hacer para automatizar tareas en nuestro sitio Web si no tenemos acceso al servidor ni a los Scheduled Tasks?

Omar Al Zabir nos ofrece una solución muy creativa: utilizar el evento que genera un objeto al ser removido del caché. Aquí la solución de Omar.

Tomando la solución propuesta pero intentando convertirla en lo más portable y menos invasiva posible desarrolle el Web Scheduled Tasks para ASP.NET 2.0 o superior. Funciona también con MVC.

Cómo funciona Web Scheduled Tasks

Web Scheduled Tasks se inicia en el Application_Start del global.asax y crea una lista de objetos IScheduleable obteniendo los datos del web.config.

En el web.config se indica cada cuanto tiempo el Web Scheduled Tasks llamará a las tareas y lo único que les proveerá son los objetos Application y Cache ya que de otra forma no estarían disponibles. El Resto depende de la tarea: cuando ejecutarse, cómo controlar si ya se está ejecutando, log de errores, etc.

Las tareas se ejecutarán en un thread que no estará vinculado con un request de un usuario por lo que no se puede utilizar cosas como HttpContext.Current o Server.MapPath.

Implementar Web Scheduled Tasks en 4 pasos

Paso 1: copiar  WebScheduledTasks.dll en la carpeta BIN de nuestra Aplicación Web.

Paso 2: crear las clases que implementen IScheduleable. La interfaz es muy sencilla con un método y dos propiedades.

IScheduleable

El método Run recibe el objeto Application y el objeto Cache ya que de otra forma serían inaccesibles.

Paso 3: configurar Web Scheduled Tasks a través del web.config. Para hacer esto utilicé el muy buen tutorial Creating Custom Configuration Sections in Web.config using .NET 2.0.

Son dos bloques. El primero hay que agregarlo dentro de <configSections> y define la nueva sección del Web.config y la clase que lo controla. El segundo va dentro de <configuration> y son los settings propios de Web Secheduled Tasks. El primer seteo es el intervalo que define cada cuantos minutos el sistema revisará las tareas para ejecutarlas.

web.config

Dentro de <tasks> están definidos los objetos que deben ejecutarse periódicamente. Debe colocarse el AssemblyQualifiedName, de otra forma no sabrá como instanciarlo. El AssemblyQualifiedName de mi tarea de ejemplo es "ActualizaHoraTask, App_Code.owmojsxy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null". Si no saben como armarlo, pueden ejecutar esto: Response.Write((new Objeto()).GetType.AssemblyQualifiedName).

Paso 4: modificar el Global.asax. Simplemente debemos agregar la siguiente línea al evento Application_Start: bd.WebScheduledTasks.Scheduler.RunTimer();

globalasax

Cómo saber el estado de Web Scheduled Tasks

Scheduler expone la propiedad “Status” que devuelve un XML con el estado de Web Scheduled Tasks y las tareas.

En en XML se puede ver:

  • StartTime: fecha y hora en que se inicializó Web Scheduled Tasks
  • Interval: definido en el Web.config
  • LastTickTime: hora a la que se ejecutó por última vez
  • CacheTimerExist: muestra si existe el objeto en Cache que permite que todo funcione.
  • LastError: en “object” veremos el objeto que generó el último error y en “error” su descripción.
  • ScheduledTasks: veremos la lista de los objetos que invocará el sistema.

Web Scheduled Tasks Status

Además de Status, Scheduler expone el método “ScheduleTick” que nos permite, tal vez desde algún administrador, ejecutar las tareas programadas manualmente. En realidad lo que lograremos es “despertar” a Web Scheduled Tasks para que revise cuales tareas deben ser ejecutadas.

Descargar Web Scheduled Tasks

Pueden descargar:

Espero que les sea útil. Cualquier sugerencia, corrección, o aporte será más que bienvenido.

lunes, septiembre 07, 2009

Includes en ASP.NET MVC

De pronto me surgió la necesidad de usar INCLUDES en el sitio que estoy creando en ASP.NET y MVC. Como siempre fui a Google pero esta vez no encontré ninguna respuesta satisfactoria (alguno recomendó hacer un Html helper para leer el contenido de un archivo).

Alguien podría preguntar cual es la necesidad de usar Includes teniendo tantas otras alternativas. En mi caso, tengo un proceso que genera HTMLs estáticos y necesito mostrarlos en una "caja" en el sitio.

Luego de algunas pruebas, estas son las mejores formas, según mi criterio, de usar Includes en ASP.NET y MVC.

Los includes tradicionales siguen funcionando

En principio los Includes tradicionales de ASP siguen funcionando, de modo que podemos usar:
<!--#include virtual="/includes/pagina.htm"-->
para incluír un html a partir del root. También podemos usar
<!--#include virtual="../includes/pagina.htm"-->
para incluir un html en forma relativa a donde "estamos parados".

Esto funciona incluso si el TAG Include se encuentra dentro de un Partial View. El inconveniente es el de siempre: no podemos usar variables para definir cual archivos queremos incluir. Es decir, no podemos hacer esto:
<!--#include virtual="../includes/<%= nombreArchivo %>"-->
ya que el TAG include se interpretará antes que ASP.NET (aún con MVC donde todo pasa por ASP.NET).

Includes dinámicos

La forma que encontré para lograr "Includes dinámicos" es usar la sentencia
Html.RenderPartial("PartialView")
La única restricción es que el archivo debe tener extensión .ascx (o aspx) pero no necesita la cabecera que lo define como Partial View si guardamos el archivo en la carpeta /Views/Shared. Es decir, podemos tomar una HTML, le cambiamos la extensión y lo incluimos con Html.RenderPartial.

En mi caso, el proceso que genera el HTML, ahora lo graba a disco con la extensión .ascx