【C#】パラメータ付きURLクエリ文字列を安全かつ簡潔に組み立てる方法

目次

概要

Web APIの呼び出しなどで、ベースとなるURLに対して複数のクエリパラメータ(?key=value)を付与する際、手動で文字列連結を行うと区切り文字(?&)の管理やURLエンコードの処理が煩雑になります。 Microsoft.AspNetCore.WebUtilities パッケージに含まれる QueryHelpers クラスを使用することで、ディクショナリから自動的に正しい形式のURLを生成できます。

仕様(入出力)

  • 入力: ベースURL(文字列)、追加したいパラメータのキーと値のペア(Dictionaryなど)。
  • 出力: クエリパラメータが正しく結合され、エンコードされた完全なURL文字列。
  • 前提: .NET Standard 2.0 以上。外部パッケージ Microsoft.AspNetCore.WebUtilities が必要。

基本の使い方

まず、NuGetパッケージを追加します。

dotnet add package Microsoft.AspNetCore.WebUtilities

ディクショナリを渡すだけで、自動的に ?& を付与し、値をエンコードして結合します。

var params = new Dictionary<string, string?>
{
    ["city"] = "Tokyo",
    ["q"] = "C# & .NET" // 自動でエンコードされます
};

// https://example.com/api?city=Tokyo&q=C%23%20%26%20.NET
var url = QueryHelpers.AddQueryString("https://example.com/api", params);

コード全文

ここでは「天気予報API」に対して、都市名、取得日数、APIキーなどのパラメータを動的に構築するシミュレーションを行います。

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.WebUtilities;

public class Program
{
    public static void Main()
    {
        // ベースとなるAPIのエンドポイント
        const string BaseUrl = "https://api.weather-service.com/v1/forecast";

        // パラメータの準備
        // 値にスペースや記号が含まれていても、自動的にURLエンコードされます
        var queryParams = new Dictionary<string, string?>
        {
            ["location"] = "New York",    // スペースを含む値
            ["days"] = "7",               // 数値も文字列として渡す
            ["unit"] = "metric",          // 単位
            ["appid"] = "Key_12345!@#",   // 記号を含むAPIキー
            ["lang"] = null               // nullの値(後述の注意点参照)
        };

        Console.WriteLine("--- URL生成開始 ---");

        // クエリ文字列の組み立て
        // AddQueryStringは、既存のURLにクエリがあるか判定し、適切に '?' または '&' で結合します
        string requestUrl = QueryHelpers.AddQueryString(BaseUrl, queryParams);

        Console.WriteLine("生成されたURL:");
        Console.WriteLine(requestUrl);

        // --- 確認用: 生成されたURLの検証 ---
        Console.WriteLine("\n[検証]");
        // "New York" が "New%20York" になっているか確認
        if (requestUrl.Contains("New%20York"))
        {
            Console.WriteLine("判定: スペースが正しくエンコードされています。");
        }
        
        // "Key_12345!@#" が適切に処理されているか
        // ! や @ など一部の記号はRFC標準によりそのまま残る場合がありますが、
        // # はフラグメントと混同するためエンコード(%23)されるべきです
        if (requestUrl.Contains("%23"))
        {
            Console.WriteLine("判定: 特殊記号(#)が正しくエンコードされています。");
        }
    }
}

実行結果例

--- URL生成開始 ---
生成されたURL:
https://api.weather-service.com/v1/forecast?location=New%20York&days=7&unit=metric&appid=Key_12345!%40%23&lang=

[検証]
判定: スペースが正しくエンコードされています。
判定: 特殊記号(#)が正しくエンコードされています。

カスタムポイント

  • null値の除外: デフォルトでは値が null の場合、空文字としてキーだけ(例: &lang=)追加されるか、空文字が設定されます(バージョンによる)。値が null のパラメータをURLに含めたくない場合は、Dictionaryを作成する段階で Where などを使ってフィルタリングしてください。
  • 単一パラメータの追加: Dictionaryを使わず、QueryHelpers.AddQueryString(url, "key", "value") を使えば、パラメータを1つだけ追加できます。メソッドチェーンで繋ぐことも可能です。
  • コレクションの扱い: 同じキーで複数の値を渡したい場合(例: ?id=1&id=2)、値の型として Microsoft.Extensions.Primitives.StringValues を使用するか、ライブラリの仕様に合わせて工夫が必要です。

注意点

  1. 依存関係: この機能は標準ライブラリ(System.Net等)ではなく、ASP.NET Core向けのライブラリに含まれています。コンソールアプリやWPFで使用する場合は必ずNuGetパッケージのインストールが必要です。
  2. エンコード仕様: 内部的に Uri.EscapeDataString 相当の処理が行われますが、ブラウザやサーバーの仕様によっては挙動の差異に注意が必要です。
  3. 既存パラメータの結合: ベースURLに既に ?id=1 のようなクエリが含まれている場合でも、QueryHelpers はそれを検知して正しく & で後続パラメータを繋いでくれます。

応用

Nullを除外してクリーンなURLを作る

値が存在しない(nullまたは空文字)パラメータを自動的に除外する拡張メソッド風の実装例です。

var parameters = new Dictionary<string, string?>
{
    ["id"] = "101",
    ["filter"] = null, // これは除外したい
    ["sort"] = ""      // これも除外したい
};

// 値があるものだけを抽出してDictionary化
var validParams = parameters
    .Where(kv => !string.IsNullOrEmpty(kv.Value))
    .ToDictionary(kv => kv.Key, kv => kv.Value);

var cleanUrl = QueryHelpers.AddQueryString("https://example.com", validParams);
// 結果: https://example.com?id=101

まとめ

null 値の扱いに注意し、必要に応じて事前にフィルタリングを行ってください。

QueryHelpers.AddQueryString を使うことで、面倒なURLエンコードや区切り文字の結合処理を委譲できます。

Web APIクライアントの実装において、可読性と安全性を高めるために非常に有用です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次