URL.Combine的URL?

时间:2008-12-16 21:42:27

标签: c# .net asp.net url path

Path.Combine很方便,但URLs的.NET框架中是否有类似的功能?

我正在寻找这样的语法:

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

会返回:

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

41 个答案:

答案 0 :(得分:1088)

Uri有一个构造函数可以为您执行此操作:new Uri(Uri baseUri, string relativeUri)

以下是一个例子:

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

编辑注意:请注意,此方法无法按预期工作。在某些情况下,它可以削减部分baseUri。请参阅评论和其他答案。

答案 1 :(得分:138)

您使用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

答案 2 :(得分:131)

这可能是一个非常简单的解决方案:

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

答案 3 :(得分:117)

这里已经有了一些很棒的答案。基于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

答案 4 :(得分:82)

Ryan Cook的答案接近我所追求的,可能更适合其他开发者。但是,它将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

答案 5 :(得分:33)

根据您提供的示例URL,我假设您要合并相对于您网站的网址。

根据这个假设,我会建议这个解决方案作为对你的问题的最恰当的回答:“Path.Combine很方便,是否有 类似的功能 在URL框架中?“

由于URL框架中存在 类似功能 ,我建议正确的是:“VirtualPathUtility.Combine”方法。 这是MSDN参考链接:VirtualPathUtility.Combine Method

有一点需要注意:我认为这仅适用于相对于您网站的网址(也就是说,您无法使用它来生成指向其他网站的链接。例如,var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");)。

答案 6 :(得分:29)

Path.Combine对我不起作用,因为可能有像“|”这样的字符在QueryString参数中,因此是URL,这将导致ArgumentException。

我首先尝试了新的Uri(Uri baseUri, string relativeUri)方法,由于像http://www.mediawiki.org/wiki/Special:SpecialPages这样的URI,我失败了:

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

将导致Special:SpecialPages,因为Special之后的冒号表示方案。

所以我最终不得不采用mdsharpe / Brian MacKays路线并进一步开发它以处理多个URI部分:

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

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

答案 7 :(得分:24)

is a Todd Menier's comment above Flurl包含Url.Combine。

更多详情:

  

Url.Combine基本上是URL的Path.Combine,确保一个   部分之间只有一个分隔符:

var url = Url.Combine(
    "http://foo.com/",
    "/too/", "/many/", "/slashes/",
    "too", "few?",
    "x=1", "y=2"
// result: "http://www.foo.com/too/many/slashes/too/few?x=1&y=2" 

获取Flurl.Http on NuGet

PM&GT;安装包Flurl.Http

get the stand-alone URL builder没有HTTP功能:

PM&GT; Install-Package Flurl

答案 8 :(得分:23)

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

答案 9 :(得分:16)

我刚刚整理了一个小扩展方法:

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

答案 10 :(得分:12)

Witty示例,Ryan,以该函数的链接结束。做得好。

建议Brian:如果将此代码包装在函数中,您可能希望在TryCreate调用之前使用UriBuilder来包装基本URL。

否则,基本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");
}

答案 11 :(得分:8)

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

找到用于演示使用情况的单元测试的完整代码

我有单元测试来涵盖三种最常见的情况:

Enter image description here

答案 12 :(得分:7)

将它们组合起来并确保始终正确的简单方法是:

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

答案 13 :(得分:6)

我发现UriBuilder非常适合这类事情:

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

有关更多构造函数和文档,请参阅UriBuilder Class - MSDN

答案 14 :(得分:5)

我认为这应该为您提供更大的灵活性,因为您可以处理任意数量的路径段:

public static string UrlCombine(this string baseUrl, params string[] segments)
=> string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));

答案 15 :(得分:4)

如果您不想像Flurl这样的依赖项,可以使用其源代码:

    /// <summary>
    /// Basically a Path.Combine for URLs. Ensures exactly one '/' separates each segment,
    /// and exactly on '&amp;' separates each query parameter.
    /// URL-encodes illegal characters but not reserved characters.
    /// </summary>
    /// <param name="parts">URL parts to combine.</param>
    public static string Combine(params string[] parts) {
        if (parts == null)
            throw new ArgumentNullException(nameof(parts));

        string result = "";
        bool inQuery = false, inFragment = false;

        string CombineEnsureSingleSeparator(string a, string b, char separator) {
            if (string.IsNullOrEmpty(a)) return b;
            if (string.IsNullOrEmpty(b)) return a;
            return a.TrimEnd(separator) + separator + b.TrimStart(separator);
        }

        foreach (var part in parts) {
            if (string.IsNullOrEmpty(part))
                continue;

            if (result.EndsWith("?") || part.StartsWith("?"))
                result = CombineEnsureSingleSeparator(result, part, '?');
            else if (result.EndsWith("#") || part.StartsWith("#"))
                result = CombineEnsureSingleSeparator(result, part, '#');
            else if (inFragment)
                result += part;
            else if (inQuery)
                result = CombineEnsureSingleSeparator(result, part, '&');
            else
                result = CombineEnsureSingleSeparator(result, part, '/');

            if (part.Contains("#")) {
                inQuery = false;
                inFragment = true;
            }
            else if (!inFragment && part.Contains("?")) {
                inQuery = true;
            }
        }
        return EncodeIllegalCharacters(result);
    }

    /// <summary>
    /// URL-encodes characters in a string that are neither reserved nor unreserved. Avoids encoding reserved characters such as '/' and '?'. Avoids encoding '%' if it begins a %-hex-hex sequence (i.e. avoids double-encoding).
    /// </summary>
    /// <param name="s">The string to encode.</param>
    /// <param name="encodeSpaceAsPlus">If true, spaces will be encoded as + signs. Otherwise, they'll be encoded as %20.</param>
    /// <returns>The encoded URL.</returns>
    public static string EncodeIllegalCharacters(string s, bool encodeSpaceAsPlus = false) {
        if (string.IsNullOrEmpty(s))
            return s;

        if (encodeSpaceAsPlus)
            s = s.Replace(" ", "+");

        // Uri.EscapeUriString mostly does what we want - encodes illegal characters only - but it has a quirk
        // in that % isn't illegal if it's the start of a %-encoded sequence https://stackoverflow.com/a/47636037/62600

        // no % characters, so avoid the regex overhead
        if (!s.Contains("%"))
            return Uri.EscapeUriString(s);

        // pick out all %-hex-hex matches and avoid double-encoding 
        return Regex.Replace(s, "(.*?)((%[0-9A-Fa-f]{2})|$)", c => {
            var a = c.Groups[1].Value; // group 1 is a sequence with no %-encoding - encode illegal characters
            var b = c.Groups[2].Value; // group 2 is a valid 3-character %-encoded sequence - leave it alone!
            return Uri.EscapeUriString(a) + b;
        });
    }

答案 16 :(得分: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

答案 17 :(得分: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;
}

答案 18 :(得分:3)

我发现以下内容很有用,并具有以下功能:

  • 抛出空格或空格
  • 为多个Url细分受众群提供多个params参数
  • 抛出null或为空

<强>类

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

答案 19 :(得分: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;
    }

适用于网址和普通路径。

用法:

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

答案 20 :(得分:2)

将网址与URI相结合的规则

为了避免出现奇怪的行为,需遵循以下规则:

  • 路径(目录)必须以'/'结尾。如果路径没有'/'结束,则最后一部分被视为文件名,并且在尝试与下一个URL部分组合时它将被连接。
  • 有一个例外:基本URL地址(没有目录信息)不需要以'/'结尾
  • 路径部分不得以'/'开头。如果它以'/'开头,则删除URL中的每个现有相关信息...添加string.Empty部分路径也会从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();
        });

答案 21 :(得分: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完全相同。

答案 22 :(得分:1)

// 阅读以上所有示例,结果创建了我自己:

static string UrlCombine(params string[] items)
{
    if (items?.Any() != true)
    {
        return string.Empty;
    }

    return string.Join("/", items.Where(u => !string.IsNullOrWhiteSpace(u)).Select(u => u.Trim('/', '\\')));
}

// 用法

UrlCombine("https://microsoft.com","en-us")

答案 23 :(得分: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);
    }
}

答案 24 :(得分:1)

最近在 Energy.Core 包中添加了 Combine 方法,因此您可能希望使用它来连接URL部分。

    string url;
    url = Energy.Base.Url.Combine("https://www.youtube.com", "watch?v=NHCgbs3TcYg");
    Console.WriteLine(url);
    url = Energy.Base.Url.Combine("https://www.youtube.com", "watch?v=NHCgbs3TcYg", "t=150");
    Console.WriteLine(url);

此外,它将识别参数部分,因此它将按您期望的那样工作(连接路径以斜杠和参数以&符)。

https://www.youtube.com/watch?v=NHCgbs3TcYg

https://www.youtube.com/watch?v=NHCgbs3TcYg&t=150

Documentation for Energy.Base.Url class

Package on NuGet gallery

Code sample

答案 25 :(得分:1)

如其他答案所示,新的Uri()TryCreate()都可以打勾。 但是,基本Uri必须以/结尾,而亲属则不必以/开头;否则,它将删除基本网址的尾部

我认为最好将其作为一种扩展方法,即

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秒钟内完成了100万次操作。 这将适用于大多数情况,但是要提高效率,最好将所有内容作为字符串进行处理,这需要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,则一百万次操作大约需要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);
}

我希望这会有所帮助。

答案 26 :(得分:1)

对于正在寻找单行代码并且只想联接路径的一部分而无需创建新方法或引用新库或构造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

答案 27 :(得分:1)

所以我有另一种方法,类似于使用UriBuilder的每个人。

我不想像http://mybaseurl.com/dev/那样拆分我的BaseUrl(它可以包含路径的一部分,例如javajavajavajavajava)。

以下代码段显示了代码+测试。

当心::此解决方案可小写主机并附加端口。如果不希望这样,可以用例如利用Uri的{​​{1}}属性。

UriBuilder

在Windows 10上使用.NET Core 2.1进行了测试。

为什么这样做?

即使 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)); } } 将返回反斜杠(在Windows上至少是这样),但UriBuilder仍会在Path.Combine的Setter中处理这种情况。

来自https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs(注意对Path的呼叫)

string.Replace

这是最好的方法吗?

当然,这种解决方案非常自我描述(至少在我看来)。但是,您依赖.NET API中未记录的功能(至少在Google谷歌快速搜索中没有找到任何内容)“功能”。将来的版本可能会有所更改,因此请涵盖“测试方法”。

https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs[AllowNull] public string Path { get { return _path; } set { if ((value == null) || (value.Length == 0)) { value = "/"; } _path = Uri.InternalEscapeString(value.Replace('\\', '/')); _changed = true; } } )中有一些测试可以检查Path_Get_Set是否正确转换。

侧面说明:如果uri将用于\ ctor,则也可以直接使用UriBuilder.Uri属性。

答案 28 :(得分:1)

如果不想在ASP.NET Core(也可以在Microsoft.Owin中使用)中添加第三方依赖项(例如Flurl)或创建自定义扩展方法,则可以使用PathString目的是为了建立URI路径。然后,您可以使用UriUriBuilder的组合来创建完整的URI。

在这种情况下,它将是:

new Uri(new UriBuilder("http", "MyUrl.com").Uri, new PathString("/Images").Add("/Image.jpg").ToString())

这为您提供了所有组成部分,而无需在基本URL中指定分隔符。不幸的是,PathString要求在每个字符串之前加/,否则实际上会抛出一个ArgumentException!但是至少您可以以易于进行单元测试的方式确定性地构建URI。

答案 29 :(得分: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();
    }

答案 30 :(得分:1)

我发现Uri构造函数将'\'翻转为'/'。因此,您也可以将Path.CombineUri构造函数结合使用。

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

答案 31 :(得分:1)

为什么不使用以下内容。

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

答案 32 :(得分: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);
}

答案 33 :(得分:0)

我们使用以下简单的帮助方法将任意数量的URL部分连接在一起:

public static string JoinUrlParts(params string[] urlParts)
{
    return string.Join("/", urlParts.Where(up => !string.IsNullOrEmpty(up)).ToList().Select(up => up.Trim('/')).ToArray());
}

请注意,它不支持&#39; ../../ something / page.htm&#39; -style相对网址!

答案 34 :(得分:0)

一个简单的衬垫:

public static string Combine(this string uri1, string uri2) => $"{uri1.TrimEnd('/')}/{uri2.TrimStart('/')}";

受@Matt Sharpe的回答启发。

答案 35 :(得分:0)

这两项工作都是:

  Uri final = new Uri(Regex.Replace(baseUrl + "/" + relativePath, "(?<!http:)/{2,}", "/"));

或者

  Uri final =new Uri(string.Format("{0}/{1}", baseUrl.ToString().TrimEnd('/'), relativePath.ToString().TrimStart('/')));

即。如果

baseUrl = "http://tesrurl.test.com/Int18"

relativePath = "To_Folder"

output = http://tesrurl.test.com/Int18/To_Folder

以下代码会出现一些错误:

 // If you use the below code, some issues will be there in the final URI
 Uri final = new Uri(baseUrl, relativePath);

答案 36 :(得分:0)

我结合了之前的所有答案:

    public static string UrlPathCombine(string path1, string path2)
    {
        path1 = path1.TrimEnd('/') + "/";
        path2 = path2.TrimStart('/');

        return Path.Combine(path1, path2)
            .Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
    }

    [TestMethod]
    public void TestUrl()
    {
        const string P1 = "http://msdn.microsoft.com/slash/library//";
        Assert.AreEqual("http://msdn.microsoft.com/slash/library/site.aspx", UrlPathCombine(P1, "//site.aspx"));

        var path = UrlPathCombine("Http://MyUrl.com/", "Images/Image.jpg");

        Assert.AreEqual(
            "Http://MyUrl.com/Images/Image.jpg",
            path);
    }

答案 37 :(得分:0)

我使用此代码来解决问题:

string[] brokenBaseUrl = Context.Url.TrimEnd('/').Split('/');
string[] brokenRootFolderPath = RootFolderPath.Split('/');

for (int x = 0; x < brokenRootFolderPath.Length; x++)
{
    //if url doesn't already contain member, append it to the end of the string with / in front
    if (!brokenBaseUrl.Contains(brokenRootFolderPath[x]))
    {
        if (x == 0)
        {
            RootLocationUrl = Context.Url.TrimEnd('/');
        }
        else
        {
            RootLocationUrl += String.Format("/{0}", brokenRootFolderPath[x]);
        }
    }
}

答案 38 :(得分:0)

好吧,我只是连接两个字符串并使用正则表达式来执行清理部分。

    public class UriTool
    {
        public static Uri Join(string path1, string path2)
        {
            string url = path1 + "/" + path2;
            url = Regex.Replace(url, "(?<!http:)/{2,}", "/");

            return new Uri(url);
        }
    }

所以,你可以像这样使用它:

    string path1 = "http://someaddress.com/something/";
    string path2 = "/another/address.html";
    Uri joinedUri = UriTool.Join(path1, path2);

    // joinedUri.ToString() returns "http://someaddress.com/something/another/address.html"

答案 39 :(得分:-1)

我必须指出Path.Combine似乎也可以直接使用,至少在.NET 4上。

答案 40 :(得分:-2)

我还没有使用下面的代码,但是在我的网络旅行中发现它解决了URL组合问题 - 希望它是一个简洁(并且成功!)的答案:

VirtualPathUtility.Combine