.Net framework の標準機能である DataContractJsonSerializer で JSON のデシリアイズします。有名なところだと Json.NET などがありますが、諸事情でそれらのライブラリが使えないような場合、この方法が選択します。
サンプルでは C# から HTTP リクエストを送って、サーバ側の CakePHP が JSON を返し、それをデシリアイズしています。
DataContractJsonSerializer Class
環境
- クライアント
- Windows 10
- Visual Studio 2019
- .Net Core 2.1
- サーバー
- Ubuntu 18.04.2 LTS (WSL)
- Apache 2.4
- CakePHP 3.8
- PHP 7.2.19
- MariaDB 10.3.15
サーバ側は何でもよかったのですが、今仕事で使っている CakePHP にしました。Ubuntu は WSL 上で動いています。
レスポンスJSON
[
{
"id":1,
"name":"田中望",
"nickname":"バカ",
"birthday":"8月10日",
"constellation":"しし",
"blood_type":"O",
"height":158,
"weight":41
},
{
"id":2,
"name":"菊池茜",
"nickname":"ヲタ",
"birthday":"3月3日",
"constellation":"うお",
"blood_type":"O",
"height":160,
"weight":50
},
// ...
]
クライアントサイド
リクエスト送信、レスポンス受信処理
1.GetResponse メソッドでリクエスト送信とレスポンス受信を行います。
2.取得したレスポンスのストリームを MemoryStream に代入します。
3.DataContractJsonSerializer クラスの ReadObject でデシリアイズします。値のセットは次項の「JSON 格納用の POCO」の記述に従います。
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json; // DataContractJsonSerializer が入っています。
using System.Text;
namespace WebApiReciever
{
class Program
static void Main(string[] args)
{
var url = @"http://localhost:8080/~urushibata/my_cake/Person/rest";
var req = WebRequest.Create(url);
req.Method = "GET";
var res = req.GetResponse(); // 1.リクエスト送信
using (var reader = new StreamReader(res.GetResponseStream()))
// 2.UTF8 に変換し MemoryStream に格納します。
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(reader.ReadToEnd())))
{
// デシリアイズする型を指定します。
var serializer = new DataContractJsonSerializer(typeof(IList<Person>));
// デシリアイズします。
var persons = (IList<Person>)serializer.ReadObject(ms);
Debug.WriteLine($"名前\t通称\t誕生日\t星座\t血液型\t身長\t体重");
foreach(var p in persons)
{
Debug.WriteLine($"{p.Name}\t{p.Nickname}\t{p.Birthday}\t{p.Constellatione}\t"
+ $"{p.BloodType}\t{p.Height}\t{p.Weight}");
}
}
}
}
}
JSON 格納用の POCO
クラスに DataContractAttribute を付与することでシリアライズ化可能とします。
フィールドメンバーに DataMemberAttribute を付与するとシリアライズの対象となります。対象外としたい場合は、IgnoreDataMemberAttribute を付与します。
JSON のプロパティ名と異なるプロパティにセットしたい場合、DataMemberAttribute の Name プロパティで JSON のプロパティ名をマッピングできます。(C# の命名規約(パスカルケース)と CakePHP の命名規約(スネークケース)は相性悪いですな…)
using System.Runtime.Serialization;
namespace WebApiReciever
{
[DataContract]
public class Person
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "nickname")]
public string Nickname { get; set; }
[DataMember(Name = "birthday")]
public string Birthday { get; set; }
[DataMember(Name = "constellatione")]
public string Constellatione { get; set; }
[DataMember(Name = "blood_type")]
public string BloodType { get; set; }
[DataMember(Name = "height")]
public int Height { get; set; }
[DataMember(Name = "weight")]
public int Weight { get; set; }
}
}
サーバーサイド
処理内容は、person テーブルを全件取得して、JSON 文字列に変換して返します。
今回の主題とは離れるので詳細は割愛します。
<?php
namespace App\Controller;
use App\Controller\AppController;
final class PersonController extends AppController
{
public function rest()
{
$this->autoRender = false;
$this->response->type('application/json');
$person = $this->Person->find()->all();
// 第2引数に JSON_UNESCAPED_UNICODE を入れないと、マルチバイト文字は \u30ef というようにコードポイントになります。
$this->response->body(json_encode($person, JSON_UNESCAPED_UNICODE));
}
}
結果
「女子高生の無駄遣い」のキャラクターデータを取得できました。
名前 通称 誕生日 星座 血液型 身長 体重
田中望 バカ 8月10日 158 41
菊池茜 ヲタ 3月3日 160 50
鷺宮しおり ロボ 10月24日 155 41
百井咲久 ロリ 7月21日 142 35
山本美波 ヤマイ 4月17日 159 39
一奏 マジメ 5月9日 170 55
染谷リリィ リリィ 9月12日 164 44
久条翡翠 マジョ 6月6日 157 42
佐渡正敬 ワセダ 10月21日 178 65