ScriptReferenceProfiler Bug con el nuevo release de AjaxControlToolkit

Ya no hay duda de la gran utilidad que nos proporciona la nueva opción CompositeScript de nuestro ScriptManager para combinar scripts y la utilidad ScriptReferenceProfile para conocer los scripts que tenemos que referenciar. Si queréis más información sobre este tema podéis consultar la entrada de José Manuel Alarcón o la de Chalalo Land sobre el tema.

Pero esta utilidad que hace más óptimas nuestras aplicaciones webs, me ha provocado estar un par de días desesperado buscando un error que me estaba volviendo loco y no había manera de poder solucionar.

Os pondré en antecedentes sobre el entorno y el posterior error:

Me encontraba yo realizando una aplicación web con Visual Studio 2008 y el framework 3.5, esta solución también utilizaba los controles ASP.NET AJAX y JQuery.

Y no se me ocurre otra cosa que en medio del desarrollo actualizar las librerías de AJAXControlToolKit para utilizar los nuevos controles incluidos en la nueva versión AJAX Control Toolkit (May 2009 Release).

Iluso de mi, creía que como el proyecto hace referencia a los asemblies independientemente de la versión, solo tendría que actualizar y todo funcionaría a la primera XD. Sigue leyendo

JSON con ASP.NET II

Por petición popular voy a ampliar el artículo que dedique en su día a la clase DataContractJsonSerializer la cual podemos utilizar para serializar o deserializar objetos JSon a objetos .NET.

En este artículo explicaré como pasar una colección de objetos JSON al servidor mediante ASP.Net AJAX de una forma muy sencilla.

Puedes ojear el artículo inicial en : serializar-deserializar-json-en-asp-net

Simplemente ampliaré el ejemplo que ya utilicé en el primer artículo, para que podamos seleccionar varios registros de la grid y posteriormente pasar esta lista de objetos al servidor utilizando un método accesible desde el cliente “PageMethod” con ASP.NET AJAX.

 

Este “PageMethod” es muy sencillo, simplemente espera una colección de objetos ProductoData.

Por defecto nuestro método utilizará el formato JSon para recibir los datos, pero he dejado el atributo ResponseFormat para que veáis como se puede especificar si queremos utilizar XML o JSON para nuestro tratamiento de los datos. Sigue leyendo

Jquery check all CheckBox

Hacía ya tiempo que no dedicaba ni un solo minuto a preparar una entrada para el blog, pero hoy me he plantado y le voy a dedicar un poco para solucionar una de las dudas que suelen salir en los foros de MMSDN.

Como seleccionar todos los checkBox de un DataList o un GridView, esto que puede parecer muy sencillo se nos puede complicar bastante si utilizamos directamente JavaScript, pero con JQuery solo necesitaremos una línea de código Si, solo una línea de código”.

Supongo que a estas alturas la gran mayoría ya conoce que es el la librería Jquery y las ventajas que nos ofrece al escribir nuestro código de cliente y sobre todo porque ahora nos permite tener inteligencie, sumando más potencia a esta productiva librería que os la podéis bajar desdehttp://jquery.com .

 

Lo primero que voy a hacer es crear una lista para enlazar los datos en el Datalist. No voy a entra en la mejor forma de crear datos ni validarlos simplemente utilizaré un tipo anónimo para realizar el ejemplo lo más simple y rápido posible ;-). Sigue leyendo

Localizar nuestro código Script

Uno de los grandes inconvenientes que nos solemos encontrar en los desarrollos web, es tratar de localizar nuestros recursos y asegurarnos que toda nuestra aplicación este bien traducida.

Pero claro una aplicación web 3.0 no solo se basa en páginas de servidor, hoy en día tenemos ASP.NET, AJAX, javascript, Json, etc. Y claro todos estos recursos no los podemos controlar únicamente desde el servidor y desde el cliente no podemos acceder a los recursos utilizados por asp.net.
Estos inconvenientes hacen que a los programadores web se nos dispare la imaginación para poder solucionar estos baches cotidianos.

Una solución si utilizamos ASP.NET AJAX es utilizar diferentes ficheros javaScript como recursos, podéis encontrar más información en http://msdn.microsoft.com/es-es/library/bb398935.aspx.

