Serializando JSON en ASP.NET Web Api: Vigilando los nombres de las propiedades e ignorando propiedades a null

Hace unos días publiqué un post sobre cómo podíamos comprimir las peticiones de tipo JSON, con el fin de que las mismas tuvieran un tamaño menor durante el transporte. Si bien es una buena práctica, no es la única que deberíamos tener en cuenta.

En ocasiones, por comodidad, se están utilizando clases que no son lo suficientemente óptimas para ser serializadas al formato JSON. Lo realmente preocupante es que no somos conscientes muchas veces de lo que puede conllevar utilizar clases con más propiedades de las necesarias para responder una petición o cómo incluso el nombre que le damos a sus miembros puede penalizar en tamaño y tiempo.

Para verlo con un ejemplo, tenemos la siguiente clase con un par de propiedades:

        public class Profile
        {
            public string Name { get; set; }
            public int? Devices { get; set; }
        }

Cuando utilizamos la misma para transportar nuestros datos al cliente, el resultado puede ser similar al siguiente:

Short property names

Estos valores por sí solos no dicen mucho, pero si tuviéramos otra clase a la que asignamos los mismos datos pero con unas propiedades, en este ejemplo, muy exageradas:

        public class Profile2
        {
            public string ALongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongName { get; set; }
            public int? ALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotDevices { get; set; }
        }

Podríamos encontrarnos con un resultado más preocupante:

Extra long property names

El contenido a enviar es exactamente el mismo:

var profile = new Profile
{
Name = "Gis",
Devices = 5
};

var sameProfile = new Profile2
{
ALongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongName = "Gis",
ALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotALotDevices = 5
};

Obviamente se trata de un ejemplo exagerado, pero lo suficiente para que podamos comprobar que tanto el tamaño como la latencia se ven involucrados por una mala elección en los nombres de los miembros de la clase utilizada.

Por otro lado, también se tiende a trabajar con clases que no eran concebidas para ser serializadas, por lo que muchas de sus propiedades son enviadas con un valor null, haciendo que nuestra respuesta crezca también en tamaño y tiempo. A pesar de ello, si fuera necesario trabajar con las mismas, podemos indicar al serializador que todas aquellas propiedades que tengan valor null no se incluyan en el resultado, con el objetivo de simplificarlo.

Esta operación se puede realizar a nivel global (Global.asax):

using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Newtonsoft.Json;

namespace IgnoreProperties
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode,
    // visit http://go.microsoft.com/?LinkId=9394801

    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            var jSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };

            GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = jSettings;

        }
    }
}

O bien a nivel de acción, si fuera necesario:

        public HttpResponseMessage Get()
        {
            var profile = new Profile
            {
                Name = "Gis"
            };

            return Request.CreateResponse(HttpStatusCode.OK, profile, new JsonMediaTypeFormatter
            {
                 SerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }
            });
        }

Cuando manejamos grandes cantidades de datos es muy importante que analicemos bien si las clases que estamos utilizando son aptas para este trabajo, puesto que pueden ayudarnos a simplificar y reducir posibles escenarios, donde no sólo la experiencia de usuario se ve perjudicada sino también el esfuerzo por parte del servidor.

Espero que sea de utilidad.

¡Saludos!