Redwood
Redwood

Reputation: 69302

Combining two relative Uris

I need to combine two relative Uris, e.g. ../mypath/ and myimage.png to create ../mypath/myimage.png. They are not paths to files on disk so Path.Combine is not appropriate (they are relative paths to resources for a web page). new Uri throws an ArgumentOutOfRangeException because the base uri is relative (not absolute).

Do I have any options other than checking for a trailing slash and then combining the paths myself?

EDIT:

Here is a test case that demonstrates that Path.Combine will not work for the case when the first url does not already contain a trailing slash:

// The first case fails with result "../testpath\resource.png"
[TestCase("../testpath", "resource.png", "../testpath/resource.png")] 
[TestCase("../testpath/", "resource.png", "../testpath/resource.png")]
public void TestPathCombine(string path, string resourceName, string expectedResult) {
    string result = Path.Combine(path, resourceName);
    Assert.AreEqual(expectedResult, result);
}

Upvotes: 12

Views: 7897

Answers (3)

Frédéric
Frédéric

Reputation: 9854

If your second part is (like in my own case) really a file name without any escaping (and as such may contain invalids chars for an url), here is the solution I have ended up with:

VirtualPathUtility.Combine(
    VirtualPathUtility.AppendTrailingSlash(relativeUri), 
    Uri.EscapeDataString(fileName));

Beware that this solution will not support a full uri (with scheme, host, port): it will throw an exception with a full uri. Thanks to Manish Pansiniya for mentioning System.Web.VirtualPathUtility.

In addition, as my file name was in fact a partial file path (some folder names followed by file name), rather than calling directly System.Uri.EscapeDataString, I have call the following function:

/// <summary>
/// Convert a partial file path to a partial url path.
/// </summary>
/// <param name="partialFilePath">The partial file path.</param>
/// <returns>A partial url path.</returns>
public static string ConvertPartialFilePathToPartialUrlPath(
    string partialFilePath)
{
    if (partialFilePath == null)
        return null;
    return string.Join("/", 
        partialFilePath.Split('/', '\\')
            .Select(part => Uri.EscapeDataString(part)));
}

(Requires using System.Linq for .Select and fx4 for the used string.Join overload.)

Upvotes: 8

Philip Rieck
Philip Rieck

Reputation: 32568

You can use the Uri constructor that takes a base and a relative part to do the combination - but note that the behavior will possibly not be what you expect. The Uri class will see the end part of your base as either a "directory" or a "file" (to put it in path terms). If it sees the end as a file, that will get removed.

For example, combining http://server/something/ with resource.png will give you http://server/something/resource.png.

Now omit the trailing slash: combine http://server/something with resource.png and get http://server/resource.png.

This makes sense if you think of it as starting with a base Uri of http://server/something.png and asking for the relative uri resource.png: http://server/something.png/resource.png isn't what you're looking for.

If you ALWAYS know that they should be appended, you need to make sure that the base ends with a slash before combining.

Upvotes: 3

Manish Pansiniya
Manish Pansiniya

Reputation: 545

Do not use path.combine as it is for physcial path so it might confuse you with slashes. You can make your own function of Uri combine. Checking slash at the end and append it to next one.

Can URI constructor with two argument help?

new Uri(Uri baseUri, string relativeUri)

Upvotes: 1

Related Questions