Path.Combine สำหรับ URL?


1243

Path.Combineมีประโยชน์ แต่มีหน้าที่คล้ายกันใน. NET Framework สำหรับURLหรือไม่

ฉันกำลังหาไวยากรณ์เช่นนี้

Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")

ซึ่งจะกลับมา:

"http://MyUrl.com/Images/Image.jpg"


14
FlurlมีUrl.Combineวิธีการที่ทำได้
ทอดด์ Menier

2
อันที่จริงแล้ว // ถูกจัดการโดยการกำหนดเส้นทางของเว็บไซต์หรือเซิร์ฟเวอร์ไม่ใช่เบราว์เซอร์ มันจะส่งสิ่งที่คุณใส่ลงในแถบที่อยู่ นั่นเป็นสาเหตุที่เราพบปัญหาเมื่อเราพิมพ์ htp: // แทน http: // ดังนั้น // อาจทำให้เกิดปัญหาที่สำคัญในบางไซต์ ฉันกำลังเขียน. dll สำหรับโปรแกรมรวบรวมข้อมูลซึ่งจัดการเว็บไซต์เฉพาะซึ่งมี 404 ถ้าคุณมี // ใน URL
Dave Gordon

คำตอบ:


73

มีความคิดเห็น 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


4
คำถามนี้ได้รับปริมาณการใช้งานมากและคำตอบที่มีมากกว่า 1,000 upvotes นั้นใช้ไม่ได้ในทุกกรณี หลายปีต่อมาฉันใช้ Flurl กับสิ่งนี้จริงๆดังนั้นฉันจึงยอมรับสิ่งนี้ ดูเหมือนว่าจะทำงานได้ในทุกกรณีที่ฉันพบ หากคนไม่ต้องการพึ่งพาฉันโพสต์คำตอบที่ใช้งานได้ดี
Brian MacKay

และถ้าคุณไม่ได้ใช้Flurlและอยากได้รุ่นที่มีน้ำหนักเบาgithub.com/jean-lourenco/UrlCombine
lizzy91

1156

Uri มีนวกรรมิกที่ควรทำเพื่อคุณ: new Uri(Uri baseUri, string relativeUri)

นี่คือตัวอย่าง:

Uri baseUri = new Uri("http://www.contoso.com");
Uri myUri = new Uri(baseUri, "catalog/shownew.htm");

หมายเหตุจากบรรณาธิการ: ระวังวิธีนี้ใช้ไม่ได้ตามที่คาดไว้ มันสามารถตัดส่วนของ baseUri ในบางกรณี ดูความคิดเห็นและคำตอบอื่น ๆ


369
ฉันชอบการใช้คลาส Uri แต่น่าเสียดายที่มันจะไม่ทำงานเหมือน Path.Combine ตามที่ OP ถาม ตัวอย่างเช่น Uri ใหม่ (Uri ใหม่ (" test.com/mydirectory/" ), "/helloworld.aspx") ToString () ให้ " test.com/helloworld.aspx " ให้คุณ ซึ่งจะไม่ถูกต้องหากเราต้องการผลลัพธ์สไตล์ Path.Combine
หมอโจนส์

195
มันอยู่ในเครื่องหมายทับ หากส่วนพา ธ สัมพัทธ์เริ่มต้นด้วยเครื่องหมายทับแล้วส่วนนั้นจะทำงานตามที่คุณอธิบาย แต่ถ้าคุณปล่อยเครื่องหมายทับออกมันจะทำงานตามที่คุณคาดหวัง (สังเกตเครื่องหมายทับที่หายไปของพารามิเตอร์ที่สอง): Uri ใหม่ (ใหม่ Uri (" test.com/mydirectory/" ), "helloworld.aspx" ) .ToString () ผลลัพธ์เป็น " test.com/mydirectory/helloworld.aspx " Path.Combine ทำงานในทำนองเดียวกัน หากพารามิเตอร์พา ธ สัมพัทธ์เริ่มต้นด้วยเครื่องหมายสแลชก็จะส่งกลับเฉพาะเส้นทางสัมพัทธ์และจะไม่รวม
Joel Beckham

