c# concatenation - Path.Combine per URL?





.net asp.net (25)


La risposta di Ryan Cook è vicina a quello che sto cercando e potrebbe essere più appropriata per altri sviluppatori. Tuttavia, aggiunge http: // all'inizio della stringa e in generale fa un po 'più di formattazione di quello che sto cercando.

Inoltre, per i miei casi d'uso, la risoluzione dei percorsi relativi non è importante.

La risposta di mdsharp contiene anche il seme di una buona idea, sebbene quell'attuale implementazione necessitasse di qualche altro dettaglio per essere completata. Questo è un tentativo di estrapolarlo (e sto usando questo in produzione):

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

Questo codice supera il test seguente, che si verifica in 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

Path.Combine è utile, ma esiste una funzione simile nel framework .NET per gli URLs ?

Sto cercando una sintassi come questa:

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

che restituirebbe:

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




Questa potrebbe essere una soluzione opportunamente semplice:

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



Un modo semplice per combinarli e assicurarsi che sia sempre corretto è:

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



Ecco il mio approccio e lo userò anche per me:

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



Una semplice fodera:

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

Ispirato alla risposta di @Matt Sharpe.




C'è un commento di Todd Menier sopra che Flurl include un Url.Combine.

Più dettagli:

Url.Combine è fondamentalmente un Path.Combine per URL, che garantisce un solo carattere separatore tra le parti:

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



Bene, ho solo concatenato due stringhe e uso espressioni regolari per fare la parte di pulizia.

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

Quindi, puoi usarlo in questo modo:

    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"



Ho combinato tutte le risposte precedenti:

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



La mia soluzione generica:

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



Regole durante la combinazione di URL con un URI

Per evitare comportamenti strani c'è una regola da seguire:

  • Il percorso (directory) deve terminare con '/'. Se il percorso termina senza "/", l'ultima parte viene trattata come un nome file e verrà concatenata quando si tenta di combinare con la parte successiva dell'URL.
  • C'è un'eccezione: l'indirizzo URL di base (senza informazioni sulla directory) non deve terminare con '/'
  • la parte del percorso non deve iniziare con '/'. Se inizia con "/", tutte le informazioni relative relative all'URL vengono eliminate ... aggiungendo una string.Empty percorso parte string.Empty rimuoverà anche la relativa directory dall'URL!

Se si seguono le regole di cui sopra, è possibile combinare gli URL con il codice sottostante. A seconda della situazione, puoi aggiungere più parti "directory" all'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();
        });



Entrambi questi lavori:

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

O

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

Cioè se

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

e

relativePath = "To_Folder"

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

Alcuni errori appariranno per il codice qui sotto:

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






Perché non usare solo quanto segue

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



Esempio spiritoso, Ryan, per finire con un link alla funzione. Molto bene.

Una raccomandazione Brian: se si avvolge questo codice in una funzione, è possibile che si desideri utilizzare un UriBuilder per racchiudere l'URL di base prima della chiamata TryCreate.

In caso contrario, l'URL di base DEVE includere lo schema (dove UriBuilder assumerà http: //). Solo un pensiero:

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



Ho trovato che il Uricostruttore gira "\" in "/". Quindi puoi anche usare Path.Combine, con il Uricostruttore.

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



Path.Combine non funziona per me perché possono esistere caratteri come "|" in argomenti QueryString e quindi l'URL, che genererà ArgumentException.

Ho provato per la prima volta il nuovo approccio Uri(Uri baseUri, string relativeUri) , che non è riuscito a causa degli URI come http://www.mediawiki.org/wiki/Special:SpecialPages :

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

risulterà in Special: SpecialPages, a causa dei due punti dopo Special che denota uno schema.

Quindi alla fine ho dovuto prendere mdsharpe / Brian MacKays e l'ho sviluppato un po 'oltre per lavorare con più parti 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;
}

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




Usiamo il seguente semplice metodo di supporto per unire un numero arbitrario di parti di URL insieme:

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

Nota che non supporta gli URL relativi a "../../something/page.htm" in stile!




Ho usato questo codice per risolvere il problema:

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



Uri ha un costruttore che dovrebbe fare questo per te: new Uri(Uri baseUri, string relativeUri)

Ecco un esempio:

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



Ho trovato che UriBuilder funzionato molto bene per questo genere di cose:

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

Vedi Classe UriBuilder - MSDN per ulteriori costruttori e documentazione.




Combinare più parti di un URL potrebbe essere un po 'complicato. È possibile utilizzare il costruttore di due parametri Uri(baseUri, relativeUri) oppure è possibile utilizzare la funzione di utilità Uri.TryCreate() .

In entrambi i casi, si potrebbe finire per restituire un risultato errato perché questi metodi continuano a troncare le parti relative al primo parametro baseUri , cioè da qualcosa come http://google.com/some/thing a http://google.com .

Per poter combinare più parti in un URL finale, puoi copiare le due funzioni seguenti:

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

Il codice completo con test unitari per dimostrare l'utilizzo può essere trovato su https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs

Ho dei test unitari per coprire i tre casi più comuni:




Trovo il seguente utile e ha le seguenti caratteristiche:

  • Getti su spazio nullo o bianco
  • Prende più parametri params per più segmenti Url
  • getta su null o vuoto

Classe

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

test

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



Usa questo:

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



Ho creato questa funzione che ti renderà la vita più facile:

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

Funziona sia per gli URL che per i percorsi normali.

Uso:

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" 



Vedi purl.js Questo sarà davvero d'aiuto e può anche essere usato, a seconda di jQuery. Usalo in questo modo:

$.url().param("yourparam");






c# .net asp.net url path