In web development, a query string is a crucial URL component that facilitates data exchange between clients and servers. In this article, we will learn how to build a query string for a URL in C#.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

What Is a Query String?

At its core, a query string is a string of characters appended to a URL, typically following a question mark (?). It consists of key-value pairs separated by ampersands (&). Each key is associated with a value and ampersands (&) separate multiple key-value pairs.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

Let’s see an example of a query string:

https://test.com/api/Books?author=rowling&language=english

Here, for instance, the URL starts with the base address https://test.com/api/Books. After the question mark (?), the query string begins with the first key-value pair: author=rowling. Here, “author” is the key, and “rowling” is the value. The ampersand (&) separates the first key-value pair from the second: language=english.

Different Ways to Build a Query String

There are several ways we can build a query string for a URL:

  • String Concatenation
  • UriBuilder
  • ParseQueryString
  • QueryHelpers
  • QueryBuilder
  • QueryString.Create

Let’s look at each approach to build a query string.

Setting up the Application

To mimic a real API call using the query string, we can set up a simple GET API that accepts a query string for testing purposes. This API represents a book service that accepts author and language as query parameters and returns some book details.

We can construct a query string and then make an API call using it to test if it works. However, setting up the API is optional and not compulsory in this article. Please visit the code for more information about the API.

To begin with, let’s proceed to create a console app and define a BooksApiService class:

public class BooksApiService
{
    private const string BaseApiUrl = "https://localhost:7220/api/Books";
}

Here, we declare a BaseApiUrl constant, which holds the base URL for an API endpoint.

Now, let’s explore each section in detail.

Using the String Concatenation Technique

String concatenation is one of the traditional techniques for constructing query strings in C#. This technique combines multiple strings, including parameter names and values, to create a complete query string. While it offers control, it can be cumbersome when dealing with complex queries or numerous parameters.

First, we’ll create a QueryStringHelper utility class. This class will contain various methods, each employing a different technique to construct query strings.

Now, let’s create our first method to build a query string using string concatenation:

public static class QueryStringHelper
{
    public static string BuildUrlWithQueryStringUsingStringConcat(
        string basePath, Dictionary<string, string> queryParams)
    {
        var queryString = string.Join("&", queryParams.Select(kvp => $"{kvp.Key}={kvp.Value}"));

        return $"{basePath}?{queryString}";
    }
}

First, inside the QueryStringHelper class, we define a method that accepts the basePath and queryParams as the input parameters. We then use the Select() LINQ method to transform the dictionary into a collection of formatted key-value pairs. Then, we use the string.Join() method to concatenate these pairs with “&” as the separator.

Moving forward, we concatenate the basePath and the queryString to form the complete URL and return it.

In this example, one of the primary challenges we face is the URI encoding of the query parameters. If we have an author name with special characters, we might end up with a malformed URL if we don’t encode the special characters when passing the name as a query parameter.

Let’s see an example of how to encode the query parameters:

public static string BuildUrlWithQueryStringUsingStringConcat(
    string basePath, Dictionary<string, string> queryParams)
{
    var queryString = string.Join("&",
        queryParams.Select(kvp => $"{HttpUtility.UrlEncode(kvp.Key)}={HttpUtility.UrlEncode(kvp.Value)}"));

    return $"{basePath}?{queryString}";
}

Here, we use the HttpUtility.UrlEncode() method to encode both the Key and Value of the queryParams. 

Finally, let’s invoke the BuildUrlWithQueryStringUsingStringConcat() method:

var query = new Dictionary<string, string>
{
    { "author", "George Orwell" },
    { "language", "english" }
};

Console.WriteLine(QueryStringHelper.BuildUrlWithQueryStringUsingStringConcat(BaseApiUrl, query));
//prints https://localhost:7220/api/Books?author=George+Orwell&language=english

We start by initializing a Dictionary object, which contains key-value pairs representing the query parameters for the API request. We pass “George Orwell” as the author and “english” as the language.

Finally, we call the BuildUrlWithQueryStringUsingStringConcat() method, passing the BaseApiUrl and query variables to build the complete URL.

It’s important to note that besides string concatenation, there are alternative manual techniques for building query strings in C#. Please visit these articles to learn more: String Interpolation and Different Ways to Concatenate String.

Using the UriBuilder Class

The UriBuilder class in C# provides a powerful and convenient way to construct and modify System.Uri instances. We can create or manipulate URLs with various components like the scheme, host, port, path, and query string.

The UriBuilder class handles the URL encoding, ensuring that parameter names and values are correctly encoded for safe URL construction.

Let’s create another method in the QueryStringHelper class to demonstrate using the UriBuilder class:

