Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Better URL Building with Flurl

4.84/5 (20 votes)
19 Jun 2018CPOL3 min read 39.7K  
An introduction to Flurl, an open-source .NET library for fluently building URLs

Introduction

If you build a lot of URLs in .NET, you've probably found that it can be get a bit cumbersome. You start with basic string building. But even with proper use of String.Format, dealing optional parameters and URL encoding still gets messy quickly. You can't help but think there must be a better way.

At some point, you discover UriBuilder and think all your problems are solved. But you quickly realize that while UriBuilder is great for assembling the bits on the left side of the URL (host, port, scheme, etc.), it offers little help on the right side (path segments and query string), and that's where all the variability tends to be. You find that most of the time you're starting with a config setting or fixed constant representing some "base" URL, and regress back to string-building to construct the rest.

Sound familiar? Maybe you've rolled your own library to address some of these gaps. If not, you might want to check out Flurl. Flurl is a tiny library that sets out to solve these problems with as little "noise" as possible.

Show Me Some Code!

Here's what Flurl looks like:

JavaScript
using Flurl;

var url = "http://www.some-api.com"
    .AppendPathSegments("path", "to", "endpoint")
    .SetQueryParams(new {
        api_key = ConfigurationManager.AppSettings["SomeApiKey"],
        max_results = 20,
        q = "Don't worry, I'll get encoded!"
    });

If extension methods, fluent APIs, and anonymous objects are not your cup of tea, Flurl supports a more traditional style that gives you the same results:

C#
Url url = new Url("http://www.some-api.com");
url.AppendPathSegment("endpoint");
url.QueryParams["api_key"] = ConfigurationManager.AppSettings["SomeApiKey"];
url.QueryParams["max_results"] = 20;
url.QueryParams["q"] = "Don't worry, I'll get encoded!";

There's also a singular version of AppendPathSegments and SetQueryParams:

JavaScript
url.AppendPathSegment("one").SetQueryParam("x", 5);

SetQueryParam(s) overwrites existing values of the same name:

JavaScript
"http://mysite.com".SetQueryParams(new { x = 1, y = 2 }).SetQueryParam("y", 3);
// result: http://mysite.com?x=1&y=3

In some rare cases, you might actually want the same key specified multiple times in the query string. Pass an array of values to achieve this:

JavaScript
"http://mysite.com".SetQueryParam("x", new[] { 1, 2 });
// result: http://mysite.com?x=1&x=2

When a null value is passed to SetQueryParam(s), the key/value pair is excluded entirely. This behavior can be leveraged to help cut down on messy conditional logic.

JavaScript
"http://mysite.com".SetQueryParams(new { x = 1, y = null, z = 3 });
// result: http://mysite.com?x=1&z=3

A URL object converts back to a string implicitly. You can use ToString() explicitly if you prefer, but the compiler won't complain if you don't:

JavaScript
Response.Redirect(url);

Flurl can also be used to parse an existing URL, again focusing on the "right side":

JavaScript
var url = new Url("http://site.com/some/long/path?x=1&y=2");
var path = url.Path; // contains "http://site.com/some/long/path"
var query = url.QueryParams; // an IDictionary<string, object> containing x and y
var root = Url.GetRoot(url); // contains "http://site.com"

How often do you forget whether that "BaseURL" app setting already contains a trailing slash? Wish there was an equivalent to Path.Combine for URLs so you don't need to worry about it? Flurl gives you one:

JavaScript
var url = Url.Combine("http://foo.com/", "/too/", "/many/", "/slashes", "too", "few");
// result: http://foo.com/too/many/slashes/too/few

AppendPathSegment has the same behavior with respect to ensuring there is one and only one separator between segments.

Encoding

Flurl takes care of encoding characters in URLs but takes a different approach with path segments than it does with query string values. The assumption is that query string values are highly variable (such as from user input), whereas path segments tend to be more "fixed" and may already be encoded, in which case you don't want to double-encode. Here are the rules Flurl follows:

  • Query string values are fully URL-encoded.
  • For path segments, reserved characters such as / and % are not encoded.
  • For path segments, illegal characters such as spaces are encoded.
  • For path segments, the ? character is encoded, since query strings get special treatment.

Portability

Flurl is a portable class library, meaning you can use it in your Xamarin, Silverlight, and Windows Phone apps just as easily as applications targeting the "full" .NET framework.

Where Do I Get it?

Flurl is freely available on NuGet:

PM> Install-Package Flurl 

Flurl.Http

There are many reasons you might need to build URLs. For me, it's mostly for the purpose of calling RESTful APIs. I built Flurl.Http as companion library that allows you to seamlessly call the URL along the same fluent chain that you build it. It covers a lot of the same territory as other HTTP client libraries like RestSharp. I plan to cover Flurl.Http in depth in a future article, but for now you can check out the main website for details.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)