Flurl включает Url.Combineметод, который делает именно это.
Тодд Меньер
2
На самом деле // обрабатывается маршрутизацией веб-сайта или сервера, а не браузером. Он отправит то, что вы положили в адресную строку. Вот почему у нас возникают проблемы, когда мы вводим htp: // вместо http: // Таким образом, // может вызвать серьезные проблемы на некоторых сайтах. Я пишу .dll для сканера, который обрабатывает определенный веб-сайт, который выбрасывает 404, если у вас есть // в URL.
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"
Ну, этот вопрос получает много трафика, и ответ с 1000+ upvotes на самом деле не работает во всех случаях. Спустя годы я фактически использую Flurl для этого, поэтому я принимаю этот. Кажется, работает во всех случаях, с которыми я столкнулся. Если люди не хотят получать зависимость, я разместил ответ, который также отлично работает.
Uri есть конструктор, который должен сделать это для вас: new Uri(Uri baseUri, string relativeUri)
Вот пример:
Uri baseUri =newUri("http://www.contoso.com");Uri myUri =newUri(baseUri,"catalog/shownew.htm");
Примечание редактора: будьте осторожны, этот метод не работает должным образом. В некоторых случаях он может вырезать часть baseUri. Смотрите комментарии и другие ответы.
Мне нравится использование класса Uri, к сожалению, он не будет вести себя как Path.Combine, как спросил ОП. Например, новый Uri (новый Uri (« test.com/mydirectory/» ), «/helloworld.aspx»). ToString () дает вам « test.com/helloworld.aspx »; что было бы неправильно, если бы мы хотели получить результат в стиле Path.Combine.
Доктор Джонс
195
Это все в разрезе. Если относительная часть пути начинается с косой черты, она ведет себя так, как вы описали. Но если вы оставите косую черту, то она будет работать так, как вы ожидаете (обратите внимание на отсутствующую косую черту во втором параметре): new Uri (new Uri (" test.com/mydirectory/" ), "helloworld.aspx") ) .ToString () приводит к « test.com/mydirectory/helloworld.aspx ». Path.Combine ведет себя аналогично. Если параметр относительного пути начинается с косой черты, он возвращает только относительный путь и не объединяет их.
Джоэл Бекхэм
70
Если ваш baseUri оказался «test.com/mydirectory/mysubdirectory», то результатом будет «test.com/mydirectory/helloworld.aspx» вместо «test.com/mydirectory/mysubdirectory/helloworld.aspx». Тонкая разница - отсутствие косой черты по первому параметру. Я целиком и полностью использую существующие методы фреймворка. Если у меня уже есть косая черта, то я думаю, что выполнение partUrl1 + partUrl2 пахнет намного меньше - я мог бы довольно долго гоняться за этой косой чертой, ради того, чтобы не делать строки concat.
Карл
64
Единственная причина, по которой мне нужен метод комбинирования URI, заключается в том, что мне не нужно проверять конечный слеш. Request.ApplicationPath - это «/», если ваше приложение находится в корневом каталоге, но «/ foo», если это не так.
nickd
24
Я -1 этот ответ, потому что это не отвечает на проблему. Когда вы хотите объединить URL, например, когда вы хотите использовать Path.Combine, вы не хотите заботиться о трейлинг /. и с этим вы должны заботиться. Я предпочитаю решение Брайана Маккея или mdsharpe выше
+1: хотя это не относится к путям относительного стиля (../../whwhat.html), мне нравится этот из-за его простоты. Я бы также добавил обрезки для символа '\'.
Брайан Маккей
3
Смотрите мой ответ для более полной версии этого.
Брайан Маккей
149
Вы используете Uri.TryCreate( ... ):
Uri result =null;if(Uri.TryCreate(newUri("http://msdn.microsoft.com/en-us/library/"),"/en-us/library/system.uri.trycreate.aspx",out result)){Console.WriteLine(result);}
+1: это хорошо, хотя у меня иррациональная проблема с выходным параметром. ;)
Брайан Маккей
10
@Brian: если это помогает, все методы TryXXX ( int.TryParse, DateTime.TryParseExact) имеют этот выходной параметр, чтобы их было проще использовать в операторе if. Кстати, вам не нужно инициализировать переменную, как это сделал Райан в этом примере.
Авель
41
Этот ответ страдает той же проблемой, что и Джоэл : присоединение test.com/mydirectory/и /helloworld.aspxприведет к тому, test.com/helloworld.aspxчто, казалось бы, не то, что вы хотите.
Matt Kocaj
3
Здравствуйте, это не удалось для следующего: if (Uri.TryCreate (new Uri (" localhost / MyService /" ), "/ Event / SomeMethod? Abc = 123", out result)) {Console.WriteLine (result); } Это показывает мне результат как: localhost / Event / SomeMethod? Abc = 123 Примечание: здесь «http: //» заменяется из базового Uri на stackoverflow
Faisal Mq
3
@FaisalMq Это правильное поведение, поскольку вы передали второй относительный параметр root. Если бы вы пропустили ведущий / второй параметр, вы получили бы ожидаемый результат.
Том Линт
127
Здесь уже есть несколько отличных ответов. Основываясь на предложении mdsharpe, вот метод расширения, который можно легко использовать, когда вы хотите иметь дело с экземплярами Uri:
using System;
using System.Linq;publicstaticclassUriExtensions{publicstaticUriAppend(thisUri uri,paramsstring[] paths){returnnewUri(paths.Aggregate(uri.AbsoluteUri,(current, path)=>string.Format("{0}/{1}", current.TrimEnd('/'), path.TrimStart('/'))));}}
И пример использования:
var url =newUri("http://example.com/subpath/").Append("/part1/","part2").AbsoluteUri;
Это решение упрощает написание статического метода UriUtils.Combine ("base url", "part1", "part2", ...), который очень похож на Path.Combine (). Ницца!
angularsen
Для поддержки относительных URI мне пришлось использовать ToString () вместо AbsoluteUri и UriKind.AbsoluteOrRelative в конструкторе Uri.
angularsen
Спасибо за совет об относительной Юрис. К сожалению, Uri не позволяет легко иметь дело с относительными путями, поскольку всегда существует некоторая путаница с вовлеченным Request.ApplicationPath. Возможно, вы также можете попробовать использовать новый Uri (HttpContext.Current.Request.ApplicationPath) в качестве базы и просто вызвать на нем команду Append? Это даст вам абсолютные пути, но должно работать в любом месте структуры сайта.
Алесь Поточник Хахонина
Отлично. Рад, что это помогло кому-то еще. Использовал это в течение некоторого времени и не имел никаких проблем.
Алесь Поточник Хахонина
Я также добавил проверку, если какой-либо из путей для добавления не является ни нулевой, ни пустой строкой.
н.подбельски
92
Ответ Райана Кука близок к тому, что мне нужно, и может быть более подходящим для других разработчиков. Тем не менее, он добавляет http: // в начало строки и в целом он делает немного больше форматирования, чем я после.
Кроме того, для моих случаев использования определение относительных путей не важно.
Ответ mdsharp также содержит в себе идею хорошей идеи, хотя для ее фактической реализации потребовалось еще несколько подробностей. Это попытка уточнить это (и я использую это в производстве):
Говоря о деталях: как насчет обязательного, ArgumentNullException("url1")если аргумент Nothing? Извините, просто придирчивый ;-). Обратите внимание, что обратный слеш не имеет ничего общего с URI (и, если он есть, его не следует обрезать), так что вы можете удалить его из TrimXXX.
Авель
4
Вы можете использовать params string [] и рекурсивно объединять их, чтобы разрешить более 2 комбинаций
Jaider
4
Я уверен, что хотелось бы, чтобы это было в библиотеке базовых классов, как Path.Combine.
Урия Блатервик
1
@MarkHurd Я снова отредактировал код, так что он по поведению такой же, как C #, и синтаксически эквивалентен.
JJS
1
@BrianMacKay, я сломал это, Маркхурд указал на мою ошибку и откатился, я обновил снова ... ура
JJS
36
Path.Combine не работает для меня, потому что могут быть такие символы, как "|" в аргументах QueryString и, следовательно, в URL, что приведет к ArgumentException.
Я сначала попробовал новый Uri(Uri baseUri, string relativeUri)подход, который потерпел неудачу для меня из-за URI как http://www.mediawiki.org/wiki/Special:SpecialPages:
приведет к Special: SpecialPages, потому что двоеточие после Specialэтого обозначает схему.
Поэтому мне, наконец, пришлось выбрать маршрут mdsharpe / Brian MacKays, и я разработал его немного дальше, чтобы работать с несколькими частями URI:
publicstaticstringCombineUri(paramsstring[] uriParts){string uri =string.Empty;if(uriParts !=null&& uriParts.Length>0){char[] trims =newchar[]{'\\','/'};
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;}
+1: Теперь мы говорим ... Я собираюсь попробовать это. Это может даже оказаться новым принятым ответом. После попытки нового метода Uri () он мне действительно не нравится. Слишком привередливый.
Брайан Маккей
Это именно то, что мне было нужно! Не был фанатом необходимости заботиться о том, где я ставлю косые черты и т. Д.
Громер
+1 за бросок в нулевой проверке, чтобы она не взорвалась.
NightOwl888
Count () должен быть Length, чтобы вам не нужно было включать Linq в вашу библиотеку только для этого.
PRMan
Это было именно то, что я искал.
ThePeter
34
Основываясь на приведенном вами примере URL , я предполагаю, что вы хотите объединить URL, относящиеся к вашему сайту.
Исходя из этого предположения, я предложу это решение как наиболее подходящий ответ на ваш вопрос: «Path.Combine удобен, есть ли подобная функция в структуре для URL-адресов?»
Поскольку в структуре для URL-адресов есть аналогичная функция, я предлагаю правильный метод: «VirtualPathUtility.Combine». Вот ссылка на MSDN: VirtualPathUtility.Combine Метод
Есть одно предостережение: я считаю, что это работает только для URL, относящихся к вашему сайту (то есть вы не можете использовать его для создания ссылок на другой веб-сайт. Например, var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");).
+1, потому что это близко к тому, что я ищу, хотя было бы идеально, если бы он работал для любого старого URL. Я удвою это получится намного элегантнее, чем предложено mdsharpe.
Брайан Маккей
2
Предостережение правильное, оно не может работать с абсолютным URIS, и результат всегда является относительным от корня. Но у него есть дополнительное преимущество: он обрабатывает тильду, как и «~ /». Это делает это ярлыком Server.MapPathи объединением.
Для того, чтобы получить его Wrk U необходимо удалить первый / второй в агд т.е. "/ Images" - / Path.Combine ( " Http://MyUrl.com ", "Images / Image.jpg")
Per G
8
@SliverNinja Это неверно . Значение этого поля - обратная косая черта ('\') в UNIX и косая черта ('/') в операционных системах Windows и Macintosh. При использовании Mono в системе Linux вы получите неправильный разделитель.
user247702
6
Все те, кто отвлекается на разделитель каталогов, забывают, что строки могли прийти из другой ОС, чем вы сейчас. Просто замените обратную косую черту на переднюю, и все будет в порядке.
Остроумный пример, Райан, чтобы закончить ссылкой на функцию. Отлично сработано.
Одна рекомендация Брайана: если вы заключите этот код в функцию, вы можете использовать UriBuilder для переноса базового URL-адреса перед вызовом TryCreate.
В противном случае базовый URL ДОЛЖЕН включать схему (где UriBuilder примет http: //). Просто мысль:
+1, хотя это очень похоже на ответ mdsharpe, который я улучшил в своем ответе. Эта версия прекрасно работает, если Url2 не начинается с / или \, или Url1 случайно не заканчивается на \, или один из них не пуст! :)
Брайан Маккей
9
Объединение нескольких частей URL может быть немного сложнее. Вы можете использовать двухпараметрический конструктор Uri(baseUri, relativeUri)или Uri.TryCreate()функцию полезности.
В любом случае, вы могли бы в конечном итоге возвращаются неправильный результат , потому что эти методы продолжают усечения относительные части от первого параметра baseUri, то есть с чем - то вроде http://google.com/some/thingк http://google.com.
Чтобы иметь возможность объединить несколько частей в окончательный URL-адрес, вы можете скопировать две функции ниже:
publicstaticstringCombine(paramsstring[] parts){if(parts ==null|| parts.Length==0)returnstring.Empty;var urlBuilder =newStringBuilder();foreach(var part in parts){var tempUrl = tryCreateRelativeOrAbsolute(part);
urlBuilder.Append(tempUrl);}returnVirtualPathUtility.RemoveTrailingSlash(urlBuilder.ToString());}privatestaticstring tryCreateRelativeOrAbsolute(string s){System.Uri uri;System.Uri.TryCreate(s,UriKind.RelativeOrAbsolute,out uri);string tempUrl =VirtualPathUtility.AppendTrailingSlash(uri.ToString());return tempUrl;}
Выглядит довольно хорошо для меня. Хотя вы можете заменить цикл I циклом foreach для большей ясности.
Крис Марисик
Спасибо, Крис. Я только что изменил свой код для использования Foreach.
Believe2014
1
+1 за все дополнительные усилия. Мне нужно немного поддержать этот вопрос для некоторых ответов с более высоким рейтингом, вы бросили вызов. ;)
Брайан Маккей,
Извините, но не достаточно. Работает в тех немногих случаях, которые вы показываете, но далеко не пригоден для использования в любых комбинациях. Например, двоеточие на пути причинит вред.
Габор
Можете ли вы привести пример того, что вы имеете в виду? Я буду рад решить проблему и помочь следующим пользователям.
Believe2014
7
Я нашел, UriBuilderработал действительно хорошо для такого рода вещей:
Похоже, что это может быть для путей, а не URL-адресов.
Брайан Маккей
@BrianMacKay Согласился, что это похоже на это, но это из класса UrlUtility и используется в контексте объединения URL
2
Отредактировано, чтобы уточнить, к какому классу он принадлежит
Будьте осторожны при использовании этого класса, остальная часть класса содержит специфичные для SharePoint артефакты.
Гарри Берри
4
Я считаю следующее полезным и имеет следующие функции:
Броски на ноль или пробел
Принимает несколько paramsпараметров для нескольких сегментов URL
бросает на ноль или пусто
Учебный класс
publicstaticclassUrlPath{privatestaticstringInternalCombine(string source,string dest){if(string.IsNullOrWhiteSpace(source))thrownewArgumentException("Cannot be null or white space", nameof(source));if(string.IsNullOrWhiteSpace(dest))thrownewArgumentException("Cannot be null or white space", nameof(dest));return $"{source.TrimEnd('/', '\\')}/{dest.TrimStart('/', '\\')}";}publicstaticstringCombine(string source,paramsstring[] args)=> args.Aggregate(source,InternalCombine);}
тесты
UrlPath.Combine("test1","test2");UrlPath.Combine("test1//","test2");UrlPath.Combine("test1","/test2");// Result = test1/test2UrlPath.Combine(@"test1\/\/\/",@"\/\/\\\\\//test2",@"\/\/\\\\\//test3\");// Result = test1/test2/test3UrlPath.Combine("/test1/","/test2/",null);UrlPath.Combine("","/test2/");UrlPath.Combine("/test1/",null);// Throws an ArgumentException
Некоторые проблемы с тестами: // Result = test1 / test2 / test3 \ для 4-го и последний из тестов throws дает ArgumentNullException вместо ArgumentException
Мория
3
Мое общее решение:
publicstaticstringCombine(paramsstring[] uriParts){string uri =string.Empty;if(uriParts !=null&& uriParts.Any()){char[] trims =newchar[]{'\\','/'};
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;}
Этот вспомогательный метод очень гибок и хорошо работает во многих различных случаях использования. Спасибо!
Шива
3
Я создал эту функцию, которая сделает вашу жизнь проще:
/// <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>publicstaticstringPathCombine(boolIsURL,boolIsRelative,boolIsFixInternal,paramsstring[] parts){if(parts ==null|| parts.Length==0)returnstring.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;}
Я искал версию PowerShell этого , который будет: [System.IO.Path]::Combine("http://MyUrl.com/","/Images/Image.jpg")однако это не удается с результатом: /Images/Image.jpg. Удалите /из второго subPath, и это работает:[System.IO.Path]::Combine("http://MyUrl.com/","Images/Image.jpg")
Underverse
Хорошая идея, но она терпит неудачу, когда один из параметров имеет значение null.
pholpar
2
Правила при объединении URL с URI
Чтобы избежать странного поведения, есть одно правило:
Путь (каталог) должен заканчиваться на '/'. Если путь заканчивается без '/', последняя часть обрабатывается как имя файла и будет объединена при попытке объединить со следующей частью URL.
Есть одно исключение: базовый URL-адрес (без информации каталога) не должен заканчиваться на '/'
часть пути не должна начинаться с '/'. Если он начинается с '/', каждая существующая относительная информация из URL удаляется ... добавление string.Emptyпути к детали также удалит относительный каталог из URL!
Если вы следуете правилам выше, вы можете комбинировать URL с кодом ниже. В зависимости от вашей ситуации, вы можете добавить несколько частей «каталога» в URL ...
Если вы не хотите добавлять стороннюю зависимость, такую как Flurl, или создавать собственный метод расширения, в ASP.NET Core (также доступен в Microsoft.Owin), вы можете использовать тот, PathStringкоторый предназначен для создания URI пути. Затем вы можете создать свой полный URI, используя комбинацию этого Uriи UriBuilder.
Это дает вам все составные части без необходимости указывать разделители в базовом URL. К сожалению, PathStringтребует, чтобы /к каждой строке был добавлен префикс, в противном случае он фактически выбрасывает ArgumentException! Но, по крайней мере, вы можете создать свой URI детерминистическим способом, который легко тестируется юнитами.
Осторожно: это решение строчной буквы хоста и добавляет порт. Если это нежелательно, можно написать строковое представление, например, используя Uriсвойство UriBuilder.
Конечно, это решение довольно самоописуемо (по крайней мере, на мой взгляд). Но вы полагаетесь на недокументированную (по крайней мере, я ничего не нашел с помощью быстрого поиска в Google) «функцию» из .NET API. Это может измениться в будущем выпуске, поэтому, пожалуйста, опишите метод с помощью тестов.
Это очень надежный подход. Недурно для модульного теста!
Aggsol
2
Для тех, кто ищет однострочник и просто хочет соединить части пути, не создавая новый метод, не ссылаясь на новую библиотеку, не создавая значение URI и не преобразовывая его в строку, тогда ...
Это довольно просто, но я не вижу, что тебе еще нужно. Если вы боитесь удвоить «/», то вы можете просто сделать .Replace("//", "/")потом. Если вы боитесь заменить удвоенный «//» в «https: //», вместо этого сделайте одно объединение, замените удвоенный «/», а затем присоединитесь к URL веб-сайта (однако я уверен, что большинство браузеров автоматически преобразовать что-нибудь с «https:» перед ним, чтобы прочитать в правильном формате). Это будет выглядеть так:
Здесь есть множество ответов, которые помогут справиться со всем вышеперечисленным, но в моем случае он мне понадобился только один раз в одном месте, и мне не нужно было на него сильно полагаться. Кроме того, действительно легко увидеть, что здесь происходит.
Вот мой подход, и я буду использовать его и для себя:
publicstaticstringUrlCombine(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 seperatorif(string.IsNullOrEmpty(part1)||string.IsNullOrEmpty(part2)){
seperator =string.Empty;}// If part1 is not empty,// remove '/' at lastif(!string.IsNullOrEmpty(part1)){
newPart1 = part1.TrimEnd('/');}// If part2 is not empty,// remove '/' at firstif(!string.IsNullOrEmpty(part2)){
newPart2 = part2.TrimStart('/');}// Now finally combinereturnstring.Format("{0}{1}{2}", newPart1, seperator, newPart2);}
Это приемлемо только для вашего случая. Есть случаи, которые могут сломать ваш код. Кроме того, вы не сделали правильное кодирование частей пути. Это может быть огромной уязвимостью, когда речь идет о межсайтовых скриптовых атаках.
Believe2014
Я согласен с вашими пунктами. Код должен делать простое объединение двух частей url.
Приятное прикосновение с «WebPath». :) Код может быть излишне плотным, хотя мне трудно взглянуть на это и сказать: да, это прекрасно. Это заставляет меня хотеть видеть юнит-тесты. Может быть, это только я!
Брайан Маккей
1
x.StartsWith ("/") &&! x.StartsWith ("http") - почему проверка http? что ты получаешь?
пингват
Вы не хотите пытаться удалить слеш, если он начинается с http.
Мартин Мерфи,
@BrianMacKay, я не уверен, что два лайнера требуют модульного теста, но, если хотите, можете его предоставить. Не то чтобы я принимаю патчи или что-то еще, но не стесняйтесь редактировать предложение.
Мартин Мерфи,
1
Я обнаружил, что Uriконструктор переворачивает '\' в '/'. Таким образом, вы также можете использовать Path.Combine, с Uriконструктором.
Uri baseUri =newUri("http://MyUrl.com");string path =Path.Combine("Images","Image.jpg");Uri myUri =newUri(baseUri, path);
Как и в других ответах, либо новый, Uri()либо TryCreate()можно сделать галочку. Однако базовый Uri должен заканчиваться, /а родственник НЕ должен начинаться с/ ; в противном случае он удалит завершающую часть базового URL
Я думаю, что это лучше всего сделать как метод расширения, т.е.
var baseUri =newUri("http://test.com/test/");var combinedUri = baseUri.Append("/Do/Something");
С точки зрения производительности, это потребляет больше ресурсов, чем нужно, из-за класса Uri, который выполняет большой анализ и проверку; очень грубое профилирование (отладка) сделало миллион операций примерно за 2 секунды. Это будет работать для большинства сценариев, однако, чтобы быть более эффективным, лучше манипулировать всем как строками, это займет 125 миллисекунд на 1 миллион операций. Т.е.
publicstaticstringAppend(thisUri 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 itvar baseUri = absoluteUri.EndsWith('/')? absoluteUri : absoluteUri +'/';var relative = relativePath.StartsWith('/')? relativePath.Substring(1): relativePath;return baseUri + relative;}
И если вы все еще хотите вернуть URI, это займет около 600 миллисекунд на 1 миллион операций.
publicstaticUriAppendUri(thisUri 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 itvar baseUri = absoluteUri.EndsWith('/')? absoluteUri : absoluteUri +'/';var relative = relativePath.StartsWith('/')? relativePath.Substring(1): relativePath;returnnewUri(baseUri + relative);}
Url.Combine
метод, который делает именно это.Ответы:
Существует комментарий Тодда Меньера, что Flurl включает в себя
Url.Combine
.Больше деталей:
Получить Flurl.Http на NuGet :
PM> Install-Package Flurl.Http
Или получите автономный построитель URL без функций HTTP:
PM> Install-Package Flurl
источник
Flurl
и предпочитаете облегченную версию, github.com/jean-lourenco/UrlCombineUri
есть конструктор, который должен сделать это для вас:new Uri(Uri baseUri, string relativeUri)
Вот пример:
Примечание редактора: будьте осторожны, этот метод не работает должным образом. В некоторых случаях он может вырезать часть baseUri. Смотрите комментарии и другие ответы.
источник
Это может быть достаточно простым решением:
источник
Вы используете
Uri.TryCreate( ... )
:Вернусь:
источник
int.TryParse
,DateTime.TryParseExact
) имеют этот выходной параметр, чтобы их было проще использовать в операторе if. Кстати, вам не нужно инициализировать переменную, как это сделал Райан в этом примере.test.com/mydirectory/
и/helloworld.aspx
приведет к тому,test.com/helloworld.aspx
что, казалось бы, не то, что вы хотите.Здесь уже есть несколько отличных ответов. Основываясь на предложении mdsharpe, вот метод расширения, который можно легко использовать, когда вы хотите иметь дело с экземплярами Uri:
И пример использования:
Это создаст http://example.com/subpath/part1/part2
источник
Ответ Райана Кука близок к тому, что мне нужно, и может быть более подходящим для других разработчиков. Тем не менее, он добавляет http: // в начало строки и в целом он делает немного больше форматирования, чем я после.
Кроме того, для моих случаев использования определение относительных путей не важно.
Ответ mdsharp также содержит в себе идею хорошей идеи, хотя для ее фактической реализации потребовалось еще несколько подробностей. Это попытка уточнить это (и я использую это в производстве):
C #
VB.NET
Этот код проходит следующий тест, который происходит в VB:
источник
ArgumentNullException("url1")
если аргументNothing
? Извините, просто придирчивый ;-). Обратите внимание, что обратный слеш не имеет ничего общего с URI (и, если он есть, его не следует обрезать), так что вы можете удалить его из TrimXXX.Path.Combine не работает для меня, потому что могут быть такие символы, как "|" в аргументах QueryString и, следовательно, в URL, что приведет к ArgumentException.
Я сначала попробовал новый
Uri(Uri baseUri, string relativeUri)
подход, который потерпел неудачу для меня из-за URI какhttp://www.mediawiki.org/wiki/Special:SpecialPages
:приведет к Special: SpecialPages, потому что двоеточие после
Special
этого обозначает схему.Поэтому мне, наконец, пришлось выбрать маршрут mdsharpe / Brian MacKays, и я разработал его немного дальше, чтобы работать с несколькими частями 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.Replace(Path.DirectorySeparatorChar, '/');
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
Я просто собрал небольшой метод расширения:
Это можно использовать так:
источник
Остроумный пример, Райан, чтобы закончить ссылкой на функцию. Отлично сработано.
Одна рекомендация Брайана: если вы заключите этот код в функцию, вы можете использовать UriBuilder для переноса базового URL-адреса перед вызовом TryCreate.
В противном случае базовый URL ДОЛЖЕН включать схему (где UriBuilder примет http: //). Просто мысль:
источник
Простой способ объединить их и убедиться, что это всегда правильно:
источник
Объединение нескольких частей URL может быть немного сложнее. Вы можете использовать двухпараметрический конструктор
Uri(baseUri, relativeUri)
илиUri.TryCreate()
функцию полезности.В любом случае, вы могли бы в конечном итоге возвращаются неправильный результат , потому что эти методы продолжают усечения относительные части от первого параметра
baseUri
, то есть с чем - то вродеhttp://google.com/some/thing
кhttp://google.com
.Чтобы иметь возможность объединить несколько частей в окончательный URL-адрес, вы можете скопировать две функции ниже:
Полный код с модульными тестами для демонстрации использования можно найти по адресу https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs.
У меня есть модульные тесты, чтобы охватить три наиболее распространенных случая:
источник
Я нашел,
UriBuilder
работал действительно хорошо для такого рода вещей:Посмотрите Класс UriBuilder - MSDN для большего количества конструкторов и документации.
источник
Вот метод Microsoft (OfficeDev PnP) UrlUtility.Combine :
Источник: GitHub
источник
Я считаю следующее полезным и имеет следующие функции:
params
параметров для нескольких сегментов URLУчебный класс
тесты
источник
Мое общее решение:
источник
Я создал эту функцию, которая сделает вашу жизнь проще:
Он работает как для URL, так и для обычных путей.
Применение:
источник
Почему бы просто не использовать следующее.
источник
[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 ...
источник
Если вы не хотите добавлять стороннюю зависимость, такую как Flurl, или создавать собственный метод расширения, в ASP.NET Core (также доступен в Microsoft.Owin), вы можете использовать тот,
PathString
который предназначен для создания URI пути. Затем вы можете создать свой полный URI, используя комбинацию этогоUri
иUriBuilder
.В этом случае это будет:
Это дает вам все составные части без необходимости указывать разделители в базовом URL. К сожалению,
PathString
требует, чтобы/
к каждой строке был добавлен префикс, в противном случае он фактически выбрасываетArgumentException
! Но, по крайней мере, вы можете создать свой URI детерминистическим способом, который легко тестируется юнитами.источник
Так что у меня есть другой подход, похожий на всех, кто использовал UriBuilder.
Я не хотел разделять свой BaseUrl (который может содержать часть пути - например, http://mybaseurl.com/dev/ ), как это сделал javajavajavajavajava .
Следующий фрагмент кода показывает код + тесты.
Осторожно: это решение строчной буквы хоста и добавляет порт. Если это нежелательно, можно написать строковое представление, например, используя
Uri
свойствоUriBuilder
.Протестировано с .NET Core 2.1 на Windows 10.
Почему это работает?
Даже если
Path.Combine
будет возвращаться обратная косая черта (по крайней мере в Windows), UriBuilder обрабатывает этот случай в Setter ofPath
.Взято из https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs (обращайтесь к
string.Replace
)Это лучший подход?
Конечно, это решение довольно самоописуемо (по крайней мере, на мой взгляд). Но вы полагаетесь на недокументированную (по крайней мере, я ничего не нашел с помощью быстрого поиска в 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 и не преобразовывая его в строку, тогда ...
Это довольно просто, но я не вижу, что тебе еще нужно. Если вы боитесь удвоить «/», то вы можете просто сделать
.Replace("//", "/")
потом. Если вы боитесь заменить удвоенный «//» в «https: //», вместо этого сделайте одно объединение, замените удвоенный «/», а затем присоединитесь к URL веб-сайта (однако я уверен, что большинство браузеров автоматически преобразовать что-нибудь с «https:» перед ним, чтобы прочитать в правильном формате). Это будет выглядеть так:Здесь есть множество ответов, которые помогут справиться со всем вышеперечисленным, но в моем случае он мне понадобился только один раз в одном месте, и мне не нужно было на него сильно полагаться. Кроме того, действительно легко увидеть, что здесь происходит.
См .: https://docs.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8.
источник
Использование:
Он имеет то преимущество, что ведет себя точно так же
Path.Combine
.источник
Вот мой подход, и я буду использовать его и для себя:
источник
Использовать этот:
источник
Я обнаружил, что
Uri
конструктор переворачивает '\' в '/'. Таким образом, вы также можете использоватьPath.Combine
, сUri
конструктором.источник
Для чего это стоит, здесь пара методов расширения. Первый объединяет пути, а второй добавляет параметры в URL.
источник
Как и в других ответах, либо новый,
Uri()
либоTryCreate()
можно сделать галочку. Однако базовый Uri должен заканчиваться,/
а родственник НЕ должен начинаться с/
; в противном случае он удалит завершающую часть базового URLЯ думаю, что это лучше всего сделать как метод расширения, т.е.
и использовать это:
С точки зрения производительности, это потребляет больше ресурсов, чем нужно, из-за класса Uri, который выполняет большой анализ и проверку; очень грубое профилирование (отладка) сделало миллион операций примерно за 2 секунды. Это будет работать для большинства сценариев, однако, чтобы быть более эффективным, лучше манипулировать всем как строками, это займет 125 миллисекунд на 1 миллион операций. Т.е.
И если вы все еще хотите вернуть URI, это займет около 600 миллисекунд на 1 миллион операций.
Надеюсь, это поможет.
источник
Я думаю, что это должно дать вам больше гибкости, поскольку вы можете работать с любым количеством отрезков пути:
источник