Ich versuche, den JSON zu deserialisieren, der von der http://api.usa.gov/jobs/search.json?query=nursing+jobs
Verwendung des .NET 4.0-Taskmusters zurückgegeben wurde. Es gibt diesen JSON zurück ('JSON-Daten laden' @ 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"
},
...
]
Indexaktion:
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();
...
}
Jobs und Jobklasse:
[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; }
}
Wenn ich einen Haltepunkt einstelle jsonTask.Wait();
und prüfe, ist jsonTask
der Status Fehler. Die InnerException lautet "Typ ProjectName.Jobs ist keine Sammlung."
Ich habe mit dem Jobtyp ohne das JsonArray-Attribut und Jobs als Array (Job []) begonnen und diesen Fehler erhalten.
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}
Wie würde ich den JSON dieser Site mit dem .NET 4.0-Taskmuster verarbeiten? Ich möchte dies zum Laufen bringen, bevor ich mit dem await async
Muster in .NET 4.5 fortfahre.
ANTWORT-UPDATE:
Hier ist ein Beispiel für die Verwendung des asynchronen Wartemusters .NET 4.5 mit der Antwort von 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);
}
Sie müssen den System.Threading.Tasks
Namespace einbringen .
Hinweis: Es ist keine .ReadAsString
Methode verfügbar .Content
, weshalb ich die .ReadAsStringAsync
Methode verwendet habe.
ReadAsAsync<Job[]>()
?ReadAsAsync()
kann nicht ändern, wie sich der Code verhält, bevor er sich verhält.Antworten:
Versuchen Sie, die Modelle von Json2csharp.com zu verwenden, anstatt Ihre Modelle von Hand anzukurbeln. Einfügen In einer Beispiel-JSON-Antwort gilt: Je voller, desto besser und ziehen Sie die resultierenden generierten Klassen ein. Dadurch werden zumindest einige bewegliche Teile entfernt, und Sie erhalten die Form des JSON in csharp, wodurch der Serialisierer einfacher wird und Sie keine Attribute hinzufügen müssen.
Lassen Sie es einfach funktionieren und nehmen Sie dann Änderungen an Ihren Klassennamen vor, um Ihren Namenskonventionen zu entsprechen, und fügen Sie später Attribute hinzu.
EDIT: Ok, nach einigem Herumspielen habe ich das Ergebnis erfolgreich in eine Jobliste deserialisiert (ich habe Json2csharp.com verwendet, um die Klasse für mich zu erstellen).
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; } }
Und eine Bearbeitung Ihres Codes:
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();
Dies bedeutet, dass Sie Ihr enthaltenes Objekt entfernen können. Es ist erwähnenswert, dass dies kein aufgabenbezogenes Problem ist, sondern ein Deserialisierungsproblem.
EDIT 2:
Es gibt eine Möglichkeit, ein JSON-Objekt zu nehmen und Klassen in Visual Studio zu generieren. Kopieren Sie einfach den JSON Ihrer Wahl und dann Bearbeiten> Spezial einfügen> JSON als Klassen einfügen. Hier ist eine ganze Seite dazu gewidmet:
http://blog.codeinside.eu/2014/09/08/Visual-Studio-2013-Paste-Special-JSON-And-Xml/
quelle
var response = taskwithresponse.Result; var jsonString = response.ReadAsAsync<List<Job>>().Result;
quelle
.Result
da es den Thread blockiert. Sollte etwas verwenden wie:var jsonString = await taskwithresponse.ReadAsAsync<List<Job>>()
Der Rückgabetyp hängt vom Server ab. Manchmal ist die Antwort zwar ein JSON-Array, wird jedoch als Text / Nur gesendet
Das Setzen der Accept-Header in der Anfrage sollte den richtigen Typ erhalten:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Diese können dann in eine JSON-Liste oder ein JSON-Array serialisiert werden. Vielen Dank für den Kommentar von @svick, der mich neugierig gemacht hat, dass es funktionieren sollte.
Die Ausnahme, die ich ohne Konfiguration der Accept-Header erhalten habe, war System.Net.Http.UnsupportedMediaTypeException.
Der folgende Code ist sauberer und sollte funktionieren (ungetestet, funktioniert aber in meinem Fall):
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 = await response.Content.ReadAsAsync<List<Job>>();
quelle
ReadAsAsync
. Die letzte Zeile sollte lauten:var model = await response.Content.ReadAsAsync<List<Job>>();