【C#】zipcloudのAPIからJSONを取得してパースする

C#でzipcloudのAPIを動かしたかったのでJSONをパースしようと思ったのですが、無駄につまづいたのでメモ。

郵便番号から県とか住所を引いてきて自動挿入してくれる感じのやつが作りたかったので試してました。

参考サイト

VB/C#でJSONの読み込み(System.Text.Json編)
System.Text.Jsonの考え方。JSONの列挙やクラスへのマッピング、位置を指定して読み込む方法などをサンプルつきで説明します。
WebClient.Encoding プロパティ (System.Net)
文字列のアップロードとダウンロードに使用する Encoding を取得または設定します。Gets or sets the Encoding used to upload and download strings.

やったこと

System.Text.Jsonのインストール

VisualStudioのメニューバーから、ツール→NuGetパッケージマネージャー→ソリューションのNuGetパッケージマネージャーの管理を開きます。
参照タブで System.Text.Json を検索してインストールしたら利用できました。
作成者はMicrosoftです。

取得部分のコード

//検索したい郵便番号
string zipcode = "000-0000";

//URL
string url = "https://zipcloud.ibsnet.co.jp/api/search?zipcode=" + zipcode;

using (var webClient = new System.Net.WebClient())
{
    // エンコーディングをUTF-8にしておく(取得してからEncoding変えてもパースできなかった)
    webClient.Encoding = System.Text.Encoding.UTF8;
    
    // JSONのテキストを取得
    string jsonStr = webClient.DownloadString(url);
    
    // JSON文字列をオブジェクトに変換
    Rootobject obj = JsonSerializer.Deserialize<Rootobject>(jsonStr);
    
    // 正常にデータ取得できたか確認
    if (obj.status == 200 && obj.results != null)
    {
        // なんらかの処理
    }
}

JSONパースするためのクラス

パース用のクラス(今回はRootobject)を作成しないといけないので作成します。

郵便番号検索API - zipcloud
日本郵便が公開している郵便番号データを検索する機能をRESTで提供しています。

上記のページにある、レスポンスサンプルをコピーして、Visual Studioのメニューバーから、編集→型式を選択して貼り付け→JSONをクラスとして貼り付ける。
で貼り付けると下記のようなクラスができるので、今回はそちらを利用しました。

public class Rootobject
{
    public object message { get; set; }
    public Result[] results { get; set; }
    public int status { get; set; }
}

public class Result
{
    public string address1 { get; set; }
    public string address2 { get; set; }
    public string address3 { get; set; }
    public string kana1 { get; set; }
    public string kana2 { get; set; }
    public string kana3 { get; set; }
    public string prefcode { get; set; }
    public string zipcode { get; set; }
}

おまけ:出てきたエラー

webclientでエンコーディングを指定するまでは、下記のようなエラーが出ていました。
一見、改行やタブのような制御文字っぽいものでつまづいているように見えたのでそうかなと思っていました。

System.Text.Json.JsonException: ''0x0A' is invalid within a JSON string. The string should be correctly escaped. Path: $.results[0].address1 | LineNumber: 4 | BytePositionInLine: 32.'
System.Text.Json.JsonException: ''0x09' is invalid within a JSON string. The string should be correctly escaped. Path: $.results[0].address1 | LineNumber: 0 | BytePositionInLine: 61.'

その時解消のために書いたコードはこんなかんじ。
URLからとってきたjson文字列をbyteにしてエンコードかけています。見るからにうまくいくか怪しいコードです。

string url = "https://zipcloud.ibsnet.co.jp/api/search?zipcode="+ zipcode;
using (var webClient = new System.Net.WebClient())
{
    string jsonStr = webClient.DownloadString(url);

    //バイト配列に変換
    byte[] bytesUTF8 = System.Text.Encoding.Default.GetBytes(jsonStr);

    //バイト配列をUTF8の文字コードとしてStringに変換
    string stringSJIS = System.Text.Encoding.UTF8.GetString(bytesUTF8);
    
    // 改行とタブの置換
    stringSJIS = stringSJIS.Replace("\n", "");// 0x0Aの置換
    stringSJIS = stringSJIS.Replace("\t", "");// 0x09の置換

    Rootobject obj = JsonSerializer.Deserialize(stringSJIS);

    Console.Write(obj);
}

改行やタブを置換したのですが、下記のようなエラー。

System.Text.Json.JsonException: 'The JSON value could not be converted to System.String. Path: $.results[0].address1 | LineNumber: 0 | BytePositionInLine: 55.'

置換後の文字列を見ると中途半端に文字化けしていました。(「埼玉県」が「埼玉省E」みたいな感じに一部だけ文字化けする)

途中までエンコードの方法が悪いのかと思っていたのですが、このあたりでいいかげん「変換前の文字列がまずいんだろうな…」と気づきました。
なので、webclientにエンコーディングをつけたら正常にパースできた次第です。そりゃそうだよね…。UTF-8のデータはもとからUTF-8でよむべきだよね…。ごめんな…。

おわり。