Buscar en este blog....

viernes, 5 de junio de 2015

Web Service que recibe y devuelve JSON

La verdad es que si JSON se utiliza tanto hoy en día, decididamente su simplicidad de uso es uno de los factores más decisivos para esta tendencia.

Actualmente estoy haciendo unos Web Services en C# que deben ser consultados por un cliente enviando como request una cadena en formato JSON. Y no solo eso, el cliente también espera que el WS le devuelva su respuesta.. también en formato JSON.

Esto es, tremendamente simple de lograr. Para mostrar, voy a crear un proyecto muy simple. No será un WS porque no amerita la complicación. Quiero decir que lo que voy a hacer aquí se aplica a un WS o a un proyecto cualquiera... de hecho, voy a hacerlo para un método aislado.

Vamos a hacer una calculadora. Pero para darle un poco de "complejidad", vamos a hacer la calculadora reciba una lista de pares de números. Se tomarán los números de cada uno de estos pares y se los sumará. De forma que se devolverá una lista de "sumas". Por ejemplo:

Una lista para enviarle a la calculadora podría ser:
listaEntrada = [5,2],[1,-3],[-2,-2]
y la correspondiente lista de respuesta:
listaRepsuesta = 7,-2,-4

¿Estamos de acuerdo? Bien. Sigamos.

Si el Web Service va a recibir la lista de pares en formato JSON, debemos definir exactamente cómo.Podemos imaginar algo así:

{
    "pares": 
    [
  {
   "numero1":"5",
   "numero2":"2"
  },
  {
   "numero1":"1",
   "numero2":"-3"
  },
  {
   "numero1":"-2",
   "numero2":"-2"
  } 
    ]
}


y por lo tanto, la siguiente respuesta:

{  
   "sumas":[  
      7,
      -2,
      -4
   ]
}


Entonces, considerando esta decisión, vamos a armar dos entidades: una entidad para tener los datos de entrada, y otra entidad para poner los datos de salida. Las mismas podrían llamarse sumaRequest y sumaResponse, por ejemplo.

Escribamos estas entidades entonces, pero además agregamos una nueva: "Pares". Esta entidad, es el "tipo de dato" (por llamarlo de alguna manera) que contiene dos enteros, los cuales vamos a sumar.

public class sumaRequest
{
 public List<pares> pares { get; set; }
}


public class Pares
{
 public int numero1  { get; set; }
 public int numero2  { get; set; }
}


public class sumaResponse
{
 public List<int> sumas { get; set; }
}


Bueno, creando objetos de estas entidades y llenándolos con la información necesaria, ya podríamos trabajar perfectamente. LA operación suma, recibe la lista, y simplemente la procesa. Es decir, esto:

sumaResponse hacerTodasLasSumas(sumaRequest request)
{
 sumaResponse ret = new sumaResponse();
    ret.sumas = new List<int>();

 foreach(Pares pareja in request.pares)
 {
  int suma = pareja.numero1 + pareja.numero2;
  ret.sumas.Add(suma);
 }

 return ret;
}

Bueno, esto es muy lindo, pero aún no hemos metido a JSON en todo esto. Pero en realidad, es muy poco lo de tenemos que hacer. Solo hay que desserializar sumaRequest de un string que nos llegue, por otra parte serializar sumaResponse antes de devolverlo al usuario/cliente.

Para esto vamos a agregar el paquete JSON.NET desde Nuget (o la línea de comandos, como quieran). Una vez agregado, modificamos las entidades que directa o indirectamente entran en el JSON.
La diferencia entre entrar directamente o indirectamente, es simple: sumaRequest entra directamente, porque es la entidad que contiene la información del JSON de forma directa. Lo mismo ocurre con sumaResponse, que contiene la información directa que queremos almacenar. Sin embargo la entidad Pares entra de manera indirecta, ya que en realidad, debemos utilizar su contenido dentro del JSON, pero sólo por ser parte de la entidad sumaRequest.
Las entidades, las modificamos de la siguiente manera:

[JsonObject(MemberSerialization.OptIn)]
public class sumaRequest
{
 [JsonProperty(PropertyName = "pares")]
 public List<Pares> pares { get; set; }
}