public static string BuildUrlWithQueryStringUsingUriBuilder(string basePath, Dictionary<string, string> queryParams)
{
    var uriBuilder = new UriBuilder(basePath)
    {
        Query = string.Join("&", queryParams.Select(kvp => $"{kvp.Key}={kvp.Value}"))
    };

    return uriBuilder.Uri.AbsoluteUri;
}

We start by creating an instance of the UriBuilder class and initialize it with a base API URL. Then, we concatenate the key-value pairs using string.Join() method and set the Query property of the uriBuilder instance. Finally, we obtain the complete API URL by accessing the Uri property of the UriBuilder instance and then retrieving its AbsoluteUri property. 

So, let’s proceed to invoke the BuildUrlWithQueryStringUsingUriBuilder() method:

var query = new Dictionary<string, string>
{
    { "author", "Jane Austen" },
    { "language", "english" }
};

Console.WriteLine(QueryStringHelper.BuildUrlWithQueryStringUsingUriBuilder(BaseApiUrl, query));
//prints https://localhost:7220/api/Books?author=Jane%20Austen&language=english

In a similar fashion, we initialize a Dictionary object that holds the query parameters. Then, we pass the BaseApiUrl and the query variables to the BuildUrlWithQueryStringUsingUriBuilder() method to get a complete URL. The UriBuilder class encodes the author parameter value that contains a space.

Building a Query String Using HttpUtility.ParseQueryString Method

The HttpUtility.ParseQueryString() method is part of the System.Web namespace in C#. This method is beneficial when we create or manipulate query strings in web applications.

It allows us to parse an existing query string into a collection of key-value pairs, modify those pairs, and generate a new query string.

We will create a new method within the QueryStringHelper class to demonstrate this technique:

public static string BuildUrlWithQueryStringUsingParseQueryStringMethod(
    string basePath, Dictionary<string, string> queryParams)
{
    var query = HttpUtility.ParseQueryString(string.Empty);

    foreach (var dict in queryParams)
    {
        query[dict.Key] = dict.Value;
    }

    return string.Join("?", basePath, query.ToString());
}

Here, we create an empty NameValueCollection using the HttpUtility.ParseQueryString(string.Empty) method.

This method internally creates an instance of HttpQSCollection, which is a non-publicly accessible overload of NameValueCollection. Because it is an internal class, we have to use this non-standard method of initialization. The upside of this special collection is its automatic handling of null values, along with proper URL encoding of all key-value pairs.

Once we have our query collection, we add our key-value pairs to it. And finally, we build the complete URL by passing the separator (?), basePath, and the query variable to the string.Join() method.

If we provide multiple query parameters and one of them has a null value, it will skip the query parameter with a null value and print the rest in the query string when we call the ToString() method. However, if every query parameter passed has a null value, an ArgumentOutOfRangeException exception will be thrown. In this case, we assume no null values will be passed.

Now, let’s call the method:

var query = new Dictionary<string, string>
{
    { "author", "Agatha Christie" },
    { "language", "english" }
};

Console.WriteLine(QueryStringHelper.BuildUrlWithQueryStringUsingParseQueryStringMethod(BaseApiUrl, query));
//prints https://localhost:7220/api/Books?author=Agatha+Christie&language=english

Here, we create the query parameters using the Dictionary object and invoke the BuildUrlWithQueryStringUsingParseQueryStringMethod() method to obtain the complete URL.

Creating a Query String With the QueryHelpers.AddQueryString Method

The QueryHelpers is a utility class provided by the Microsoft.AspNetCore.WebUtilities namespace. It includes the AddQueryString() method that builds the query string by adding or appending parameters to an existing URL.

The QueryHelpers.AddQueryString() method ensures correct URL encoding of parameter names and values for proper URL formation.

As a first step, let’s include the Microsoft.AspNetCore.App as a FrameworkReference in the .csproj file within an ItemGroup:

<FrameworkReference Include="Microsoft.AspNetCore.App" />

Adding this reference ensures that we can use the QueryHelpers.AddQueryString() method from the Microsoft.AspNetCore.WebUtilities namespace.

Now, let’s create a new method to demonstrate using the QueryHelpers.AddQueryString() method:

public static string BuildUrlWithQueryStringUsingAddQueryStringMethod(
    string basePath, Dictionary<string, string?> queryParams)
{
    return QueryHelpers.AddQueryString(basePath, queryParams);
}

Here, we use the QueryHelpers.AddQueryString() method to generate the query string. We pass the basePath and the queryParams dictionary as input, and we get the complete URL.

In this method, we specifically accept the Dictionary<string, string?> with nullable string values because of the QueryHelpers.AddQueryString() method supports nullable values, providing flexibility in handling optional query parameters.

