Aplicación de formato a datos de respuesta en ASP.NET Core Web API

ASP.NET Core MVC admite el formato de los datos de respuesta, mediante formatos especificados o en respuesta a la solicitud de un cliente.

Resultados de acción específicos del formato

Algunos tipos de resultado de acción son específicos de un formato determinado, como JsonResult y ContentResult. Las acciones pueden devolver resultados que siempre usan un formato especificado, ignorando la solicitud de un cliente para un formato diferente. Por ejemplo, devolver JsonResult devuelve JSdatos con formato ON y devuelve ContentResult datos de cadena con formato de texto sin formato.

No se requiere una acción para devolver ningún tipo específico. ASP.NET Core admite cualquier valor devuelto de objeto. Los resultados de acciones que devuelven objetos que no son tipos IActionResult se serializan con la implementación IOutputFormatter correspondiente. Para obtener más información, consulte Tipos de valor devuelto de acción del controlador en ASP.NET Core API web.

El método auxiliar integrado ControllerBase.Ok devuelve datos con formato JSON:

[HttpGet]
public IActionResult Get() =>
    Ok(_todoItemStore.GetList());

El código de ejemplo devuelve una lista de elementos de tareas pendientes. Con las herramientas para desarrolladores del explorador F12 o http-repl con el código anterior se muestra:

  • Se muestra el encabezado de respuesta que contiene content-type:application/json; charset=utf-8.
  • Encabezados de solicitud. Por ejemplo, el encabezado Accept. El código anterior omite el encabezado Accept.

Para devolver datos con formato de texto sin formato, use ContentResult y el método del asistente Content:

[HttpGet("Version")]
public ContentResult GetVersion() =>
    Content("v1.0.0");

En el código anterior, el Content-Type devuelto es text/plain.

Para las acciones con varios tipos de valor devuelto, devuelva IActionResult. Por ejemplo, la devolución de códigos de estado HTTP diferentes en función del resultado de las operaciones realizadas.

Negociación de contenido

La negociación de contenido se produce cuando el cliente especifica un encabezado Accept. El formato predeterminado que ASP.NET Core usa es JSON. La negociación de contenido:

  • La implementa ObjectResult.
  • Se integra en los resultados de acción específicos del código de estado devueltos por los métodos auxiliares. Los métodos auxiliares de los resultados de acción se basan en ObjectResult.

Cuando se devuelve un tipo de modelo, el tipo de valor devuelto es ObjectResult.

El siguiente método de acción usa los métodos del asistente Ok y NotFound:

[HttpGet("{id:long}")]
public IActionResult GetById(long id)
{
    var todo = _todoItemStore.GetById(id);

    if (todo is null)
    {
        return NotFound();
    }

    return Ok(todo);
}

De forma predeterminada, ASP.NET Core admite los siguientes tipos de medios:

  • application/json
  • text/json
  • text/plain

Las herramientas como Fiddler o Postman pueden establecer el encabezado de solicitud Accept para especificar el formato de devolución. Cuando el encabezado Accept contiene un tipo que el servidor admite, se devuelve ese tipo. En la sección siguiente se muestra cómo agregar otros formateadores.

Las acciones del controlador pueden devolver POCO (objetos CLR antiguos sin formato). Cuando se devuelve un objeto POCO, el tiempo de ejecución crea automáticamente un ObjectResult que encapsula al objeto. El cliente obtiene el objeto serializado con formato. Si el objeto que se va a devolver es null, se devuelve una respuesta 204 No Content.

En el ejemplo siguiente se devuelve un tipo de objeto:

[HttpGet("{id:long}")]
public TodoItem? GetById(long id) =>
    _todoItemStore.GetById(id);

En el código anterior, una solicitud de un elemento todo válido devuelve una 200 OK respuesta. Una solicitud de un elemento de tareas inválido devuelve una respuesta 204 No Content.

El encabezado Accept

La negociación de contenido se lleva a cabo cuando en la solicitud aparece un encabezado Accept. Cuando una solicitud contiene un encabezado Accept, ASP.NET Core:

  • Enumera los tipos de medios del encabezado Accept en orden de preferencia.
  • Intenta encontrar un formateador que pueda generar una respuesta en uno de los formatos especificados.

Si no se encuentra ningún formateador que pueda satisfacer la solicitud del cliente, ASP.NET Core:

Si no se ha configurado ningún formateador para el formato solicitado, se usará el primer formateador que pueda dar formato al objeto. Si no aparece ningún encabezado Accept en la solicitud:

  • El primer formateador que puede controlar el objeto se usa para serializar la respuesta.
  • No tiene lugar ninguna negociación. El servidor está determinando el formato que se va a devolver.

