1547

Path.Combine is handy, but is there a similar function in the .NET framework for URLs?

I'm looking for syntax like this:

Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")

which would return:

"http://MyUrl.com/Images/Image.jpg"

3
  • 19
    Flurl includes a Url.Combine method that does just that. Commented Feb 21, 2014 at 6:18
  • 2
    Actually, the // is handled by the routing of the website or server and not by the browser. It will send what you put into the address bar. That's why we get problems when we type htp:// instead of http:// So the // can cause major problems on some sites. I am writing a .dll for a crawler which handles a particular website which throws a 404 if you have // in the url. Commented Jul 7, 2014 at 8:11
  • Note to all: remember to properly URL-encode the input strings (e.g. using WebUtility.UrlEncode). I found that the constructor of Uri does not do that for you, leading to invalid URLs!! Commented Jan 23, 2023 at 15:17

41 Answers 41

1
2
3

If you don't want to add a third-party dependency such as Flurl or create a custom extension method, in ASP.NET Core (also available in Microsoft.Owin), you can use PathString which is intended for the purpose of building up URI paths. You can then create your full URI using a combination of this, Uri and UriBuilder.

In this case, it would be:

new Uri(new UriBuilder("http", "MyUrl.com").Uri, new PathString("/Images").Add("/Image.jpg").ToString())

This gives you all the constituent parts without having to specify the separators in the base URL. Unfortunately, PathString requires that / is prepended to each string otherwise it in fact throws an ArgumentException! But at least you can build up your URI deterministically in a way that is easily unit-testable.

Sign up to request clarification or add additional context in comments.

1 Comment

I tried this out - 1. It seems to require that your first .Uri ends with a / - otherwise it will take the root of this URI before appending. 2. PathString doc suggests it's basically about handling escaping properly, which is not an issue in this example.
2

Rules while combining URLs with a URI

To avoid strange behaviour there's one rule to follow:

  • The path (directory) must end with '/'. If the path ends without '/', the last part is treated like a file-name, and it'll be concatenated when trying to combine with the next URL part.
  • There's one exception: the base URL address (without directory info) needs not to end with '/'
  • the path part must not start with '/'. If it start with '/', every existing relative information from URL is dropped...adding a string.Empty part path will remove the relative directory from the URL too!

If you follow rules above, you can combine URLs with the code below. Depending on your situation, you can add multiple 'directory' parts to the URL...

        var pathParts = new string[] { destinationBaseUrl, destinationFolderUrl, fileName };

        var destination = pathParts.Aggregate((left, right) =>
        {
            if (string.IsNullOrWhiteSpace(right))
                return left;

            return new Uri(new Uri(left), right).ToString();
        });

Comments

2

Use this:

public static class WebPath
{
    public static string Combine(params string[] args)
    {
        var prefixAdjusted = args.Select(x => x.StartsWith("/") && !x.StartsWith("http") ? x.Substring(1) : x);
        return string.Join("/", prefixAdjusted);
    }
}

4 Comments

Nice touch with 'WebPath'. :) The code might be unecessarily dense though - it's hard for me to glance at this and say, yes, that's perfect. It makes me want to see unit tests. Maybe that's just me!
x.StartsWith("/") && !x.StartsWith("http") - why the http check? what do you gain?
You don't want to try to strip off the slash if it starts with http.
@BrianMacKay, I'm not sure a two liner warrants a unit test but if you like feel free to provide one. It's not like I'm accepting patches or anything, but feel free to edit the suggestion.
2

Recently Combine method was added to Energy.Core package, so you might want to use it to join URL parts.

    string url;
    url = Energy.Base.Url.Combine("https://www.youtube.com", "watch?v=NHCgbs3TcYg");
    Console.WriteLine(url);
    url = Energy.Base.Url.Combine("https://www.youtube.com", "watch?v=NHCgbs3TcYg", "t=150");
    Console.WriteLine(url);

Additionally it will recognize parameter part, so it will work as you might expect (joining path with slash and parameters with ampersand).

https://www.youtube.com/watch?v=NHCgbs3TcYg

https://www.youtube.com/watch?v=NHCgbs3TcYg&t=150

