Chapter 35

ステップ9-2: ロジックの記述

Apterygiformes-zenn
Apterygiformes-zenn
2022.01.05に更新

Web API仕様

郵便番号検索には、こちらの郵便番号検索APIを使用します。

http://zipcloud.ibsnet.co.jp/

Web APIを呼び出すクラスを作成

プロジェクト直下にWebAPIというフォルダを作成します。

WebAPIフォルダを右クリックし、追加 > クラスを選択します。

ZipCloudAPI.csの名前でファイルを作成します。

プロジェクトを右クリックしてNuGetパッケージの管理を選択します。

参照タブを選択してMicrosoft.Extensions.Httpをインストールします。

ZipCloudAPI.csを以下のように編集します。

/// <summary>
/// 戻り値
/// </summary>
/// <param name="Success">true:取得成功、false:取得失敗</param>
/// <param name="Addresses">住所</param>
/// <param name="ErrorMessage">エラーメッセージ(Successがfalseの時に設定される)</param>
internal record ZipCloudResult(bool Success, List<string> Addresses, string ErrorMessage);

/// <summary>
/// 郵便番号検索API
/// </summary>
internal class ZipCloudAPI
{
    private static readonly string BaseUrl = "https://zipcloud.ibsnet.co.jp/api/search";

    private readonly IHttpClientFactory _clientFactory;
}

IHttpClientFactoryでエラーが出たらいつものショートカットキーでエラーを解消してください。

ZipCloudAPIクラスの中でctorと入力し、TABキーを2回押してください。

コンストラクタが生成されます。

コンストラクタの引数をIHttpClientFactory clientFactoryに、
中の処理に_clientFactory = clientFactory;を書きます。

Web APIを呼び出して住所を取得する処理を書きます。

/// <summary>
/// 住所取得
/// </summary>
/// <param name="zipCode">郵便番号</param>
/// <returns>検索結果</returns>
public async Task<ZipCloudResult> GetAddressAsync(string zipCode)
{
    List<string> addresses = new();
    var client = _clientFactory.CreateClient();

    // 検索
    string response = await client.GetStringAsync($"{BaseUrl}?zipcode={zipCode}");

    var node = JsonNode.Parse(response);
    if (node is null)
    {
        return new ZipCloudResult(false, addresses, "情報取得失敗");
    }

    string? status = node?["status"]?.ToString();

    // ステータス確認
    if (status is null)
    {
        return new ZipCloudResult(false, addresses, "ステータス取得失敗");
    }
    else if (status != "200")
    {
        return new ZipCloudResult(false, addresses, $"{status}:{node?["message"]}");
    }

    var resultNodes = node?["results"]?.AsArray();
    if (resultNodes is null)
    {
        return new ZipCloudResult(false, addresses, "該当なし");
    }

    foreach (var item in resultNodes)
    {
        if (item is null)
        {
            continue;
        }
        // 郵便番号、都道府県名、市区町村名、町域名
        addresses.Add($"〒{item["zipcode"]} {item["address1"]} {item["address2"]}{item["address3"]}");
    }

    return new ZipCloudResult(true, addresses, "");
}

リクエストパラメータzipcodeに郵便番号を指定してAPIを呼び出します。
レスポンスフィールドのstatusをチェックし、正常ならresultsから必要な情報を取り出します。

https://docs.microsoft.com/ja-jp/dotnet/api/system.net.http.ihttpclientfactory?view=dotnet-plat-ext-6.0

https://docs.microsoft.com/ja-jp/dotnet/api/system.text.json.nodes.jsonnode?view=net-6.0

https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-

メイン処理

MainWindow.xaml.csZipCloudAPIクラスを利用する処理を書きます。

/// <summary>
/// 郵便番号検索API
/// </summary>
private ZipCloudAPI? _zipCloud;

public MainWindow()
{
    InitializeComponent();
}

/// <summary>
/// 郵便番号検索
/// </summary>
/// <returns></returns>
private async Task SearchAddressAsync()
{
    try
    {
        // 処理中表示
        this.IsEnabled = false;
        SearchProgress.Visibility = Visibility.Visible;

        if (_zipCloud is null)
        {
            var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
            var factory = serviceProvider.GetService<IHttpClientFactory>();
            if (factory is null)
            {
                throw new Exception("初期化失敗");
            }

            // API呼び出しクラスの初期化
            _zipCloud = new ZipCloudAPI(factory);
        }

        // 郵便番号から住所を取得
        var response = await _zipCloud.GetAddressAsync(ZipCode.Text);

        // 検索結果をテキストボックスに設定
        ResultText.Text = response.Success
            ? string.Join(Environment.NewLine, response.Addresses)
            : response.ErrorMessage;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
    finally
    {
        // 処理中表示解除
        this.IsEnabled = true;
        SearchProgress.Visibility = Visibility.Collapsed;
    }
}

SearchAddressAsyncメソッドにエラーチェックを追加します。
郵便番号が未入力、または0~9以外が入力されていたらエラーとします。

/// <summary>
/// 数値以外の正規表現パターン
/// </summary>
private static readonly Regex NonNumericPattern = new("[^0-9]");
#region ローカル関数

void ErrorProc(string msg)
{
    MessageBox.Show(msg);
    ZipCode.Focus();
}

#endregion

if (string.IsNullOrWhiteSpace(ZipCode.Text))
{
    ErrorProc("郵便番号を入力してください。");
    return;
}
if (NonNumericPattern.IsMatch(ZipCode.Text))
{
    ErrorProc("正しい郵便番号を入力してください。");
    return;
}

住所検索ボタンのClickイベントにSearchButton_Clickの名前でイベントハンドラを作成します。

SearchButton_Clickasyncを付け、
中にawait SearchAddressAsync();を書きます。

WindowKeyDownイベントで以下の処理をするようにします。
こちらにもasyncを付けます。

// 郵便番号テキストボックスにフォーカスがあるときEnterで検索実行
if ((e.Key == System.Windows.Input.Key.Enter) &&
    ZipCode.IsFocused)
{
    // 検索
    await SearchAddressAsync();
}

実行

実行してみます。

郵便番号を入力して住所検索ボタンを押します。
住所が表示されました。

🎞動作イメージ