Path.Combine удобен, но есть ли подобная функция в .NET Framework для URL ?
Я ищу синтаксис, как это:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
который бы вернулся:
"http://MyUrl.com/Images/Image.jpg"
Path.Combine удобен, но есть ли подобная функция в .NET Framework для URL ?
Я ищу синтаксис, как это:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
который бы вернулся:
"http://MyUrl.com/Images/Image.jpg"
Ответы:
Существует комментарий Тодда Меньера, что Flurl включает в себя Url.Combine
.
Больше деталей:
Url.Combine - это, по сути, Path.Combine для URL, обеспечивающий один и только один символ-разделитель между частями:
var url = Url.Combine(
"http://MyUrl.com/",
"/too/", "/many/", "/slashes/",
"too", "few?",
"x=1", "y=2"
// result: "http://www.MyUrl.com/too/many/slashes/too/few?x=1&y=2"
Получить Flurl.Http на NuGet :
PM> Install-Package Flurl.Http
Или получите автономный построитель URL без функций HTTP:
PM> Install-Package Flurl
Flurl
и предпочитаете облегченную версию, github.com/jean-lourenco/UrlCombine
Uri
есть конструктор, который должен сделать это для вас: new Uri(Uri baseUri, string relativeUri)
Вот пример:
Uri baseUri = new Uri("http://www.contoso.com");
Uri myUri = new Uri(baseUri, "catalog/shownew.htm");
Примечание редактора: будьте осторожны, этот метод не работает должным образом. В некоторых случаях он может вырезать часть baseUri. Смотрите комментарии и другие ответы.
Это может быть достаточно простым решением:
public static string Combine(string uri1, string uri2)
{
uri1 = uri1.TrimEnd('/');
uri2 = uri2.TrimStart('/');
return string.Format("{0}/{1}", uri1, uri2);
}
Вы используете Uri.TryCreate( ... )
:
Uri result = null;
if (Uri.TryCreate(new Uri("http://msdn.microsoft.com/en-us/library/"), "/en-us/library/system.uri.trycreate.aspx", out result))
{
Console.WriteLine(result);
}
Вернусь:
http://msdn.microsoft.com/en-us/library/system.uri.trycreate.aspx
int.TryParse
, DateTime.TryParseExact
) имеют этот выходной параметр, чтобы их было проще использовать в операторе if. Кстати, вам не нужно инициализировать переменную, как это сделал Райан в этом примере.
test.com/mydirectory/
и /helloworld.aspx
приведет к тому, test.com/helloworld.aspx
что, казалось бы, не то, что вы хотите.
Здесь уже есть несколько отличных ответов. Основываясь на предложении mdsharpe, вот метод расширения, который можно легко использовать, когда вы хотите иметь дело с экземплярами Uri:
using System;
using System.Linq;
public static class UriExtensions
{
public static Uri Append(this Uri uri, params string[] paths)
{
return new Uri(paths.Aggregate(uri.AbsoluteUri, (current, path) => string.Format("{0}/{1}", current.TrimEnd('/'), path.TrimStart('/'))));
}
}
И пример использования:
var url = new Uri("http://example.com/subpath/").Append("/part1/", "part2").AbsoluteUri;
Это создаст http://example.com/subpath/part1/part2
Ответ Райана Кука близок к тому, что мне нужно, и может быть более подходящим для других разработчиков. Тем не менее, он добавляет http: // в начало строки и в целом он делает немного больше форматирования, чем я после.
Кроме того, для моих случаев использования определение относительных путей не важно.
Ответ mdsharp также содержит в себе идею хорошей идеи, хотя для ее фактической реализации потребовалось еще несколько подробностей. Это попытка уточнить это (и я использую это в производстве):
C #
public string UrlCombine(string url1, string url2)
{
if (url1.Length == 0) {
return url2;
}
if (url2.Length == 0) {
return url1;
}
url1 = url1.TrimEnd('/', '\\');
url2 = url2.TrimStart('/', '\\');
return string.Format("{0}/{1}", url1, url2);
}
VB.NET
Public Function UrlCombine(ByVal url1 As String, ByVal url2 As String) As String
If url1.Length = 0 Then
Return url2
End If
If url2.Length = 0 Then
Return url1
End If
url1 = url1.TrimEnd("/"c, "\"c)
url2 = url2.TrimStart("/"c, "\"c)
Return String.Format("{0}/{1}", url1, url2)
End Function
Этот код проходит следующий тест, который происходит в VB:
<TestMethod()> Public Sub UrlCombineTest()
Dim target As StringHelpers = New StringHelpers()
Assert.IsTrue(target.UrlCombine("test1", "test2") = "test1/test2")
Assert.IsTrue(target.UrlCombine("test1/", "test2") = "test1/test2")
Assert.IsTrue(target.UrlCombine("test1", "/test2") = "test1/test2")
Assert.IsTrue(target.UrlCombine("test1/", "/test2") = "test1/test2")
Assert.IsTrue(target.UrlCombine("/test1/", "/test2/") = "/test1/test2/")
Assert.IsTrue(target.UrlCombine("", "/test2/") = "/test2/")
Assert.IsTrue(target.UrlCombine("/test1/", "") = "/test1/")
End Sub
ArgumentNullException("url1")
если аргумент Nothing
? Извините, просто придирчивый ;-). Обратите внимание, что обратный слеш не имеет ничего общего с URI (и, если он есть, его не следует обрезать), так что вы можете удалить его из TrimXXX.
Path.Combine не работает для меня, потому что могут быть такие символы, как "|" в аргументах QueryString и, следовательно, в URL, что приведет к ArgumentException.
Я сначала попробовал новый Uri(Uri baseUri, string relativeUri)
подход, который потерпел неудачу для меня из-за URI как http://www.mediawiki.org/wiki/Special:SpecialPages
:
new Uri(new Uri("http://www.mediawiki.org/wiki/"), "Special:SpecialPages")
приведет к Special: SpecialPages, потому что двоеточие после Special
этого обозначает схему.
Поэтому мне, наконец, пришлось выбрать маршрут mdsharpe / Brian MacKays, и я разработал его немного дальше, чтобы работать с несколькими частями URI:
public static string CombineUri(params string[] uriParts)
{
string uri = string.Empty;
if (uriParts != null && uriParts.Length > 0)
{
char[] trims = new char[] { '\\', '/' };
uri = (uriParts[0] ?? string.Empty).TrimEnd(trims);
for (int i = 1; i < uriParts.Length; i++)
{
uri = string.Format("{0}/{1}", uri.TrimEnd(trims), (uriParts[i] ?? string.Empty).TrimStart(trims));
}
}
return uri;
}
Применение: CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")
Основываясь на приведенном вами примере URL , я предполагаю, что вы хотите объединить URL, относящиеся к вашему сайту.
Исходя из этого предположения, я предложу это решение как наиболее подходящий ответ на ваш вопрос: «Path.Combine удобен, есть ли подобная функция в структуре для URL-адресов?»
Поскольку в структуре для URL-адресов есть аналогичная функция, я предлагаю правильный метод: «VirtualPathUtility.Combine». Вот ссылка на MSDN: VirtualPathUtility.Combine Метод
Есть одно предостережение: я считаю, что это работает только для URL, относящихся к вашему сайту (то есть вы не можете использовать его для создания ссылок на другой веб-сайт. Например, var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");
).
Server.MapPath
и объединением.
Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")
path.Replace(Path.DirectorySeparatorChar, '/');
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
Я просто собрал небольшой метод расширения:
public static string UriCombine (this string val, string append)
{
if (String.IsNullOrEmpty(val)) return append;
if (String.IsNullOrEmpty(append)) return val;
return val.TrimEnd('/') + "/" + append.TrimStart('/');
}
Это можно использовать так:
"www.example.com/".UriCombine("/images").UriCombine("first.jpeg");
Остроумный пример, Райан, чтобы закончить ссылкой на функцию. Отлично сработано.
Одна рекомендация Брайана: если вы заключите этот код в функцию, вы можете использовать UriBuilder для переноса базового URL-адреса перед вызовом TryCreate.
В противном случае базовый URL ДОЛЖЕН включать схему (где UriBuilder примет http: //). Просто мысль:
public string CombineUrl(string baseUrl, string relativeUrl) {
UriBuilder baseUri = new UriBuilder(baseUrl);
Uri newUri;
if (Uri.TryCreate(baseUri.Uri, relativeUrl, out newUri))
return newUri.ToString();
else
throw new ArgumentException("Unable to combine specified url values");
}
Простой способ объединить их и убедиться, что это всегда правильно:
string.Format("{0}/{1}", Url1.Trim('/'), Url2);
Объединение нескольких частей URL может быть немного сложнее. Вы можете использовать двухпараметрический конструктор Uri(baseUri, relativeUri)
или Uri.TryCreate()
функцию полезности.
В любом случае, вы могли бы в конечном итоге возвращаются неправильный результат , потому что эти методы продолжают усечения относительные части от первого параметра baseUri
, то есть с чем - то вроде http://google.com/some/thing
к http://google.com
.
Чтобы иметь возможность объединить несколько частей в окончательный URL-адрес, вы можете скопировать две функции ниже:
public static string Combine(params string[] parts)
{
if (parts == null || parts.Length == 0) return string.Empty;
var urlBuilder = new StringBuilder();
foreach (var part in parts)
{
var tempUrl = tryCreateRelativeOrAbsolute(part);
urlBuilder.Append(tempUrl);
}
return VirtualPathUtility.RemoveTrailingSlash(urlBuilder.ToString());
}
private static string tryCreateRelativeOrAbsolute(string s)
{
System.Uri uri;
System.Uri.TryCreate(s, UriKind.RelativeOrAbsolute, out uri);
string tempUrl = VirtualPathUtility.AppendTrailingSlash(uri.ToString());
return tempUrl;
}
Полный код с модульными тестами для демонстрации использования можно найти по адресу https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs.
У меня есть модульные тесты, чтобы охватить три наиболее распространенных случая:
Я нашел, UriBuilder
работал действительно хорошо для такого рода вещей:
UriBuilder urlb = new UriBuilder("http", _serverAddress, _webPort, _filePath);
Uri url = urlb.Uri;
return url.AbsoluteUri;
Посмотрите Класс UriBuilder - MSDN для большего количества конструкторов и документации.
Вот метод Microsoft (OfficeDev PnP) UrlUtility.Combine :
const char PATH_DELIMITER = '/';
/// <summary>
/// Combines a path and a relative path.
/// </summary>
/// <param name="path"></param>
/// <param name="relative"></param>
/// <returns></returns>
public static string Combine(string path, string relative)
{
if(relative == null)
relative = String.Empty;
if(path == null)
path = String.Empty;
if(relative.Length == 0 && path.Length == 0)
return String.Empty;
if(relative.Length == 0)
return path;
if(path.Length == 0)
return relative;
path = path.Replace('\\', PATH_DELIMITER);
relative = relative.Replace('\\', PATH_DELIMITER);
return path.TrimEnd(PATH_DELIMITER) + PATH_DELIMITER + relative.TrimStart(PATH_DELIMITER);
}
Источник: GitHub
Я считаю следующее полезным и имеет следующие функции:
params
параметров для нескольких сегментов URLУчебный класс
public static class UrlPath
{
private static string InternalCombine(string source, string dest)
{
if (string.IsNullOrWhiteSpace(source))
throw new ArgumentException("Cannot be null or white space", nameof(source));
if (string.IsNullOrWhiteSpace(dest))
throw new ArgumentException("Cannot be null or white space", nameof(dest));
return $"{source.TrimEnd('/', '\\')}/{dest.TrimStart('/', '\\')}";
}
public static string Combine(string source, params string[] args)
=> args.Aggregate(source, InternalCombine);
}
тесты
UrlPath.Combine("test1", "test2");
UrlPath.Combine("test1//", "test2");
UrlPath.Combine("test1", "/test2");
// Result = test1/test2
UrlPath.Combine(@"test1\/\/\/", @"\/\/\\\\\//test2", @"\/\/\\\\\//test3\") ;
// Result = test1/test2/test3
UrlPath.Combine("/test1/", "/test2/", null);
UrlPath.Combine("", "/test2/");
UrlPath.Combine("/test1/", null);
// Throws an ArgumentException
Мое общее решение:
public static string Combine(params string[] uriParts)
{
string uri = string.Empty;
if (uriParts != null && uriParts.Any())
{
char[] trims = new char[] { '\\', '/' };
uri = (uriParts[0] ?? string.Empty).TrimEnd(trims);
for (int i = 1; i < uriParts.Length; i++)
{
uri = string.Format("{0}/{1}", uri.TrimEnd(trims), (uriParts[i] ?? string.Empty).TrimStart(trims));
}
}
return uri;
}
Я создал эту функцию, которая сделает вашу жизнь проще:
/// <summary>
/// The ultimate Path combiner of all time
/// </summary>
/// <param name="IsURL">
/// true - if the paths are Internet URLs, false - if the paths are local URLs, this is very important as this will be used to decide which separator will be used.
/// </param>
/// <param name="IsRelative">Just adds the separator at the beginning</param>
/// <param name="IsFixInternal">Fix the paths from within (by removing duplicate separators and correcting the separators)</param>
/// <param name="parts">The paths to combine</param>
/// <returns>the combined path</returns>
public static string PathCombine(bool IsURL , bool IsRelative , bool IsFixInternal , params string[] parts)
{
if (parts == null || parts.Length == 0) return string.Empty;
char separator = IsURL ? '/' : '\\';
if (parts.Length == 1 && IsFixInternal)
{
string validsingle;
if (IsURL)
{
validsingle = parts[0].Replace('\\' , '/');
}
else
{
validsingle = parts[0].Replace('/' , '\\');
}
validsingle = validsingle.Trim(separator);
return (IsRelative ? separator.ToString() : string.Empty) + validsingle;
}
string final = parts
.Aggregate
(
(string first , string second) =>
{
string validfirst;
string validsecond;
if (IsURL)
{
validfirst = first.Replace('\\' , '/');
validsecond = second.Replace('\\' , '/');
}
else
{
validfirst = first.Replace('/' , '\\');
validsecond = second.Replace('/' , '\\');
}
var prefix = string.Empty;
if (IsFixInternal)
{
if (IsURL)
{
if (validfirst.Contains("://"))
{
var tofix = validfirst.Substring(validfirst.IndexOf("://") + 3);
prefix = validfirst.Replace(tofix , string.Empty).TrimStart(separator);
var tofixlist = tofix.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
validfirst = separator + string.Join(separator.ToString() , tofixlist);
}
else
{
var firstlist = validfirst.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
validfirst = string.Join(separator.ToString() , firstlist);
}
var secondlist = validsecond.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
validsecond = string.Join(separator.ToString() , secondlist);
}
else
{
var firstlist = validfirst.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
var secondlist = validsecond.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
validfirst = string.Join(separator.ToString() , firstlist);
validsecond = string.Join(separator.ToString() , secondlist);
}
}
return prefix + validfirst.Trim(separator) + separator + validsecond.Trim(separator);
}
);
return (IsRelative ? separator.ToString() : string.Empty) + final;
}
Он работает как для URL, так и для обычных путей.
Применение:
// Fixes internal paths
Console.WriteLine(PathCombine(true , true , true , @"\/\/folder 1\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
// Result: /folder 1/folder2/folder3/somefile.ext
// Doesn't fix internal paths
Console.WriteLine(PathCombine(true , true , false , @"\/\/folder 1\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
//result : /folder 1//////////folder2////folder3/somefile.ext
// Don't worry about URL prefixes when fixing internal paths
Console.WriteLine(PathCombine(true , false , true , @"/\/\/https:/\/\/\lul.com\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
// Result: https://lul.com/folder2/folder3/somefile.ext
Console.WriteLine(PathCombine(false , true , true , @"../../../\\..\...\./../somepath" , @"anotherpath"));
// Result: \..\..\..\..\...\.\..\somepath\anotherpath
Почему бы просто не использовать следующее.
System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/")
[System.IO.Path]::Combine("http://MyUrl.com/","/Images/Image.jpg")
однако это не удается с результатом: /Images/Image.jpg
. Удалите /
из второго subPath, и это работает:[System.IO.Path]::Combine("http://MyUrl.com/","Images/Image.jpg")
Правила при объединении URL с URI
Чтобы избежать странного поведения, есть одно правило:
string.Empty
пути к детали также удалит относительный каталог из URL!Если вы следуете правилам выше, вы можете комбинировать URL с кодом ниже. В зависимости от вашей ситуации, вы можете добавить несколько частей «каталога» в 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();
});
Если вы не хотите добавлять стороннюю зависимость, такую как Flurl, или создавать собственный метод расширения, в ASP.NET Core (также доступен в Microsoft.Owin), вы можете использовать тот, PathString
который предназначен для создания URI пути. Затем вы можете создать свой полный URI, используя комбинацию этого Uri
и UriBuilder
.
В этом случае это будет:
new Uri(new UriBuilder("http", "MyUrl.com").Uri, new PathString("/Images").Add("/Image.jpg").ToString())
Это дает вам все составные части без необходимости указывать разделители в базовом URL. К сожалению, PathString
требует, чтобы /
к каждой строке был добавлен префикс, в противном случае он фактически выбрасывает ArgumentException
! Но, по крайней мере, вы можете создать свой URI детерминистическим способом, который легко тестируется юнитами.
Так что у меня есть другой подход, похожий на всех, кто использовал UriBuilder.
Я не хотел разделять свой BaseUrl (который может содержать часть пути - например, http://mybaseurl.com/dev/ ), как это сделал javajavajavajavajava .
Следующий фрагмент кода показывает код + тесты.
Осторожно: это решение строчной буквы хоста и добавляет порт. Если это нежелательно, можно написать строковое представление, например, используя Uri
свойство UriBuilder
.
public class Tests
{
public static string CombineUrl (string baseUrl, string path)
{
var uriBuilder = new UriBuilder (baseUrl);
uriBuilder.Path = Path.Combine (uriBuilder.Path, path);
return uriBuilder.ToString();
}
[TestCase("http://MyUrl.com/", "/Images/Image.jpg", "http://myurl.com:80/Images/Image.jpg")]
[TestCase("http://MyUrl.com/basePath", "/Images/Image.jpg", "http://myurl.com:80/Images/Image.jpg")]
[TestCase("http://MyUrl.com/basePath", "Images/Image.jpg", "http://myurl.com:80/basePath/Images/Image.jpg")]
[TestCase("http://MyUrl.com/basePath/", "Images/Image.jpg", "http://myurl.com:80/basePath/Images/Image.jpg")]
public void Test1 (string baseUrl, string path, string expected)
{
var result = CombineUrl (baseUrl, path);
Assert.That (result, Is.EqualTo (expected));
}
}
Протестировано с .NET Core 2.1 на Windows 10.
Почему это работает?
Даже если Path.Combine
будет возвращаться обратная косая черта (по крайней мере в Windows), UriBuilder обрабатывает этот случай в Setter of Path
.
Взято из https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs (обращайтесь к string.Replace
)
[AllowNull]
public string Path
{
get
{
return _path;
}
set
{
if ((value == null) || (value.Length == 0))
{
value = "/";
}
_path = Uri.InternalEscapeString(value.Replace('\\', '/'));
_changed = true;
}
}
Это лучший подход?
Конечно, это решение довольно самоописуемо (по крайней мере, на мой взгляд). Но вы полагаетесь на недокументированную (по крайней мере, я ничего не нашел с помощью быстрого поиска в Google) «функцию» из .NET API. Это может измениться в будущем выпуске, поэтому, пожалуйста, опишите метод с помощью тестов.
В https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs ( Path_Get_Set
) есть тесты, которые проверяют \
правильность преобразования.
Примечание: можно также работать со UriBuilder.Uri
свойством напрямую, если URI будет использоваться дляSystem.Uri
ctor uri.
Для тех, кто ищет однострочник и просто хочет соединить части пути, не создавая новый метод, не ссылаясь на новую библиотеку, не создавая значение URI и не преобразовывая его в строку, тогда ...
string urlToImage = String.Join("/", "websiteUrl", "folder1", "folder2", "folder3", "item");
Это довольно просто, но я не вижу, что тебе еще нужно. Если вы боитесь удвоить «/», то вы можете просто сделать .Replace("//", "/")
потом. Если вы боитесь заменить удвоенный «//» в «https: //», вместо этого сделайте одно объединение, замените удвоенный «/», а затем присоединитесь к URL веб-сайта (однако я уверен, что большинство браузеров автоматически преобразовать что-нибудь с «https:» перед ним, чтобы прочитать в правильном формате). Это будет выглядеть так:
string urlToImage = String.Join("/","websiteUrl", String.Join("/", "folder1", "folder2", "folder3", "item").Replace("//","/"));
Здесь есть множество ответов, которые помогут справиться со всем вышеперечисленным, но в моем случае он мне понадобился только один раз в одном месте, и мне не нужно было на него сильно полагаться. Кроме того, действительно легко увидеть, что здесь происходит.
См .: https://docs.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8.
Использование:
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);
}
Он имеет то преимущество, что ведет себя точно так же Path.Combine
.
Вот мой подход, и я буду использовать его и для себя:
public static string UrlCombine(string part1, string part2)
{
string newPart1 = string.Empty;
string newPart2 = string.Empty;
string seperator = "/";
// If either part1 or part 2 is empty,
// we don't need to combine with seperator
if (string.IsNullOrEmpty(part1) || string.IsNullOrEmpty(part2))
{
seperator = string.Empty;
}
// If part1 is not empty,
// remove '/' at last
if (!string.IsNullOrEmpty(part1))
{
newPart1 = part1.TrimEnd('/');
}
// If part2 is not empty,
// remove '/' at first
if (!string.IsNullOrEmpty(part2))
{
newPart2 = part2.TrimStart('/');
}
// Now finally combine
return string.Format("{0}{1}{2}", newPart1, seperator, newPart2);
}
Использовать этот:
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);
}
}
Для чего это стоит, здесь пара методов расширения. Первый объединяет пути, а второй добавляет параметры в URL.
public static string CombineUrl(this string root, string path, params string[] paths)
{
if (string.IsNullOrWhiteSpace(path))
{
return root;
}
Uri baseUri = new Uri(root);
Uri combinedPaths = new Uri(baseUri, path);
foreach (string extendedPath in paths)
{
combinedPaths = new Uri(combinedPaths, extendedPath);
}
return combinedPaths.AbsoluteUri;
}
public static string AddUrlParams(this string url, Dictionary<string, string> parameters)
{
if (parameters == null || !parameters.Keys.Any())
{
return url;
}
var tempUrl = new StringBuilder($"{url}?");
int count = 0;
foreach (KeyValuePair<string, string> parameter in parameters)
{
if (count > 0)
{
tempUrl.Append("&");
}
tempUrl.Append($"{WebUtility.UrlEncode(parameter.Key)}={WebUtility.UrlEncode(parameter.Value)}");
count++;
}
return tempUrl.ToString();
}
Как и в других ответах, либо новый, Uri()
либо TryCreate()
можно сделать галочку. Однако базовый Uri должен заканчиваться, /
а родственник НЕ должен начинаться с/
; в противном случае он удалит завершающую часть базового URL
Я думаю, что это лучше всего сделать как метод расширения, т.е.
public static Uri Append(this Uri uri, string relativePath)
{
var baseUri = uri.AbsoluteUri.EndsWith('/') ? uri : new Uri(uri.AbsoluteUri + '/');
var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
return new Uri(baseUri, relative);
}
и использовать это:
var baseUri = new Uri("http://test.com/test/");
var combinedUri = baseUri.Append("/Do/Something");
С точки зрения производительности, это потребляет больше ресурсов, чем нужно, из-за класса Uri, который выполняет большой анализ и проверку; очень грубое профилирование (отладка) сделало миллион операций примерно за 2 секунды. Это будет работать для большинства сценариев, однако, чтобы быть более эффективным, лучше манипулировать всем как строками, это займет 125 миллисекунд на 1 миллион операций. Т.е.
public static string Append(this Uri uri, string relativePath)
{
//avoid the use of Uri as it's not needed, and adds a bit of overhead.
var absoluteUri = uri.AbsoluteUri; //a calculated property, better cache it
var baseUri = absoluteUri.EndsWith('/') ? absoluteUri : absoluteUri + '/';
var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
return baseUri + relative;
}
И если вы все еще хотите вернуть URI, это займет около 600 миллисекунд на 1 миллион операций.
public static Uri AppendUri(this Uri uri, string relativePath)
{
//avoid the use of Uri as it's not needed, and adds a bit of overhead.
var absoluteUri = uri.AbsoluteUri; //a calculated property, better cache it
var baseUri = absoluteUri.EndsWith('/') ? absoluteUri : absoluteUri + '/';
var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
return new Uri(baseUri + relative);
}
Надеюсь, это поможет.
Я думаю, что это должно дать вам больше гибкости, поскольку вы можете работать с любым количеством отрезков пути:
public static string UrlCombine(this string baseUrl, params string[] segments)
=> string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));
Url.Combine
метод, который делает именно это.