Marc Rubiño

ASP.NET, C#, AJAX.NET, JavaScript, etc.

diciembre 2008 - Artículos

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 os adjunto el proyecto que he utilizado para que podáis jugar con él como siempre.

Nos vemos en el próximo artículo.   

 

 

ASP.NET CODEBARS

 

En el foro de MSDN han consultado como poder generar códigos de barra en una aplicación ASP.NET, yo hace bastante tiempo hice un ejemplo para una aplicación windows utilizando unas fuentes True Type para este menester y ahora haré lo mismo pero para una aplicación web.

 

El artículo original para Windows lo podéis encontrar en la web del guille en http://www.elguille.info/colabora/NET2006/Marckys_BarCode.htm .

 

Lo primero que voy a hacer es un proyecto web con una simple página donde podré introducir los datos para generar el código de barras y una combo para seleccionar las fuentes que me darán los diferentes formatos de código de barras.

     

La idea de esta utilidad es mostrar los datos en un formato de código de barras y la opción que he considerado más oportuna es generar una imagen con este texto y mostrarlo en la web como un simple control de servidor image de toda la vida.

 

Para poder realizar esto si tenernos que complicar muchísimo la vida. Lo mejor es crear un http handler que nos genere esta imagen y la muestre en el control.

 Que es un Http Handler ??  

Pues un manejador de las solicitudes http que  implementa la interface IHttpHandler y nos puede servir tanto para interceptar las llamadas de un fichero con una extensión en particular como para llamarlo directamente, como va a ser nuestro caso.

 

Nuestro Manejador:

 

Tan sencillo como una clase pública que implementa la interfaz IHttpHandler.

 public class MarckysCodeBar : IHttpHandler Implementa el método ProcessRequest y la propiedad IsReusable. 

El Método ProcessRequest recuperamos los parámetros que necesitamos para generar la imagen y enviamos la respuesta a la petición http.

 

public void ProcessRequest (HttpContext context) {

string cd = context.Request.QueryString.Get("code");
string fm = context.Request.QueryString.Get("format");
int width = (!string.IsNullOrEmpty(context.Request.QueryString.Get("width"))) ? int.Parse(context.Request.QueryString.Get("width")) : 200;
int height = (!string.IsNullOrEmpty(context.Request.QueryString.Get("height"))) ? int.Parse(context.Request.QueryString.Get("height")) : 60;
int size = (!string.IsNullOrEmpty(context.Request.QueryString.Get("size"))) ? int.Parse(context.Request.QueryString.Get("size")) : 60;
if (!string.IsNullOrEmpty(cd))
{
System.IO.MemoryStream memStream = new System.IO.MemoryStream();

Bitmap bitmap = new Bitmap(width, height);
Graphics grafic = Graphics.FromImage(bitmap);
grafic.FillRectangle(new SolidBrush(Color.White), 0, 0, (float)width, (float)height);
Font fuente = CargarFuente(fm, size);
Point point = new Point();
SolidBrush brush = new SolidBrush(Color.Black);
grafic.DrawString(FormatBarCode(cd), fuente, brush, point);

context.Response.ContentType = "image/jpeg";
bitmap.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
else
context.Response.Write("");
}

Este manejador simplemente recupera la fuente que utilizaremos de la lista disponible crea un bitmap y le inserta el texto con la fuente del código de barras para mostrar el resultado como una imagen jpeg.

Los otros dos métodos a destacar es el formateo de los datos para que se puedan leer desde un lector de códigos de barras añadiendo los caracteres de escape correspondientes.

private string FormatBarCode(string code)
    {
        string barcode = string.Empty;
        barcode = string.Format("*{0}*", code);
        return barcode;
    }

Y cuando generamos la nueva fuente para cargar en el bitmap.

 private Font CargarFuente(string fuente, int size)
{
string f = "BARCOD39.TTF";

switch (fuente)
{
case "E39":
f = "BARCOD39.TTF";
break;
case "E13":
f = "EAN-13.TTF";
break;
case "E9":
f = "FRE3OF9X.TTF";
break;
}
PrivateFontCollection pfc = new PrivateFontCollection();

pfc.AddFontFile(System.Configuration.ConfigurationManager.AppSettings.Get("PATH_FONTS") + @"\" + f);
FontFamily fontFamily = pfc.Families[0];
Font _Font =
<input type="button" id="print" onclick="imprimir()" value="Imprimir" />
Font(fontFamily, (float)size);
return _Font;
}

Finalmente para que todo esto funcione simplemente tenemos que añadir una imagen en nuestro formulario web y al lanzar el evento del botón definir la Url de la imagen desde nuestro Handler con los parámetros que necesitamos para generar el código de barras correctamente.

    protected void Button1_Click(object sender, EventArgs e)
{
Image2.ImageUrl = string.Format(@"MarckysCodeBar.ashx?code={0}&format={1}"
&width=400&height=60&size=50", TextBox1.Text, "
ddlFuents.SelectedItem.Value);
Image2.Visible = true;
}

Y como una imagen vale más que mil palabras este es el resultado final.

Podeis bajar el proyecto de Prueba desde Proyecto-CodeBar

## EDICIÓN ##

Como imprimir el código de barras: Para poder imprimir en la impresora del cliente solo podemos utilizar un script de cliente y con javaScript es muy sencillo poder habilitar imprimir la página.

 Insertamos un botón al formulario que llame a nuestra función de imprimir 


<input type="button" id="print" onclick="imprimir()" value="Imprimir" />

 Con este simple escript podemos imprimir la página que contiene el código.


<script type="text/javascript"> function imprimir() { window.print(); } </script>