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.0or higher. Requires the external packageMicrosoft.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 excludenullparameters 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 useMicrosoft.Extensions.Primitives.StringValuesas the dictionary value type.
Important Notes
- Dependencies: This feature is part of the ASP.NET Core utilities, not the core
System.Netnamespace. 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),QueryHelpersis 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.