Pero claro si no utilizamos ASP.NET AJAX o no nos interesa crear múltiples ficheros js podemos intentar aprovechar los recursos que ya utilizamos con ASP.NET y aquí va mi propuesta.  He creado un pequeño proyecto el cual valida con un script si el cliente entra números en un TextBox, pero claro si intento aprovechar el código de asp.net para utilizar los recursos en el fichero script resulta que no funciona.

function Validar()
{
   var check = true;
   var obj = document.getElementById('TextBox1');
   var value = obj.value;
   for(var i=0;i < obj.value.length; ++i)
   {
     var new_key = value.charAt(i);
     if(((new_key < "0") || (new_key > "9")) &&
       !(new_key == ""))
     {
        check = false;
        break;
     }
    }
    if(!check)
      alert("<%$ Resources:Resource, Saludo %>");
}

Esto no tiene nada de texto traducido. ver que podemos hacer con lo que ya contamos ;-)  Primero aprovecharemos los ficheros de recursos que ya utilizamos en nuestra aplicación asp.net.  Luego crearemos un método que guarde en el cliente los recursos que necesitaremos utilizar en nuestro código script.

privatevoid RecursosJavascript(Dictionary<string,string> recursos)
{
  System.Text.StringBuilder script = new System.Text.StringBuilder();
  script.AppendLine("recursos = new Object;");
  foreach (KeyValuePair<string, string> recurso in recursos)
  {
    script.AppendFormat("recursos.{0} = '{1}';", recurso.Key,
       recurso.Value);
  }

    ScriptManager.RegisterStartupScript(this, this.GetType(),
         "recursos", script.ToString(), true);
}

Un código muy sencillo que creará una variable donde se guardarán los recursos como texto en un objeto creado para este menester y registrará un script en la página.  Luego al cargar la página inicializamos este objeto con los mismos recursos que utilizamos en la página asp.net y lo tendremos disponible desde nuestro validador script.

Finalmente desde el script utilizamos la variable de recursos generada especialmente para esta página y la utilizamos para mostrar el mensaje de error correctamente localizado.

Ya tenemos nuestra aplicación funcionando al 100% sin tenernos que preocupar por esos mensajes incontrolados desde el código de cliente.

Espero que esta idea sea util ;-)

 

Serializar – Deserializar JSON en ASP.NET

Cuando trabajamos con AJAX no tardaremos en darnos cuenta lo complicado que se nos puede hacer enviar y recuperar datos entre el cliente y el servidor.

El viaje entre el servidor y el cliente no es tanto el problema, porque un método web utiliza la serialización JSon por defecto y si queremos utilizar XML como tipo de datos devuelto tendremos que especificar el formato con el atributo [ScriptMethod(ResponseFormat = ResponseFormat.Xml)].

Hoy voy a hacer una pequeña página web que recupere la información de la base de datos y la muestre en una tabla directamente desde el cliente con JQuery. Los datos los recuperaré de la famosa base de datos NorthWind que la podéis descargar desde http://technet.microsoft.com/es-es/library/ms143221.aspx

Para garantizar que los datos se serializan correctamente vamos a crear una clase llamada ProductoData que será el objeto que pasaremos entre el servidor y el cliente, para garantizar su correcta serialización utilizaremos los atributos de System.Runtime.Serialization para definir el contrato y sus Datamember. Esto nos servirá para los métodos web y para WCF con AJAX.

using System.Runtime.Serialization;

[DataContract]
public class ProductoData
{
    [DataMember]
    public int ProductID { get; set; }
    [DataMember]
    public string ProductName { get; set; }
    [DataMember]
    public decimal UnitPrice { get; set; }
    [DataMember]
    public int UnitsInStock { get; set; }

    public ProductoData(){}
    public ProductoData( int id, string name, decimal price, int stock)
    {
        this.ProductID = id;
        this.ProductName = name;
        this.UnitPrice = price;
        this.UnitsInStock = stock;
    }
}

Luego para tratar los datos crearé una clase Productos que nos hará el servicio de capa lógica de Negocios para cargar y añadir campos en la base de datos. Como es un simple ejemplo no iremos más allá de recuperar los datos y añadir uno nuevo para mostrar el envío y recuperación de datos serializados, no entraremos en conexiones, capas y validaciones de datos.

