Sending query strings using HttpClient in C#

By FoxLearn 1/21/2025 9:59:48 AM   13
Query strings consist of a ? followed by one or more key-value pairs separated by &. It is essential to ensure that special characters, such as spaces or Unicode characters, are properly encoded.

When using HttpClient, it handles the encoding of the URI internally using the Uri class, so you don’t need to encode the query string manually.

For example, sending a request with a query string:

await httpClient.GetAsync("https://localhost:5000/movies/search?title=Inception&genre=Science Fiction");

This results in the following encoded request:

GET https://localhost:5000/movies/search?title=Inception&genre=Science%20Fiction HTTP/1.1

In this case, "Inception" remains unchanged, but "Science Fiction" gets encoded as Science%20Fiction, where the space is replaced with %20.

Building a query string with QueryHelpers.AddQueryString()

You can build the query string dynamically using QueryHelpers.AddQueryString() from Microsoft.AspNetCore.WebUtilities.

using Microsoft.AspNetCore.WebUtilities;

var query = new Dictionary<string, string>
{
    ["title"] = "The Matrix",
    ["director"] = "Wachowski"
};

var uri = QueryHelpers.AddQueryString("https://localhost:5000/movies/search", query);

var result = await httpClient.GetAsync(uri);

This will generate the following request:

GET https://localhost:5000/movies/search?title=The%20Matrix&director=Wachowski HTTP/1.1

If you prefer not to use QueryHelpers or want more control over how the query string is built, you can create your own query string builder.

public static class RequestUriUtil
{
    public static string GetUriWithQueryString(string requestUri, Dictionary<string, string> queryStringParams)
    {
        var sb = new StringBuilder();
        sb.Append(requestUri);

        bool firstParam = true;
        foreach (var param in queryStringParams)
        {
            if (param.Value != null)
            {
                sb.Append(firstParam ? "?" : "&");
                sb.Append(param.Key);
                sb.Append("=");
                sb.Append(param.Value);
                firstParam = false;
            }
        }
        return sb.ToString();
    }
}

Usage:

var query = new Dictionary<string, string>
{
    ["title"] = "Blade Runner",
    ["year"] = "1982"
};

var requestUriWithQuery = RequestUriUtil.GetUriWithQueryString("https://localhost:5000/movies/search", query);

var result = await httpClient.GetAsync(requestUriWithQuery);

This generates:

GET https://localhost:5000/movies/search?title=Blade%20Runner&year=1982 HTTP/1.1

HttpClient Extension Method for Query Strings

You can simplify using query strings with an extension method on HttpClient:

public static class HttpClientExtensions
{
    public static async Task<HttpResponseMessage> GetWithQueryStringAsync(this HttpClient client, string uri, Dictionary<string, string> queryStringParams)
    {
        var url = QueryHelpers.AddQueryString(uri, queryStringParams);
        return await client.GetAsync(url);
    }
}

Usage:

var query = new Dictionary<string, string>
{
    ["title"] = "Interstellar",
    ["director"] = "Nolan"
};

var result = await httpClient.GetWithQueryStringAsync("https://localhost:5000/movies/search", query);

This will send the following request:

GET https://localhost:5000/movies/search?title=Interstellar&director=Nolan HTTP/1.1

This method helps encapsulate the query string construction logic and makes the calling code more concise.