Flurl incluye un Url.Combinemétodo que hace exactamente eso.
Todd Menier
2
En realidad, el // es manejado por el enrutamiento del sitio web o servidor y no por el navegador. Enviará lo que pones en la barra de direcciones. Es por eso que tenemos problemas cuando escribimos htp: // en lugar de http: // Por lo tanto, // puede causar problemas importantes en algunos sitios. Estoy escribiendo un .dll para un rastreador que maneja un sitio web en particular que arroja un 404 si tiene // en la url.
Url.Combine es básicamente un Path.Combine para URL, asegurando un único carácter separador entre las partes:
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"
Bueno, esta pregunta recibe mucho tráfico, y la respuesta con más de 1000 votos positivos no funciona en todos los casos. Años más tarde, en realidad uso Flurl para esto, así que estoy aceptando este. Parece funcionar en todos los casos que he encontrado. Si las personas no quieren tomar una dependencia, publiqué una respuesta que también funciona bien.
Uri tiene un constructor que debería hacer esto por usted: new Uri(Uri baseUri, string relativeUri)
Aquí hay un ejemplo:
Uri baseUri =newUri("http://www.contoso.com");Uri myUri =newUri(baseUri,"catalog/shownew.htm");
Nota del editor: Cuidado, este método no funciona como se esperaba. Puede cortar parte de baseUri en algunos casos. Ver comentarios y otras respuestas.
Me gusta el uso de la clase Uri, desafortunadamente no se comportará como Path.Combine como lo solicitó el OP. Por ejemplo, nuevo Uri (nuevo Uri (" test.com/mydirectory/" ), "/helloworld.aspx"). ToString () le ofrece " test.com/helloworld.aspx "; lo cual sería incorrecto si quisiéramos un resultado de estilo Path.Combine.
Doctor Jones
195
Todo está en las barras. Si la parte de ruta relativa comienza con una barra inclinada, entonces se comporta como usted describió. Pero, si deja la barra oblicua, entonces funciona de la manera esperada (tenga en cuenta la barra oblicua faltante en el segundo parámetro): nuevo Uri (nuevo Uri (" test.com/mydirectory/" ), "helloworld.aspx" ) .ToString () da como resultado " test.com/mydirectory/helloworld.aspx ". Path.Combine se comporta de manera similar. Si el parámetro de ruta relativa comienza con una barra diagonal, solo devuelve la ruta relativa y no los combina.
Joel Beckham
70
Si su baseUri fuera "test.com/mydirectory/mysubdirectory", entonces el resultado sería "test.com/mydirectory/helloworld.aspx" en lugar de "test.com/mydirectory/mysubdirectory/helloworld.aspx". La sutil diferencia es la falta de barra diagonal en el primer parámetro. Estoy totalmente de acuerdo con el uso de los métodos de marco existentes, si ya tengo que tener la barra inclinada final allí, entonces creo que hacer partUrl1 + partUrl2 huele mucho menos: podría haber estado persiguiendo esa barra diagonal durante bastante tiempo durante todo un tiempo en aras de no hacer cuerda concat.
Carl
64
La única razón por la que quiero un método de combinación URI es para no tener que verificar la barra diagonal final. Request.ApplicationPath es '/' si su aplicación está en la raíz, pero '/ foo' si no lo está.
nickd
24
I -1 esta respuesta porque esto no responde al problema. Cuando desee combinar la URL, como cuando quiera usar Path.Combine, no querrá preocuparse por el final /. y con esto, tienes que preocuparte. Prefiero la solución de Brian MacKay o mdsharpe arriba
Baptiste Pernet
161
Esta puede ser una solución convenientemente simple:
+1: Aunque esto no maneja rutas de estilo relativas (../../whatever.html), me gusta esta por su simplicidad. También agregaría adornos para el carácter '\'.
Brian MacKay
3
Vea mi respuesta para una versión más completa de esto.
Brian MacKay
149
Usted usa Uri.TryCreate( ... ):
Uri result =null;if(Uri.TryCreate(newUri("http://msdn.microsoft.com/en-us/library/"),"/en-us/library/system.uri.trycreate.aspx",out result)){Console.WriteLine(result);}
+1: Esto es bueno, aunque tengo un problema irracional con el parámetro de salida. ;)
Brian MacKay
10
@Brian: si ayuda, todos los métodos TryXXX ( int.TryParse, DateTime.TryParseExact) tienen este parámetro de salida para que sea más fácil usarlos en una declaración if. Por cierto, no tiene que inicializar la variable como lo hizo Ryan en este ejemplo.
Abel
41
Esta respuesta sufre el mismo problema que la de Joel : unirse test.com/mydirectory/y /helloworld.aspxresultará en lo test.com/helloworld.aspxque aparentemente no es lo que quieres.
Matt Kocaj
3
Hola, esto falló por lo siguiente: if (Uri. TryCreate (new Uri (" localhost / MyService /" ), "/ Event / SomeMethod? Abc = 123", out result)) {Console.WriteLine (result); } Me muestra el resultado como: localhost / Event / SomeMethod? Abc = 123 Nota: "http: //" se reemplaza de la base Uri aquí por stackoverflow
Faisal Mq
3
@FaisalMq Este es el comportamiento correcto, ya que pasó un segundo parámetro relativo a la raíz. Si hubiera omitido el inicio / en el segundo parámetro, habría obtenido el resultado que esperaba.
Tom Lint
127
Ya hay algunas respuestas geniales aquí. Basado en la sugerencia de mdsharpe, aquí hay un método de extensión que puede usarse fácilmente cuando desee tratar con instancias de Uri:
using System;
using System.Linq;publicstaticclassUriExtensions{publicstaticUriAppend(thisUri uri,paramsstring[] paths){returnnewUri(paths.Aggregate(uri.AbsoluteUri,(current, path)=>string.Format("{0}/{1}", current.TrimEnd('/'), path.TrimStart('/'))));}}
Y ejemplo de uso:
var url =newUri("http://example.com/subpath/").Append("/part1/","part2").AbsoluteUri;
Esta solución hace que sea trivial escribir un método estático UriUtils.Combine ("base url", "part1", "part2", ...) que es muy similar a Path.Combine (). ¡Agradable!
angularsen
Para admitir URI relativos, tuve que usar ToString () en lugar de AbsoluteUri y UriKind.AbsoluteOrRelative en el constructor de Uri.
angularsen
Gracias por el consejo sobre el pariente Uris. Desafortunadamente, Uri no facilita el manejo de rutas relativas, ya que siempre hay algo de burla con Request.ApplicationPath involucrado. ¿Quizás también podría intentar usar un nuevo Uri (HttpContext.Current.Request.ApplicationPath) como base y simplemente llamar a Append en él? Esto le dará rutas absolutas, pero debería funcionar en cualquier lugar dentro de la estructura del sitio.
Ales Potocnik Hahonina
Excelente. Me alegro de que haya ayudado a alguien más. He estado usando esto por algún tiempo y no he tenido ningún problema.
Ales Potocnik Hahonina
También agregué verificar si alguna de las rutas para agregar no es nula ni vacía.
n.podbielski
92
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, resolver 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 intento de desarrollarlo (y lo estoy usando en producción):
Hablando de detalles: ¿qué pasa con lo obligatorio ArgumentNullException("url1")si el argumento es Nothing? Lo siento, solo soy exigente ;-). Tenga en cuenta que una barra invertida no tiene nada que ver en un URI (y si está allí, no debe recortarse), por lo que puede eliminarla de su TrimXXX.
Abel
44
puede usar la cadena de parámetros [] y unirlos recursivamente para permitir más de 2 combinaciones
Jaider
44
Desearía que esto estuviera en la Biblioteca de la Clase Base como Path.Combine.
Uriah Blatherwick
1
@MarkHurd Volví a editar el código, para que sea conductualmente igual que C #, y también sintácticamente equivalente.
JJS
1
@BrianMacKay Lo rompí, Markhurd señaló mi error y retrocedí, actualicé nuevamente ... saludos
JJS
36
Path.Combine no funciona para mí porque puede haber caracteres como "|" en los argumentos de QueryString y, por lo tanto, en la URL, lo que dará como resultado una excepción ArgumentException.
Primero probé el nuevo Uri(Uri baseUri, string relativeUri)enfoque, que me falló debido a URI como http://www.mediawiki.org/wiki/Special:SpecialPages:
resultará en Special: SpecialPages, debido a los dos puntos Specialque indican un esquema.
Así que finalmente tuve que tomar la ruta mdsharpe / Brian MacKays y la desarrollé un poco más para trabajar con múltiples partes URI:
publicstaticstringCombineUri(paramsstring[] uriParts){string uri =string.Empty;if(uriParts !=null&& uriParts.Length>0){char[] trims =newchar[]{'\\','/'};
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;}
+1: Ahora estamos hablando ... Voy a probar esto. Esto incluso podría terminar siendo la nueva respuesta aceptada. Después de intentar el nuevo método Uri (), realmente no me gusta. Demasiado quisquilloso.
Brian MacKay
¡Esto es exactamente lo que necesitaba! No era fanático de tener que preocuparme de dónde ponía las barras inclinadas, etc ...
Gromer
+1 por rodar en la comprobación nula para que no explote.
NightOwl888
Count () debe ser Longitud para que no necesite incluir Linq en su biblioteca solo por eso.
PRMan
Esto era exactamente lo que estaba buscando.
ThePeter
34
Según la URL de ejemplo que proporcionó, voy a suponer que desea combinar las URL relacionadas con su sitio.
En base a esta suposición, propondré esta solución como la respuesta más adecuada a su pregunta, que fue: "Path.Combine es útil, ¿hay una función similar en el marco para las URL?"
Dado que existe una función similar en el marco para las URL, propongo que la correcta es: método "VirtualPathUtility.Combine". Aquí está el enlace de referencia de MSDN: VirtualPathUtility.Combine Method
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");).
+1 porque está cerca de lo que estoy buscando, aunque sería ideal si funcionara para cualquier URL antigua. Doblarlo será mucho más elegante de lo que propuso mdsharpe.
Brian MacKay
2
La advertencia es correcta, no puede funcionar con uris absolutas y el resultado siempre es relativo desde la raíz. Pero tiene un beneficio adicional, procesa la tilde, como con "~ /". Esto lo convierte en un atajo Server.MapPathy combinación.
Para hacerlo funcionar, debe eliminar primero / en el segundo argumento, es decir, "/ Images" - / Path.Combine (" Http://MyUrl.com ", "Images / Image.jpg")
Por G
8
@SliverNinja Eso no es correcto El valor de este campo es una barra diagonal inversa ('\') en UNIX y una barra diagonal ('/') en los sistemas operativos Windows y Macintosh. Al usar Mono en un sistema Linux, obtendría el separador incorrecto.
user247702
66
Todos los que se están escapando en el Separador de directorios están olvidando que las cadenas podrían haber venido de un sistema operativo diferente al que usted tiene ahora. Simplemente reemplace la barra diagonal inversa por barra diagonal y estará cubierto.
Ejemplo ingenioso, Ryan, para terminar con un enlace a la función. Bien hecho.
Una recomendación Brian: si envuelve este código en una función, es posible que desee utilizar un UriBuilder para envolver la URL base antes de la llamada TryCreate.
De lo contrario, la URL base DEBE incluir el esquema (donde UriBuilder asumirá http: //). Solo un pensamiento:
+1, aunque esto es muy similar a la respuesta de mdsharpe, que mejoré en mi respuesta. ¡Esta versión funciona muy bien a menos que Url2 comience con / o \, o Url1 accidentalmente termine en \, o cualquiera de los dos esté vacío! :)
Brian MacKay
9
Combinar varias partes de una URL podría ser un poco complicado. Puede usar el constructor de dos parámetros Uri(baseUri, relativeUri), o puede usar la Uri.TryCreate()función de utilidad.
En cualquier caso, usted podría terminar de devolver un resultado incorrecto debido a que estos métodos siguen truncar las partes relativas fuera del primer parámetro baseUri, es decir, de algo así como http://google.com/some/thinga http://google.com.
Para poder combinar varias partes en una URL final, puede copiar las dos funciones a continuación:
publicstaticstringCombine(paramsstring[] parts){if(parts ==null|| parts.Length==0)returnstring.Empty;var urlBuilder =newStringBuilder();foreach(var part in parts){var tempUrl = tryCreateRelativeOrAbsolute(part);
urlBuilder.Append(tempUrl);}returnVirtualPathUtility.RemoveTrailingSlash(urlBuilder.ToString());}privatestaticstring tryCreateRelativeOrAbsolute(string s){System.Uri uri;System.Uri.TryCreate(s,UriKind.RelativeOrAbsolute,out uri);string tempUrl =VirtualPathUtility.AppendTrailingSlash(uri.ToString());return tempUrl;}
Se ve muy bien para mí. Aunque podría reemplazar el bucle I con un bucle foreach para una mejor claridad.
Chris Marisic
Gracias Chris Acabo de cambiar mi código para usar Foreach.
Believe2014
1
+1 por todo el esfuerzo extra. Necesito mantener esta pregunta un poco para algunas de las respuestas más votadas, ustedes han arrojado el guante. ;)
Brian MacKay
Lo siento, pero no lo suficiente. Funciona en los pocos casos que muestra, pero lejos de ser utilizable en todas las combinaciones. Por ejemplo, los dos puntos en el camino causarán daño.
Gábor
¿Puedes dar un ejemplo de lo que quieres decir? Estaré encantado de solucionar el problema y ayudar a los próximos usuarios.
Believe2014
7
Encontré que UriBuilderfuncionó muy bien para este tipo de cosas:
Parece que esto podría ser para rutas, en lugar de URL.
Brian MacKay
@BrianMacKay Estuvo de acuerdo en que lo parece, pero es de la clase UrlUtility y se usa en el contexto de la combinación de URL
2
Editado para aclarar a qué clase pertenece
Tenga cuidado al usar esta clase, el resto de la clase contiene artefactos específicos de SharePoint.
Harry Berry
4
Encuentro lo siguiente útil y tiene las siguientes características:
Lanza en espacios nulos o blancos
Toma múltiples paramsparámetros para múltiples segmentos de URL
tira en nulo o vacío
Clase
publicstaticclassUrlPath{privatestaticstringInternalCombine(string source,string dest){if(string.IsNullOrWhiteSpace(source))thrownewArgumentException("Cannot be null or white space", nameof(source));if(string.IsNullOrWhiteSpace(dest))thrownewArgumentException("Cannot be null or white space", nameof(dest));return $"{source.TrimEnd('/', '\\')}/{dest.TrimStart('/', '\\')}";}publicstaticstringCombine(string source,paramsstring[] args)=> args.Aggregate(source,InternalCombine);}
Pruebas
UrlPath.Combine("test1","test2");UrlPath.Combine("test1//","test2");UrlPath.Combine("test1","/test2");// Result = test1/test2UrlPath.Combine(@"test1\/\/\/",@"\/\/\\\\\//test2",@"\/\/\\\\\//test3\");// Result = test1/test2/test3UrlPath.Combine("/test1/","/test2/",null);UrlPath.Combine("","/test2/");UrlPath.Combine("/test1/",null);// Throws an ArgumentException
Algunos problemas con las pruebas: // Resultado = prueba1 / prueba2 / prueba3 \ para la cuarta y la última de las pruebas de lanzamiento da ArgumentNullException en lugar de ArgumentException
Moriya
3
Mi solución genérica:
publicstaticstringCombine(paramsstring[] uriParts){string uri =string.Empty;if(uriParts !=null&& uriParts.Any()){char[] trims =newchar[]{'\\','/'};
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;}
Este método auxiliar es muy flexible y funciona bien en muchos casos de uso diferentes. ¡Gracias!
Shiva
3
Creé esta función que te facilitará la vida:
/// <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>publicstaticstringPathCombine(boolIsURL,boolIsRelative,boolIsFixInternal,paramsstring[] parts){if(parts ==null|| parts.Length==0)returnstring.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;}
Yo estaba buscando la versión de este PowerShell que serían: [System.IO.Path]::Combine("http://MyUrl.com/","/Images/Image.jpg")sin embargo, esto no funciona con un resultado de: /Images/Image.jpg. Elimine el /del segundo subPath y funciona:[System.IO.Path]::Combine("http://MyUrl.com/","Images/Image.jpg")
Underverse
Buena idea, pero falla, cuando uno de los parámetros es nulo.
pholpar
2
Reglas al combinar URL con un URI
Para evitar comportamientos extraños hay una regla a seguir:
La ruta (directorio) debe terminar con '/'. Si la ruta termina sin '/', la última parte se trata como un nombre de archivo, y se concatenará cuando se intente combinar con la siguiente parte de URL.
Hay una excepción: la dirección URL base (sin información del directorio) no necesita terminar con '/'
la parte de la ruta no debe comenzar con '/'. Si comienza con '/', string.Emptyse elimina toda la información relativa existente de la URL ... al agregar una ruta parcial, también se eliminará el directorio relativo de la URL.
Si sigue las reglas anteriores, puede combinar las URL con el código a continuación. Dependiendo de su situación, puede agregar múltiples partes de 'directorio' a la URL ...
Si no desea agregar una dependencia de terceros como Flurl o crear un método de extensión personalizado, en ASP.NET Core (también disponible en Microsoft.Owin), puede usar el PathStringque está destinado a construir URI rutas. Luego puede crear su URI completo usando una combinación de esto, Uriy UriBuilder.
Esto le proporciona todas las partes constituyentes sin tener que especificar los separadores en la URL base. Desafortunadamente, PathStringrequiere que /se anteponga a cada cadena; de lo contrario, arroja un ArgumentException! Pero al menos puede construir su URI de manera determinista de una manera que sea fácilmente comprobable por unidad.
El siguiente fragmento muestra el código + Pruebas.
Cuidado: esta solución pone en minúscula el host y agrega un puerto. Si esto no se desea, se puede escribir una representación de cadena, por ejemplo, aprovechando la UriPropiedad de UriBuilder.
Ciertamente, esta solución es bastante autodescriptiva (al menos en mi opinión). Pero confía en la "característica" indocumentada (al menos no encontré nada con una búsqueda rápida en Google) de la API de .NET. Esto puede cambiar con una versión futura, así que cubra el Método con Pruebas.
Este es un enfoque muy confiable. ¡Pulgares para la prueba de la unidad!
aggsol
2
Para cualquiera que esté buscando una línea y simplemente quiera unir partes de una ruta sin crear un nuevo método o hacer referencia a una nueva biblioteca o construir un valor de URI y convertirlo en una cadena, entonces ...
Es bastante básico, pero no veo qué más necesitas. Si tienes miedo de duplicar '/', entonces simplemente puedes hacer un .Replace("//", "/")después. Si tiene miedo de reemplazar el '//' duplicado en 'https: //', haga una unión, reemplace el '/' duplicado, luego únase a la URL del sitio web (sin embargo, estoy bastante seguro de que la mayoría de los navegadores automáticamente convierta cualquier cosa con 'https:' al frente para leer en el formato correcto). Esto se vería así:
Aquí hay muchas respuestas que manejarán todo lo anterior, pero en mi caso, solo lo necesitaba una vez en una ubicación y no necesitaré depender mucho de él. Además, es realmente fácil ver lo que está pasando aquí.
publicstaticstringUrlCombine(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 seperatorif(string.IsNullOrEmpty(part1)||string.IsNullOrEmpty(part2)){
seperator =string.Empty;}// If part1 is not empty,// remove '/' at lastif(!string.IsNullOrEmpty(part1)){
newPart1 = part1.TrimEnd('/');}// If part2 is not empty,// remove '/' at firstif(!string.IsNullOrEmpty(part2)){
newPart2 = part2.TrimStart('/');}// Now finally combinereturnstring.Format("{0}{1}{2}", newPart1, seperator, newPart2);}
Esto es aceptable solo para su caso. Hay casos que podrían romper su código. Además, no realizó la codificación adecuada de las partes de la ruta. Esto podría ser una gran vulnerabilidad cuando se trata de ataques de secuencias de comandos en sitios cruzados.
Believe2014
Estoy de acuerdo con tus puntos. Se supone que el código debe hacer una simple combinación de dos partes de URL.
Buen toque con 'WebPath'. :) Sin embargo, el código puede ser excesivamente denso; es difícil para mí mirar esto y decir, sí, eso es perfecto. Me dan ganas de ver pruebas unitarias. ¡Tal vez solo soy yo!
No desea intentar quitar la barra inclinada si comienza con http.
Martin Murphy
@BrianMacKay, no estoy seguro de que un revestimiento doble justifique una prueba unitaria, pero si lo desea, no dude en proporcionar una. No es que esté aceptando parches ni nada, pero puede editar la sugerencia.
Martin Murphy
1
Descubrí que el Uriconstructor voltea '\' a '/'. Entonces también puedes usar Path.Combine, con el Uriconstructor.
Uri baseUri =newUri("http://MyUrl.com");string path =Path.Combine("Images","Image.jpg");Uri myUri =newUri(baseUri, path);
Como se encuentra en otras respuestas, ya sea nuevo Uri()o TryCreate()puede hacer el tic. Sin embargo, la base Uri tiene que terminar /y el pariente NO debe comenzar con/ ; de lo contrario, eliminará la parte posterior de la URL base
Creo que esto se hace mejor como un método de extensión, es decir
var baseUri =newUri("http://test.com/test/");var combinedUri = baseUri.Append("/Do/Something");
En términos de rendimiento, esto consume más recursos de los que necesita, debido a la clase Uri que analiza y valida mucho; un perfil muy tosco (depuración) realizó un millón de operaciones en aproximadamente 2 segundos. Esto funcionará para la mayoría de los escenarios, sin embargo, para ser más eficiente, es mejor manipular todo como cadenas, esto toma 125 milisegundos para 1 millón de operaciones. Es decir
publicstaticstringAppend(thisUri 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 itvar baseUri = absoluteUri.EndsWith('/')? absoluteUri : absoluteUri +'/';var relative = relativePath.StartsWith('/')? relativePath.Substring(1): relativePath;return baseUri + relative;}
Y si aún desea devolver un URI, se necesitan alrededor de 600 milisegundos para 1 millón de operaciones.
publicstaticUriAppendUri(thisUri 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 itvar baseUri = absoluteUri.EndsWith('/')? absoluteUri : absoluteUri +'/';var relative = relativePath.StartsWith('/')? relativePath.Substring(1): relativePath;returnnewUri(baseUri + relative);}
Url.Combine
método que hace exactamente eso.Respuestas:
Hay un comentario de Todd Menier arriba de que Flurl incluye a
Url.Combine
.Más detalles:
Obtenga Flurl.Http en NuGet :
PM> Install-Package Flurl.Http
O obtenga el creador de URL independiente sin las características HTTP:
PM> Instalar paquete Flurl
fuente
Flurl
y prefiere una versión ligera, github.com/jean-lourenco/UrlCombineUri
tiene un constructor que debería hacer esto por usted:new Uri(Uri baseUri, string relativeUri)
Aquí hay un ejemplo:
Nota del editor: Cuidado, este método no funciona como se esperaba. Puede cortar parte de baseUri en algunos casos. Ver comentarios y otras respuestas.
fuente
Esta puede ser una solución convenientemente simple:
fuente
Usted usa
Uri.TryCreate( ... )
:Volveremos:
fuente
int.TryParse
,DateTime.TryParseExact
) tienen este parámetro de salida para que sea más fácil usarlos en una declaración if. Por cierto, no tiene que inicializar la variable como lo hizo Ryan en este ejemplo.test.com/mydirectory/
y/helloworld.aspx
resultará en lotest.com/helloworld.aspx
que aparentemente no es lo que quieres.Ya hay algunas respuestas geniales aquí. Basado en la sugerencia de mdsharpe, aquí hay un método de extensión que puede usarse fácilmente cuando desee tratar con instancias de Uri:
Y ejemplo de uso:
Esto producirá http://example.com/subpath/part1/part2
fuente
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, resolver 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 intento de desarrollarlo (y lo estoy usando en producción):
C#
VB.NET
Este código pasa la siguiente prueba, que está en VB:
fuente
ArgumentNullException("url1")
si el argumento esNothing
? Lo siento, solo soy exigente ;-). Tenga en cuenta que una barra invertida no tiene nada que ver en un URI (y si está allí, no debe recortarse), por lo que puede eliminarla de su TrimXXX.Path.Combine no funciona para mí porque puede haber caracteres como "|" en los argumentos de QueryString y, por lo tanto, en la URL, lo que dará como resultado una excepción ArgumentException.
Primero probé el nuevo
Uri(Uri baseUri, string relativeUri)
enfoque, que me falló debido a URI comohttp://www.mediawiki.org/wiki/Special:SpecialPages
:resultará en Special: SpecialPages, debido a los dos puntos
Special
que indican un esquema.Así que finalmente tuve que tomar la ruta mdsharpe / Brian MacKays y la desarrollé un poco más para trabajar con múltiples partes URI:
Uso:
CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")
fuente
Según la URL de ejemplo que proporcionó, voy a suponer que desea combinar las URL relacionadas con su sitio.
En base a esta suposición, propondré esta solución como la respuesta más adecuada a su pregunta, que fue: "Path.Combine es útil, ¿hay una función similar en el marco para las URL?"
Dado que existe una función similar en el marco para las URL, propongo que la correcta es: método "VirtualPathUtility.Combine". Aquí está el enlace de referencia de MSDN: VirtualPathUtility.Combine Method
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");
).fuente
Server.MapPath
y combinación.fuente
path.Replace(Path.DirectorySeparatorChar, '/');
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
Acabo de armar un pequeño método de extensión:
Se puede usar así:
fuente
Ejemplo ingenioso, Ryan, para terminar con un enlace a la función. Bien hecho.
Una recomendación Brian: si envuelve este código en una función, es posible que desee utilizar un UriBuilder para envolver la URL base antes de la llamada TryCreate.
De lo contrario, la URL base DEBE incluir el esquema (donde UriBuilder asumirá http: //). Solo un pensamiento:
fuente
Una manera fácil de combinarlos y garantizar que siempre sea correcta es:
fuente
Combinar varias partes de una URL podría ser un poco complicado. Puede usar el constructor de dos parámetros
Uri(baseUri, relativeUri)
, o puede usar laUri.TryCreate()
función de utilidad.En cualquier caso, usted podría terminar de devolver un resultado incorrecto debido a que estos métodos siguen truncar las partes relativas fuera del primer parámetro
baseUri
, es decir, de algo así comohttp://google.com/some/thing
ahttp://google.com
.Para poder combinar varias partes en una URL final, puede copiar las dos funciones a continuación:
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 tres casos más comunes:
fuente
Encontré que
UriBuilder
funcionó muy bien para este tipo de cosas:Ver Clase UriBuilder - MSDN para más constructores y documentación.
fuente
Aquí está el método UrlUtility.Combine de Microsoft (OfficeDev PnP) :
Fuente: GitHub
fuente
Encuentro lo siguiente útil y tiene las siguientes características:
params
parámetros para múltiples segmentos de URLClase
Pruebas
fuente
Mi solución genérica:
fuente
Creé esta función que te facilitará la vida:
Funciona tanto para URL como para rutas normales.
Uso:
fuente
¿Por qué no simplemente usar lo siguiente?
fuente
[System.IO.Path]::Combine("http://MyUrl.com/","/Images/Image.jpg")
sin embargo, esto no funciona con un resultado de:/Images/Image.jpg
. Elimine el/
del segundo subPath y funciona:[System.IO.Path]::Combine("http://MyUrl.com/","Images/Image.jpg")
Reglas al combinar URL con un URI
Para evitar comportamientos extraños hay una regla a seguir:
string.Empty
se elimina toda la información relativa existente de la URL ... al agregar una ruta parcial, también se eliminará el directorio relativo de la URL.Si sigue las reglas anteriores, puede combinar las URL con el código a continuación. Dependiendo de su situación, puede agregar múltiples partes de 'directorio' a la URL ...
fuente
Si no desea agregar una dependencia de terceros como Flurl o crear un método de extensión personalizado, en ASP.NET Core (también disponible en Microsoft.Owin), puede usar el
PathString
que está destinado a construir URI rutas. Luego puede crear su URI completo usando una combinación de esto,Uri
yUriBuilder
.En este caso, sería:
Esto le proporciona todas las partes constituyentes sin tener que especificar los separadores en la URL base. Desafortunadamente,
PathString
requiere que/
se anteponga a cada cadena; de lo contrario, arroja unArgumentException
! Pero al menos puede construir su URI de manera determinista de una manera que sea fácilmente comprobable por unidad.fuente
Así que tengo otro enfoque, similar a todos los que usaron UriBuilder.
No quería dividir mi BaseUrl (que puede contener una parte de la ruta, por ejemplo, http://mybaseurl.com/dev/ ) como lo hizo javajavajavajavajava .
El siguiente fragmento muestra el código + Pruebas.
Cuidado: esta solución pone en minúscula el host y agrega un puerto. Si esto no se desea, se puede escribir una representación de cadena, por ejemplo, aprovechando la
Uri
Propiedad deUriBuilder
.Probado con .NET Core 2.1 en Windows 10.
¿Por qué funciona esto?
Aunque
Path.Combine
devolverá las barras invertidas (al menos en Windows), el UriBuilder maneja este caso en el Setter dePath
.Tomado de https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs (importa la llamada a
string.Replace
)¿Es este el mejor enfoque?
Ciertamente, esta solución es bastante autodescriptiva (al menos en mi opinión). Pero confía en la "característica" indocumentada (al menos no encontré nada con una búsqueda rápida en Google) de la API de .NET. Esto puede cambiar con una versión futura, así que cubra el Método con Pruebas.
Hay pruebas en https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs (
Path_Get_Set
) que comprueban si\
se transforma correctamente.Nota al margen: Uno también podría trabajar con la
UriBuilder.Uri
propiedad directamente, si la uri se usará para unSystem.Uri
ctor.fuente
Para cualquiera que esté buscando una línea y simplemente quiera unir partes de una ruta sin crear un nuevo método o hacer referencia a una nueva biblioteca o construir un valor de URI y convertirlo en una cadena, entonces ...
Es bastante básico, pero no veo qué más necesitas. Si tienes miedo de duplicar '/', entonces simplemente puedes hacer un
.Replace("//", "/")
después. Si tiene miedo de reemplazar el '//' duplicado en 'https: //', haga una unión, reemplace el '/' duplicado, luego únase a la URL del sitio web (sin embargo, estoy bastante seguro de que la mayoría de los navegadores automáticamente convierta cualquier cosa con 'https:' al frente para leer en el formato correcto). Esto se vería así:Aquí hay muchas respuestas que manejarán todo lo anterior, pero en mi caso, solo lo necesitaba una vez en una ubicación y no necesitaré depender mucho de él. Además, es realmente fácil ver lo que está pasando aquí.
Ver: https://docs.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8
fuente
Utilizar:
Tiene el beneficio de comportarse exactamente igual
Path.Combine
.fuente
Aquí está mi enfoque y lo usaré también para mí:
fuente
Utilizar este:
fuente
Descubrí que el
Uri
constructor voltea '\' a '/'. Entonces también puedes usarPath.Combine
, con elUri
constructor.fuente
Para lo que vale, aquí hay un par de métodos de extensión. El primero combinará rutas y el segundo agregará parámetros a la URL.
fuente
Como se encuentra en otras respuestas, ya sea nuevo
Uri()
oTryCreate()
puede hacer el tic. Sin embargo, la base Uri tiene que terminar/
y el pariente NO debe comenzar con/
; de lo contrario, eliminará la parte posterior de la URL baseCreo que esto se hace mejor como un método de extensión, es decir
y para usarlo:
En términos de rendimiento, esto consume más recursos de los que necesita, debido a la clase Uri que analiza y valida mucho; un perfil muy tosco (depuración) realizó un millón de operaciones en aproximadamente 2 segundos. Esto funcionará para la mayoría de los escenarios, sin embargo, para ser más eficiente, es mejor manipular todo como cadenas, esto toma 125 milisegundos para 1 millón de operaciones. Es decir
Y si aún desea devolver un URI, se necesitan alrededor de 600 milisegundos para 1 millón de operaciones.
Espero que esto ayude.
fuente
Creo que esto debería darle más flexibilidad, ya que puede manejar tantos segmentos de ruta como desee:
fuente