public List<ProductoData> GetProductos(string idCategoria )
{
   List<ProductoData> productos = new List<ProductoData>();
   SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);
   SqlCommand command = new SqlCommand(@"SELECT ProductID, ProductName, "
   UnitPrice, UnitsInStock FROM  Products where CategoryID = @CategoryID", con);"
   command.Parameters.Add(new SqlParameter("@CategoryID", idCategoria));
   SqlDataReader reader = null;
   try
   {
       con.Open();
       reader = command.ExecuteReader();
       while (reader.Read())
       {
          productos.Add(new ProductoData(int.Parse(reader["ProductID"].ToString()),
              reader["ProductName"].ToString(),
              decimal.Parse(reader["UnitPrice"].ToString()),
              int.Parse(reader["UnitsInStock"].ToString())));
       }
   }
   catch (Exception ex)
   {
       string error = ex.Message;
   }
   finally
   {
     con.Close();
     reader.Close();
   }

   return productos;
}

Para recuperar los productos de la base de datos y mostrarla en el cliente sin hacer una recarga completa de la página utilizaremos un PageMethod, eso quiere decir que será un método público y estático que se accederá desde el cliente como si fuera una método de un webService. A este método le tenemos que decir que es accesible desde el cliente con el atributo [WebMethod].

[WebMethod]
 public static List<ProductoData> GetProductos(string idCategoria)
 {
     List<ProductoData> productos;
     Productos srvProductos = new Productos();
     productos = srvProductos.GetProductos(idCategoria);
     return productos;
 }

Este método simplemente carga una lista de productos filtrado por su categoría que nos viene en forma de parámetro y retorna una colección de objetos productos para que podamos los datos en cliente en formato JSon.

Primero de todo necesitamos tener un ScriptManager para poder dotar de toda la funcionalidad AJAX a nuestra página ASP.NET y habilitaremos los PageMethods en el scriptManager para poder acceder a los métodos de servidor. Registraremos un fichero JS en el ScriptManager que será el encargado de llamar a los Metodos de página y cargar los datos en la tabla.

Luego en la página contaremos con un dropDownList con las categorías de los productos, una tabla donde mostraremos los productos y dos botones para la edición de los datos. En el evento onchange de la lista utilizaremos una función javascript para cargar los datos “onchange=Cargarproductos(this)“.

function  CargarProductos(list)
{
   PageMethods.GetProductos(list.options[list.selectedIndex].value,
    OnLlamadaProductos);
}

Esta función es la que llama al método de página que tenemos preparado en el servidor para cargar los datos. El primer parámetro es el identificador de la familia para filtrar los datos y el segundo es la función que utilizaremos pra tratar los datos devueltos.

function OnLlamadaProductos(resultado)
{
    var etiqueta = $get("lblMensaje");  

    $('#tableproductos tr').next().remove();
    for( var x = 0; x < resultado.length; x++)
    {
        $('#tableproductos tr:last').after('<tr><td>'+
        resultado[x].ProductID+'</td>'+
        '<td>'+resultado[x].ProductName+'</td>'+
        '<td>'+resultado[x].UnitPrice +'</td>' +
        '<td>'+resultado[x].UnitsInStock+'</td></tr>');

    }

    $('#tableproductos tr:odd').css('background-color','#CCCCCC');
}

Esta función utiliza JQuery para recorrer el resultado y añadir las rows a la tabla y dar el formato a las alternateRows.

Como podréis comprobar en esta imagen los datos vienen perfectamente serializados en Json para poder trabajar desde nuestro código JavaScript como una colección de objetos perfectamente definidos.

Hasta ahora no hemos tenido que hacer nada especial para enviar los datos serializados desde el servidor hasta el cliente. Pero cuando queremos hacer le paso contrario y enviar los datos serializados desde el cliente al servidor se nos complica un poco más la cosa.

Para mostrar un ejemplo sencillo de este proceso, vamos a dar la opción de añadir nuevos registros a nuestra base de datos desde el cliente, para eso utilizaremos otra función javascript llamada AddProducto.

function AddProducto()
{
    var nom = $('#txtNom')[0].value;
    var precio = $('#txtPrecio')[0].value;
    var stock = $('#txtStock')[0].value;
    var producto = "{"ProductName":""+nom+"
        "","UnitPrice":"+precio+"
        ","UnitsInStock":"+stock+"}";

    PageMethods.AddProducto( producto,
        OnAddProductoOK, OnAddProductoKO);
}

Para no entrar en profundidad en como poder trabajar con JSon desde JavaScript y el tema de la inyección de script vamos a enviar al servidor un formato correcto JSon pero trabajaremos con los datos como texto plano. Esta función simplemente recupera los datos de los textbox de edición los formatea y los envía al servidor mediante otro page Method donde le pasamos los datos y la función que seguirá si todo ha ido correcto y la función si ocurre un error.

