Path.Combine es útil, pero ¿hay una función similar en el marco .NET para las URL ?
Estoy buscando una sintaxis como esta:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
que volvería:
"http://MyUrl.com/Images/Image.jpg"
Path.Combine es útil, pero ¿hay una función similar en el marco .NET para las URL ?
Estoy buscando una sintaxis como esta:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
que volvería:
"http://MyUrl.com/Images/Image.jpg"
Respuestas:
Hay un comentario de Todd Menier arriba de que Flurl incluye a Url.Combine
.
Más detalles:
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"
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
Flurl
y prefiere una versión ligera, github.com/jean-lourenco/UrlCombine
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");
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.
Esta puede ser una solución convenientemente simple:
public static string Combine(string uri1, string uri2)
{
uri1 = uri1.TrimEnd('/');
uri2 = uri2.TrimStart('/');
return string.Format("{0}/{1}", uri1, uri2);
}
Usted usa 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);
}
Volveremos:
http://msdn.microsoft.com/en-us/library/system.uri.trycreate.aspx
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 lo test.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:
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
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#
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 está en 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
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.
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
:
new Uri(new Uri("http://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:
public static string CombineUri(params string[] uriParts)
{
string uri = string.Empty;
if (uriParts != null && uriParts.Length > 0)
{
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;
}
Uso: CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")
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");
).
Server.MapPath
y combinación.
Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")
path.Replace(Path.DirectorySeparatorChar, '/');
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
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 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:
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");
}
Una manera fácil de combinarlos y garantizar que siempre sea correcta es:
string.Format("{0}/{1}", Url1.Trim('/'), Url2);
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/thing
a http://google.com
.
Para poder combinar varias partes en una URL final, puede copiar las dos funciones a continuación:
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 tres casos más comunes:
Encontré 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;
Ver Clase UriBuilder - MSDN para más constructores y documentación.
Aquí está el método UrlUtility.Combine de Microsoft (OfficeDev PnP) :
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);
}
Fuente: GitHub
Encuentro lo siguiente útil y tiene las siguientes características:
params
parámetros para múltiples segmentos de URLClase
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);
}
Pruebas
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
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;
}
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>
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
¿Por qué no simplemente usar lo siguiente?
System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/")
[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 ...
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();
});
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
y UriBuilder
.
En este caso, sería:
new Uri(new UriBuilder("http", "MyUrl.com").Uri, new PathString("/Images").Add("/Image.jpg").ToString())
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 un ArgumentException
! Pero al menos puede construir su URI de manera determinista de una manera que sea fácilmente comprobable por unidad.
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 de UriBuilder
.
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));
}
}
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 de Path
.
Tomado de https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs (importa la llamada a string.Replace
)
[AllowNull]
public string Path
{
get
{
return _path;
}
set
{
if ((value == null) || (value.Length == 0))
{
value = "/";
}
_path = Uri.InternalEscapeString(value.Replace('\\', '/'));
_changed = true;
}
}
¿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 un System.Uri
ctor.
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 ...
string urlToImage = String.Join("/", "websiteUrl", "folder1", "folder2", "folder3", "item");
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í:
string urlToImage = String.Join("/","websiteUrl", String.Join("/", "folder1", "folder2", "folder3", "item").Replace("//","/"));
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
Utilizar:
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 el beneficio de comportarse exactamente igual Path.Combine
.
Aquí está mi enfoque y lo usaré también para mí:
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);
}
Utilizar este:
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);
}
}
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.
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();
}
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
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);
}
y para usarlo:
var baseUri = new Uri("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
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;
}
Y si aún desea devolver un URI, se necesitan alrededor de 600 milisegundos para 1 millón de operaciones.
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);
}
Espero que esto ayude.
Creo que esto debería darle más flexibilidad, ya que puede manejar tantos segmentos de ruta como desee:
public static string UrlCombine(this string baseUrl, params string[] segments)
=> string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));
Url.Combine
método que hace exactamente eso.