Сочетание двух относительных Uris

Мне нужно объединить два относительных Uris, например. ../mypath/ и myimage.png, чтобы создать ../mypath/myimage.png. Они не являются путями для файлов на диске, поэтому Path.Combine не подходит (это относительные пути к ресурсам для веб-страницы). new Uri выбрасывает ArgumentOutOfRangeException, потому что базовый uri является относительным (не абсолютным).

Есть ли у меня какие-либо параметры, кроме проверки конечной косой черты, а затем комбинирование путей?

EDIT:

Вот тестовый пример, демонстрирующий, что Path.Combine не будет работать для случая, когда первый URL-адрес еще не содержит конечную косую черту:

// 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);
}

Ответ 1

Не используйте path.combine так же, как для физического пути, чтобы он мог смутить вас с помощью слэшей. Вы можете сделать свою собственную функцию Uri comb. Проверка косой черты в конце и добавление ее к следующей.

Может ли конструктор URI с помощью двух аргументов?

new Uri(Uri baseUri, string relativeUri)

Ответ 2

Если ваша вторая часть (например, в моем собственном случае) действительно является именем файла без какого-либо экранирования (и как таковая может содержать символы invalids для URL-адреса), вот решение, в котором я закончил:

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

Остерегайтесь, что это решение не будет поддерживать полный uri (со схемой, хостом, портом): он выдает исключение с полным uri. Спасибо Manish Pansiniya за за упоминание System.Web.VirtualPathUtility.

Кроме того, поскольку мое имя файла было фактически частичным файловым путем (некоторые имена папок, за которыми следует имя файла), вместо того, чтобы напрямую обращаться к System.Uri.EscapeDataString, я вызываю следующую функцию:

/// <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)));
}

(Требуется использовать System.Linq для .Select и fx4 для используемой string.Join перегрузки.)

Ответ 3

Вы можете использовать конструктор Uri, который берет базу и относительную часть, чтобы выполнить комбинацию, - но обратите внимание, что поведение, возможно, не будет тем, что вы ожидаете. Класс Uri будет видеть конечную часть вашей базы как "каталог" или "файл" (чтобы указать его в терминах пути). Если он видит конец как файл, он будет удален.

Например, объединение http://server/something/ с resource.png даст вам http://server/something/resource.png.

Теперь оставьте конечную косую черту: объедините http://server/something с resource.png и получите http://server/resource.png.

Это имеет смысл, если вы думаете об этом, начиная с базы Uri http://server/something.png и запрашивая относительный uri resource.png: http://server/something.png/resource.png не то, что вы ищете.

Если вы ВСЕГДА знаете, что они должны быть добавлены, вам необходимо убедиться, что база заканчивается косой чертой перед объединением.