1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C# API処理時のデシリアライズについて

Last updated at Posted at 2024-12-14

■概要

C#でのHTTP通信を用いたAPI処理時のデシリアライズについてまとめました。
API処理の詳細は以前記載した以下。

上記では、Newtonsoft.Jsonを用いていたが今回はSystem.Net.Http.Jsonを用いて記載。

■デシリアライズとは

JSON文字列やバイト型に変換されたデータを元の複合的なデータ構造やオブジェクトに
復元すること。
逆シリアル化とも呼ぶ。
→つまり、APIを呼び出して受け取ったJSON文字列を扱いやすい値に復元すること。

今回はHTTP通信を用いるためSystem.Net.Http.Jsonを使用。

※その他API処理について
その他API処理については、System.Text.JsonNewtonsoft.Jsonがあるが今回は割愛。
以下の記事が参考になる。

>引用

■デシリアライズ処理について

System.Net.Http.Jsonに含まれるデシリアライズ処理についてもいくつかの方法がある。

GetFromJsonAsync
データ形式がJSONデータと分かっており一発でデイシリアライズしたい場合に使う。
HTTPリクエスト&レスポンスとデシリアライズを一度に行うことが可能。

一方、内部でレスポンスを受け取った後レスポンスボディ(JSONデータ)全体を
一度メモリに保持してからデシリアライズを行うため、データサイズが大きい場合は
メモリの負担が増える。

GetFromJsonAsync
var todos = await httpClient.GetFromJsonAsync<Todo>("******");

ReadFromJsonAsync
GetAsyncでリクエスト&レスポンスを行い、ReadFromJsonAsyncでデシリアライズを
行うため任意のタイミングでデシリアライズが可能。

レスポンスボディ(JSONデータ)をストリームとして読み込みつつ、同時にデシリアライズを行うためメモリ効率が良い。

ReadFromJsonAsync
using HttpResponseMessage response = await httpClient.GetAsync("******");
T? result = await response.Content.ReadFromJsonAsync<T>();
機能 GetFromJsonAsync ReadFromJsonAsync
リクエストの実行 HTTPリクエスト + デシリアライズを同時に処理 デシリアライズのみ
対応するHTTPメソッド GET専用 任意のメソッド(GET, POST, etc.)
コードの簡潔さ 簡潔に書ける 柔軟な処理が可能

今回は、応答本文JSONの中身の確認等デバッグしたいためReadFromJsonAsyncを使用

■コード①:応答本文がオブジェクト型{ }

天気を取得するAPI処理

Weather.cs

//=====================================
//デシリアライズした値を格納するプロパティ
//=====================================
public class WeatherData
{
    public string Name { get; set; }
    public MainData Main { get; set; }
    public Weather[] Weather { get; set; }
    public Wind Wind { get; set; }
    public Clouds Clouds { get; set; }
}
public class MainData
{
    public double Temp { get; set; }
    public double Feels_Like { get; set; }
    public int Humidity { get; set; }
}
public class Weather
{
    public string Description { get; set; }
}
public class Wind
{
    public double Speed { get; set; }
}
public class Clouds
{
    public int All { get; set; }
}

