Cómo mostrar notificaciones de escritorio con Chrome

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Como-mostrar-notificaciones-de-escritorio-con-Chrome.aspx

NotifEjemploGoogle Chrome posee una característica sensacional que le permite mostrar notificaciones en el escritorio desde código JavaScript.

Lo estupendo de estas notificaciones es que se ven en el escritorio y las puedes mostrar en cualquier momento, aunque el navegador no esté en primer plano o esté minimizado. Si tu aplicación comprueba información en segundo plano con AJAX (como hace GMail con los nuevos correos) el usuario puede dejar el navegador minimizado y aún así recibirá notificaciones cuando haya algo nuevo que atender. Como vemos las posibilidades son muchas

Nota: Internet Explorer dispone de un método createPopup disponible desde la versión 7 análogo al método window.open de JavaScript de toda la vida, y desde la versión 9 es posible mostrar iconos superpuestos en el botón de la barra de tareas de la Web si esta se “engancha” allí, pero no son de lejos tan potentes como los de Google Chrome. El W3C tiene un borrador para crear notificaciones Web desde el año 2006 (última versión de este año), pero nadie lo ha implementado (lo cual me parece incomprensible), por lo que en la práctica sólo Google Chrome ofrece esta funcionalidad, y es la que voy a reflejar en este artículo.

Toda la funcionalidad de las notificaciones de Chrome se encuentra en el objeto webkitNotifications que posee la ventana del navegador. Vamos a ver lo que nos ofrece.

Pidiendo permiso

Lo primero que tenemos que hacer para poder mostrar notificaciones en el escritorio es pedir permiso al usuario. Sin este paso previo las notificaciones fallarán.

Para pedir permiso necesitamos usar la función requestPermission, a la que llamaremos sin argumentos (línea 4) con un código similar a este:

   1: function setNotificationsPermissions()

   2: {

   3:     if (window.webkitNotifications)

   4:         window.webkitNotifications.requestPermission();

   5:     else

   6:         alert("Tu navegador no soporta notificaciones Web de escritorio");

   7: }

Lo que se hace es comprobar si el navegador soporta las notificaciones de Chrome, en cuyo caso se llama a la función, mostrando un aviso en caso contrario.

El navegador muestra un barra en la parte superior para reclamar ese permiso:

SolicitarPermiso_Notif

MUY IMPORTANTE: La función requestPermission sólo funcionará si es llamada como resultado de una acción directa del usuario, es decir, al pulsar un botón o un enlace. No podemos llamarla directamente desde cualquier sitio, por ejemplo al cargar la página. El motivo es evitar que páginas malintencionadas nos puedan estar incordiando todo el tiempo pidiéndonos este permiso para que al final se lo acabemos dando para que nos dejen tranquilo. Es algo parecido a lo que ocurre con la apertura de ventanas: si no queremos que el bloqueador de pop-ups las bloquee tenemos que hacerlo como consecuencia de la acción de un usuario. En el ejemplo descargable al final se hace desde un botón específico, como muestra la figura anterior, pero puede ser de cualquier otra manera. Por ejemplo GMail lo hace a través de unos botones de radio en la configuración:

PermisoGMail

Tú hazlo como quieras, pero siempre debes asegurarte de pedir ese permiso antes de intentar mostrar notificaciones nuevas.

Generando notificaciones

Una vez que tenemos permiso podemos generar notificaciones con dos funciones:

  • createNotification: crea una notificación en la que especificamos el icono a mostrar en el lateral, un título y un texto plano. Es la más común y la que utilizaremos más frecuentemente.
  • createHTMLNotification: toma como único argumento una URL que contiene el HTML a mostrar en la ventana de notificación. Debemos tener cuidado con no mostrar nada demasiado grande o no se verá correctamente.

Estas dos funciones crean un objeto de notificación, pero para mostrarla tendremos que llamar a su método show. Mientras no lo hagamos no se verá.

