una recorrer objeto net leer deserializar crear convertir como cadena asp c# json asp.net-core asp.net-core-webapi

c# - recorrer - ASP.NET Core devuelve JSON con código de estado



leer json en c# (9)

Estoy buscando la forma correcta de devolver JSON con un código de estado HTTP en mi controlador de API web .NET Core. Solía ​​usarlo así:

public IHttpActionResult GetResourceData() { return this.Content(HttpStatusCode.OK, new { response = "Hello"}); }

Esto estaba en una aplicación 4.6 MVC, pero ahora con .NET Core no parece tener este IHttpActionResult Tengo ActionResult y lo uso de esta manera:

public ActionResult IsAuthenticated() { return Ok(Json("123")); }

Pero la respuesta del servidor es extraña, como en la imagen a continuación:

Solo quiero que el controlador de API web devuelva JSON con un código de estado HTTP como lo hice en Web API 2.


¡Las respuestas impresionantes que encontré aquí y también probé esta declaración de retorno, vea StatusCode(whatever code you wish) y funcionó!

return Ok(new { Token = new JwtSecurityTokenHandler().WriteToken(token), Expiration = token.ValidTo, username = user.FullName, StatusCode = StatusCode(200) });


Con ASP.NET Core 2.0 , la forma ideal de devolver objetos desde la Web API (que está unificada con MVC y utiliza el mismo Controller clase base) es

public IActionResult Get() { return new OkObjectResult(new Item { Id = 123, Name = "Hero" }); }

Darse cuenta de

  1. Regresa con un código de estado de 200 OK (es un tipo Ok de ObjectResult )
  2. Hace negociación de contenido, es decir, regresará en función del encabezado Accept en la solicitud. Si Accept: application/xml se envía en la solicitud, volverá como XML . Si no se envía nada, JSON es el predeterminado.

Si necesita enviar con un código de estado específico , use ObjectResult o StatusCode en StatusCode lugar. Ambos hacen lo mismo y admiten la negociación de contenido.

return new ObjectResult(new Item { Id = 123, Name = "Hero" }) { StatusCode = 200 }; return StatusCode( 200, new Item { Id = 123, Name = "Hero" });

Si desea regresar específicamente como JSON , hay dos formas

//GET http://example.com/api/test/asjson [HttpGet("AsJson")] public JsonResult GetAsJson() { return Json(new Item { Id = 123, Name = "Hero" }); } //GET http://example.com/api/test/withproduces [HttpGet("WithProduces")] [Produces("application/json")] public Item GetWithProduces() { return new Item { Id = 123, Name = "Hero" }; }

Darse cuenta de

  1. Ambos hacen cumplir JSON de dos maneras diferentes.
  2. Ambos ignoran la negociación de contenido.
  3. El primer método impone JSON con un serializador específico Json(object) .
  4. El segundo método hace lo mismo al usar el atributo ResultFilter Produces() (que es un ResultFilter ) con contentType = application/json

Lea más sobre ellos en los documentos oficiales . Aprende sobre los filtros aquí .

La clase de modelo simple que se utiliza en las muestras.

public class Item { public int Id { get; set; } public string Name { get; set; } }


Consulte el código a continuación, puede administrar múltiples códigos de estado con diferentes tipos JSON

public async Task<HttpResponseMessage> GetAsync() { try { using (var entities = new DbEntities()) { var resourceModelList = entities.Resources.Select(r=> new ResourceModel{Build Your Resource Model}).ToList(); if (resourceModelList.Count == 0) { return this.Request.CreateResponse<string>(HttpStatusCode.NotFound, "No resources found."); } return this.Request.CreateResponse<List<ResourceModel>>(HttpStatusCode.OK, resourceModelList, "application/json"); } } catch (Exception ex) { return this.Request.CreateResponse<string>(HttpStatusCode.InternalServerError, "Something went wrong."); } }


En lugar de usar códigos de estado 404/201 usando enum