70
หาก baseUri ของคุณเป็น "test.com/mydirectory/mysubdirectory" ผลลัพธ์จะเป็น "test.com/mydirectory/helloworld.aspx" แทนที่จะเป็น "test.com/mydirectory/mysubdirectory/helloworld.aspx" ความแตกต่างที่ลึกซึ้งคือการขาดการต่อท้ายเฉือนในพารามิเตอร์แรก ฉันทุกคนใช้วิธีเฟรมเวิร์กที่มีอยู่แล้วถ้าฉันต้องมีการต่อท้ายสแลชที่นั่นฉันคิดว่าการทำ partUrl1 + partUrl2 มีกลิ่นน้อยลงมาก - ฉันอาจได้ไล่ล่าสแลชต่อท้ายมานานพอสมควร ประโยชน์ของการไม่ทำสตริง concat
Carl

63
เหตุผลเดียวที่ฉันต้องการวิธีการรวม URI คือเพื่อให้ฉันไม่ต้องตรวจสอบสแลชต่อท้าย Request.ApplicationPath คือ '/' หากแอปพลิเคชันของคุณอยู่ที่รูท แต่ '/ foo' หากไม่ใช่
nickd

24
ฉัน -1 คำตอบนี้เพราะมันไม่ตอบปัญหา เมื่อคุณต้องการรวม url เช่นเมื่อคุณต้องการใช้ Path.Combine คุณไม่ต้องการที่จะใส่ใจกับ / ท้าย และด้วยสิ่งนี้คุณต้องใส่ใจ ฉันชอบวิธีแก้ปัญหาของ Brian MacKay หรือ mdsharpe ด้านบน
Baptiste Pernet

160

นี่อาจเป็นวิธีที่ง่าย ๆ ที่เหมาะสม:

public static string Combine(string uri1, string uri2)
{
    uri1 = uri1.TrimEnd('/');
    uri2 = uri2.TrimStart('/');
    return string.Format("{0}/{1}", uri1, uri2);
}

7
+1: แม้ว่าสิ่งนี้จะไม่จัดการกับเส้นทางแบบสัมพันธ์ (../../wh ก็ตาม.html) แต่ฉันชอบอันนี้เพราะความเรียบง่าย ฉันจะเพิ่มการตัดขอบสำหรับอักขระ '\' ด้วย
Brian MacKay

3
ดูคำตอบของฉันสำหรับรุ่นนี้ออกเนื้อมากขึ้น
Brian MacKay

149

คุณใช้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


53
+1: นี่เป็นสิ่งที่ดีแม้ว่าฉันจะมีปัญหาไม่ลงตัวกับพารามิเตอร์เอาท์พุท ;)
Brian MacKay

10
@Brian: ถ้าเป็นไปได้วิธี TryXXX ทั้งหมด ( int.TryParse, DateTime.TryParseExact) มีพารามิเตอร์ผลลัพธ์เพื่อให้ง่ายต่อการใช้ใน if-statement แต่คุณไม่ต้องเริ่มต้นตัวแปรตามที่ Ryan ทำในตัวอย่างนี้
อาเบล

41
คำตอบนี้ทำให้เกิดปัญหาเช่นเดียวกับJoel's : การเข้าร่วมtest.com/mydirectory/และ/helloworld.aspxจะทำให้test.com/helloworld.aspxดูเหมือนว่าคุณไม่ต้องการ
Matt Kocaj

3
สวัสดีสิ่งนี้ล้มเหลวในการติดตาม: if (Uri.TryCreate (ใหม่ Uri (" localhost / MyService /" ), "/ กิจกรรม / SomeMethod? abc = 123", ผลลัพธ์)) {Console.WriteLine (ผลลัพธ์); } มันแสดงให้ฉันเห็นผลลัพธ์เป็น: localhost / เหตุการณ์ / SomeMethod? abc = 123 หมายเหตุ: "http: //" ถูกแทนที่จาก Uri ฐานที่นี่โดย stackoverflow
Faisal Mq

3
@FaisalMq นี่เป็นพฤติกรรมที่ถูกต้องเนื่องจากคุณผ่านพารามิเตอร์ตัวที่สองที่สัมพันธ์กับรูท หากคุณละทิ้งพารามิเตอร์นำหน้า / ตัวที่สองคุณจะได้ผลลัพธ์ที่คุณคาดหวัง
Tom Lint

127

มีคำตอบที่ดีอยู่แล้วที่นี่ ตามคำแนะนำ 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


2
วิธีแก้ปัญหานี้ทำให้การเขียน UriUtils.Combine ("url ฐาน", "part1", "part2", ... ) เป็นวิธีที่คงที่ซึ่งคล้ายกับ Path.Combine () ดี!
angularsen

