Flurl: ToUri() fails with relative URLs

Created on 19 Dec 2018  路  6Comments  路  Source: tmenier/Flurl

I noticed I could pass string.Empty to the Url constructor, and that correctly created a relative URL which is exactly what I wanted. Cool.

Then, I proceeded to convert it to a Uri instance using .ToUri and was greeted and an exception (which was to be expected once I saw how it was implemented):

System.UriFormatException: Invalid URI: The format of the URI could not be determined

It looks like Url is just calling the simple Uri constructor on conversions, which will of course fail if the URL is not absolute.

While I understand absolute urls is the more common scenario, this issue needs to be fixed for relative urls.

I can see two potential approaches to fix this:

  1. Call the more specific Uri constructor with the proper UriKind on all conversions.
  2. Remove support for relative urls (that would be a breaking change)

For now, I'm going to create a custom extension method (something like .ToRelativeUri() to avoid this problem, but I wish I didn't need to.

3.0 bug url-builder-only

Most helpful comment

After looking things over I've decided "officially" supporting relative URLs makes sense, but I'm going to make it a 3.0 enhancement, mainly because I'd like to change the meaning of the IsValid() method, which would be breaking. Here's a to-do list for this one as I see it:

  • [ ] Change IsValid to return true for valid relative or absolute URLs, and make it a property instead of a method
  • [ ] Add IsAbsolute property
  • [ ] Fix ToUri so it doesn't throw on valid relative URLs (as originally reported)
  • [ ] Add IsAbsolute check to FlurlClient and FlurlRequest constructors

All 6 comments

Sorry for the delay. This is interesting. To be honest, I never intended to support relative URLs. But if that's a useful thing and it's already close to working, I might consider closing the gaps.

In my mind it doesn't make much sense to support it anywhere on the HTTP side, so I'd want to catch it and perhaps throw a custom exception whenever you "cross over" to Flurl.Http, such as calling url.GetAsync() etc. (A FlurlRequest always gets created implicitly at that point, so that ctor might be the only place that needs to happen.)

Just curious though - what is your use case for relative URLs?

After looking things over I've decided "officially" supporting relative URLs makes sense, but I'm going to make it a 3.0 enhancement, mainly because I'd like to change the meaning of the IsValid() method, which would be breaking. Here's a to-do list for this one as I see it:

  • [ ] Change IsValid to return true for valid relative or absolute URLs, and make it a property instead of a method
  • [ ] Add IsAbsolute property
  • [ ] Fix ToUri so it doesn't throw on valid relative URLs (as originally reported)
  • [ ] Add IsAbsolute check to FlurlClient and FlurlRequest constructors

I'm actively gathering feedback to help prioritize issues for 3.0. If this one is important to you, please vote for it here!

I'm scaling back my ambitions on this one a bit. It's hard to decide what the exact behavior of IsValid should be in the case of a relative URL. I find the behavior of Uri.IsWellFormed a little awkward/confusing in this case, so I'm thinking I might just err on the side of leaving it alone. i.e. IsValid() returns true if it's a valid _absolute_ URL, otherwise false. (I'll better document it too.)

Aside that and the specific ToUri bug originally reported, I don't believe there's any gaps in functionality related to using Flurl to build relative URLs. So I'll treat this issue just as a bug fix. If anyone has other thoughts, please chime in.

Apologies for taking so long to report back on this.

Just curious though - what is your use case for relative URLs?

I needed this one to build a relative URL inside a class relying on an injected HttpClient class with a populated BaseAddress. In this scenario, the class only handles the relative part of the URL, while the aggregation root is responsible for constructing it with the correct base.

This same requirement appeared again in a different project now (that's when I noticed the latest version still didn't have support for relative URLs and reminded me of this issue).

I have julealgon's same use case.

Was this page helpful?
0 / 5 - 0 ratings