Then, let’s invoke the method:

var query = new Dictionary<string, string>
{
    { "author", "Haruki Murakami" },
    { "language", "japanese" }
};

Console.WriteLine(QueryStringHelper.BuildUrlWithQueryStringUsingAddQueryStringMethod(BaseApiUrl, query));
//prints https://localhost:7220/api/Books?author=Haruki%20Murakami&language=japanese

Similarly, we create a Dictionary object that holds the query parameters and passes the query and the BaseApiUrl variables to the BuildUrlWithQueryStringUsingAddQueryStringMethod() method to build the complete URL.

Using the QueryBuilder Class

The QueryBuilder class is part of the Microsoft.AspNetCore.Http.Extensions namespace and is used to construct a query string. In essence, the QueryBuilder class allows us to build a query string by adding key-value pairs. It implements the IEnumerable<KeyValuePair<String,String>> interface, which means we can iterate over the key-value pairs contained within it.

Let’s take a look at an example:

public static string BuildUrlWithQueryStringUsingQueryBuilderClass(
    string basePath, Dictionary<string, string> queryParams)
{
    var queryBuilder = new QueryBuilder(queryParams);

    return basePath + queryBuilder;
}

Here, we create an instance of QueryBuilder class, and we pass the queryParams to the constructor, which returns the instance of the QueryBuilder class.

When we concatenate a queryBuilder object with a string, it implicitly calls the ToString() method of the QueryBuilder class. In the context of the QueryBuilder class, it overrides the ToString() method to return the query string representation of the key-value pairs stored in the queryBuilder object.

Consequently, we can concatenate the queryBuilderobject with the basePath to create a complete URL.

Let’s proceed and invoke the method:

var query = new Dictionary<string, string>
{
    { "author", "Gabriel Garcia" },
    { "language", "spanish" }
};

Console.WriteLine(QueryStringHelper.BuildUrlWithQueryStringUsingQueryBuilderClass(BaseApiUrl, query));
//prints https://localhost:7220/api/Books?author=Gabriel%20Garcia&language=spanish

Here, we initialize a Dictionary object and pass the BuildUrlWithQueryStringUsingQueryBuilderClass() method to construct the complete URL.

Building a Query String With the QueryString.Create Method

The QueryString.Create() method is a convenient way to create a key-value pair query string object.

The QueryString.Create() method offers three overloads. The first overload, Create(string name, string value), allows us to create a query string with a single key-value pair.

The second overload, Create(IEnumerable<KeyValuePair<string, string?>> parameters), accepts a collection of key-value pairs, where values are nullable strings.

Lastly, the third overload, Create(IEnumerable<KeyValuePair<string, StringValues>> parameters), takes a collection of key-value pairs where the values are of type StringValues.

Let’s create a new method in the QueryStringHelper class:

public static string BuildUrlWithQueryStringUsingCreateMethod(
    string basePath, Dictionary<string, string?> queryParams)
{
    var queryString = QueryString.Create(queryParams);

    return basePath + queryString;
}

Here, we define a method that accepts a Dictionary<string, string?>, allowing nullable string values. This choice is made because the second overload of the QueryString.Create() method supports nullable values.

Although this method doesn’t explicitly accept a Dictionary, we can still pass a Dictionary to it. This is possible because Dictionary implements the IEnumerable<KeyValuePair<string, string>> interface. Then, we use the QueryString.Create() method and pass the queryParams dictionary object to build a query string.

Finally, let’s call the method:

var query = new Dictionary<string, string>
{
    { "author", "Leo Tolstoy" },
    { "language", "russian" }
};

Console.WriteLine(QueryStringHelper.BuildUrlWithQueryStringUsingCreateMethod(BaseApiUrl, query));
//prints https://localhost:7220/api/Books?author=Leo%20Tolstoy&language=russian

Here, we create a Dictionary object to represent the query parameters and invoke the BuildUrlWithQueryStringUsingCreateMethod() method to form the complete URL.

Conclusion

In this article, we have explored various approaches for building a query string in C#. The method we choose will depend on our specific needs and preferences.

To conclude, we can use string concatenation and other manual techniques if we need a straightforward way to build a query string. However, using the string concatenation technique, we must ensure that we properly encode the parameter names and values.

On the other hand, if we need to build complex queries or deal with numerous parameters, we may use a more robust method, such as the UriBuilder class, the HttpUtility.ParseQueryString() method, the QueryHelpers.AddQueryString() method, the QueryBuilder class, or the QueryString.Create() method.

We do not need to manually encode the query string parameters when employing any of these methods. These methods handle URL encoding internally, ensuring secure and accurate URL formation.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!