เพื่อสนับสนุน URIs ที่เกี่ยวข้องฉันต้องใช้ ToString () แทน AbsoluteUri และ UriKind.AbsoluteOrRelative ใน Conor Uri
angularsen

ขอบคุณสำหรับเคล็ดลับเกี่ยวกับ Uris ที่เกี่ยวข้อง น่าเสียดายที่ Uri ไม่ได้ทำให้ง่ายต่อการจัดการกับเส้นทางที่เกี่ยวข้องเนื่องจากมีการล้อเล่นเกี่ยวกับ Request.ApplicationPath ที่เกี่ยวข้อง บางทีคุณอาจลองใช้ Uri ใหม่ (HttpContext.Current.Request.ApplicationPath) เป็นฐานและเรียกใช้ผนวกเข้าด้วยหรือไม่ สิ่งนี้จะให้เส้นทางที่สมบูรณ์ แต่ควรจะทำงานได้ทุกที่ภายในโครงสร้างไซต์
Ales Potocnik Hahonina

ยิ่งใหญ่ ดีใจที่มันช่วยคนอื่น เคยใช้งานมาระยะหนึ่งแล้วและยังไม่มีปัญหาใด ๆ
Ales Potocnik Hahonina

ฉันยังได้เพิ่มการตรวจสอบว่าเส้นทางใด ๆ ที่จะต่อท้ายไม่ใช่ null หรือสตริงว่าง
n.podbielski

91

คำตอบของ 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

4
การพูดคุยของรายละเอียด: สิ่งที่เกี่ยวกับการบังคับArgumentNullException("url1")ถ้าข้อโต้แย้งคือNothingอะไร? ขออภัยเพิ่งจะจู้จี้จุกจิก ;-) โปรดทราบว่าแบ็กสแลชไม่มีอะไรที่ต้องทำใน URI (และถ้ามันอยู่ที่นั่นมันไม่ควรถูกตัดแต่ง) ดังนั้นคุณสามารถลบมันออกจาก TrimXXX ของคุณได้
อาเบล

4
คุณสามารถใช้พารามิเตอร์ params [] และร่วมซ้ำเพื่ออนุญาตให้มีมากกว่า 2 ชุด
Jaider

4
ฉันแน่ใจว่านี่คือในไลบรารีคลาสพื้นฐานเช่น Path.Combine
Uriah Blatherwick

1
@ MarkHurd ฉันแก้ไขโค้ดอีกครั้งเพื่อให้เป็นพฤติกรรมเหมือนกับ C # และเทียบเท่า syntactically เช่นกัน
JJS

1
@BrianMacKay ฉันทำมันผิดมาร์คฮาร์ดชี้ให้เห็นความผิดพลาดของฉันและย้อนกลับไปฉันได้รับการอัปเดตอีกครั้ง ... ไชโย
JJS

36

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")


1
+1: ตอนนี้เรากำลังพูดถึง ... ฉันจะลองทำดู นี่อาจเป็นคำตอบที่ยอมรับใหม่ หลังจากลองใช้วิธี Uri () ใหม่ฉันไม่ชอบจริงๆ จู้จี้จุกจิกเกินไป
Brian MacKay

นี่คือสิ่งที่ฉันต้องการ! ก็ไม่ได้เป็นแฟนของการมีการดูแลที่ฉันใส่ต่อท้ายทับ ฯลฯ ที่ ...
Gromer

+1 สำหรับการหมุนในการตรวจสอบค่าว่างดังนั้นมันจะไม่ระเบิด
NightOwl888

Count () ควรมีความยาวเพื่อที่คุณจะได้ไม่ต้องรวม Linq ไว้ในไลบรารี่ของคุณ
PRMan

นี่คือสิ่งที่ฉันกำลังมองหา
ThePeter

34

อ้างอิงจากURLตัวอย่างคุณให้ฉันจะถือว่าคุณต้องการรวม URL ที่เกี่ยวข้องกับเว็บไซต์ของคุณ

จากสมมติฐานนี้ฉันจะเสนอวิธีแก้ปัญหานี้เป็นการตอบสนองที่เหมาะสมที่สุดสำหรับคำถามของคุณซึ่งก็คือ: "Path.Combine นั้นมีประโยชน์มีฟังก์ชั่นที่คล้ายกันหรือไม่ในเฟรมเวิร์กสำหรับ URL หรือไม่"