Antes de llamar al método show, aparte de comprobar que el navegador soporta las notificaciones, hay que determinar si tenemos los permisos suficientes, otorgados en el paso anterior. Puede que el usuario no haya solicitado el permiso o puede que lo haya revocado desde el propio menú de herramientas de la notificación:

RevocarPermiso

La existencia de permiso se comprueba mediante la función checkPermission del objeto webkitNotifications. Puede devolver tres valores:

  • PERMISSION_ALLOWED (0): si tenemos permiso
  • PERMISSION_NOT_ALLOWED (1): si no tenemos permiso
  • PERMISSION_DENIED (2): si se ha denegado explícitamente el permiso.

Sólo si devuelve un 0 tenemos permiso, y es cuando mostraremos la notificación.

Nota: Cuando mostramos la notificación ésta generalmente se mostrará de manera inmediata, aunque en realidad lo que ocurre es que se mete en una cola de notificaciones. Chrome mete en la cola las notificaciones y las va mostrando mientras tiene espacio, guardando las demás para cuando pueda. Así, por ejemplo, en mi pantalla lo máximo que muestra son cuatro notificaciones al mismo tiempo, una encima de otra. Las demás están en la cola y hasta que cierre una de las que están visibles no se mostrarán, por lo que no podemos contar con que las notificaciones se verán instantáneamente. Puedes hacer la prueba con el ejemplo del final pulsando el botón varias veces y viendo lo que pasa.

Así, el código para mostrar la notificación quedaría del siguiente modo:

   1: function showNotification(title, msg, icon){

   2:   if (window.webkitNotifications)

   3:   {

   4:       var wkn = window.webkitNotifications;

   5:       var notif;

   6:       if (wkn.checkPermission() == PERMISSION_ALLOWED) {

   7:           notif = wkn.createNotification(icon, title, msg);

   8:           notif.show();

   9:       }

  10:   }

  11: }

También podemos cancelar la notificación (cerrarla por código) llamando al método cancel de las mismas. Por ejemplo, una buena práctica sería usar un temporizador para cerrar automáticamente la notificación al cabo de unos segundos si el usuario no la ha cerrado de forma manual, y quizá dejar abiertas solamente las que sean muy urgentes. Si guardamos una referencia al objeto notificación que se ha creado sólo tenemos que llamar a cancel() sobre éste y listo.

Eventos de las notificaciones

Las dos funciones anteriores devuelven un objeto de notificación que como hemos visto sirve para mostrar (show) y ocultar (cancel) la ventana con el mensaje.

Esta referencia a la notificación se puede utilizar para asignarle manejadores de eventos al objeto y detectar cuatro cuestiones interesantes:

  • ondisplay: este evento se llama en el momento en que se muestra la notificación. Ver la nota anterior para entender porqué eso no tiene que ser en el momento en el que llamamos a show.
  • onclose: se genera cuando la notificación se cierra, bien por código o bien por que lo hace el usuario.
  • onclick: cuando el usuario pulsa sobre la notificación. Muy interesante para enviarlo a una vista concreta de la aplicación o a otra página.
  • onerror: se produce cuando ha habido errores al mostrar la notificación.

Podemos responder a estos eventos para tomar acciones en cada caso. En el ejemplo lo que he hecho es loguear el resultado de la ejecución en cada uno de los eventos:

LogEventos

y así sabremos cuándo se produce cada uno de ellos.

Usando Chrome, prueba el ejemplo que he colgado y, tras haber otorgado permisos muestra varias notificaciones para ver cómo se van mostrando y logueando, y cómo si hay muchas se encolan y tardan en aparecer.

Es una característica muy útil que esperemos que pronto incorporen todos los navegadores´. Teniendo en cuenta la tendencia actual a que la mayor parte de las aplicaciones se ejecuten en un navegador, en detrimento de las tradicionales de escritorio, es algo que cada vez se hará más necesario.

¡Espero que te resulte útil!

