Compartir a través de


Formato de 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 acciones específicos para el 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 datos con formato JSON y devolver ContentResult datos de texto sin formato.

No se necesita realizar ninguna acción para devolver un 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 devolución de acción del controlador en API web de ASP.NET Core.

De forma predeterminada, 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. Al usar las herramientas de desarrollo del navegador F12 o http-repl con el código anterior se muestra:

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

Para devolver datos en texto plano, use ContentResult y el 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:

  • Implementado por 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 curl 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 objetos POCO (Plain Old CLR Objects). 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 formateado. 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 la lista de tareas pendientes 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:

  • Devuelve 406 Not Acceptable si MvcOptions.ReturnHttpNotAcceptable se establece en true, o -
  • Intenta encontrar el primer formateador que sea capaz de generar una respuesta.

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 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 mediante el primer formateador de salida registrado que puede controlar el tipo de respuesta, a menos que se configure lo contrario.

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. La vinculación de modelos utiliza formatos 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 formateadores basados en System.Text.Json

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 siguiente método de acción llama ControllerBase.Problem para crear una respuesta de ProblemDetails.

[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 la RFC 7807, que especifica el uso de 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
        });

Adición de soporte para formato JSON basado en Newtonsoft.Json

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

var builder = WebApplication.CreateBuilder(args);

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

En el código anterior, la llamada a AddNewtonsoftJson configura las siguientes funcionalidades de la API web, MVC y Razor Páginas 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].
  • Personaliza 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 respuestas con formato JSON para POCOs (Plain Old CLR Objects, objetos CLR sencillos y clásicos) o ObjectResult, y sus tipos derivados.
  • Devuelve respuestas con formato JSON 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 son eliminados en Program.cs. Las acciones que tienen un tipo de retorno de objeto de modelo devuelven 204 No Content cuando retornan 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 da formato a los tipos de retorno 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 de retorno 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.

Mapeos de URLs del 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.
  • Mediante el uso de una extensión de archivo específica del formato como .xml o .json.

La asignación desde la ruta de acceso de la solicitud debe especificarse en la ruta que utiliza 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.

Route Formatter
/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. Devolver ContentResult o una cadena retorna datos 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 valores devueltos de acciones del controlador en la API web de ASP.NET Core.

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. Utilizando las herramientas de desarrollador del navegador F12 o http-repl con el código mencionado anteriormente:

  • 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 en texto plano, use ContentResult y el 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:

  • Implementado por 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 objetos POCO (Plain Old CLR Objects). 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 formateado. Si el objeto que se va a devolver es null, se devuelve una respuesta 204 No Content.

Devolver un objeto tipo:

// 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:

  • Devuelve 406 Not Acceptable si MvcOptions.ReturnHttpNotAcceptable se establece en true, o -
  • Intenta encontrar el primer formateador que sea capaz de generar una respuesta.

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 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 mediante el primer formateador de salida registrado que puede controlar el tipo de respuesta, a menos que se configure lo contrario.

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. La vinculación de modelos utiliza formatos 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 siguiente método de acción llama a ControllerBase.Problem para crear una respuesta ProblemDetails.

[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 la RFC 7807, que especifica en 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,
    });
}

Agregar compatibilidad con el formato JSON basado en Newtonsoft.Json

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

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

En el código anterior, la llamada a AddNewtonsoftJson configura las siguientes funcionalidades de la API web, MVC y Razor Páginas 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].
  • Personaliza 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 respuestas con formato JSON para POCOs (Plain Old CLR Objects, objetos CLR sencillos y clásicos) o ObjectResult, y 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. Se eliminan formateadores en el método ConfigureServices. Las acciones que tienen un tipo de retorno de objeto de modelo devuelven 204 No Content cuando retornan 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 da formato a los tipos de retorno 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 de retorno 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.

Mapeos de URLs del 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.
  • Mediante el uso de una extensión de archivo específica del formato como .xml o .json.

La asignación desde la ruta de acceso de la solicitud debe especificarse en la ruta que utiliza 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.

Route Formatter
/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 acciones específicos para el 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 datos con formato JSON y devolver ContentResult datos de texto sin formato.

No se necesita realizar ninguna acción para devolver un 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 devolución de acción del controlador en API web de ASP.NET Core.

De forma predeterminada, 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. Al usar las herramientas de desarrollo del navegador F12 o http-repl con el código anterior se muestra:

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

Para devolver datos en texto plano, use ContentResult y el 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:

  • Implementado por 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 objetos POCO (Plain Old CLR Objects). 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 formateado. 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 la lista de tareas pendientes 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:

  • Devuelve 406 Not Acceptable si MvcOptions.ReturnHttpNotAcceptable se establece en true, o -
  • Intenta encontrar el primer formateador que sea capaz de generar una respuesta.

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 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 mediante el primer formateador de salida registrado que puede controlar el tipo de respuesta, a menos que se configure lo contrario.

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. La vinculación de modelos utiliza formatos 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 formateadores basados en System.Text.Json

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 });

Adición de soporte para formato JSON basado en Newtonsoft.Json

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

var builder = WebApplication.CreateBuilder(args);

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

En el código anterior, la llamada a AddNewtonsoftJson configura las siguientes funcionalidades de la API web, MVC y Razor Páginas 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].
  • Personaliza 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() });

Formatear las respuestas ProblemDetails y ValidationProblemDetails

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

[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 la 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; }
}

La respuesta ValidationProblemDetails devuelta para el modelo anterior cuando la propiedad Value 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 respuestas con formato JSON para POCOs (Plain Old CLR Objects, objetos CLR sencillos y clásicos) o ObjectResult, y sus tipos derivados.
  • Devuelve respuestas con formato JSON 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 son eliminados en Program.cs. Las acciones que tienen un tipo de retorno de objeto de modelo devuelven 204 No Content cuando retornan 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 da formato a los tipos de retorno 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 de retorno 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.

Mapeos de URLs del 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.
  • Mediante el uso de una extensión de archivo específica del formato como .xml o .json.

La asignación desde la ruta de acceso de la solicitud debe especificarse en la ruta que utiliza 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.

Route Formatter
/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