เนื่องจากมีฟังก์ชั่นที่คล้ายกันในกรอบงานสำหรับ URL ที่ฉันเสนอที่ถูกต้องคือ: "VirtualPathUtility.Combine" วิธีการ นี่คือลิงค์อ้างอิง MSDN: VirtualPathUtility.Combine Method

มีข้อแม้หนึ่งข้อ: ฉันเชื่อว่านี่จะใช้ได้กับ URL ที่เกี่ยวข้องกับเว็บไซต์ของคุณเท่านั้น (นั่นคือคุณไม่สามารถใช้เพื่อสร้างลิงก์ไปยังเว็บไซต์อื่นได้ตัวอย่างเช่นvar url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");)


+1 เพราะใกล้กับสิ่งที่ฉันกำลังมองหาแม้ว่ามันจะเหมาะถ้ามันใช้ได้กับ URL เก่า ๆ ฉันจะเพิ่มความสวยงามเป็นสองเท่าของสิ่งที่ mdsharpe เสนอ
Brian MacKay

2
ข้อแม้นั้นถูกต้องมันไม่สามารถใช้ได้กับ uris สัมบูรณ์และผลลัพธ์นั้นสัมพันธ์กันจากรูทเสมอ แต่มันมีข้อดีเพิ่มเติมมันประมวลผลตัวหนอนเช่นเดียวกับ "~ /" สิ่งนี้ทำให้เป็นทางลัดServer.MapPathและการรวม
อาเบล

25
Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")

12
path.Replace(Path.DirectorySeparatorChar, '/');
Jaider

5
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
SliverNinja - MSFT

1
ในการรับไปยัง wrk u ต้องลบ ARG ครั้งแรก / ครั้งที่สองเช่น "/ Images" - / Path.Combine (" Http://MyUrl.com ", "Images / Image.jpg")
ต่อ G

8
@SliverNinja ไม่ถูกต้องค่าของฟิลด์นี้คือแบ็กสแลช ('\') บน UNIX และเครื่องหมายสแลช ('/') บนระบบปฏิบัติการ Windows และ Macintosh เมื่อใช้ Mono บนระบบ Linux คุณจะได้รับตัวคั่นที่ไม่ถูกต้อง
user247702

6
ทุกคนที่จ้องมองตัวแยกไดเรกทอรีกำลังลืมว่าสตริงอาจมาจากระบบปฏิบัติการที่แตกต่างจากตอนนี้ เพียงแค่แทนที่แบ็กสแลชด้วยสแลชแล้วคุณก็จะได้รับความคุ้มครอง
JeremyWeir

17

ฉันเพิ่งรวบรวมวิธีการขยายขนาดเล็ก:

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");

12

ตัวอย่างที่มีไหวพริบ 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");
}

10

วิธีที่ง่ายในการรวมเข้าด้วยกันและให้แน่ใจว่าถูกต้องอยู่เสมอคือ:

string.Format("{0}/{1}", Url1.Trim('/'), Url2);

+1 แม้ว่าสิ่งนี้จะคล้ายกับคำตอบของ mdsharpe ซึ่งฉันได้ปรับปรุงในคำตอบของฉัน รุ่นนี้ใช้งานได้ดีเว้นแต่ Url2 เริ่มต้นด้วย / หรือ \, หรือ Url1 สิ้นสุดโดยไม่ตั้งใจใน \, หรืออันใดอันหนึ่งว่างเปล่า! :)
Brian MacKay

9

การรวม URL หลายส่วนเข้าด้วยกันอาจเป็นเรื่องยุ่งยากเล็กน้อย คุณสามารถใช้ตัวสร้างสองพารามิเตอร์Uri(baseUri, relativeUri)หรือคุณสามารถใช้Uri.TryCreate()ฟังก์ชันยูทิลิตี้

ในทั้งสองกรณีที่คุณอาจท้ายกลับผลลัพธ์ไม่ถูกต้องเพราะวิธีการเหล่านี้ให้กับการตัดทอนส่วนญาติออกจากพารามิเตอร์แรกbaseUriคือจากสิ่งที่ชอบที่จะhttp://google.com/some/thinghttp://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

ฉันมีการทดสอบหน่วยเพื่อครอบคลุมสามกรณีที่พบบ่อยที่สุด:

ป้อนคำอธิบายภาพที่นี่