Si el encabezado Accept contiene */*, el encabezado se omite a menos que RespectBrowserAcceptHeader esté establecido en true en MvcOptions.

Exploradores y negociación de contenido

A diferencia de los clientes de API típicos, los exploradores web proporcionan encabezados Accept. Los navegadores web especifican muchos formatos, incluidos los comodines. De forma predeterminada, cuando el marco detecta que la solicitud procede de un explorador:

  • El encabezado Accept se omite.
  • El contenido se devuelve en JSON, a menos que se configure de otra manera.

Esto proporciona una experiencia más coherente entre los exploradores al consumir las API.

Para configurar una aplicación para que respete las cabeceras de aceptación del navegador, establezca la propiedad RespectBrowserAcceptHeader en true:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true;
});

Configuración de formateadores

Las aplicaciones que necesitan admitir formatos adicionales pueden agregar los paquetes NuGet adecuados y configurar la compatibilidad. Hay formateadores independientes para la entrada y la salida. El enlace de modelos usa formateadores de entrada. Los formateadores de salida se usan para dar formato a las respuestas. Para obtener información sobre la creación de un formateador personalizado, vea Formateadores personalizados.

Adición de compatibilidad con el formato XML

Para configurar formateadores XML implementados mediante XmlSerializer, llame a AddXmlSerializerFormatters:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddXmlSerializerFormatters();

Cuando se usa el código anterior, los métodos de controlador devuelven el formato adecuado en función del encabezado Accept de la solicitud.

Configurar System.Text.Json formateadores basados en

Para configurar las características de los formateadores basados en System.Text.Json, use Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions. El código resaltado siguiente configura el formato PascalCase en lugar del formato camelCase predeterminado:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
    });

El método de acción siguiente llama ControllerBase.Problem a para crear una ProblemDetails respuesta:

[HttpGet("Error")]
public IActionResult GetError() =>
    Problem("Something went wrong.");

Una ProblemDetails respuesta siempre es camelCase, incluso cuando la aplicación establece el formato en PascalCase. ProblemDetails sigue a RFC 7807, que especifica minúsculas.

Para configurar las opciones de serialización de salida para acciones específicas, use JsonResult. Por ejemplo:

[HttpGet]
public IActionResult Get() =>
    new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerOptions
        {
            PropertyNamingPolicy = null
        });

Se ha agregado compatibilidad con formato JSON basado en Newtonsoft.Json

Los formateadores JSON predeterminados usan System.Text.Json. Para usar los Newtonsoft.Jsonformateadores basados en , instale el Microsoft.AspNetCore.Mvc.NewtonsoftJson paquete NuGet y configúrelo en Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddNewtonsoftJson();

En el código anterior, la llamada a configura AddNewtonsoftJson las siguientes características de API web, MVC y Razor Pages para usar Newtonsoft.Json:

Es posible que algunas características no funcionen bien con formateadores basados en System.Text.Json y requieren una referencia a los formateadores basados en Newtonsoft.Json. Siga usando los formateadores basados en Newtonsoft.Json si la aplicación:

  • Usa atributos Newtonsoft.Json. Por ejemplo, [JsonProperty] o [JsonIgnore].
  • Proporciona la configuración de la serialización.
  • Se basa en las características que Newtonsoft.Json proporciona.

Para configurar las características de los formateadores basados en Newtonsoft.Json, use SerializerSettings:

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

Para configurar las opciones de serialización de salida para acciones específicas, use JsonResult. Por ejemplo:

[HttpGet]
public IActionResult GetNewtonsoftJson() =>
    new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerSettings
        {
            ContractResolver = new DefaultContractResolver()
        });

Especificación de un formato

Para restringir los formatos de respuesta, aplique el filtro [Produces]. Al igual que la mayoría de los filtros, [Produces] puede aplicarse a la acción, el controlador o el ámbito global:

[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class TodoItemsController : ControllerBase

El filtro [Produces] anterior:

  • Obliga a todas las acciones dentro del controlador a devolver JSrespuestas con formato ON para poCOs (objetos CLR antiguos sin formato) o ObjectResult sus tipos derivados.
  • Devuelve JSrespuestas con formato ON incluso si se configuran otros formateadores y el cliente especifica un formato diferente.

Para más información, consulte Filtros.

Formateadores de casos especiales

Algunos casos especiales se implementan mediante formateadores integrados. De forma predeterminada, los tipos de valor devueltos string se formatean como texto/sin formato (texto/html si se solicita a través del encabezado Accept). Este comportamiento se puede quitar mediante la eliminación de StringOutputFormatter. Los formateadores se quitan en el método Program.cs. Las acciones que tienen un tipo de valor devuelto de objeto de modelo devuelven 204 No Content al devolver null. Este comportamiento se puede quitar mediante la eliminación de HttpNoContentOutputFormatter. El código siguiente quita StringOutputFormatter y HttpNoContentOutputFormatter.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    // using Microsoft.AspNetCore.Mvc.Formatters;
    options.OutputFormatters.RemoveType<StringOutputFormatter>();
    options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
});

Sin StringOutputFormatter, el formateador de JSON integrado aplica formato a los tipos devueltos string. Si se quita el formateador JSON integrado y está disponible un formateador XML, el formateador XML aplica formato a los tipos devueltos string. De lo contrario, los tipos devueltos string devuelven 406 Not Acceptable.

Sin HttpNoContentOutputFormatter, se da formato a los objetos nulos mediante el formateador configurado. Por ejemplo:

  • El formateador JSON devuelve una respuesta con un cuerpo de null.
  • El formateador XML devuelve un elemento XML vacío con el atributo xsi:nil="true" establecido.

Asignaciones de direcciones URL de formato de respuesta

Los clientes pueden solicitar un formato determinado como parte de la dirección URL, por ejemplo:

  • En la cadena de consulta o en una parte de la ruta de acceso.
  • Mediante el uso de una extensión de archivo específica del formato como .xml o .json.

La asignación de la ruta de acceso de la solicitud debe especificarse en la ruta que use la API. Por ejemplo:

[ApiController]
[Route("api/[controller]")]
[FormatFilter]
public class TodoItemsController : ControllerBase
{
    private readonly TodoItemStore _todoItemStore;

    public TodoItemsController(TodoItemStore todoItemStore) =>
        _todoItemStore = todoItemStore;

    [HttpGet("{id:long}.{format?}")]
    public TodoItem? GetById(long id) =>
        _todoItemStore.GetById(id);

Esta ruta anterior permite especificar el formato solicitado como una extensión de archivo opcional. El atributo [FormatFilter] comprueba la existencia del valor de formato en RouteData y asigna el formato de respuesta al formateador adecuado cuando se crea la respuesta.

Ruta Formateador
/api/todoitems/5 Formateador de salida predeterminado
/api/todoitems/5.json Formateador JSON (si está configurado)
/api/todoitems/5.xml Formateador XML (si está configurado)

Deserialización polimórfica

Las características integradas proporcionan una gama limitada de serialización polimórfica, pero no admiten ningún tipo de deserialización. La deserialización requiere un convertidor personalizado. Consulte Deserialización polimórfica para obtener una muestra completa de deserialización polimórfica.

Recursos adicionales

ASP.NET Core MVC tiene compatibilidad para formatear datos de respuesta. Se pueden formatear los datos de respuesta con formatos específicos o en respuesta al formato solicitado por el cliente.

Vea o descargue el código de ejemplo (cómo descargarlo)

Resultados de acción específicos del formato

Algunos tipos de resultado de acción son específicos de un formato determinado, como JsonResult y ContentResult. Las acciones pueden devolver resultados con un formato determinado, independientemente de las preferencias del cliente. Por ejemplo, la devolución de JsonResult devuelve datos con formato JSON. Al devolver ContentResult o una cadena se devuelven datos de cadena con formato de texto sin formato.

No se requiere una acción para devolver ningún tipo específico. ASP.NET Core admite cualquier valor devuelto de objeto. Los resultados de acciones que devuelven objetos que no son tipos IActionResult se serializan con la implementación IOutputFormatter correspondiente. Para obtener más información, consulte Tipos de valor devuelto de acción del controlador en ASP.NET Core API web.

El método auxiliar integrado Ok devuelve datos con formato JSON:

// GET: api/authors
[HttpGet]
public ActionResult Get()
{
    return Ok(_authors.List());
}

La descarga de ejemplo devuelve la lista de autores. Con las herramientas para desarrolladores del explorador F12 o http-repl con el código anterior:

  • Se muestra el encabezado de respuesta que contiene content-type:application/json; charset=utf-8.
  • Se muestran los encabezados de solicitud. Por ejemplo, el encabezado Accept. El código anterior omite el encabezado Accept.

Para devolver datos con formato de texto sin formato, use ContentResult y el método del asistente Content:

// GET api/authors/about
[HttpGet("About")]
public ContentResult About()
{
    return Content("An API listing authors of docs.asp.net.");
}

En el código anterior, el Content-Type devuelto es text/plain. Al devolver una cadena se proporciona Content-Type de text/plain:

// GET api/authors/version
[HttpGet("version")]
public string Version()
{
    return "Version 1.0.0";
}

Para las acciones con varios tipos de valor devuelto, devuelva IActionResult. Por ejemplo, la devolución de códigos de estado HTTP diferentes en función del resultado de las operaciones realizadas.

Negociación de contenido

La negociación de contenido se produce cuando el cliente especifica un encabezado Accept. El formato predeterminado que ASP.NET Core usa es JSON. La negociación de contenido:

  • La implementa ObjectResult.
  • Se integra en los resultados de acción específicos del código de estado devueltos por los métodos auxiliares. Los métodos auxiliares de los resultados de acción se basan en ObjectResult.

Cuando se devuelve un tipo de modelo, el tipo de valor devuelto es ObjectResult.

El siguiente método de acción usa los métodos del asistente Ok y NotFound:

// GET: api/authors/search?namelike=th
[HttpGet("Search")]
public IActionResult Search(string namelike)
{
    var result = _authors.GetByNameSubstring(namelike);
    if (!result.Any())
    {
        return NotFound(namelike);
    }
    return Ok(result);
}

De forma predeterminada, ASP.NET Core admite los tipos de medios application/json, text/json y text/plain. Las herramientas como Fiddler o http-repl pueden establecer el encabezado de solicitud Accept para especificar el formato de devolución. Cuando el encabezado Accept contiene un tipo que el servidor admite, se devuelve ese tipo. En la sección siguiente se muestra cómo agregar otros formateadores.

Las acciones del controlador pueden devolver POCO (objetos CLR antiguos sin formato). Cuando se devuelve un objeto POCO, el tiempo de ejecución crea automáticamente un ObjectResult que encapsula al objeto. El cliente obtiene el objeto serializado con formato. Si el objeto que se va a devolver es null, se devuelve una respuesta 204 No Content.

Devolución de un tipo de objeto:

// GET api/authors/RickAndMSFT
[HttpGet("{alias}")]
public Author Get(string alias)
{
    return _authors.GetByAlias(alias);
}

En el código anterior, una solicitud de un alias de autor válido devuelve una respuesta 200 OK con los datos del autor. Una solicitud de un alias no válido devuelve una respuesta 204 No Content.

El encabezado Accept

La negociación de contenido se lleva a cabo cuando en la solicitud aparece un encabezado Accept. Cuando una solicitud contiene un encabezado Accept, ASP.NET Core:

  • Enumera los tipos de medios del encabezado Accept en orden de preferencia.
  • Intenta encontrar un formateador que pueda generar una respuesta en uno de los formatos especificados.

Si no se encuentra ningún formateador que pueda satisfacer la solicitud del cliente, ASP.NET Core:

Si no se ha configurado ningún formateador para el formato solicitado, se usará el primer formateador que pueda dar formato al objeto. Si no aparece ningún encabezado Accept en la solicitud:

  • El primer formateador que puede controlar el objeto se usa para serializar la respuesta.
  • No tiene lugar ninguna negociación. El servidor está determinando el formato que se va a devolver.

Si el encabezado Accept contiene */*, el encabezado se omite a menos que RespectBrowserAcceptHeader esté establecido en true en MvcOptions.