Cómo depurar el evento Application_End en ASP.NET

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Como-depurar-el-evento-Application_End-en-ASPNET.aspx

El evento Application_End se desata en una aplicación Web cuando ésta termina por cualquier motivo, aunque sea para reiniciarse. Escribimos un gestor de este evento dentro de Global.asax en el que incluimos cualquier tipo de código que se encargará de dejar en el estado correcto cualquier recurso global que hayamos inicializado en el evento complementario que se lanza cuando arranca la aplicación: Application_Start.

Esto es válido tanto para aplicaciones Web Forms como MVC.

PushToResetEl código que pongamos en estos eventos se lanzará únicamente cuando se arranque y se detenga la aplicación. Si queremos depurarlo desde Visual Studio, usando el servidor de desarrollo (que es lo habitual), la cosa tiene algo de truco.

El problema es que no es tan fácil conseguir que se cierre la aplicación y que puedas depurarlo al mismo tiempo.

Al contrario de lo que muchos programadores se piensan, cerrar el navegador no detiene la aplicación, que sigue activa por detrás, sólo cierras la sesión actual del usuario pero nada más, por lo que el evento Application_End no saltará.

También puedes pensar que si paras el servidor (que es el de desarrollo, Cassini), sería suficiente. Pero como el depurador de Visual Studio está adjuntado al proceso de ese servidor, se pierde el proceso justo antes de cerrarlo y por lo tanto no puedes depurar tampoco (eso no significa que no salte, sino que Visual Studio no tiene forma de enterarse).

Una forma de poder depurar el evento es utilizar un Internet Information Server real en lugar del servidor de desarrollo para hacer la depuración. Si usas IIS puedes detener (o mejor, reciclar) el grupo de aplicaciones de tu aplicación para forzar su detención y que se pare la aplicación (ojo, no llega con parar la aplicación Web). De todos modos esto es engorroso y tienes que andar configurando tanto IIS como Visual Studio para poder hacerlo.

La solución es mucho más fácil de conseguir y consiste en provocar alguna de las cosas que hacen que una aplicación se reinicie, que son bastantes: cambiar los contenidos de la carpeta "bin" si es una aplicación Web, cambiar los contenidos de web.config, renombrar o eliminar una subcarpeta de la aplicación (sí, esto también), etc…

Así que una forma sencilla y rápida de provocar que salte Application_End (y luego Application_Start) y poder depurarlos en Visual Studio con el servidor normal de desarrollo es la siguiente:

  1. Lanza tu aplicación pulsando F5
  2. Abre el explorador de archivos de Windows y vete hasta la carpeta física en donde está tu aplicación guardada.
  3. Abre el archivo web.config con el bloc de notas y simplemente vete a Archivo·Guardar, para que lo escriba de nuevo (sin ni siquiera cambiarlo)
  4. Voilà! De repente se recicla la aplicación y te salta el evento en el depurador

 

¡Espero que te sea útil!

photo credit: voodooangelcc

Solucionar el error: “BC30456: ‘InitializeCulture’ is not a member of” en ASP.NET

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Solucionar-el-error-BC30456-InitializeCulture-is-not-a-member-of-en-ASPNET.aspx

Este es un error muy típico en algunas aplicaciones y me he acordado de él a raíz de la pregunta de un alumno de mi curso de preparación del examen 70-515 en campusMVP.

La situación es la siguiente: tenemos un desarrollo ASP.NET hecho y todo funciona en Visual Studio a las mil maravillas. Lo publicamos al servidor Web y de repente, al intentar acceder al sitio Web, nos encontramos un error como este:

ErrorBC30456

“¿Cómo?¿Inicializar cultura? Pero si yo no tengo nada de esto en mi aplicación. ¿Qué demonios pasa aquí?“

Por más que buscas en tu código no eres capaz de encontrar nada mal, y es que además “¡en mi máquina funciona!” (que es lo que decimos todos cuando algo falla en producción).