2
ดูดีสวยสำหรับฉัน แม้ว่าคุณสามารถแทนที่ I loop ด้วย foreach loop เพื่อความชัดเจนที่ดีขึ้น
Chris Marisic

ขอบคุณคริส ฉันเพิ่งเปลี่ยนรหัสเพื่อใช้ Foreach
Believe2014

1
+1 สำหรับความพยายามพิเศษทั้งหมด ฉันต้องการรักษาคำถามนี้ไว้เล็กน้อยสำหรับคำตอบที่ได้รับการโหวตที่สูงกว่าคุณได้โยนถุงมือลงไป ;)
Brian MacKay

ขออภัย แต่ไม่เพียงพอ ใช้งานได้ในบางกรณีที่คุณแสดง แต่อยู่ไกลจากการใช้งานในชุดค่าผสม ตัวอย่างเช่นโคลอนในเส้นทางจะทำให้เกิดอันตราย
Gábor

คุณช่วยยกตัวอย่างสิ่งที่คุณหมายถึงได้ไหม ฉันยินดีที่จะแก้ไขปัญหาและช่วยเหลือผู้ใช้รายต่อไป
Believe2014

7

ฉันพบว่าใช้UriBuilderงานได้ดีจริง ๆ สำหรับสิ่งนี้:

UriBuilder urlb = new UriBuilder("http", _serverAddress, _webPort, _filePath);
Uri url = urlb.Uri;
return url.AbsoluteUri;

ดูUriBuilder Class - MSDNสำหรับตัวสร้างและเอกสารเพิ่มเติม


4

นี่คือวิธีของ 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


ดูเหมือนว่านี่อาจเป็นเส้นทางแทนที่จะเป็น URL
Brian MacKay

@BrianMacKay เห็นด้วยว่ามันดูเหมือนว่า แต่มาจากคลาส UrlUtility และใช้ในบริบทของการรวม URL

2
แก้ไขเพื่อให้ชัดเจนว่าเป็นคลาสใด

ระวังเมื่อใช้คลาสนี้ส่วนที่เหลือของคลาสจะมีส่วนเฉพาะของ SharePoint
Harry Berry

4

ฉันพบว่ามีประโยชน์ดังต่อไปนี้และมีคุณสมบัติดังต่อไปนี้:

  • โยนลงบนช่องว่างว่างเปล่าหรือสีขาว
  • ใช้เวลาหลายครั้ง 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

@PeterMortensen ขอบคุณสำหรับการแก้ไข
TheGeneral

บางประเด็นเกี่ยวกับการทดสอบ: // Result = test1 / test2 / test3 \ สำหรับการทดสอบครั้งที่ 4 และครั้งสุดท้ายของการส่งพ่นให้ ArgumentNullException แทน ArgumentException
Moriya

3

โซลูชันทั่วไปของฉัน:

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;
}

วิธีการช่วยเหลือนี้มีความยืดหยุ่นสูงและทำงานได้ดีในกรณีการใช้งานที่แตกต่างกันมากมาย ขอบคุณ!
พระอิศวร

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>
    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

3

ทำไมไม่ใช้เพียงต่อไปนี้

System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/")

ผมกำลังมองหารุ่น 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

แนวคิดที่ดี แต่ล้มเหลวเมื่อพารามิเตอร์ตัวใดตัวหนึ่งเป็นโมฆะ
pholpar

2

กฎขณะรวม URL กับ URI

เพื่อหลีกเลี่ยงพฤติกรรมแปลก ๆ มีกฎข้อหนึ่งที่ต้องปฏิบัติดังนี้:

  • เส้นทาง (ไดเรกทอรี) จะต้องลงท้ายด้วย '/' หากเส้นทางสิ้นสุดโดยไม่มี '/' ส่วนสุดท้ายจะถือว่าเป็นชื่อไฟล์และจะถูกต่อกันเมื่อพยายามรวมกับส่วน URL ถัดไป
  • มีข้อยกเว้นหนึ่งประการ: ที่อยู่ URL หลัก (ไม่มีข้อมูลไดเรกทอรี) ไม่จำเป็นต้องลงท้ายด้วย '/'
  • ส่วนของเส้นทางจะต้องไม่ขึ้นต้นด้วย '/' หากเริ่มต้นด้วย '/' ข้อมูลที่สัมพันธ์กันที่มีอยู่ทั้งหมดจาก URL จะถูกทิ้ง ... การเพิ่ม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();
        });

2

