Как правильно объединять части URL в C#? Аналог Path.Combine для URL
Правильное решение: используйте Uri или Flurl
Проблема, которую вы описали, очень распространена. Path.Combine действительно не подходит для URL, потому что он работает с файловыми путями Windows, используя обратную косую черту. Для URL нужно использовать прямой слеш и учитывать особенности протокола.
В .NET есть несколько способов корректно объединить части URL. Рассмотрим лучшие из них.
Способ 1: Класс Uri (встроенный, без сторонних библиотек)
Самый простой и надёжный способ — использовать конструктор Uri(Uri baseUri, string relativeUri). Он автоматически корректно объединит базовый URL с относительным путём, учитывая все слеши.
string baseUrl = "https://example.com/api/";
string endpoint = "users/get";
// Создаём базовый Uri
Uri baseUri = new Uri(baseUrl);
// Объединяем с относительным путём
Uri fullUri = new Uri(baseUri, endpoint);
string fullUrl = fullUri.ToString();
Console.WriteLine(fullUrl);
// Вывод: https://example.com/api/users/get
Этот метод работает без ошибок в следующих случаях:
- Базовый URL с завершающим слешом:
https://example.com/api/+users/get→https://example.com/api/users/get - Базовый URL без завершающего слеша:
https://example.com/api+users/get→https://example.com/users/get(внимание: базовый путь "api" будет потерян, так какUriинтерпретирует его как файл, а не как каталог) - Относительный путь с начальным слешом:
https://example.com/api/+/users/get→https://example.com/users/get(начальный слеш означает "относительно корня")
Чтобы избежать сюрпризов, всегда добавляйте завершающий слеш к базовому URL, если он указывает на каталог:
string baseUrl = "https://example.com/api".TrimEnd('/') + "/"; // гарантируем слеш
Uri baseUri = new Uri(baseUrl);
Uri fullUri = new Uri(baseUri, "users/get");
Console.WriteLine(fullUri); // https://example.com/api/users/get
Способ 2: Метод Uri.TryCreate
Если вы хотите избежать исключений при некорректных данных, используйте Uri.TryCreate:
string baseUrl = "https://example.com/api/";
string endpoint = "users/get";
if (Uri.TryCreate(baseUrl, UriKind.Absolute, out Uri baseUri) &&
Uri.TryCreate(baseUri, endpoint, out Uri fullUri))
{
Console.WriteLine(fullUri); // https://example.com/api/users/get
}
else
{
Console.WriteLine("Некорректный URL");
}
Способ 3: Сторонняя библиотека Flurl
Если вы часто работаете с URL, рекомендую установить пакет Flurl через NuGet. Он предоставляет элегантный fluent-интерфейс:
// Установка: Install-Package Flurl
using Flurl;
string fullUrl = "https://example.com/api"
.AppendPathSegment("users")
.AppendPathSegment("get")
.ToString();
Console.WriteLine(fullUrl); // https://example.com/api/users/get
Flurl автоматически управляет слешами и поддерживает добавление query-параметров:
string url = "https://example.com/api"
.AppendPathSegment("users")
.SetQueryParams(new { page = 1, limit = 10 })
.ToString();
Console.WriteLine(url); // https://example.com/api/users?page=1&limit=10
Вывод
Используйте встроенный класс Uri для простых случаев — это надёжно и не требует дополнительных зависимостей. Для сложных сценариев (много сегментов, query-параметры) лучше взять Flurl — он значительно упрощает код и снижает риск ошибок.
Альтернативный подход: ручное объединение с помощью String.Join и Trim
Если по каким-то причинам вы не хотите использовать Uri или сторонние библиотеки, можно написать простой вспомогательный метод. Он будет работать корректно, если правильно обрабатывать слеши.
public static string CombineUrl(string baseUrl, string relativePath)
{
// Убираем завершающий слеш у базового URL (если есть)
baseUrl = baseUrl.TrimEnd('/');
// Убираем начальный слеш у относительного пути (если есть)
relativePath = relativePath.TrimStart('/');
// Объединяем через один слеш
return $"{baseUrl}/{relativePath}";
}
// Использование:
string fullUrl = CombineUrl("https://example.com/api/", "users/get");
Console.WriteLine(fullUrl); // https://example.com/api/users/get
fullUrl = CombineUrl("https://example.com/api", "/users/get");
Console.WriteLine(fullUrl); // https://example.com/api/users/get
Этот метод подходит для простых случаев, но у него есть недостатки:
- Не проверяет валидность URL (например, не обработает протокол или порт)
- Не работает с query-параметрами или фрагментами (якорями)
- Может дать неверный результат для абсолютных путей (например, если
relativePathначинается сhttp://)
Тем не менее, для внутренних проектов или простых сценариев это быстрое и лёгкое решение. Если вам нужно что-то более надёжное — используйте Uri из первого ответа.
Ответов пока нет.
Войдите чтобы оставить ответ