public async Task<IActionResult> Login(string email, string password) { if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password)) { return StatusCode((int)HttpStatusCode.BadRequest, Json("email or password is null")); } var user = await _userManager.FindByEmailAsync(email); if (user == null) { return StatusCode((int)HttpStatusCode.BadRequest, Json("Invalid Login and/or password")); } var passwordSignInResult = await _signInManager.PasswordSignInAsync(user, password, isPersistent: true, lockoutOnFailure: false); if (!passwordSignInResult.Succeeded) { return StatusCode((int)HttpStatusCode.BadRequest, Json("Invalid Login and/or password")); } return StatusCode((int)HttpStatusCode.OK, Json("Sucess !!!")); }


Esta es mi solución más fácil:

public IActionResult InfoTag() { return Ok(new {name = "Fabio", age = 42, gender = "M"}); }

o

public IActionResult InfoTag() { return Json(new {name = "Fabio", age = 42, gender = "M"}); }


La forma más fácil que se me ocurrió es:

var result = new Item { Id = 123, Name = "Hero" }; return new JsonResult(result) { StatusCode = StatusCodes.Status201Created // Status code here };


La versión más básica que responde con un JsonResult es:

// GET: api/authors [HttpGet] public JsonResult Get() { return Json(_authorRepository.List()); }

Sin embargo, esto no ayudará con su problema porque no puede manejar explícitamente su propio código de respuesta.

La forma de obtener control sobre los resultados de estado es si necesita devolver un ActionResult que es donde puede aprovechar el tipo StatusCodeResult .

por ejemplo:

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

Tenga en cuenta que ambos ejemplos anteriores provienen de una excelente guía disponible de la documentación de Microsoft: Formateo de datos de respuesta

Cosas extra

El problema que encuentro con bastante frecuencia es que quería un control más granular sobre mi WebAPI en lugar de simplemente ir con la configuración predeterminada de la plantilla "Nuevo proyecto" en VS.

Asegurémonos de tener algunos de los conceptos básicos ...

Paso 1: configura tu servicio

Para que su ASP.NET Core WebAPI responda con un objeto serializado JSON junto con el control total del código de estado, debe comenzar asegurándose de haber incluido el servicio AddMvc() en su método ConfigureServices que generalmente se encuentra en Startup.cs .

Es importante tener en cuenta que AddMvc() incluirá automáticamente el formateador de entrada / salida para JSON junto con la respuesta a otros tipos de solicitud.

Si su proyecto requiere control total y desea definir estrictamente sus servicios, por ejemplo, cómo se comportará su WebAPI con varios tipos de solicitud, incluida la application/json y no responderá a otros tipos de solicitud (como una solicitud estándar del navegador), puede definirla manualmente con el siguiente código:

public void ConfigureServices(IServiceCollection services) { // Build a customized MVC implementation, without using the default AddMvc(), instead use AddMvcCore(). // https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc/MvcServiceCollectionExtensions.cs services .AddMvcCore(options => { options.RequireHttpsPermanent = true; // does not affect api requests options.RespectBrowserAcceptHeader = true; // false by default //options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>(); //remove these two below, but added so you know where to place them... options.OutputFormatters.Add(new YourCustomOutputFormatter()); options.InputFormatters.Add(new YourCustomInputFormatter()); }) //.AddApiExplorer() //.AddAuthorization() .AddFormatterMappings() //.AddCacheTagHelper() //.AddDataAnnotations() //.AddCors() .AddJsonFormatters(); // JSON, or you can build your own custom one (above) }

Notará que también he incluido una forma de agregar sus propios formateadores de entrada / salida personalizados, en caso de que desee responder a otro formato de serialización (protobuf, ahorro, etc.).

El fragmento de código anterior es principalmente un duplicado del método AddMvc() . Sin embargo, estamos implementando cada servicio "predeterminado" por nuestra cuenta definiendo todos y cada uno de los servicios en lugar de ir con el preenviado con la plantilla. He agregado el enlace del repositorio en el bloque de código, o puede consultar AddMvc() desde el repositorio de GitHub. .

Tenga en cuenta que hay algunas guías que tratarán de resolver esto "deshaciendo" los valores predeterminados, en lugar de simplemente no implementarlo en primer lugar ... Si considera que ahora estamos trabajando con Open Source, este es un trabajo redundante , mal código y, francamente, un viejo hábito que desaparecerá pronto.

Paso 2: crear un controlador

Te voy a mostrar una muy sencilla para resolver tu pregunta.

public class FooController { [HttpPost] public async Task<IActionResult> Create([FromBody] Object item) { if (item == null) return BadRequest(); var newItem = new Object(); // create the object to return if (newItem != null) return Ok(newItem); else return NotFound(); } }

Paso 3: verifique su tipo de Content-Type y Accept

Debe asegurarse de que sus Content-Type y Accept en su solicitud estén configurados correctamente. En su caso (JSON), querrá configurarlo para que sea application/json .

Si desea que su WebAPI responda como JSON de forma predeterminada, independientemente de lo que especifique el encabezado de la solicitud, puede hacerlo de dos maneras .

Forma 1 Como se muestra en el artículo que recomendé anteriormente ( Formatear datos de respuesta ), podría forzar un formato particular en el nivel Controlador / Acción. Personalmente no me gusta este enfoque ... pero aquí está para completar:

Forzar un formato particular Si desea restringir los formatos de respuesta para una acción específica, puede aplicar el filtro [Produce]. El filtro [Produce] especifica los formatos de respuesta para una acción específica (o controlador). Como la mayoría de los filtros, esto se puede aplicar en la acción, el controlador o el alcance global.

[Produces("application/json")] public class AuthorsController

El filtro [Produces] obligará a todas las acciones dentro del AuthorsController a devolver respuestas con formato JSON, incluso si se configuraron otros formateadores para la aplicación y el cliente proporcionó un encabezado Accept solicita un formato diferente y disponible.

Modo 2 Mi método preferido es que WebAPI responda a todas las solicitudes con el formato solicitado. Sin embargo, en el caso de que no acepte el formato solicitado, recurra a un valor predeterminado (es decir, JSON)

Primero, deberá registrar eso en sus opciones (necesitamos modificar el comportamiento predeterminado, como se señaló anteriormente)

options.RespectBrowserAcceptHeader = true; // false by default

Finalmente, simplemente reordenando la lista de los formateadores que se definieron en el creador de servicios, el proveedor de alojamiento web establecerá de manera predeterminada el formateador que coloque en la parte superior de la lista (es decir, posición 0).

Se puede encontrar más información en esta entrada de Blog de herramientas y desarrollo web .NET


Lo que hago en mis aplicaciones Asp Net Core Api es crear una clase que se extiende desde ObjectResult y proporcionar muchos constructores para personalizar el contenido y el código de estado. Entonces, todas mis acciones de controlador usan uno de los costructores como corresponda. Puede ver mi implementación en: https://github.com/melardev/AspNetCoreApiPaginatedCrud

y

https://github.com/melardev/ApiAspCoreEcommerce

así es como se ve la clase (vaya a mi repositorio para obtener el código completo):

public class StatusCodeAndDtoWrapper : ObjectResult { public StatusCodeAndDtoWrapper(AppResponse dto, int statusCode = 200) : base(dto) { StatusCode = statusCode; } private StatusCodeAndDtoWrapper(AppResponse dto, int statusCode, string message) : base(dto) { StatusCode = statusCode; if (dto.FullMessages == null) dto.FullMessages = new List<string>(1); dto.FullMessages.Add(message); } private StatusCodeAndDtoWrapper(AppResponse dto, int statusCode, ICollection<string> messages) : base(dto) { StatusCode = statusCode; dto.FullMessages = messages; } }

Observe la base (dto) que reemplaza dto por su objeto y debería estar listo.


Tiene métodos predefinidos para los códigos de estado más comunes.

  • Ok(result) devuelve 200 con respuesta
  • CreatedAtRoute devuelve 201 + nueva URL de recurso
  • NotFound devuelve 404
  • BadRequest devuelve 400 etc.

Consulte BaseController.cs y Controller.cs para obtener una lista de todos los métodos.

Pero si realmente insiste, puede usar StatusCode para establecer un código personalizado, pero realmente no debería, ya que hace que el código sea menos legible y tendrá que repetir el código para establecer encabezados (como en CreatedAtRoute ).

public ActionResult IsAuthenticated() { return StatusCode(200, Json("123")); }