c# - httpresponsemessage - Deserializar JSON para Matriz o Lista con HTTPClient.ReadAsAsync usando el patrĂ³n de tarea.NET 4.0
parse http response content c# (3)
El tipo de devolución depende del servidor, a veces la respuesta es de hecho una matriz JSON pero se envía como texto / normal
Establecer los encabezados de aceptación en la solicitud debe obtener el tipo correcto:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
que luego se puede serializar a una lista o matriz JSON. Gracias por el comentario de @svick que me dio curiosidad de que debería funcionar.
La excepción que obtuve sin configurar los encabezados de aceptación fue System.Net.Http.UnsupportedMediaTypeException.
El siguiente código es más limpio y debería funcionar (no probado, pero funciona en mi caso):
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("http://api.usa.gov/jobs/search.json?query=nursing+jobs");
var model = response.Content.ReadAsAsync<List<Job>>();
Estoy tratando de deserializar el JSON devuelto por http://api.usa.gov/jobs/search.json?query=nursing+jobs
usando el patrón de tarea .NET 4.0. Devuelve este JSON (''Cargar datos JSON'' @ http://jsonviewer.stack.hu/
).
[
{
"id": "usajobs:353400300",
"position_title": "Nurse",
"organization_name": "Indian Health Service",
"rate_interval_code": "PA",
"minimum": 42492,
"maximum": 61171,
"start_date": "2013-10-01",
"end_date": "2014-09-30",
"locations": [
"Gallup, NM"
],
"url": "https://www.usajobs.gov/GetJob/ViewDetails/353400300"
},
{
"id": "usajobs:359509200",
"position_title": "Nurse",
"organization_name": "Indian Health Service",
"rate_interval_code": "PA",
"minimum": 42913,
"maximum": 61775,
"start_date": "2014-01-16",
"end_date": "2014-12-31",
"locations": [
"Gallup, NM"
],
"url": "https://www.usajobs.gov/GetJob/ViewDetails/359509200"
},
...
]
Acción del índice:
public class HomeController : Controller
{
public ActionResult Index()
{
Jobs model = null;
var client = new HttpClient();
var task = client.GetAsync("http://api.usa.gov/jobs/search.json?query=nursing+jobs")
.ContinueWith((taskwithresponse) =>
{
var response = taskwithresponse.Result;
var jsonTask = response.Content.ReadAsAsync<Jobs>();
jsonTask.Wait();
model = jsonTask.Result;
});
task.Wait();
...
}
Trabajos y clase de trabajo:
[JsonArray]
public class Jobs { public List<Job> JSON; }
public class Job
{
[JsonProperty("organization_name")]
public string Organization { get; set; }
[JsonProperty("position_title")]
public string Title { get; set; }
}
Cuando establezco un punto de interrupción en jsonTask.Wait();
y examine jsonTask
el estado está fallado. InnerException es "Tipo ProjectName.Jobs no es una colección".
Comencé con el tipo de Trabajos sin el atributo JsonArray y Trabajos como una matriz (Trabajo []) y obtuve este error.
public class Jobs { public Job[] JSON; }
+ InnerException {"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type ''ProjectName.Models.Jobs'' because the type requires a JSON object (e.g. {/"name/":/"value/"}) to deserialize correctly./r/n
To fix this error either change the JSON to a JSON object (e.g. {/"name/":/"value/"}) or change the deserialized type to an array or a type that implements a collection interface
(e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array./r/n
Path '''', line 1, position 1."} System.Exception {Newtonsoft.Json.JsonSerializationException}
¿Cómo procesaría el JSON de este sitio con el patrón de tarea .NET 4.0? Me gustaría hacerlo funcionar antes de pasar al patrón await async
en .NET 4.5.
ACTUALIZAR RESPUESTA:
Aquí hay un ejemplo que usa el patrón .NET 4.5 async await con la respuesta de brumScouse.
public async Task<ActionResult>Index()
{
List<Job> model = null;
var client = newHttpClient();
// .NET 4.5 async await pattern
var task = await client.GetAsync(http://api.usa.gov/jobs/search.json?query=nursing+jobs);
var jsonString = await task.Content.ReadAsStringAsync();
model = JsonConvert.DeserializeObject<List<Job>>(jsonString);
returnView(model);
}
Deberá ingresar el System.Threading.Tasks
nombres System.Threading.Tasks
.
Nota: no hay .ReadAsString
método .ReadAsString
disponible en .Content
por lo que utilicé el método .ReadAsStringAsync
.
En lugar de manipular sus modelos intente utilizar algo como el sitio web Json2csharp.com. Pegar En una respuesta JSON de ejemplo, cuanto más completa, mejor y luego incorporar las clases generadas resultantes. Esto, al menos, le quita algunas partes móviles, le dará la forma del JSON en csharp, dando al serializador un tiempo más fácil y no debería tener que agregar atributos.
Simplemente haga que funcione y luego haga modificaciones a los nombres de sus clases, para cumplir con sus convenciones de nombres y agregue los atributos más adelante.
EDIT: Ok, después de un pequeño juego, he deserializado con éxito el resultado en una Lista de trabajo (utilicé Json2csharp.com para crear la clase para mí)
public class Job
{
public string id { get; set; }
public string position_title { get; set; }
public string organization_name { get; set; }
public string rate_interval_code { get; set; }
public int minimum { get; set; }
public int maximum { get; set; }
public string start_date { get; set; }
public string end_date { get; set; }
public List<string> locations { get; set; }
public string url { get; set; }
}
Y una edición de tu código:
List<Job> model = null;
var client = new HttpClient();
var task = client.GetAsync("http://api.usa.gov/jobs/search.json?query=nursing+jobs")
.ContinueWith((taskwithresponse) =>
{
var response = taskwithresponse.Result;
var jsonString = response.Content.ReadAsStringAsync();
jsonString.Wait();
model = JsonConvert.DeserializeObject<List<Job>>(jsonString.Result);
});
task.Wait();
Esto significa que puede deshacerse de su objeto que contiene. Vale la pena señalar que esto no es un problema relacionado con la Tarea, sino un problema de deserialización.
EDICION 2:
Hay una forma de tomar un objeto JSON y generar clases en Visual Studio. Simplemente copie el JSON de elección y luego Editar> Pegar especial> Pegar JSON como clases. Aquí se dedica una página entera a esto:
http://blog.codeinside.eu/2014/09/08/Visual-Studio-2013-Paste-Special-JSON-And-Xml/
var response = taskwithresponse.Result;
var jsonString = response.ReadAsAsync<List<Job>>().Result;