El código realmente interesante está en el método del servidor que recibiremos los datos del cliente.

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static int AddProducto(string producto)
{
   System.IO.MemoryStream stream = new System.IO.MemoryStream(
    System.Text.ASCIIEncoding.UTF8.GetBytes(producto));
   DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ProductoData));
   stream.Position = 0;
   ProductoData dsProducto = (ProductoData)ser.ReadObject(stream);

   Productos srvProductos = new Productos();
   int id = srvProductos.AddProducto(dsProducto);
   return id;
}

Para recuperar los datos del cliente en formato JSon y convertirlo en un tipo personalizado utilizaremos la clase DataContractJsonSerializer, esta clase será la encargada de coger el texto que hemos enviado desde el cliente y convertirlo en nuestro Tipo ProductoData.

DataContractJsonSerializer nos servirá tanto para serializar como para deserializar datos Json a objetos.

using System.Runtime.Serialization.Json

Como podréis comprobar con esta clase podemos recuperar fácilmente los datos del cliente como json y convertirlos en objetos para trabajar con estos datos más fácilmente desde nuestro código.

Bueno, como ejemplo me parece que ya está todo explicado .

 

 

Centrar UpdateProgress en un UpdatePanel ( JQuery )

Todos conocemos el control UpdateProgress de ASP.NET y el gran avance que supone para la experiencia de usuario cuando trabajamos con UpdatePanels.

Pero para mi gusto le ha faltado poder posicionar ese control sobre el panel que estamos actualizando y de esta manera dejar mucho más claro al usuario que parte de la pantalla estamos actualizando.

Para eso después de consultar muchos ejemplos que no me terminaban de convencer y con un poquito de imaginación he utilizado un poquito de Javascript para poder realizar este efecto.

Comencemos con los controles que necesitamos para recrear este efecto:

  • Progress.ascx: Este control de usuario es el que contendrá la barra de proceso, en este caso una animación y una label con el texto “cargando…”, la ventaja de utilizar un control de usuario es que no tendremos que repetir el código para cada página que necesitemos una barra de progreso y si nuestra aplicación es multiidioma podremos utilizar los recursos para mostrar el mensaje en el idioma adecuado.

Sigue leyendo

Asp.net PoPup sin JavaScript !!!

En ASP siempre que hemos querido abrir una nueva ventana desde un botón, imageButton, etc. Hemos tenido que echar mano de JavaScript para poder abrir un nuevo navegador.

Pero hay un truco que podemos utilizar directamente desde asp.net y que gracias a la propiedad Target del formulario podemos definir como queremos que se muestre la página web.

protected void Page_Load(object sender, EventArgs e)
{
    if(!IsPostBack)
        this.Form.Target = "_blank";
}

Para hacer la prueba hemos definido la propiedad Target del formulario como _blank  y cada vez que recargemos la página lo hará en una nueva ventana. Si le damos un par de vueltas a esta propiedad le podemos sacar mucho partido.

Otra manera de hacer lo mismo pero que solo afecte por ejemplo cuando hacemos click en un botón y no siempre que recargamos la página sería. Sigue leyendo

ASP.NET AJAX Async Page_Load

Ya es por todos sobradamente conocido los grandes beneficios que nos aporta ASP.NET AJAX a nuestras aplicaciones web. Pero no solo de Postbacks vive el hombre, que pasa si yo no solo quiero recargar partes de mi página web en un postback, sino cargar la primera vez las partes de la página asincronamente?

Pues de eso precisamente pretendo hablar hoy, imaginaros la típica web con diferentes apartados y que es muy posible que más de un apartado hagan que nuestra página tarde mucho en cargar, siempre tendremos la posibilidad de mostrar una barra de progreso en nuestra web, pero porque no utilizar la potencia de ASP.NET Ajax para cargar independientemente cada parte y que el resto de nuestra página se cargue con normalidad.

Para demostrar esto he creado una página web dividida en dos partes:

  1. Nuestro ScritManager para que nuestra aplicación ASP.NET AJAX funcione.
  2. Un UpdatePanel con un DataList en su interior que será nuestra parte asincrona.
  3. Una Label y un botón que actualizará nuestro updataPanel de la forma clásica.

El funcionamiento del ejemplo es muy simple, la página carga el texto de la label y el botón. Al mismo tiempo carga los datos de la lista asincronamente mostrando una progressbar.

