Path.Combine para URLs?

Path.Combine es útil, pero ¿existe una función similar en el marco de .NET para las URL ?

Estoy buscando una syntax como esta:

Url.Combine("http://sofes.miximages.com/c%23/f") 

que regresaría:

"http://sofes.miximages.com/c%23/f"

Uri tiene un constructor que debería hacer esto por usted: new Uri(Uri baseUri, string relativeUri)

Aquí hay un ejemplo:

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

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

Regresará:

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

Esta puede ser una solución adecuadamente simple:

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

Ya hay algunas buenas respuestas aquí. En función de la sugerencia de mdsharpe, este es un método de extensión que se puede usar fácilmente cuando desee tratar instancias de 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('/')))); } } 

Y ejemplo de uso:

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

Esto producirá http://example.com/subpath/part1/part2

¡Esta pregunta obtuvo respuestas excelentes y altamente votadas!

La respuesta de Ryan Cook está cerca de lo que busco y puede ser más apropiada para otros desarrolladores. Sin embargo, agrega http: // al comienzo de la cadena y, en general, formatea un poco más de lo que estoy buscando.

Además, para mis casos de uso, la resolución de rutas relativas no es importante.

La respuesta de mdsharp también contiene la semilla de una buena idea, aunque esa implementación real necesitaba algunos detalles más para completarse. Este es un bash de desarrollarlo (y estoy usando esto en producción):

DO#

 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 

Este código pasa la siguiente prueba, que sucede que está en VB:

  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 

En función de la URL de muestra que proporcionó, supongo que desea combinar las URL relacionadas con su sitio.

Con base en esta suposición, propondré esta solución como la respuesta más adecuada a su pregunta que fue: “Path.Combine es útil, ¿hay alguna función similar en el marco de las URL?”

Como existe una función similar en el marco de las URL, propongo que el método correcto es “VirtualPathUtility.Combine”. Aquí está el enlace de referencia de MSDN: Método VirtualPathUtility.Combine

Hay una advertencia: creo que esto solo funciona para las URL relativas a su sitio (es decir, no puede usarlo para generar enlaces a otro sitio web. Por ejemplo, var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets"); ).

Path.Combine no funciona para mí porque puede haber caracteres como “|” en los argumentos QueryString y, por lo tanto, en la Url, que dará como resultado una ArgumentException.

Primero probé el nuevo enfoque de Uri (Uri baseUri, string relativeUri), que me falló a causa de Uri como http://www.mediawiki.org/wiki/Special:SpecialPages :

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

dará como resultado Special: SpecialPages, debido a los dos puntos después de Special que denota un esquema.

Así que finalmente tuve que tomar la ruta de mdsharpe / Brian MacKays y la desarrollé un poco más para trabajar con múltiples partes de 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; } 

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

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

Acabo de armar un pequeño método de extensión

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

se puede usar así:

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

Ejemplo ingenioso, Ryan, para terminar con un enlace a la función. Bien hecho.

Una recomendación Brian: si ajusta este código en una función, es posible que desee utilizar un UriBuilder para ajustar la URL base antes de la llamada TryCreate.

