Объединить относительную базу Uri с относительным путем

Я ищу чистый способ объединить относительную базу Uri с другим относительным путем. Я пробовал следующее, но Uri(Uri, string) и UriBuilder(Uri) требуют абсолютного Uris (throwing InvalidOperationException: эта операция не поддерживается для относительного URI).

// where Settings.Default.ImagesPath is "~/path/to/images"
// attempt 1
_imagePath = new Uri(Settings.Default.ImagesPath, image);

// attempt 2
UriBuilder uriBuilder = new UriBuilder(Settings.Default.ImagesPath);
uriBuilder.Path += image;
_imagePath = uriBuilder.Uri;

Я не хочу делать никаких уродливых манипуляций с строкой, чтобы убедиться, что базовый путь заканчивается конечной косой чертой и т.д.

Ответы

Ответ 1

Это все еще немного грязнее, чем хотелось бы, но он работает.

public static class UriExtensions
{
    public static Uri Combine(this Uri relativeBaseUri, Uri relativeUri)
    {
        if (relativeBaseUri == null)
        {
            throw new ArgumentNullException("relativeBaseUri");
        }

        if (relativeUri == null)
        {
            throw new ArgumentNullException("relativeUri");
        }

        string baseUrl = VirtualPathUtility.AppendTrailingSlash(relativeBaseUri.ToString());
        string combinedUrl = VirtualPathUtility.Combine(baseUrl, relativeUri.ToString());

        return new Uri(combinedUrl, UriKind.Relative);
    }
}

Здесь пример использования:

Uri imageUrl = new Uri("profile.jpg", UriKind.Relative);
Uri baseImageUrl = new Uri("~/path/to/images", UriKind.Relative);
Uri combinedImageUrl = baseImageUrl.Combine(image);

Комбинированный файлImageUrl   ~/Путь/к/изображения/profile.jpg

Ответ 2

Try:

UriBuilder builder = new UriBuilder();
Uri baseUri = builder.Uri;
builder.Path = Settings.Default.ImagesRealtivePath;
if (!builder.Path.EndsWith("/"))
    builder.Path += "/";
_imagePath = baseUri.MakeRelativeUri(new Uri(builder.Uri, image));

Это вернет строку "~/path/to/images/image.jpg".

Ответ 3

Прежде всего, спасибо за ответ на этот пост!

Я сделал упрощенную версию метода, пропустив "сложность" использования класса Uri. Метод принимает только строки как параметры и также возвращает строку.

public static string MakeRelativeUrl(params string[] relativePaths)
{
    var res = "~/";
    foreach (var relativePath in relativePaths)
    {
        string baseUrl = VirtualPathUtility.AppendTrailingSlash(res);
        res = VirtualPathUtility.Combine(baseUrl, relativePath);
    }
    return res;
}

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

Можно, конечно, легко модифицировать, чтобы вернуть Uri, все еще сохраняя преимущество анализа параметров строки:

public static Uri MakeRelativeUrl(params string[] relativePaths)
{
    var res = "~/";
    foreach (var relativePath in relativePaths)
    {
        string baseUrl = VirtualPathUtility.AppendTrailingSlash(res);
        res = VirtualPathUtility.Combine(baseUrl, relativePath);
    }
    return new Uri(res, UriKind.Relative);
}

Использование обоих приведенных выше примеров кода:

Image.ImageUrl = MakeRelativeUrl("path", "to", "images", "image.jpg").ToString();
// Image.ImageUrl == "~/path/to/images/image.jpg"

Ответ 4

Несколько более обобщенная версия ответа jrummell, которая принимает первый параметр как абсолютный или относительный Uri, это:

    /// <summary>
    /// Combines two <see cref="Uri"/>s.
    /// </summary>
    /// <param name="baseUri">Relative or absolute base uri.</param>
    /// <param name="relativeUri">Uri to be appended.</param>
    public static Uri Combine(this Uri baseUri, Uri relativeUri)
    {
        if (baseUri == null) throw new ArgumentNullException("baseUri");
        if (relativeUri == null) throw new ArgumentNullException("relativeUri");

        string baseUrl = VirtualPathUtility.AppendTrailingSlash(baseUri.ToString());
        string combinedUrl = VirtualPathUtility.Combine(baseUrl, relativeUri.ToString());

        return new Uri(combinedUrl, baseUri.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative);
    }

Ответ 5

Try:

UriBuilder uriBuilder = new UriBuilder(Settings.Default.ImagesRealtivePath);
uriBuilder.Path += image;
_imagePath = uriBuilder.Uri;

Ответ 6

Вы можете просто использовать Path.Combine(string, string) для достижения этого. Если это относительный URL-адрес, выход будет немного напуганным, но его было бы достаточно легко исправить или вы могли бы просто проигнорировать проблему, и большинство обычаев должно работать.

Path.Combine("~/path/to/images", "image.jpg");

Выход: ~/путь/to/images\image.jpg