Exploradores y negociación de contenido

A diferencia de los clientes de API típicos, los exploradores web proporcionan encabezados Accept. Los navegadores web especifican muchos formatos, incluidos los comodines. De forma predeterminada, cuando el marco detecta que la solicitud procede de un explorador:

  • El encabezado Accept se omite.
  • El contenido se devuelve en JSON, a menos que se configure de otra manera.

Esto proporciona una experiencia más coherente entre los exploradores al consumir las API.

Para configurar una aplicación para que respete los encabezados de aceptación del explorador, establezca RespectBrowserAcceptHeader en true:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.RespectBrowserAcceptHeader = true; // false by default
    });
}

Configuración de formateadores

Las aplicaciones que necesitan admitir formatos adicionales pueden agregar los paquetes NuGet adecuados y configurar la compatibilidad. Hay formateadores independientes para la entrada y la salida. El enlace de modelos usa formateadores de entrada. Los formateadores de salida se usan para dar formato a las respuestas. Para obtener información sobre la creación de un formateador personalizado, vea Formateadores personalizados.

Adición de compatibilidad con el formato XML

Los formateadores XML que se implementan mediante XmlSerializer se configuran llamando a AddXmlSerializerFormatters:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddXmlSerializerFormatters();
}

El código anterior serializa los resultados mediante XmlSerializer.

Cuando se usa el código anterior, los métodos de controlador devuelven el formato adecuado en función del encabezado Accept de la solicitud.

Configurar formateadores basados en System.Text.Json

Las características para los formateadores basados en System.Text.Json pueden configurarse mediante Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions. El formato predeterminado es camelCase. El código resaltado siguiente establece el formato PascalCase:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddJsonOptions(options =>
            options.JsonSerializerOptions.PropertyNamingPolicy = null);
}

El método de acción siguiente llama ControllerBase.Problem a para crear una ProblemDetails respuesta:

[HttpGet("error")]
public IActionResult GetError()
{
    return Problem("Something went wrong!");
}

Con el código anterior:

  • https://localhost:5001/WeatherForecast/temperature devuelve PascalCase.
  • https://localhost:5001/WeatherForecast/error devuelve camelCase. La respuesta de error siempre es camelCase, incluso cuando la aplicación establece el formato en PascalCase. ProblemDetails sigue a RFC 7807, que especifica minúsculas

El código siguiente establece PascalCase y agrega un convertidor personalizado:

services.AddControllers().AddJsonOptions(options =>
{
    // Use the default property (Pascal) casing.
    options.JsonSerializerOptions.PropertyNamingPolicy = null;

    // Configure a custom converter.
    options.JsonSerializerOptions.Converters.Add(new MyCustomJsonConverter());
});

