[C#] Safely and Concisely Building URL Query Strings with Parameters

目次

Overview

When calling Web APIs, adding multiple query parameters (?key=value) to a base URL manually can become tedious. Managing separators (? and &) and ensuring proper URL encoding is error-prone. By using the QueryHelpers class included in the Microsoft.AspNetCore.WebUtilities package, you can automatically generate correctly formatted URLs from a dictionary.


Specifications (Input/Output)

  • Input: Base URL (string) and a collection of key-value pairs to add (e.g., Dictionary).
  • Output: A complete URL string with parameters properly joined and encoded.
  • Prerequisites: .NET Standard 2.0 or higher. Requires the external package Microsoft.AspNetCore.WebUtilities.

Basic Usage

First, add the NuGet package to your project:

dotnet add package Microsoft.AspNetCore.WebUtilities

Simply pass a dictionary, and the helper will automatically append ? or &, encode values, and join them correctly.

var queryParams = new Dictionary<string, string?>
{
    ["city"] = "Tokyo",
    ["q"] = "C# & .NET" // This will be automatically encoded
};

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

Full Code Example

The following code simulates building a request for a “Weather Forecast API” where parameters like city name, forecast days, and API keys are dynamically constructed.

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

public class Program
{
    public static void Main()
    {
        // Base API endpoint
        const string BaseUrl = "https://api.weather-service.com/v1/forecast";

        // Prepare parameters
        // Values containing spaces or symbols will be automatically URL-encoded
        var queryParams = new Dictionary<string, string?>
        {
            ["location"] = "New York",    // Contains a space
            ["days"] = "7",               // Numeric values passed as strings
            ["unit"] = "metric",          // Standard string
            ["appid"] = "Key_12345!@#",   // Contains special symbols
            ["lang"] = null               // A null value (see Notes)
        };

        Console.WriteLine("--- Starting URL Generation ---");

        // Build the query string
        // AddQueryString detects if the base URL already has a '?' and joins appropriately
        string requestUrl = QueryHelpers.AddQueryString(BaseUrl, queryParams);

        Console.WriteLine("Generated URL:");
        Console.WriteLine(requestUrl);

        // --- Verification: Validating the generated URL ---
        Console.WriteLine("\n[Verification]");
        
        // Check if "New York" became "New%20York"
        if (requestUrl.Contains("New%20York"))
        {
            Console.WriteLine("Status: Space was correctly encoded.");
        }
        
        // Special symbols: '#' must be encoded (%23) to avoid confusion with URL fragments
        if (requestUrl.Contains("%23"))
        {
            Console.WriteLine("Status: Special symbol (#) was correctly encoded.");
        }
    }
}

Example Execution Result

--- Starting URL Generation ---
Generated URL:
https://api.weather-service.com/v1/forecast?location=New%20York&days=7&unit=metric&appid=Key_12345!%40%23&lang=

[Verification]
Status: Space was correctly encoded.
Status: Special symbol (#) was correctly encoded.

Customization Points

  • Handling Null Values: By default, if a value is null, it may be appended as an empty string (e.g., &lang=). If you want to exclude null parameters entirely, filter the dictionary before passing it (see Advanced section).
  • Single Parameter Addition: You don’t always need a dictionary. Use QueryHelpers.AddQueryString(url, "key", "value") to add just one parameter. You can also chain these calls.
  • Handling Collections: If you need to pass multiple values for the same key (e.g., ?id=1&id=2), you should use Microsoft.Extensions.Primitives.StringValues as the dictionary value type.

Important Notes

  • Dependencies: This feature is part of the ASP.NET Core utilities, not the core System.Net namespace. For Console or WPF apps, the NuGet package is mandatory.
  • Encoding Standards: Internally, this uses logic similar to Uri.EscapeDataString. While robust, be aware that different servers may have slight variations in how they handle certain RFC-compliant symbols.
  • Existing Queries: If the base URL already contains a query (e.g., https://example.com/api?id=1), QueryHelpers is smart enough to use & instead of appending a second ?.

Advanced Application

Creating a Clean URL by Excluding Nulls

This implementation ensures that parameters with no value (null or empty) are automatically stripped to keep the URL clean.

var parameters = new Dictionary<string, string?>
{
    ["id"] = "101",
    ["filter"] = null, // We want to exclude this
    ["sort"] = ""      // We want to exclude this too
};

// Filter out entries where the value is null or empty
var validParams = parameters
    .Where(kv => !string.IsNullOrEmpty(kv.Value))
    .ToDictionary(kv => kv.Key, kv => kv.Value);

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

Conclusion

This is highly beneficial for readability and security when implementing Web API clients in C#.

Pay attention to how null values are handled and filter them beforehand if necessary.

QueryHelpers.AddQueryString allows you to delegate messy URL encoding and separator logic to a tested library.

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

この記事を書いた人

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

目次