Cómo trabajar con la negociación de contenido en Web API

ASP.Net Web API es un marco ligero que se utiliza para crear servicios HTTP RESTful y sin estado. Los servicios RESTful son servicios livianos, sin estado, basados ​​en cliente-servidor y que se pueden almacenar en caché que se basan en el concepto de recursos. REST es un estilo arquitectónico: un conjunto de restricciones que se utilizan para implementar servicios sin estado. Es un paradigma arquitectónico que se utiliza para crear servicios escalables y reutilizables.

La representación de un recurso en el formato solicitado es un tema interesante, ya que a menudo es posible que desee consumir sus servicios desde varios tipos de dispositivos. La negociación de contenido es uno de los conceptos más importantes de Web API. Aunque es un concepto relativamente simple, existen muchos conceptos erróneos y malos entendidos en torno a este tema. Al diseñar e implementar servicios RESTful utilizando Web API, a menudo necesitará lidiar con la negociación de contenido.

¿Qué es el contenido negociado y por qué es importante?

La negociación de contenido puede definirse como el proceso de inspeccionar la estructura de una solicitud HTTP entrante para determinar la mejor representación de un recurso entre las múltiples representaciones disponibles del mismo recurso. En esencia, la negociación de contenido es un concepto que permite que la misma URL sirva el mismo contenido en varios formatos. Puede aprovechar la negociación de contenido para seleccionar el tipo de medio preferido.

En Web API, la negociación de contenido la realiza el tiempo de ejecución (en el lado del servidor) para determinar el formateador de tipo de medio que se utilizará para devolver la respuesta a una solicitud entrante del lado del cliente.

La negociación de contenido se centra en el tipo de medio y el formateador de tipo de medio. Mientras que el primero se refiere al valor del encabezado "tipo de contenido" en la solicitud HTTP y la respuesta HTTP, el segundo se usa para convertir los tipos .NET en los datos HTTP correspondientes y viceversa. Tenga en cuenta que el formateador de tipos de medios en Web API está representado por una clase abstracta llamada MediaTypeFormatter.

El marco de la API web viene con los siguientes formateadores de forma predeterminada.

  • System.Net.Http.Formatting.JsonMediaTypeFormatter
  • System.Net.Http.Formatting.XmlMediaTypeFormatter
  • System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter
  • System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter

Para personalizar la negociación de contenido en la API web, el principal punto de extensibilidad que debería aprovechar es la asignación de tipos de medios. Tenga en cuenta que Web API ofrece las siguientes asignaciones de tipos de medios de forma predeterminada.

  • QueryStringMapping
  • UriPathExtensionMapping
  • RequestHeaderMapping
  • MediaRangeMapping

Para crear su mapeo de tipo de medio personalizado, necesitaría crear una clase que amplíe MediaTypeMapping como se muestra en el fragmento de código a continuación.

public class MediaTypeMapping : MediaTypeMapping

{

   protected override double OnTryMatchMediaType(HttpResponseMessage response)

     {

                //Write your custom code here

     }

}

El siguiente fragmento de código ilustra cómo puede recuperar los nombres de todos los formateadores admitidos en la API web iterando la colección HttpConfiguration.Formatters.

   [HttpGet]

       public List GetAllFormatters()

       {

           List lstFormaters = new List();

           foreach (var formatter in this.Configuration.Formatters)

           {

               lstFormaters.Add(formatter.GetType().Name);

           }

           return lstFormaters;

       }

Exploremos ahora cómo podemos trabajar con la negociación de contenido para seleccionar el formateador que queremos y recuperar el contenido en el formato que necesitamos. Considere la siguiente clase de entidad.

public class CustomerDTO

   {

       public Int32 Id

       { get; set; }

       public string FirstName

       { get; set; }

       public string LastName

       { get; set; }

       public string Address

      { get; set; }

   }

A continuación, suponga que tiene un método que rellena datos en una lista de tipo CustomerDTO y los devuelve.

private List GetCustomerData()

       {

           List lstCustomers = new List();

           CustomerDTO customer = new CustomerDTO();

           customer.Id = 1;

           customer.FirstName = "Joydip";

           customer.LastName = "Kanjilal";

           customer.Address = "Hyderabad, India";

           lstCustomers.Add(customer);

           return lstCustomers;

       }

El siguiente método de API web muestra cómo puede devolver HttpResponseMessage como respuesta de su método API web según el mecanismo de negociación de contenido predeterminado disponible.

[HttpGet]

       public HttpResponseMessage GetCustomers()

       {

           List lstCustomers = GetCustomerData();

           IContentNegotiator negotiator = Configuration.Services.GetContentNegotiator();

           ContentNegotiationResult result = negotiator.Negotiate(typeof(CustomerDTO), Request, Configuration.Formatters);

           return new HttpResponseMessage()

           {

               Content = new ObjectContent (lstCustomers, result.Formatter, result.MediaType.MediaType)

         };

       }

Si tuviera que utilizar un formateador específico disponible en la colección de formateadores, es posible que desee volver a escribir el mismo método que se muestra en el fragmento de código a continuación.

[HttpGet]

       public HttpResponseMessage GetCustomers()

       {

           List lstCustomers = GetCustomerData();

           return new HttpResponseMessage()

           {

               Content = new ObjectContent (lstCustomers, Configuration.Formatters[1])

           };

      }

Okay; pero, ¿cómo construyes tu propio formateador personalizado entonces? Bueno, para crear un formateador de tipo de medio personalizado, debe crear una clase que amplíe la clase abstracta MediaTypeFormatter. Luego, debe escribir su código personalizado dentro de la clase que creó para anular los métodos de la clase base abstracta MediaTypeFormatter.

public class CustomMediaTypeFormatter : MediaTypeFormatter

   {

       public override bool CanReadType(Type type)

       {

           throw new NotImplementedException();

       }

       public override bool CanWriteType(Type type)

       {

           throw new NotImplementedException();

       }

   }

Una vez que su formateador personalizado esté en su lugar, puede agregarlo a la colección de formateadores fácilmente:

config.Formatters.Add(new CustomMediaTypeFormatter ());