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"
คำตอบ:
มีความคิดเห็น Todd Menier ของข้างต้นเป็นที่FlurlUrl.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> ติดตั้งแพ็คเกจ 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-statement แต่คุณไม่ต้องเริ่มต้นตัวแปรตามที่ Ryan ทำในตัวอย่างนี้
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
คำตอบของ Ryan Cook นั้นใกล้เคียงกับที่ฉันติดตามและอาจเหมาะสมกว่าสำหรับนักพัฒนารายอื่น อย่างไรก็ตามมันเพิ่ม http: // ไปยังจุดเริ่มต้นของสตริงและโดยทั่วไปจะทำการจัดรูปแบบเพิ่มเติมเล็กน้อยหลังจาก
นอกจากนี้สำหรับกรณีการใช้งานของฉันการแก้ไขเส้นทางสัมพัทธ์ไม่สำคัญ
คำตอบของ mdsharp ยังมีเมล็ดของความคิดที่ดีแม้ว่าการใช้งานจริงนั้นจำเป็นต้องมีรายละเอียดเพิ่มเติมอีกสองสามรายการให้เสร็จสมบูรณ์ นี่เป็นความพยายามที่จะทำให้เป็นจริง (และฉันใช้สิ่งนี้ในการผลิต):
ค#
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")
จะส่งผลให้พิเศษ: 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 Method
มีข้อแม้หนึ่งข้อ: ฉันเชื่อว่านี่จะใช้ได้กับ 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");
ตัวอย่างที่มีไหวพริบ Ryan เพื่อจบด้วยลิงก์ไปยังฟังก์ชัน ทำได้ดี.
หนึ่งคำแนะนำไบรอัน: ถ้าคุณใส่รหัสนี้ในฟังก์ชั่นคุณอาจต้องการใช้ 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 Class - 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 ของ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 และแปลงเป็นสตริงแล้ว ...
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);
}
}
ฉันพบว่าตัวUri
สร้างพลิก '\' เป็น '/' ดังนั้นคุณสามารถใช้Path.Combine
กับตัวUri
สร้าง
Uri baseUri = new Uri("http://MyUrl.com");
string path = Path.Combine("Images", "Image.jpg");
Uri myUri = new Uri(baseUri, path);
สำหรับสิ่งที่คุ้มค่าลองใช้วิธีขยายสองวิธี อันแรกจะรวมเส้นทางและอันที่สองเพิ่มพารามิเตอร์ให้กับ 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 ซึ่งมีการแยกวิเคราะห์และตรวจสอบความถูกต้องจำนวนมาก การทำโปรไฟล์ที่หยาบมาก (Debug) ทำหนึ่งล้านการดำเนินการในเวลาประมาณ 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
วิธีการที่ทำได้