หากคุณไม่ต้องการเพิ่มการพึ่งพาของบุคคลที่สามเช่น 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 ของคุณขึ้นมาในลักษณะที่สามารถทำการทดสอบได้อย่างง่ายดาย


2

ดังนั้นฉันจึงมีวิธีอื่นคล้ายกับทุกคนที่ใช้ UriBuilder

ฉันไม่ต้องการแยก BaseUrl ของฉัน (ซึ่งสามารถมีส่วนของเส้นทาง - เช่นhttp://mybaseurl.com/dev/ ) เป็นjavajavajavajavajavaทำ

ตัวอย่างต่อไปนี้แสดงรหัส + การทดสอบ

ระวัง:วิธีนี้จะลดโฮสต์และผนวกพอร์ต หากไม่ต้องการให้ใครสามารถเขียนแทนสายโดยเช่นการใช้ประโยชน์จากทรัพย์สินของUriUriBuilder

  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.Urictor


นี่เป็นวิธีการที่เชื่อถือได้มาก ยกนิ้วให้สำหรับการทดสอบหน่วย !!
aggsol

2

สำหรับทุกคนที่กำลังมองหาซับในและเพียงแค่ต้องการที่จะเข้าร่วมบางส่วนของเส้นทางโดยไม่ต้องสร้างวิธีการใหม่หรือการอ้างอิงห้องสมุดใหม่หรือสร้างค่า 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


1

ใช้:

    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กัน


1

นี่คือแนวทางของฉันและฉันจะใช้เพื่อตัวเองด้วย:

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);
}

สิ่งนี้ยอมรับได้เฉพาะกรณีของคุณ มีหลายกรณีที่อาจทำให้รหัสของคุณเสียหาย นอกจากนี้คุณไม่ได้ทำการเข้ารหัสส่วนต่างๆของเส้นทางที่เหมาะสม นี่อาจเป็นช่องโหว่ขนาดใหญ่เมื่อพูดถึงการโจมตีสคริปต์ข้ามไซต์
Believe2014

ฉันเห็นด้วยกับคะแนนของคุณ รหัสควรจะรวมง่าย ๆ เพียงแค่สองส่วนของ URL
Amit Bhagat

1

ใช้สิ่งนี้:

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);
    }
}

สัมผัสที่ดีกับ 'WebPath' :) รหัสอาจมีความหนาแน่นเกินความจำเป็น - มันยากสำหรับฉันที่จะมองดูสิ่งนี้และพูดว่าใช่นั่นเป็นสิ่งที่สมบูรณ์แบบ มันทำให้ฉันต้องการดูการทดสอบหน่วย บางทีนั่นเป็นเพียงฉัน!
Brian MacKay

1
x.StartsWith ("/") &&! x.StartsWith ("http") - ทำไม http ตรวจสอบ? คุณได้อะไร
penguat

คุณไม่ต้องการลองตัดเครื่องหมายทับหากเริ่มต้นด้วย http
Martin Murphy

@BrianMacKay ฉันไม่แน่ใจว่ามีสองซับรับประกันการทดสอบหน่วย แต่ถ้าคุณชอบที่จะให้หนึ่ง ไม่ใช่ว่าฉันรับแพทช์หรืออะไรเลย แต่อย่าลังเลที่จะแก้ไขข้อเสนอแนะ
Martin Murphy

1

ฉันพบว่าตัวUriสร้างพลิก '\' เป็น '/' ดังนั้นคุณสามารถใช้Path.CombineกับตัวUriสร้าง

 Uri baseUri = new Uri("http://MyUrl.com");
 string path = Path.Combine("Images", "Image.jpg");
 Uri myUri = new Uri(baseUri, path);

1

สำหรับสิ่งที่คุ้มค่าลองใช้วิธีขยายสองวิธี อันแรกจะรวมเส้นทางและอันที่สองเพิ่มพารามิเตอร์ให้กับ 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();
    }

1

ตามที่พบในคำตอบอื่น ๆ ไม่ว่าจะใหม่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);
}

ฉันหวังว่านี่จะช่วยได้.


1

ฉันคิดว่าสิ่งนี้จะช่วยให้คุณมีความยืดหยุ่นมากขึ้นตามที่คุณสามารถจัดการกับส่วนของเส้นทางได้มากเท่าที่คุณต้องการ:

public static string UrlCombine(this string baseUrl, params string[] segments)
=> string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.