//=====================================
//API処理
//=====================================
internal class Api
{
    public async Task GetNowWeather()
    {
        //エンドポイント(URL)作成
        string wetherDayUrl = $"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={strApiKey}&lang={lang}&units=metric";
    
        try
        {
            using (HttpClient client = new HttpClient())
            {
                //HTTPリクエストの送信・レスポンス
                HttpResponseMessage response = await client.GetAsync(wetherDayUrl);

                //レスポンスが成功か確認
                response.EnsureSuccessStatusCode();
        
                //応答本文の読み取り
                string responseString = await response.Content.ReadAsStringAsync();
                //Console.WriteLine(responseString);
                
                //デシリアライズ
                var weatherData = await response.Content.ReadFromJsonAsync<WeatherData>();
        
                // 整形して表示
                Console.WriteLine($"都市: {weatherData.Name}");
                Console.WriteLine($"現在の気温: {weatherData.Main.Temp}°C");
                Console.WriteLine($"体感温度: {weatherData.Main.Temp}°C");
                Console.WriteLine($"天気: {weatherData.Weather[0].Description}");
                Console.WriteLine($"湿度: {weatherData.Main.Humidity}%");
                Console.WriteLine($"風速: {weatherData.Wind.Speed} m/s");
                Console.WriteLine($"雲量: {weatherData.Clouds.All}%");
            }
        }
        catch (Exception e)
        {
             Console.WriteLine($"エラー: {e.Message}");
        }
    }
}
応答本文
//============================
//応答本文(responseString)の中身
//============================
{
    "coord": {
        "lon": 139.7595,
        "lat": 35.6828
    },
    "weather": [
        {
            "id": 801,
            "main": "Clouds",
            "description": "薄い雲",
            "icon": "02n"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 9.47,
        "feels_like": 5.34,
        "temp_min": 8.28,
        "temp_max": 10.53,
        "pressure": 1012,
        "humidity": 33,
        "sea_level": 1012,
        "grnd_level": 1010
    },
    "visibility": 10000,
    "wind": {
        "speed": 10.8,
        "deg": 350
    },
    "clouds": {
        "all": 20
    },
    "dt": 1734161818,
    "sys": {
        "type": 2,
        "id": 268395,
        "country": "JP",
        "sunrise": 1734126166,
        "sunset": 1734161315
    },
    "timezone": 32400,
    "id": 1861060,
    "name": "日本",
    "cod": 200
}

応答本文(JSON)の一番外側がオブジェクト型{ }の場合は、通常のデシリアライズで
問題なし。
.ReadFromJsonAsync<WeatherData>()

■コード②:応答本文がリスト型[ ]

緯度・経度データを取得するAPI処理。

Geocording.cs
//=====================================
//デシリアライズした値を格納するプロパティ
//=====================================
public class GeocordingData
{
    public string Name { get; set; }
    public double Lat { get; set; }    //緯度
    public double Lon { get; set; }    //経度
}

//=====================================
//API処理
//=====================================
internal class Api
{
    public static async Task GetGeocording()
    {
        //エンドポイント(URL)作成
        string geocodingUrl = $"http://api.openweathermap.org/geo/1.0/direct?q={strCtiyName}&appid={strApiKey}";
        
        try
        {
            using (HttpClient client = new HttpClient())
            {
                //HTTPリクエストの送信・レスポンス
                HttpResponseMessage response = await client.GetAsync(geocodingUrl);

                //レスポンスが成功か確認
                response.EnsureSuccessStatusCode();
        
                //応答本文の読み取り
                string responseString  = await response.Content.ReadAsStringAsync();
                //Console.WriteLine(responseString );
        
                //デシリアライズ
                var geocodingDataList = await response.Content.ReadFromJsonAsync<List<GeocordingData>>();
                var geocodingData = geocodingDataList[0];
        
                // 整形して表示
                Console.WriteLine($"都市: {geocodingData.Name}");
                Console.WriteLine($"緯度: {geocodingData.Lat}");
                Console.WriteLine($"経度: {geocodingData.Lon}");
            }
        }
        catch (Exception e)
        {
             Console.WriteLine($"エラー: {e.Message}");
        }
    }
}
応答本文
//============================
//応答本文(responseString)の中身
//============================
[
    {
        "name": "Tokyo",
        "local_names": {
            "de": "Tokio",
            "ia": "Tokyo",
            "ja": "東京都",
        },
        "lat": 35.6828387,
        "lon": 139.7594549,
        "country": "JP"
    }
]

応答本文(JSON)の一番外側がリスト型[ ]の場合は、デシリアライズする際も
リスト型にする必要がある。
.ReadFromJsonAsync<List<GeocordingData>>()

もし単一のオブジェクトとしてデシリアライズしようとするとエラーになる。
.ReadFromJsonAsync<GeocordingData>()

1
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?