El problema viene de un hábito muy común y que, realmente, Visual Studio debería gestionar mejor: renombrar páginas ASPX en Sitios Web.

Lo típico es lo siguiente:

  1. Renombramos la página Default.aspx que tenemos por defecto en el proyecto. Para ello pulsamos sobre ella en el Explorador de soluciones y pulsamos F2 o usamos la acción de renombrar en el menú contextual.
  2. Comprobamos que tanto la página como su correspondiente archivo code-behind se han cambiado de nombre correctamente.
  3. Más adelante nos damos cuenta de que necesitamos una página Default.aspx y añadimos una nueva página con este nombre al proyecto.
  4. Ahora publicamos la aplicación al servidor Web. Para ello la pre-compilamos usando el menú “Publicar” del menú contextual del proyecto Web, como se ve en la siguiente figura, dejando los valores por defecto en esta pantalla.

ErrorBC30456_Publicar

Al ir ahora al servidor nos encontramos con el error.

¿Cuál es el problema?

El problema es que aunque Visual Studio renombra los archivos .aspx y .aspx.cs (o .vb) de la página en cuestión, lo que no hace es cambiarle el nombre a la clase subyacente que se encuentra en el archivo de código. Esto hace que haya dos clases con el mismo nombre en el proyecto, lo cual confunde al runtime de .NET.

El error que muestra no es nada intuitivo y no parece tener nada que ver con el asunto, pero así es.

¿Cuál es la solución?

Hay dos posibles soluciones:

  1. Buscar las clases duplicadas y renombrarlas. Probablemente será fácil ya que por regla general suele ser la página “Default” la que hemos renombrado.
    Es importante fijarse en que no sólo llega con cambiar el nombre de la clase, sino que además hay que cambiarlo también en la directiva @page de la página, como se ve en la figura:

    ErrorBC30456_Corregir
    Con esto el problema quedará resuelto y es la mejor opción posible.

  2. La segunda solución consiste en desmarcar la opción de “Permitir que este sitio sea actualizable” en el cuadro de diálogo de publicación.

    ErrorBC30456_PublicarAjustes

    Con esto lo que conseguimos es que todo el código HTML de las páginas .aspx se conserve en los correspondientes archivos al desplegar (si lo tenemos marcado los archivos existen pero son simples comodines sin contenido). Al hacer esto la compilación del proyecto será solamente parcial y toda la definición de los formularios Web se realiza dinámicamente en memoria  a la hora de utilizarlos, y por eso no nos da un error al entrar ya que las clases que entran en conflicto en el otro caso no se dan en este estado de compilación.

De todos modos esta segunda opción es un “apaño”, y la buena es la primera: localizar las clases duplicadas y renombrarlas.

¿Por qué en Visual Studio no ocurre?

No se produce porque en el servidor de desarrollo de Visual Studio la compilación siempre es dinámica en memoria, y no hay un paso previo de publicación como en este caso, así que no hay conflicto tampoco.

Por cierto, en los proyectos de tipo Aplicación Web tampoco se produce nunca este problema ya que éstos siempre se compilan a una única DLL y se detectará el conflicto a la hora de compilar. Es más: en este tipo de proyectos Visual Studio detecta la situación al renombrar las páginas y también cambia el nombre a las clases correspondientes, algo que debería hacer en los sitios web pero no hace :-S

¡Espero que te sea útil!

¿Te ha gustado este post? – Aprende .NET con los cursos on-line tutelados de campusMVP:
   ·
Preparación del examen 70-515: Desarrollo Web con .NET 4.0 (Tutelado por mi)
   · Desarrollo Web con ASP.NET 4.0 Web Forms (Tutelado por mi)
   · ASP.NET 4.0 Web Forms desde cero (Tutelado por mi)
   · Desarrollo Web con ASP.NET MVC 3 
   · Silverlight 4.0 – Aplicaciones Ricas para Internet (RIA)
   · jQuery paso a paso para programadores ASP.NET
   · Visual Studio 2010 desde cero