Path.Combine зручна, але чи є аналогічна функція в .NET рамці для URL-адрес ?
Я шукаю такий синтаксис:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
який би повернувся:
"http://MyUrl.com/Images/Image.jpg"
Path.Combine зручна, але чи є аналогічна функція в .NET рамці для 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
Uri
має конструктор, який повинен зробити це для вас: new Uri(Uri baseUri, string relativeUri)
Ось приклад:
Uri baseUri = new Uri("http://www.contoso.com");
Uri myUri = new Uri(baseUri, "catalog/shownew.htm");
Примітка редактора: Остерігайтеся, цей метод працює не так, як очікувалося. Він може вирізати частину основиUri в деяких випадках. Дивіться коментарі та інші відповіді.
Це може бути відповідне просте рішення:
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-адресі, що призведе до аргументації Exxception.
Я вперше спробував новий 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 / Брайан МакКейс і розробив його трохи далі для роботи з кількома частинами 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
. Вийміть /
з другого підпутника і він працює:[System.IO.Path]::Combine("http://MyUrl.com/","Images/Image.jpg")
Правила при поєднанні URL-адрес з URI
Щоб уникнути дивної поведінки, є одне правило:
string.Empty
шлях до частини, також буде видалено відповідний каталог з URL-адреси!Якщо ви дотримуєтесь правил вище, ви можете комбінувати 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/ ), як це робила javajavajaваяваява .
Наступний фрагмент показує код + Тести.
Остерігайтеся. Це рішення знижує розмір хоста та додає порт. Якщо це не бажано, можна написати рядкове подання, наприклад, використовуючи 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
, що повернеться Backslashes (у Windows atleast), 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) "функцію" від API .NET. Це може змінитися з майбутнім випуском, тому, будь ласка, накрийте Метод тестами.
Є тести на https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs ( Path_Get_Set
), які перевіряють, чи \
правильно трансформовано.
Бічна примітка: Можна також безпосередньо працювати з UriBuilder.Uri
властивістю, якщо урі буде використовуватися для System.Uri
ctor.
Для тих, хто шукає однолінійку і просто хоче приєднати частини шляху без створення нового методу або посилання на нову бібліотеку або побудувати значення 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()
можна зробити галочку. Однак основа Урі повинна закінчуватися, /
і відносна НЕ повинна починатися /
; інакше він видалить задні частини основної 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 секунди. Це буде працювати для більшості сценаріїв, однак, щоб бути ефективнішим, краще маніпулювати всім, як рядки, для 1 мільйона операцій потрібно 125 мілісекунд. Тобто
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, на 1 мільйон операцій потрібно близько 600 мілісекунд.
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
метод, який робить саме це.