Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Path.Combine for URLs (part 2)

Tags:

For awhile now, I've been searching for a Path.Combine method that works on URLs. This is similiar to Path.Combine for URLs? with one big difference.

I'll illustrate with an example. Say we have a base url: http://example.com/somefolder and a file: foo.txt. Thus, the full path would be: http://example.com/somefolder/foo.txt. Sounds simple, right? Ha.

I tried the Uri class: Uri.TryCreate(new Uri("http://example.com/somefolder"), "foo.txt", out x); which resulted in "http://example.com/foo.txt".

Then I tried Path: System.IO.Path.Combine("http://example.com/somefolder", "foo.txt"); which resulted in "http://example.com/somefolder\foo.txt"... Closer, but still no.

For kicks, I then tried: System.IO.Path.Combine("http://example.com/somefolder/", "foo.txt") which resulted in "http://example.com/somefolder/foo.txt".

The last one worked, but it's basically doing string concatenation at that point.

So I think I have two options:

  • Use Path.Combine and replace all \ with /
  • Use basic string concatenation

Am I missing a built in framework method for this?

UPDATE: The usage case I have is for downloading a bunch of files. My code looks like this:

    public void Download()     {         var folder = "http://example.com/somefolder";         var filenames = getFileNames(folder);          foreach (var name in filenames)         {             downloadFile(new Uri(folder + "/" + name));         }     } 

I'm miffed at having to use string concat in the Uri constructor, as well having to check if the slash is needed (which I omitted in the code).

It seems to me that what I'm trying to do would come up a lot, since the Uri class handles a lot of other protocols besides http.

like image 932
Xcelled Avatar asked Aug 01 '13 20:08

Xcelled


People also ask

What is path combine?

Combines two strings into a path. Combine(String, String, String) Combines three strings into a path. Combine(String, String, String, String) Combines four strings into a path.

How to append uri in c#?

The file system have the Path. Combine method to combine paths but how to combine a base URL with an absolute or relative URL/URI? var b = CombineUriToString("http://www.my.domain/something/other", "/absolute/path");

Why we use path combine?

Path. Combine uses the Path. PathSeparator and it checks whether the first path has already a separator at the end so it will not duplicate the separators. Additionally, it checks whether the path elements to combine have invalid chars.


2 Answers

Flurl [disclosure: I'm the author] is a tiny URL builder library that can fill the gap with its Url.Combine method:

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

You can get it via NuGet: Install-Package Flurl.

I also wanted to point out that you can dramatically improve the efficiency of your code by downloading the files in parallel. There's a couple ways to do that. If you're on .NET 4.5 or above and can rewrite downloadFile as an async method, then your best option would be to replace your for loop with something like this:

var tasks = filenames.Select(f => downloadFileAsync(Url.Combine(folder, f))); await Task.WhenAll(tasks); 

Otherwise, if you're stuck on .NET 4, you can still achieve parallelism easily by using Parallel.ForEach:

Parallel.ForEach(filenames, f => downloadFile(Url.Combine(folder, f))); 
like image 173
Todd Menier Avatar answered Sep 28 '22 22:09

Todd Menier


This is how the Uri class works.

var otherUri = new Uri("http://example.com/somefolder")); // somefolder is just a path var somefolder = otherUri.GetComponents(UriComponents.PathAndQuery, UriFormat.UriEscaped);  // example one var baseUri = new Uri("http://example.com/");    var relativeUri = new Uri("somefolder/file.txt",UriKind.Relative); var fullUri = new Uri(baseUri, relativeUri);  // example two var baseUri = new Uri("http://example.com/somefolder");  var relativeUri = new Uri("somefolder/file.txt",UriKind.Relative); var fullUri = new Uri(baseUri, relativeUri);  // example three var baseUri = new Uri("http://example.com/");    var fullUri = new Uri(baseUri, "somefolder/file.txt");   

Basically do it via string manipulation simplest and do

var isValid = Uri.TryCreate(..., out myUri); 

If you want to find out more. Check out this post C# Url Builder Class

Updated answer

When referring to base uri it will always be http://example.com/ anything to the right is just path.

void Main() {     var ub = new UriBuilder("http://example.com/somefolder");     ub.AddPath("file.txt");              var fullUri = ub.Uri; } public static class MyExtensions {     public static UriBuilder AddPath(this UriBuilder builder, string pathValue)     {     var path = builder.Path;      if (path.EndsWith("/") == false)     {         path = path + "/";     }      path += Uri.EscapeDataString(pathValue);      builder.Path = path;     } } 
like image 34
defong Avatar answered Sep 28 '22 23:09

defong