1. ホーム
  2. c#

[解決済み] HTTPClient .ReadAsAsync で JSON を配列またはリストにデシリアライズする .NET 4.0 Task パターン

2023-06-25 07:33:37

質問

から返されたJSONをデシリアライズしようとしています。 http://api.usa.gov/jobs/search.json?query=nursing+jobs から返されたJSONを.NET 4.0 Taskパターンを使用してデシリアライズしようとしています。 このJSONを返します(「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"
  },
  ...
]

インデックスアクションです。

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

ジョブ、ジョブクラス

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

にブレークポイントを設定すると jsonTask.Wait(); にブレークポイントを設定し jsonTask を調べると、ステータスは 失敗しました。 InnerExceptionは"Type ProjectName.Jobs is not a collection.".です。

JsonArray属性なしのJobs型で、Jobsを配列(Job[])で起動したところ、このようなエラーが発生しました。

  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}

このサイトのJSONを.NET 4.0 Taskパターンで処理するにはどうしたらよいでしょうか。 これを動作させる前に await async パターンに移行する前に、これを動作させたいと思います。

ANSWER UPDATEです。

.NET 4.5のasync awaitパターンを使った例と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);
 }

を持ってくる必要があります。 System.Threading.Tasks という名前空間があります。

注意 はありません。 .ReadAsString メソッドはありません。 .Content を使用したのはそのためです。 .ReadAsStringAsync メソッドを使用します。

どのように解決するのですか?

モデルを手作業で作成する代わりに、Json2csharp.comのウェブサイトのようなものを使用してみてください。 JSON 応答の例 (完全であればあるほど良い) を貼り付け、その結果生成されたクラスを取り込みます。 これは、少なくとも、いくつかの可動部分を取り除き、シリアライザに簡単な時間を与えるcsharpのJSONの形状を取得し、あなたは属性を追加する必要がないはずです。

ただ、それを動作させ、そして、あなたの命名規則に適合するように、クラス名を修正し、後で属性を追加してください。

EDIT 少しいじった後、結果を仕事のリストにデシリアライズすることに成功しました(Json2csharp.comを使用してクラスを作成しました)。

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

そして、コードの編集です。

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

これは、含んでいるオブジェクトを取り除くことができることを意味します。 これはTask関連の問題ではなく、むしろデシリアライズの問題であることに注目すべきです。

EDIT 2:

JSONオブジェクトを取り込んで、Visual Studioでクラスを生成する方法があります。 JSONをコピーして、Edit> Paste Special > Paste JSON as Classesとするだけです。ページ全体がここでこれに費やされています。

http://blog.codeinside.eu/2014/09/08/Visual-Studio-2013-Paste-Special-JSON-And-Xml/