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

 

13 comentarios en “Serializar – Deserializar JSON en ASP.NET”

  1. 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”.

    [‘

    ‘,

    ‘ , resultado[x].ProductID , ‘

    ‘,

    ‘ , resultado[x].ProductName , ‘

    ‘,

    ‘ , resultado[x].UnitPrice , ‘

    ‘,

    ‘ , resultado[x].UnitsInStock, ‘

    ‘,

    ‘].join();

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

    Saludos

  2. 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.

  3. 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

  4. 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!!

  5. 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 🙁

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *