Wednesday, May 30, 2012

Path.Combine for Urls?


Path.Combine is handy, but is there a similar function in the .NET framework for Urls?



I'm looking for syntax like this:




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



which would return:



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



Of course, string concatenation would be fine here since the '//' would be handled intelligently by the browser. But it feels a little less elegant.


Source: Tips4all

12 comments:

  1. Uri has a constructor that should do this for you: new Uri(Uri baseUri, string relativeUri)

    Here's an example:

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

    ReplyDelete
  2. You use 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);
    }


    Will return:


    http://msdn.microsoft.com/en-us/library/system.uri.trycreate.aspx

    ReplyDelete
  3. This may be a suitably simple solution:

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

    ReplyDelete
  4. This question got some great, highly voted answers!

    Ryan Cook's answer is close to what I'm after and may be more appropriate for other developers. However, it adds http:// to the beginning of the string and in general it does a bit more formatting than I'm after.

    Also, for my use cases, resolving relative paths is not important.

    mdsharp's answer also contains the seed of a good idea, although that actual implementation needed a few more details to be complete. This is an attempt to flesh it out (and I'm using this in production):

    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("/\")
    url2 = url2.TrimStart("/\")

    Return String.Format("{0}/{1}", url1, url2)
    End Function


    This code passes the following test:

    <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

    ReplyDelete
  5. Based on the sample Url you provided I'm going to assume you want to combine Urls that are relative to your site.

    Based on this assumption I'll propose this solution as the most appropriate response to your question which was: "Path.Combine is handy, is there a similar function in the framework for Urls?"

    Since there the is a similar function in the framework for Urls I propose the correct is: "VirtualPathUtility.Combine" method.
    Here's the MSDN reference link: VirtualPathUtility.Combine Method

    There is one caveat: I believe this only works for Urls relative to your site (i.e., you cannot use it to generate links to another web site. e.g., var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");.

    If I'm off base or missing something (which I often am) let me know... ;)

    ReplyDelete
  6. Witty example, Ryan, to end with a link to the function. Well done.

    One recommendation Brian: if you wrap this code in a function, you may want to use a UriBuilder to wrap the base Url prior to the TryCreate call.
    Otherwise, the base url MUST include the Scheme (where the UriBuilder will assume http://). Just a thought:

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

    ReplyDelete
  7. Path.Combine does not work for me because there can be characters like "|" in QueryString arguments and therefore the Url, which will result in an ArgumentException.

    I first tried the new Uri(Uri baseUri, string relativeUri) approach, which failed for me because of Uri's like http://www.mediawiki.org/wiki/Special:SpecialPages:

    new Uri(new Uri("http://www.mediawiki.org/wiki/"), "Special:SpecialPages")


    will result in Special:SpecialPages, because of the colon after Special that denotes a scheme.

    So I finally had to take mdsharpe/Brian MacKays route and developed it a bit further to work with multiple uri parts:

    public static string CombineUri(params string[] uriParts)
    {
    string uri = string.Empty;
    if (uriParts != null && uriParts.Count() > 0)
    {
    char[] trims = new char[] { '\\', '/' };
    uri = (uriParts[0] ?? string.Empty).TrimEnd(trims);
    for (int i = 1; i < uriParts.Count(); i++)
    {
    uri = string.Format("{0}/{1}", uri.TrimEnd(trims), (uriParts[i] ?? string.Empty).TrimStart(trims));
    }
    }
    return uri;
    }


    Usage: CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")

    ReplyDelete
  8. I just put together small Extension method

    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('/');
    }


    can be used like this:

    "www.example.com/".UriCombine("/images").UriCombine("first.jpeg");

    ReplyDelete
  9. There's already some great answers here. Based on mdsharpe suggestion, here's an extension method that can easily be used when you want to deal with Uri instances:

    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('/'))));
    }
    }


    And usage example:

    var url = new Uri("http://site.com/subpath/").Append("/part1/", "part2").AbsoluteUri;


    This will produce http://site.com/subpath/part1/part2

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

    ReplyDelete
  11. I know this has been answered, but an easy way to combine them and ensure it's always correct is..

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

    ReplyDelete
  12. I have to point out that Path.Combine appears to work for this also directly atleast on .NET4

    ReplyDelete