Marc Rubiño

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

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.

Nos vemos en el próximo artículo.   

 Cross-Posting www.lonetcamp.com

 

Posted: 18/12/2008 0:40 por Marc Rubiño | con 13 comment(s) |
Comparte este post:

Comentarios

Sergio Tarrillo ha opinado:

Marc, muy buen artículo, y sirve como base para hacer cualquier otro, con acceso a datos y ajax a secas.

Saludos,

# December 18, 2008 3:59 AM

Jersson ha opinado:

Marc

buen post.

Saludos.

# December 18, 2008 4:41 AM

Marc Rubiño ha opinado:

Gracias Sergio y gracias Jersson ;-)

Este es un tema muy interesante para sacarle todo el jugo. XD

No Vemos

# December 18, 2008 9:30 AM

rcastro ha opinado:

Muy buen post.

Solo una sugerencia.

Al genererar cadenas en javaScript yo utilizo la siguiente sintaxis que a mi modo de ver es "mas legible" y he leido por ahí que con más "rendimiento".

['<tr>',

'<td>' , resultado[x].ProductID   , '</td>',

'<td>' , resultado[x].ProductName , '</td>',

'<td>' , resultado[x].UnitPrice   , '</td>',

'<td>' , resultado[x].UnitsInStock, '</td>',

'</tr>'].join();

Pero ya digo, esto es solamente un pequeño apunte. A mi es que el "+" me confunde mucho.

Saludos

# December 19, 2008 9:23 AM

Marc Rubiño ha opinado:

Gracias por el aporte rCastro, supongo que lo de poner + ya es un defecto profesional de los que utilizamos c#.

La verdad es que no me he parado demasiado a testear el redimiendo en javaScript y me he basado solamente en utilizar un poco de JQuery.

Saludos.

# December 19, 2008 9:46 AM

David Daniel Arroyo Zari "Ddaz" ha opinado:

marc :

muy buen post :)

rcastro:

me parece interesante lo que dices de mejor rendimiento, plz si encuentras el vinculo de donde lo leiste, me lo pasas plz, ya que seria interesante verlo.

salu2

Ddaz

# December 19, 2008 7:54 PM

MetalPower ha opinado:

Gracias por este post, me es de mucha ayuda para empezar a utilizar un poco de ajax + json + jquery :)

# March 31, 2009 3:10 PM

AlexandroRR ha opinado:

Muy bueno tu código, ya que integra una librería de Ajax con el framework, algo que siempre quise hacer, pero nunca supe cómo hacerlo, ya que las librerías usualmente dan una experiencia visual más rica al usuario.

Sólo tengo una pregunta: En el ejemplo, en la página Default.aspx vos tenéis una referencia a un script dentro del head, y luego otra referencia al archivo JQuery.Intellisense.js pero dentro de asp:PlaceHolder dentro del head y sin ID ¿Por qué hiciste eso? Yo lo intenté cambiar, pero me manda error.

Ahora, estoy tratando de adaptar scriptaculo.us, pero igual no puedo y me manda error, así pues tal vez esté relacionado el error con el por qué pusiste la referencia al script dentro del PlaceHolder.

Muchas gracias de antemano y gracias por compartir vuestro código!!

# May 28, 2009 6:24 PM

Marc Rubiño ha opinado:

Eso era uno de los trucos para utilizar el inteligent de JQuery con VS.

No te tiene que influir en tu código.

Saludos

# June 10, 2009 10:44 AM

Enrique ha opinado:

Hola

Hay algun vinculo para poder bajarse el ejemplo??

Muchas Gracias

# November 1, 2010 9:31 PM

Marc Rubiño ha opinado:

He tenido un problema con el servidor donde teníamos la web del grupo con los ejemplos, estamos intentando recuperar la información y si es posible reactivaré los links con los recursos :(

# November 2, 2010 8:58 AM

Marc Rubiño ha opinado:

Por petición popular voy a ampliar el artículo que dedique en su día a la clase

# July 12, 2011 7:01 PM

ferfsc ha opinado:

Marc... por favor.. puedes poner los fuentes para que podamos descargarlos y ver mas a fondo tus ejemplos .. muchas gracias

# September 29, 2011 6:33 PM