Controlar cuando el usuario nos cierra el navegador ¿Es posible?

Pues sí, es posible, empleando un pequeño truquillo en la maquetación en nuestro Site.


En el cliente en el que me encuentro actualmente me lo pidieron como requisito indispensable, puesto que intentan asemejar el comportamiento de sus aplicaciones Winform y ademas así liberar todos los objetos asociados a esa sesión. Otro requerimiento es que un usuario sólo pueda abrir un ventana de IExplorer para cada aplicación, pero esto lo veremos en la siguiente entrega.


Como comenté en el primer párrafo todo se basa en el modélo de maquetación del site. Es necesario tener una página que nunca se descargue y que solo se dispare su evento JavaScript OnUnload bien cuando nos cierre el navegador de la dichosa X o cuando pulse nuestro botón de desconexión, por lo tanto vamos a utilizar una página principal que sea contenedora de otras páginas mediante un IFRAME:


   1:  <div id=”content”>
   2:      <iframe id=”contenido” src=”contenido1.aspx” 
           frameBorder=”0″ width=”100%” height=”400″></iframe>
   3:  </div>

 


En el IFRAME se realizará la navegación de nuestro Site y así podremos controlar cuando nos cierra el navegador ¿Pero como? pues sencillo, lo controlaremos con un campo oculto:


   1:  <input id=”logout” type=”hidden” value=”0″>

 


al que asignaremos un valor distinto de 0 desde nuestro botón de desconexión desde el Code-Behind:


1: private void imgBtnSalir_Click(object sender,

System.Web.UI.ImageClickEventArgs e)

   2:  {
   3:      FormsAuthentication.SignOut();
   4:      Session.Abandon();

5: Page.RegisterStartupScript(“logout”,

“<script>document.getElementById(“logout”).value=1;</script>”);

   6:      Page.RegisterStartupScript(“close”,
“<script>window.close();</script>”);
   7:  }

 


Y en el evento JavaScript OnUnload comprobamos ese valor con la función Logout (<body OnUnload=”Logout();”>):


   1:  function Logout()
   2:  {
   3:      var logout = document.getElementById(“logout”);
   4:   
   5:     if (logout.value == 0)
   6:      {
   7:          OpenCenterPopUp(“logout.aspx”, “”, 600, 70);
   8:      }
   9:  }

 


Si es 0, abrimos la ventana logout.aspx que se encarga de liberar los recursos de la sesión y de hacer un logout de la autenticación (Aunque yo esto no lo hago en mi cliente puesto que es una intranet y utilizo la autenticación de Windows integrada pero para el ejemplo he preferido añadirlo):


   1:  private void Page_Load(object sender, 
System.EventArgs e)
   2:  {
   3:      FormsAuthentication.SignOut();
   4:      Session.Abandon();

5: this.RegisterStartupScript(“close”,

“<script>setTimeout(“window.close();”,10000);</script>”);

   6:  }

 


Y para finalizar que mejor que verlo en acción (Usuario: admin Password: admin):


Bueno pues espero haberme explicado bien y como dije antes en el próximo capítulo veremos como controlar que el usuario sólo pueda abrir un explorador por aplicación.

Salu2

Session.Abandon() VS Session.Clear() ¿Que diferencia existe?

Parece una tontería pero estoy seguro que mucha gente que lea este post no sabe la diferencia que existe entre Session.Abandon() y Session.Clear(), o me equivoco???

Cuando en una aplicación Web utilizamos el método Session.Abandon(), a parte de eliminar dicha sesión, se dispara el evento Session_End del Global.asax, en el cual podemos incluir la lógica necesaria para realizar cuando una sesión termina (por ejemplo borrado de ficheros temporales asociados a al IdSesion) y en la siguiente petición que hagamos se dispará el evento Session_Start del global.asax, en el cual podemos inicializar variables, cargar objetos… mientras que con Session.Clear() sólo eliminamos la sesión.

Podríamos encontrar una similitud entre Session.Abandon() con el botón Cerrar Sesión de Windows, imaginaros que en una aplicación Web necesitamos hacer un logout y al mismo tiempo login con otro usuario, lo que nos lleva a realizar una inicialización de los datos sobre el usuario que podríamos realizar en el evento Session_Start, no??

Bueno pues esto es todo amigos!!!

Salu2.

Extendiendo nuestra BBL: Añadiendo validaciones de datos para DataSet Tipados en NET 2.0

Después de un tiempo sin escribir nada por culpa de una rotura de fibras en mi cuadriceps derecho que me ha tenido de baja 2 semanas y media (Tiempo suficiente para empollar las nuevas funcionalidades de NET 2.0 y revisar unos magníficos tutoriales) he empezado a trabajar en casa con las nuevas caracteristicas de ADO.NET y la verdad es que me ha sorprendido bastante con que facilidad se puede crear una capa de acceso a datos y su correspondientes reglas de negocio utilizando para enlazar a la capa de presentación un ObjectDataSource.


En este ejemplo concreto que voy a explicaros a modo de resumen de 2 tutoriales en inglés que os he dejado los enlaces más abajo, como podemos extender las validaciones de datos en nuestra capa de negocios sobre una capa de datos creada con un dataset tipado.


Lo primero es crear nuestra capa de datos con el diseñador de VS 2005 (El primer enlace del final), arrastramos las tablas y creamos los correspondientes TableAdapters, entre ellos para la tabla Products (No voy a comentar nada al respecto sobre como crear la DAL).


Ahora bien, imaginemos que necesitamos validar que el precio del producto que nos introduce el usuario debe ser mayor que 0,  y para ello no debemos hacerlo directamente sobre el código que genera VS 2005:



El porque es sencillo: Como es código autogenerado, cuando por algún motivo tenga que autoregenerarse porque hemos modificado algo sobre nuestro dataset tipado, perderemos automáticamente nuestras modificaciones.


Entonces, ¿Como podemos crear nuestras reglas de negocio para validar dichos datos? Pues con el uso de clases parciales. Por ejemplo, en nuestro caso necesitamos extender la clase ProductsDataTable y para ello utilizaremos el evento ColumnChanging para detectar cuando nos modifican una row del datatable:


   1:  public partial class Northwind
   2:  {
   3:      public partial class ProductsDataTable
   4:      {
   5:          public override void BeginInit()
   6:           {
   7:              this.ColumnChanging += ValidateColumn;
   8:           }
   9:   
  10:           void ValidateColumn(object sender, DataColumnChangeEventArgs e)
  11:           {
  12:              if(e.Column.Equals(this.UnitPriceColumn))
  13:              {
  14:                 if(!Convert.IsDBNull(e.ProposedValue) && (decimal)e.ProposedValue < 0)
  15:                 {
  16:                    throw new ArgumentException(“UnitPrice > 0”, “UnitPrice”);
  17:                 }
  18:              }
  19:           }
  20:      }
  21:  }

Como podeis observar es bastante sencillo validar ciertos datos en la capa de negocio que a nivel de esquema no nos lo permite VS 2005, podemos especificar su tamaño o permitir nulos o no, pero no podemos crear checks como el que hemos realizado en nuestra capa de negocio.


Los 2 tutoriales donde he podido aprender sobre este tema:


Creating a Data Access Layer


Creating a Business Logic Layer


He intentado hacer en este artículo un pequeño resumen de las cosillas que he creido mas interesantes.


Un saludo.