[JsonObject(MemberSerialization.OptIn)]
public class Pares
{
 [JsonProperty(PropertyName = "numero1")]
 public int numero1  { get; set; }

 [JsonProperty(PropertyName = "numero2")]
 public int numero2  { get; set; }
}


[JsonObject(MemberSerialization.OptIn)]
public class sumaResponse
{
 [JsonProperty(PropertyName = "sumas")]
 public List<int> sumas { get; set; }
}


Lo que hemos hecho con el atributo JsonObject, es indicar que una clase forma parte de una Serializacion/Deserialización JSON (sin importar si es de forma directa o indirecta). Y con el atributo JsonProperty indicamos que el campo en cuestión debe ser serializado. Este atributo además permite especificar cómo se llama el campo cuando la información ser serializa/deserializa a JSON. Claramente, ambos nombres no tienen porqué coincidir.

Finalmente, y para terminar, debemos indicar en algun punto de código, que una string recibida debe deserializarse como entradaRequest, y que sumaResponse debe serializarse como salida. Esto lo hacemos con las funciones JsonConvert.DeserializeObject e JsonConvert.SerializeObject respectivamente. Nos queda así:

public string operacionDelWebService (string jsonRequest)
{
 sumaRequest objectRequest = JsonConvert.DeserializeObject<sumaRequest>(jsonRequest); // (1)

 sumaResponse objectResponse = hacerTodasLasSumas(objectRequest);    // (2)

 string response = JsonConvert.SerializeObject(objectResponse); // (3)

 return response;
}


Como vemos, la funcion -que podría ser la operación visible del WS- recibe y devuelve una cadena, ambas en formato JSON.

En (1) convertimos la cadena en formato JSON a objetos conocidos por nosotros (Deserializamos).
En (2) operamos normalmente con los objetos que conocemos.
En (3) convertimos la respuesta a un string con formato JSON. (Serializamos).

Luego se devuelve el string y todos contentos.
Espero que haya sido de utilidad y simple de entender.

Dejo el código completo funcional.


using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace Borrar02
{
    class Program
    {
        static void Main(string[] args)
        {

            string stringEntrada = " {\"pares\":[{\"numero1\":\"5\",\"numero2\":\"2\"},{\"numero1\":\"1\",\"numero2\":\"-3\"},{\"numero1\":\"-2\",\"numero2\":\"-2\"}]}";
            string stringSalida;

            WebService ws = new WebService();

            stringSalida = ws.operacionDelWebService(stringEntrada);
            
            Console.WriteLine("Respuesta del WS:\n{0}", stringSalida);
        }
    }

    class WebService
    {
        public string operacionDelWebService(string jsonRequest)
        {
            sumaRequest objectRequest = JsonConvert.DeserializeObject<sumaRequest>(jsonRequest);

            sumaResponse objectResponse = hacerTodasLasSumas(objectRequest);    // (2)

            string response = JsonConvert.SerializeObject(objectResponse); // (3)

            return response;
        }
        sumaResponse hacerTodasLasSumas(sumaRequest request)
        {
            sumaResponse ret = new sumaResponse();
            ret.sumas = new List<int>();

            foreach (Pares pareja in request.pares)
            {
                int suma = pareja.numero1 + pareja.numero2;
                ret.sumas.Add(suma);
            }

            return ret;
        }

        [JsonObject(MemberSerialization.OptIn)]
        public class sumaRequest
        {
            [JsonProperty(PropertyName = "pares")]
            public List<Pares> pares { get; set; }
        }

        [JsonObject(MemberSerialization.OptIn)]
        public class Pares
        {
            [JsonProperty(PropertyName = "numero1")]
            public int numero1 { get; set; }

            [JsonProperty(PropertyName = "numero2")]
            public int numero2 { get; set; }
        }

        [JsonObject(MemberSerialization.OptIn)]
        public class sumaResponse
        {
            [JsonProperty(PropertyName = "sumas")]
            public List<int> sumas { get; set; }
        }
    }
}

No hay comentarios:

Publicar un comentario

Comments are subject to moderation, only in order to avoid insults and disguising things.

Los comentarios están sujetos a moderación, solo con el fin de evitar insultos y cosas por el estilo.