No he querido complicar demasiado el ejemplo y recuperaremos los datos desde el cliente mediante los Pagemethods.

  1. Activamos los PageMethods: <asp ScriptManager ID =”ScriptManager1″ runat=”server” EnablePageMethods=”True”>
  2. Creamos un método público y estático y utilizamos el atributo WebMethod para que sea accesible desde el cliente como si fuera un webservice. Luego le definimos que los datos se tienen que serializar de forma compatible con Json con ResponseFormat./div>
  3. Para simular mejor esta situación he añadido un sleep Threading que retrasa la carga 10 segundos.
[WebMethod()]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
static public List<string> CagarDatosAsinc()
{
    System.Threading.Thread.Sleep(10000);
    var datos = new List<string>();

    for (int x = 0; x < 4; x++)
      datos.Add("Dato - " + x);

    return datos;
}

Para hacer posible la idea tenemos que utilizar código en el cliente que se encargue de cargar la lista asincronamente y no influya en el resto de la página.

onload = function actualizar() {
   $get('progres').setyle.display = "inline";
   PageMethods.CargarDatosAsinc(atalizarOK, actualizarFail);
}

function actualizarOK(result) {
   var updatePanel = $get('UpdatePanel1');
   updatePanel.innerHTML = '<table id="DataList1_ct100_Image2"
     cellspacing="0" border="0" style="border-collapse:collapse;">';

   for (var i = 0; i < result.length; i++) {
     updatePanel.innerHTML += '<tr><td>';
     updatePanel.innerHTML += '<img id="DataList1_ct100_Image2"
        src="user1_information.gif" />';

    updatePanel.innerHTML += '<span id="DataList1_ct100_Ñabel13">' +
        result[i] + '</span></br>';
    updatePanel.innerHTML += '</td></tr>';
   }

   updatePanel.innerHTML += '</table';
   updatePanel.innerHTML += '</br>Datos Cargados
      Asincronamente al abrir el documento.';

}

function actualizarFail(error) {
   $get('Label1').innerHTML = "Intentelo más tarde.";
}
  • La primera función Actualizar es la encargada de llamar a nuestro método del servidor y enlazarla con el evento load de la página para que nuestra idea surja efecto y se cargue la lista la primera vez.
  • La función actualizarOK es la encargada de pintar los datos si todo ha ido correcto.
  • La función actualizarFAIL es la encargada de tratar los posibles errores.

El ejemplo funcionando.

El texto de la página y el botón se han cargado perfectamente mientras que la lista se está cargando…

Una vez finalizada la carga se muestran los datos correctamente. Y si forzamos un postback con el botón y actualizamos el updatepanel ya no se lanzará nuestro código de precarga.

Bueno espero que esta propuesta os haya parecido interesante, os dejo el proyecto para que podáis jugar con el y espero que lo podáis utilizar en vuestros proyectos ;-).

Happy Coding

 

 

AJAX TabControl – Tabs Optimizados II

En un artículo anterior explique como optimizar los TabPanels de ASP.NET AJAX Control Toolkit sin tener que extender ni modificar una línea de código, tan solo aprovechando la funcionalidad del UpdatePanel y cargar la información de los tabs solo cuando se selecciona y no cargar todos los datos al principio.

Pero si utilizas este truco junto a un UpdatePogress te das cuenta que al cargar la primera vez los datos no muestra el contenido del UpdatePogress y da una mala sensación de retraso al mostrar los datos.

Pero si luego lanzamos eventos que actualizan el UpdatePanel si se muestra el UpdatePogress correctamente. Sigue leyendo

Iframe Access Denied Cross Domain

Iframe + AjaxControlToolkit v1 + IE = Access Denied Cross Domain

Siempre oí hablar del infierno de las DLL pero cuando hablamos de desarrollos web no nos podemos olvidar del infierno de los iFrames. Cabe decir que este problema lo han solucionado en la nueva versión de AjaxControlToolkit v3 pero para los que tenemos algún proyecto con la versión  anterior tenemos una solución para este problema de permisos.

Primero mostraremos gráficamente cual es el problema.

Hemos creado un simple TexBox con un CalendarExtender para seleccionar una fecha del calendario y esta página de ejemplo la llamamos desde un Iframe que se encuentra en otro dominio, como si la llamada fuera desde un cliente ;-). Sigue leyendo