De lo contrario, la URL base DEBE incluir el esquema (donde el UriBuilder asumirá http: //). Solo un pensamiento:

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

Combinar varias partes de una URL puede ser un poco complicado. Puede usar el constructor de 2 parámetros Uri(baseUri, relativeUri) , o puede usar la función de utilidad Uri.TryCreate() . En ambos casos, es posible que termine arrojando un resultado incorrecto porque estos métodos continúan truncando las partes relativas del primer parámetro baseUri , es decir, desde algo como http://google.com/some/thing hasta http://google.com

Para poder combinar varias partes en una url final, puede copiar las 2 funciones siguientes:

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

El código completo con pruebas unitarias para demostrar el uso se puede encontrar en https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs

Tengo pruebas unitarias para cubrir los 3 casos más comunes: enter image description here

Esta respuesta probablemente se perderá en todas las respuestas anteriores, pero me pareció que UriBuilder funcionó muy bien para este tipo de cosas.

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

Vea UriBuilder Class – MSDN para más constructores y documentación.

Sé que esto ha sido respondido, pero una manera fácil de combinarlos y garantizar que siempre sea correcto es …

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

Aquí está el método de Microsoft (OfficeDev PnP) UrlUtility.Combine :

  const char PATH_DELIMITER = '/'; ///  /// Combines a path and a relative path. ///  ///  ///  ///  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); } 

Fuente: GitHub

Mi solución genérica:

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

Sé que llego tarde a la fiesta, pero creé esta función que hará su vida más fácil

  ///  /// the ultimate Path combiner of all time ///  ///  /// 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 ///  /// just adds the separator at the beginning /// fix the paths from within (by removing duplicate separators and correcting the separators) /// the paths to combine /// the combined path 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; } 

funciona tanto para URL como para rutas normales

Uso:

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

Sé que esta pregunta está bien respondida, sin embargo, me parece útil ya que tiene las siguientes características

  • Lanza espacio nulo o blanco
  • Clase estática que se System.Io.Path más a System.Io.Path
  • Toma el parámetro de parámetros para múltiples segmentos Url

Nota: El nombre de la clase URL podría cambiarse, ya que hay una clase de sistema System.Security.Policy.Url

Clase

 public static class Url { private static string InternalCombine(string source, string dest) { // If the source is null or white space retune the dest only if (string.IsNullOrWhiteSpace(source)) { throw new ArgumentException("Cannot be null or white space", "source"); // throw new ArgumentException("Cannot be null or white space", nameof(source)); // c# 6.0 Nameof Expression } if (string.IsNullOrWhiteSpace(dest)) { throw new ArgumentException("Cannot be null or white space", "dest"); // throw new ArgumentException("Cannot be null or white space", nameof(dest)); // c# 6.0 Nameof Expression } source = source.TrimEnd('/', '\\'); dest = dest.TrimStart('/', '\\'); return string.Format("{0}/{1}", source, dest); // return $"{source}/{dest}"; // c# 6.0 string interpolation } public static string Combine(string source, params string[] args) { return args.Aggregate(source, InternalCombine); } } 

Resultados

 Url.Combine("test1", "test2"); Url.Combine("test1//", "test2"); Url.Combine("test1", "/test2"); // Result = test1/test2 Url.Combine(@"test1\/\/\/", @"\/\/\\\\\//test2", @"\/\/\\\\\//test3\") ; // Result = test1/test2/test3 Url.Combine("/test1/", "/test2/", null); Url.Combine("", "/test2/"); Url.Combine("/test1/", null); // Throws an ArgumentException 

¿Qué tal esto?

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

Aquí está mi enfoque y lo usaré yo también

 public static string UrlCombine(string part1, string part2) { string newPart1 = string.Empty; string newPart2 = string.Empty; string seprator = "/"; // if either part1 or part 2 is empty, // we don't need to combine with seprator if (string.IsNullOrEmpty(part1) || string.IsNullOrEmpty(part2)) { seprator = 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, seprator, newPart2); } 
  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); } 

Tiene los beneficios de comportarse exactamente como Path.Combine

Reglas al combinar URL con URI

Para evitar un comportamiento extraño, hay una regla a seguir:

  • ruta (directorio) debe terminar con ‘/’. si la ruta finaliza sin ‘/’, la última parte se trata como un nombre de archivo y se concatenará cuando intente combinarse con la siguiente parte de la url.
  • hay 1 excepción: la dirección URL base (sin información de directorio) no necesita terminar con ‘/’
  • la parte de la ruta no debe comenzar con ‘/’, si comienza con ‘/’ se descarta toda la información relativa existente de la URL … añadiendo cadena. ¡La ruta de la parte vacía también eliminará el directorio relativo de la URL!

Si sigue las reglas anteriores, puede combinar las URL con el código siguiente. Dependiendo de su situación, puede agregar varias partes de ‘directorio’ a la 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(); }); 

¿Por qué no solo usa lo siguiente?

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

Hay un comentario de Todd Menier anterior que Flurl incluye un Url.Combine.

Más detalles:

Url.Combine es básicamente un Path.Combine para URLs, que garantiza un solo y único carácter de separación entre las partes:

 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" 

Más sugerencias … He combinado todo lo anterior:

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

Bueno, simplemente concateno dos cadenas y uso expresiones regulares para hacer la parte de limpieza.

  public class UriTool { public static Uri Join(string path1, string path2) { string url = path1 + "/" + path2; url = Regex.Replace(url, "(? 

Entonces, puedes usar esto:

  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" 

Espero que pueda ser útil para alguien!

Usé este código para resolver el 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]); } } } 

Ambos funcionan

  Uri final = new Uri(Regex.Replace(baseUrl + "/" + relativePath, "(? 

O

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

es decir

Si

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

y

relativePath = "To_Folder"

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

Algunos errores aparecerán para el código a continuación

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

Un simple trazador de líneas:

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

Inspirado por la respuesta de @Matt Sharpe.

We use the following simple helper method to join arbitrary number of URL parts together:

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

Note, that it doesn’t support ‘../../something/page.htm’-style relative URL-s!

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