Documentation for Energy.Base.Url class

Package on NuGet gallery

Code sample

Comments

1

Use:

    private Uri UriCombine(string path1, string path2, string path3 = "", string path4 = "")
    {
        string path = System.IO.Path.Combine(path1, path2.TrimStart('\\', '/'), path3.TrimStart('\\', '/'), path4.TrimStart('\\', '/'));
        string url = path.Replace('\\','/');
        return new Uri(url);
    }

It has the benefit of behaving exactly like Path.Combine.

Comments

1

I have combined all the previous answers:

    public static string UrlPathCombine(string path1, string path2)
    {
        path1 = path1.TrimEnd('/') + "/";
        path2 = path2.TrimStart('/');

        return Path.Combine(path1, path2)
            .Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
    }

    [TestMethod]
    public void TestUrl()
    {
        const string P1 = "http://msdn.microsoft.com/slash/library//";
        Assert.AreEqual("http://msdn.microsoft.com/slash/library/site.aspx", UrlPathCombine(P1, "//site.aspx"));

        var path = UrlPathCombine("Http://MyUrl.com/", "Images/Image.jpg");

        Assert.AreEqual(
            "Http://MyUrl.com/Images/Image.jpg",
            path);
    }

1 Comment

You could have used VirtualPathUtiliy class to append and remove trailing slashes safely. Check out my answer: stackoverflow.com/a/23399048/3481183
1

Both of these work:

  Uri final = new Uri(Regex.Replace(baseUrl + "/" + relativePath, "(?<!http:)/{2,}", "/"));

Or

  Uri final =new Uri(string.Format("{0}/{1}", baseUrl.ToString().TrimEnd('/'), relativePath.ToString().TrimStart('/')));

I.e. if

baseUrl = "http://tesrurl.test.com/Int18"

and

relativePath = "To_Folder"

output = http://tesrurl.test.com/Int18/To_Folder

Some errors will appear for the code below:

 // If you use the below code, some issues will be there in the final URI
 Uri final = new Uri(baseUrl, relativePath);

Comments

0

I used this code to solve the problem:

string[] brokenBaseUrl = Context.Url.TrimEnd('/').Split('/');
string[] brokenRootFolderPath = RootFolderPath.Split('/');

for (int x = 0; x < brokenRootFolderPath.Length; x++)
{
    //if url doesn't already contain member, append it to the end of the string with / in front
    if (!brokenBaseUrl.Contains(brokenRootFolderPath[x]))
    {
        if (x == 0)
        {
            RootLocationUrl = Context.Url.TrimEnd('/');
        }
        else
        {
            RootLocationUrl += String.Format("/{0}", brokenRootFolderPath[x]);
        }
    }
}

Comments

0

Well, I just concatenate two strings and use regular expressions to do the cleaning part.

    public class UriTool
    {
        public static Uri Join(string path1, string path2)
        {
            string url = path1 + "/" + path2;
            url = Regex.Replace(url, "(?<!http:)/{2,}", "/");

            return new Uri(url);
        }
    }

So, you can use it like this:

    string path1 = "http://someaddress.com/something/";
    string path2 = "/another/address.html";
    Uri joinedUri = UriTool.Join(path1, path2);

    // joinedUri.ToString() returns "http://someaddress.com/something/another/address.html"

Comments

0

We use the following simple helper method to join an arbitrary number of URL parts together:

public static string JoinUrlParts(params string[] urlParts)
{
    return string.Join("/", urlParts.Where(up => !string.IsNullOrEmpty(up)).ToList().Select(up => up.Trim('/')).ToArray());
}

Note, that it doesn't support '../../something/page.htm'-style relative URLs!

Comments

-2

I haven't used the following code yet, but found it during my internet travels to solve a URL combine problem - hoping it's a succinct (and successful!) answer:

VirtualPathUtility.Combine

2 Comments

Not too useful really. There's a number of Google hits explaining some of its issues, but, as well as not liking "http://..." at the start, it actually removes the last sub path of the first argument if it doesn't end in a "/"! The MSDN description sounds fine though!
I have explained and provided a solution to this problem in my answer stackoverflow.com/a/23399048/3481183
1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.