Las opciones de serialización de salida se pueden configurar para cada acción mediante JsonResult. Por ejemplo:

public IActionResult Get()
{
    return Json(model, new JsonSerializerOptions
    {
        WriteIndented = true,
    });
}

Adición de compatibilidad con el formato JSON basado en Newtonsoft.Json

Los formateadores JSON predeterminados se basan en System.Text.Json. LA compatibilidad para los formateadores basados en Newtonsoft.Json y sus características está disponible al instalar el paquete Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet y configurarlo en Startup.ConfigureServices.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson();
}

En el código anterior, la llamada a configura AddNewtonsoftJson las siguientes características de API web, MVC y Razor Pages para usar Newtonsoft.Json:

Es posible que algunas características no funcionen bien con formateadores basados en System.Text.Json y requieren una referencia a los formateadores basados en Newtonsoft.Json. Siga usando los formateadores basados en Newtonsoft.Json si la aplicación:

  • Usa atributos Newtonsoft.Json. Por ejemplo, [JsonProperty] o [JsonIgnore].
  • Proporciona la configuración de la serialización.
  • Se basa en las características que Newtonsoft.Json proporciona.

Las características para los formateadores basados en Newtonsoft.Json pueden configurarse mediante Microsoft.AspNetCore.Mvc.MvcNewtonsoftJsonOptions.SerializerSettings:

services.AddControllers().AddNewtonsoftJson(options =>
{
    // Use the default property (Pascal) casing
    options.SerializerSettings.ContractResolver = new DefaultContractResolver();

    // Configure a custom converter
    options.SerializerSettings.Converters.Add(new MyCustomJsonConverter());
});

Las opciones de serialización de salida se pueden configurar para cada acción mediante JsonResult. Por ejemplo:

public IActionResult Get()
{
    return Json(model, new JsonSerializerSettings
    {
        Formatting = Formatting.Indented,
    });
}

Especificación de un formato

Para restringir los formatos de respuesta, aplique el filtro [Produces]. Al igual que la mayoría de los filtros, [Produces] puede aplicarse a la acción, el controlador o el ámbito global:

[ApiController]
[Route("[controller]")]
[Produces("application/json")]
public class WeatherForecastController : ControllerBase
{

El filtro [Produces] anterior:

  • Obliga a todas las acciones dentro del controlador a devolver JSrespuestas con formato ON para poCOs (objetos CLR antiguos sin formato) o ObjectResult sus tipos derivados.
  • Si se configuran otros formateadores y el cliente especifica un formato diferente, se devuelve JSON.

Para más información, consulte Filtros.

Formateadores de casos especiales

Algunos casos especiales se implementan mediante formateadores integrados. De forma predeterminada, los tipos de valor devueltos string se formatean como texto/sin formato (texto/html si se solicita a través del encabezado Accept). Este comportamiento se puede quitar mediante la eliminación de StringOutputFormatter. Los formateadores se quitan en el método ConfigureServices. Las acciones que tienen un tipo de valor devuelto de objeto de modelo devuelven 204 No Content al devolver null. Este comportamiento se puede quitar mediante la eliminación de HttpNoContentOutputFormatter. El código siguiente quita StringOutputFormatter y HttpNoContentOutputFormatter.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        // requires using Microsoft.AspNetCore.Mvc.Formatters;
        options.OutputFormatters.RemoveType<StringOutputFormatter>();
        options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
    });
}

Sin StringOutputFormatter, el formateador de JSON integrado aplica formato a los tipos devueltos string. Si se quita el formateador JSON integrado y está disponible un formateador XML, el formateador XML aplica formato a los tipos devueltos string. De lo contrario, los tipos devueltos string devuelven 406 Not Acceptable.

Sin HttpNoContentOutputFormatter, se da formato a los objetos nulos mediante el formateador configurado. Por ejemplo:

  • El formateador JSON devuelve una respuesta con un cuerpo de null.
  • El formateador XML devuelve un elemento XML vacío con el atributo xsi:nil="true" establecido.

Asignaciones de direcciones URL de formato de respuesta

Los clientes pueden solicitar un formato determinado como parte de la dirección URL, por ejemplo:

  • En la cadena de consulta o en una parte de la ruta de acceso.
  • Mediante el uso de una extensión de archivo específica del formato como .xml o .json.

La asignación de la ruta de acceso de la solicitud debe especificarse en la ruta que use la API. Por ejemplo:

[Route("api/[controller]")]
[ApiController]
[FormatFilter]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}.{format?}")]
    public Product Get(int id)
    {

Esta ruta anterior permite especificar el formato solicitado como una extensión de archivo opcional. El atributo [FormatFilter] comprueba la existencia del valor de formato en RouteData y asigna el formato de respuesta al formateador adecuado cuando se crea la respuesta.

Ruta Formateador
/api/products/5 Formateador de salida predeterminado
/api/products/5.json Formateador JSON (si está configurado)
/api/products/5.xml Formateador XML (si está configurado)

ASP.NET Core MVC admite el formato de los datos de respuesta, mediante formatos especificados o en respuesta a la solicitud de un cliente.

Resultados de acción específicos del formato

Algunos tipos de resultado de acción son específicos de un formato determinado, como JsonResult y ContentResult. Las acciones pueden devolver resultados que siempre usan un formato especificado, ignorando la solicitud de un cliente para un formato diferente. Por ejemplo, devolver JsonResult devuelve JSdatos con formato ON y devuelve ContentResult datos de cadena con formato de texto sin formato.

No se requiere una acción para devolver ningún tipo específico. ASP.NET Core admite cualquier valor devuelto de objeto. Los resultados de acciones que devuelven objetos que no son tipos IActionResult se serializan con la implementación IOutputFormatter correspondiente. Para obtener más información, consulte Tipos de valor devuelto de acción del controlador en ASP.NET Core API web.

El método auxiliar integrado ControllerBase.Ok devuelve datos con formato JSON:

[HttpGet]
public IActionResult Get()
    => Ok(_todoItemStore.GetList());

El código de ejemplo devuelve una lista de elementos de tareas pendientes. Con las herramientas para desarrolladores del explorador F12 o http-repl con el código anterior se muestra:

  • Se muestra el encabezado de respuesta que contiene content-type:application/json; charset=utf-8.
  • Encabezados de solicitud. Por ejemplo, el encabezado Accept. El código anterior omite el encabezado Accept.

Para devolver datos con formato de texto sin formato, use ContentResult y el método del asistente Content:

[HttpGet("Version")]
public ContentResult GetVersion()
    => Content("v1.0.0");

En el código anterior, el Content-Type devuelto es text/plain.

Para las acciones con varios tipos de valor devuelto, devuelva IActionResult. Por ejemplo, la devolución de códigos de estado HTTP diferentes en función del resultado de las operaciones realizadas.

Negociación de contenido

La negociación de contenido se produce cuando el cliente especifica un encabezado Accept. El formato predeterminado que ASP.NET Core usa es JSON. La negociación de contenido:

  • La implementa ObjectResult.
  • Se integra en los resultados de acción específicos del código de estado devueltos por los métodos auxiliares. Los métodos auxiliares de los resultados de acción se basan en ObjectResult.

Cuando se devuelve un tipo de modelo, el tipo de valor devuelto es ObjectResult.

El siguiente método de acción usa los métodos del asistente Ok y NotFound:

[HttpGet("{id:long}")]
public IActionResult GetById(long id)
{
    var todo = _todoItemStore.GetById(id);

    if (todo is null)
    {
        return NotFound();
    }

    return Ok(todo);
}

De forma predeterminada, ASP.NET Core admite los siguientes tipos de medios:

  • application/json
  • text/json
  • text/plain

Las herramientas como Fiddler o http-repl pueden establecer el encabezado de solicitud Accept para especificar el formato de devolución. Cuando el encabezado Accept contiene un tipo que el servidor admite, se devuelve ese tipo. En la sección siguiente se muestra cómo agregar otros formateadores.

Las acciones del controlador pueden devolver POCO (objetos CLR antiguos sin formato). Cuando se devuelve un objeto POCO, el tiempo de ejecución crea automáticamente un ObjectResult que encapsula al objeto. El cliente obtiene el objeto serializado con formato. Si el objeto que se va a devolver es null, se devuelve una respuesta 204 No Content.

En el ejemplo siguiente se devuelve un tipo de objeto:

[HttpGet("{id:long}")]
public TodoItem? GetById(long id)
    => _todoItemStore.GetById(id);

En el código anterior, una solicitud de un elemento todo válido devuelve una 200 OK respuesta. Una solicitud de un elemento de tareas inválido devuelve una respuesta 204 No Content.

El encabezado Accept

La negociación de contenido se lleva a cabo cuando en la solicitud aparece un encabezado Accept. Cuando una solicitud contiene un encabezado Accept, ASP.NET Core:

  • Enumera los tipos de medios del encabezado Accept en orden de preferencia.
  • Intenta encontrar un formateador que pueda generar una respuesta en uno de los formatos especificados.

Si no se encuentra ningún formateador que pueda satisfacer la solicitud del cliente, ASP.NET Core:

Si no se ha configurado ningún formateador para el formato solicitado, se usará el primer formateador que pueda dar formato al objeto. Si no aparece ningún encabezado Accept en la solicitud:

  • El primer formateador que puede controlar el objeto se usa para serializar la respuesta.
  • No tiene lugar ninguna negociación. El servidor está determinando el formato que se va a devolver.

Si el encabezado Accept contiene */*, el encabezado se omite a menos que RespectBrowserAcceptHeader esté establecido en true en MvcOptions.

Exploradores y negociación de contenido

A diferencia de los clientes de API típicos, los exploradores web proporcionan encabezados Accept. Los navegadores web especifican muchos formatos, incluidos los comodines. De forma predeterminada, cuando el marco detecta que la solicitud procede de un explorador:

  • El encabezado Accept se omite.
  • El contenido se devuelve en JSON, a menos que se configure de otra manera.

Esto proporciona una experiencia más coherente entre los exploradores al consumir las API.

Para configurar una aplicación para que respete las cabeceras de aceptación del navegador, establezca la propiedad RespectBrowserAcceptHeader en true:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true;
});

Configuración de formateadores

Las aplicaciones que necesitan admitir formatos adicionales pueden agregar los paquetes NuGet adecuados y configurar la compatibilidad. Hay formateadores independientes para la entrada y la salida. El enlace de modelos usa formateadores de entrada. Los formateadores de salida se usan para dar formato a las respuestas. Para obtener información sobre la creación de un formateador personalizado, vea Formateadores personalizados.

Adición de compatibilidad con el formato XML

Para configurar formateadores XML implementados mediante XmlSerializer, llame a AddXmlSerializerFormatters:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddXmlSerializerFormatters();

Cuando se usa el código anterior, los métodos de controlador devuelven el formato adecuado en función del encabezado Accept de la solicitud.

Configurar System.Text.Json formateadores basados en

Para configurar las características de los formateadores basados en System.Text.Json, use Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions. El código resaltado siguiente configura el formato PascalCase en lugar del formato camelCase predeterminado:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
    });

Para configurar las opciones de serialización de salida para acciones específicas, use JsonResult. Por ejemplo:

[HttpGet]
public IActionResult Get() 
    => new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerOptions { PropertyNamingPolicy = null });

Se ha agregado compatibilidad con formato JSON basado en Newtonsoft.Json

Los formateadores JSON predeterminados usan System.Text.Json. Para usar los Newtonsoft.Jsonformateadores basados en , instale el Microsoft.AspNetCore.Mvc.NewtonsoftJson paquete NuGet y configúrelo en Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddNewtonsoftJson();

En el código anterior, la llamada a configura AddNewtonsoftJson las siguientes características de API web, MVC y Razor Pages para usar Newtonsoft.Json:

Es posible que algunas características no funcionen bien con formateadores basados en System.Text.Json y requieren una referencia a los formateadores basados en Newtonsoft.Json. Siga usando los formateadores basados en Newtonsoft.Json si la aplicación:

  • Usa atributos Newtonsoft.Json. Por ejemplo, [JsonProperty] o [JsonIgnore].
  • Proporciona la configuración de la serialización.
  • Se basa en las características que Newtonsoft.Json proporciona.

Para configurar las características de los formateadores basados en Newtonsoft.Json, use SerializerSettings:

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

Para configurar las opciones de serialización de salida para acciones específicas, use JsonResult. Por ejemplo:

[HttpGet]
public IActionResult GetNewtonsoftJson()
    => new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() });

Formato ProblemDetails y ValidationProblemDetails respuestas

El método de acción siguiente llama ControllerBase.Problem a para crear una ProblemDetails respuesta:

[HttpGet("Error")]
public IActionResult GetError()
    => Problem("Something went wrong.");

Una ProblemDetails respuesta siempre es camelCase, incluso cuando la aplicación establece el formato en PascalCase. ProblemDetails sigue a RFC 7807, que especifica minúsculas.

Cuando el [ApiController] atributo se aplica a una clase de controlador, el controlador crea una respuesta cuando se produce un ValidationProblemDetails error en la validación del modelo. Esta respuesta incluye un diccionario que usa los nombres de propiedad del modelo como claves de error, sin cambios. Por ejemplo, el siguiente modelo incluye una sola propiedad que requiere validación:

public class SampleModel
{
    [Range(1, 10)]
    public int Value { get; set; }
}

De forma predeterminada, la ValidationProblemDetails respuesta devuelta cuando la Value propiedad no es válida usa una clave de error de Value, como se muestra en el ejemplo siguiente:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-00000000000000000000000000000000-000000000000000-00",
  "errors": {
    "Value": [
      "The field Value must be between 1 and 10."
    ]
  }
}

Para dar formato a los nombres de propiedad usados como claves de error, agregue una implementación de IMetadataDetailsProvider a la MvcOptions.ModelMetadataDetailsProviders colección. En el ejemplo siguiente se agrega una implementación basada en System.Text.Json, SystemTextJsonValidationMetadataProvider, que da formato a los nombres de propiedad como camelCase de forma predeterminada:

builder.Services.AddControllers();

builder.Services.Configure<MvcOptions>(options =>
{
    options.ModelMetadataDetailsProviders.Add(
        new SystemTextJsonValidationMetadataProvider());
});

SystemTextJsonValidationMetadataProvider también acepta una implementación de JsonNamingPolicy en su constructor, que especifica una directiva de nomenclatura personalizada para dar formato a los nombres de propiedad.

Para establecer un nombre personalizado para una propiedad dentro de un modelo, use el atributo [JsonPropertyName] en la propiedad:

public class SampleModel
{
    [Range(1, 10)]
    [JsonPropertyName("sampleValue")]
    public int Value { get; set; }
}

De forma predeterminada, la ValidationProblemDetails respuesta devuelta cuando la Value propiedad no es válida usa una clave de error de sampleValue, como se muestra en el ejemplo siguiente:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-00000000000000000000000000000000-000000000000000-00",
  "errors": {
    "sampleValue": [
      "The field Value must be between 1 and 10."
    ]
  }
}

Para dar formato a la ValidationProblemDetails respuesta mediante Newtonsoft.Json, use NewtonsoftJsonValidationMetadataProvider:

builder.Services.AddControllers()
    .AddNewtonsoftJson();

builder.Services.Configure<MvcOptions>(options =>
{
    options.ModelMetadataDetailsProviders.Add(
        new NewtonsoftJsonValidationMetadataProvider());
});

De forma predeterminada, NewtonsoftJsonValidationMetadataProvider da formato a los nombres de propiedad como camelCase. NewtonsoftJsonValidationMetadataProvider también acepta una implementación de NamingPolicy en su constructor, que especifica una directiva de nomenclatura personalizada para dar formato a los nombres de propiedad. Para establecer un nombre personalizado para una propiedad dentro de un modelo, use el [JsonProperty] atributo .

Especificación de un formato

Para restringir los formatos de respuesta, aplique el filtro [Produces]. Al igual que la mayoría de los filtros, [Produces] puede aplicarse a la acción, el controlador o el ámbito global:

[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class TodoItemsController : ControllerBase

El filtro [Produces] anterior:

  • Obliga a todas las acciones dentro del controlador a devolver JSrespuestas con formato ON para poCOs (objetos CLR antiguos sin formato) o ObjectResult sus tipos derivados.
  • Devuelve JSrespuestas con formato ON incluso si se configuran otros formateadores y el cliente especifica un formato diferente.

Para más información, consulte Filtros.

Formateadores de casos especiales

Algunos casos especiales se implementan mediante formateadores integrados. De forma predeterminada, los tipos de valor devueltos string se formatean como texto/sin formato (texto/html si se solicita a través del encabezado Accept). Este comportamiento se puede quitar mediante la eliminación de StringOutputFormatter. Los formateadores se quitan en el método Program.cs. Las acciones que tienen un tipo de valor devuelto de objeto de modelo devuelven 204 No Content al devolver null. Este comportamiento se puede quitar mediante la eliminación de HttpNoContentOutputFormatter. El código siguiente quita StringOutputFormatter y HttpNoContentOutputFormatter.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    // using Microsoft.AspNetCore.Mvc.Formatters;
    options.OutputFormatters.RemoveType<StringOutputFormatter>();
    options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
});

Sin StringOutputFormatter, el formateador de JSON integrado aplica formato a los tipos devueltos string. Si se quita el formateador JSON integrado y está disponible un formateador XML, el formateador XML aplica formato a los tipos devueltos string. De lo contrario, los tipos devueltos string devuelven 406 Not Acceptable.

Sin HttpNoContentOutputFormatter, se da formato a los objetos nulos mediante el formateador configurado. Por ejemplo:

  • El formateador JSON devuelve una respuesta con un cuerpo de null.
  • El formateador XML devuelve un elemento XML vacío con el atributo xsi:nil="true" establecido.

Asignaciones de direcciones URL de formato de respuesta

Los clientes pueden solicitar un formato determinado como parte de la dirección URL, por ejemplo:

  • En la cadena de consulta o en una parte de la ruta de acceso.
  • Mediante el uso de una extensión de archivo específica del formato como .xml o .json.

La asignación de la ruta de acceso de la solicitud debe especificarse en la ruta que use la API. Por ejemplo:

[ApiController]
[Route("api/[controller]")]
[FormatFilter]
public class TodoItemsController : ControllerBase
{
    private readonly TodoItemStore _todoItemStore;

    public TodoItemsController(TodoItemStore todoItemStore)
        => _todoItemStore = todoItemStore;

    [HttpGet("{id:long}.{format?}")]
    public TodoItem? GetById(long id)
        => _todoItemStore.GetById(id);

Esta ruta anterior permite especificar el formato solicitado como una extensión de archivo opcional. El atributo [FormatFilter] comprueba la existencia del valor de formato en RouteData y asigna el formato de respuesta al formateador adecuado cuando se crea la respuesta.

Ruta Formateador
/api/todoitems/5 Formateador de salida predeterminado
/api/todoitems/5.json Formateador JSON (si está configurado)
/api/todoitems/5.xml Formateador XML (si está configurado)

Deserialización polimórfica

Las características integradas proporcionan una gama limitada de serialización polimórfica, pero no admiten ningún tipo de deserialización. La deserialización requiere un convertidor personalizado. Consulte Deserialización polimórfica para obtener una muestra completa de deserialización polimórfica.

Recursos adicionales