Path.Combine è utile, ma esiste una funzione simile nel framework .NET per gli URL ?
Sto cercando una sintassi come questa:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
che restituirebbe:
"http://MyUrl.com/Images/Image.jpg"
Path.Combine è utile, ma esiste una funzione simile nel framework .NET per gli URL ?
Sto cercando una sintassi come questa:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
che restituirebbe:
"http://MyUrl.com/Images/Image.jpg"
Risposte:
C'è un commento di Todd Menier sopra che Flurl include a Url.Combine
.
Più dettagli:
Url.Combine è fondamentalmente un Path.Combine per gli URL, garantendo uno e un solo carattere separatore tra le parti:
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"
Ottieni Flurl.Http su NuGet :
PM> Installa-pacchetto Flurl. Http
Oppure ottieni il generatore di URL autonomo senza le funzionalità HTTP:
PM> Installa pacchetto Flurl
Flurl
e preferisci una versione leggera, github.com/jean-lourenco/UrlCombine
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");
Nota dell'editor: attenzione, questo metodo non funziona come previsto. In alcuni casi può tagliare parte di BaseUri. Vedi commenti e altre risposte.
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);
}
Tu usi 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);
}
Tornerà:
http://msdn.microsoft.com/en-us/library/system.uri.trycreate.aspx
int.TryParse
, DateTime.TryParseExact
) hanno questo parametro di output per rendere più semplice il loro utilizzo in un'istruzione if. A proposito, non è necessario inizializzare la variabile come ha fatto Ryan in questo esempio.
test.com/mydirectory/
e /helloworld.aspx
risulterà in ciò test.com/helloworld.aspx
che apparentemente non è quello che vuoi.
Ci sono già delle ottime risposte qui. Sulla base del suggerimento mdsharpe, ecco un metodo di estensione che può essere facilmente utilizzato quando si desidera gestire le istanze di 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('/'))));
}
}
E esempio di utilizzo:
var url = new Uri("http://example.com/subpath/").Append("/part1/", "part2").AbsoluteUri;
Questo produrrà http://example.com/subpath/part1/part2
La risposta di Ryan Cook è vicina a ciò che sto cercando e potrebbe essere più appropriata per altri sviluppatori. Tuttavia, aggiunge http: // all'inizio della stringa e in generale esegue 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'attuazione effettiva necessitasse di qualche dettaglio in più per essere completa. Questo è un tentativo di perfezionarlo (e lo sto usando 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 seguente test, che si trova 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
ArgumentNullException("url1")
se l'argomento è Nothing
? Scusa, solo essere schizzinoso ;-). Nota che una barra rovesciata non ha nulla a che fare con un URI (e se è presente, non deve essere ritagliata), quindi puoi rimuoverla da TrimXXX.
Path.Combine non funziona per me perché ci possono essere caratteri come "|" negli argomenti QueryString e quindi nell'URL, che risulterà in ArgumentException.
Per prima cosa ho provato il nuovo Uri(Uri baseUri, string relativeUri)
approccio, che per me è fallito a causa di URI come http://www.mediawiki.org/wiki/Special:SpecialPages
:
new Uri(new Uri("http://www.mediawiki.org/wiki/"), "Special:SpecialPages")
si tradurrà in Special: SpecialPages, a causa dei due punti dopo Special
che indica uno schema.
Quindi alla fine ho dovuto prendere il percorso mdsharpe / Brian MacKays e svilupparlo ulteriormente per lavorare con più parti 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")
In base all'URL di esempio che hai fornito, suppongo che desideri combinare gli URL relativi al tuo sito.
Sulla base di questo presupposto, proporrò questa soluzione come la risposta più appropriata alla tua domanda che era: "Path.Combine è utile, esiste una funzione simile nel framework per gli URL?"
Poiché esiste una funzione simile nel framework per gli URL, propongo che il metodo corretto sia: metodo "VirtualPathUtility.Combine". Ecco il link di riferimento MSDN: Metodo VirtualPathUtility.Combine
C'è un avvertimento: credo che questo funzioni solo per gli URL relativi al tuo sito (ovvero, non puoi usarlo per generare collegamenti a un altro sito Web. Ad esempio var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");
).
Server.MapPath
e una combinazione.
Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")
path.Replace(Path.DirectorySeparatorChar, '/');
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
Ho appena messo insieme un piccolo metodo di estensione:
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('/');
}
Può essere usato in questo modo:
"www.example.com/".UriCombine("/images").UriCombine("first.jpeg");
Esempio spiritoso, Ryan, per finire con un link alla funzione. Molto bene.
Un consiglio Brian: se si avvolge questo codice in una funzione, è possibile utilizzare un UriBuilder per racchiudere l'URL di base prima della chiamata TryCreate.
Altrimenti, l'URL di base DEVE includere lo schema (in cui 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");
}
Un modo semplice per combinarli e assicurarsi che sia sempre corretto è:
string.Format("{0}/{1}", Url1.Trim('/'), Url2);
La combinazione di più parti di un URL potrebbe essere un po 'complicata. È possibile utilizzare il costruttore a due parametri Uri(baseUri, relativeUri)
oppure è possibile utilizzare la Uri.TryCreate()
funzione di utilità.
In entrambi i casi, potresti finire per restituire un risultato errato perché questi metodi continuano a troncare le parti relative fuori dal primo parametro baseUri
, cioè da qualcosa di simile http://google.com/some/thing
a http://google.com
.
Per poter combinare più parti in un URL finale, è possibile 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 unit test per dimostrare l'utilizzo è disponibile all'indirizzo https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs
Ho dei test unitari per coprire i tre casi più comuni:
Ho trovato UriBuilder
funzionato davvero bene per questo genere di cose:
UriBuilder urlb = new UriBuilder("http", _serverAddress, _webPort, _filePath);
Uri url = urlb.Uri;
return url.AbsoluteUri;
Vedi UriBuilder Class - MSDN per ulteriori costruttori e documentazione.
Ecco il metodo Microsoft (OfficeDev PnP) UrlUtility.Combine :
const char PATH_DELIMITER = '/';
/// <summary>
/// Combines a path and a relative path.
/// </summary>
/// <param name="path"></param>
/// <param name="relative"></param>
/// <returns></returns>
public static string Combine(string path, string relative)
{
if(relative == null)
relative = String.Empty;
if(path == null)
path = String.Empty;
if(relative.Length == 0 && path.Length == 0)
return String.Empty;
if(relative.Length == 0)
return path;
if(path.Length == 0)
return relative;
path = path.Replace('\\', PATH_DELIMITER);
relative = relative.Replace('\\', PATH_DELIMITER);
return path.TrimEnd(PATH_DELIMITER) + PATH_DELIMITER + relative.TrimStart(PATH_DELIMITER);
}
Fonte: GitHub
Trovo quanto segue utile e ha le seguenti caratteristiche:
params
parametri per più segmenti di URLClasse
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
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;
}
Ho creato questa funzione che ti semplificherà la vita:
/// <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;
}
Funziona con URL e percorsi normali.
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
Perché non usare solo quanto segue.
System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/")
[System.IO.Path]::Combine("http://MyUrl.com/","/Images/Image.jpg")
tuttavia questo non riesce con un risultato di: /Images/Image.jpg
. Rimuovi il /
secondo subPath e funziona:[System.IO.Path]::Combine("http://MyUrl.com/","Images/Image.jpg")
Regole durante la combinazione di URL con un URI
Per evitare comportamenti strani c'è una regola da seguire:
string.Empty
percorso parte rimuoverà anche la relativa directory dall'URL!Se segui le regole precedenti, puoi combinare gli URL con il codice seguente. A seconda della situazione, è possibile 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();
});
Se non si desidera aggiungere una dipendenza di terze parti come Flurl o creare un metodo di estensione personalizzato, in ASP.NET Core (disponibile anche in Microsoft.Owin), è possibile utilizzare quello PathString
destinato allo scopo di creare URI percorsi. È quindi possibile creare l'URI completo utilizzando una combinazione di questo Uri
e UriBuilder
.
In questo caso, sarebbe:
new Uri(new UriBuilder("http", "MyUrl.com").Uri, new PathString("/Images").Add("/Image.jpg").ToString())
Questo ti dà tutte le parti costituenti senza dover specificare i separatori nell'URL di base. Sfortunatamente, PathString
richiede che /
sia anteposto a ciascuna stringa, altrimenti in effetti genera un ArgumentException
! Ma almeno puoi costruire il tuo URI in modo deterministico in un modo che sia facilmente testabile in unità.
Quindi ho un altro approccio, simile a tutti quelli che hanno usato UriBuilder.
Non volevo dividere BaseUrl (che può contenere una parte del percorso, ad esempio http://mybaseurl.com/dev/ ) come faceva javajavajavajavajava .
Il frammento seguente mostra il codice + Test.
Attenzione: questa soluzione mette in minuscolo l'host e aggiunge una porta. Se ciò non è desiderato, è possibile scrivere una rappresentazione in forma di stringa, ad esempio sfruttando la Uri
proprietà di 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));
}
}
Testato con .NET Core 2.1 su Windows 10.
Perché funziona?
Anche se Path.Combine
restituirà Backslash (su Windows almeno), UriBuilder gestisce questo caso nel Setter di Path
.
Tratto da https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs (attenzione alla chiamata 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;
}
}
È questo l'approccio migliore?
Certamente questa soluzione è abbastanza auto-descrittiva (almeno secondo me). Ma stai facendo affidamento su "funzionalità" non documentate (almeno non ho trovato nulla con una rapida ricerca su Google) dall'API .NET. Questo potrebbe cambiare con una versione futura, quindi ti preghiamo di coprire il metodo con i test.
Ci sono test in https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs ( Path_Get_Set
) che controlla, se \
è stato correttamente trasformato.
Nota a margine: si potrebbe anche lavorare UriBuilder.Uri
direttamente con la proprietà, se l'uri verrà utilizzato per un System.Uri
ctor.
Per chiunque cerchi un one-liner e desideri semplicemente unire parti di un percorso senza creare un nuovo metodo o fare riferimento a una nuova libreria o costruire un valore URI e convertirlo in una stringa, quindi ...
string urlToImage = String.Join("/", "websiteUrl", "folder1", "folder2", "folder3", "item");
È piuttosto semplice, ma non vedo di cosa hai bisogno. Se hai paura di raddoppiare '/', allora puoi semplicemente fare un .Replace("//", "/")
dopo. Se hai paura di sostituire il "//" raddoppiato in "https: //", esegui invece un join, sostituisci il "/" raddoppiato, quindi unisciti all'URL del sito Web (tuttavia sono abbastanza sicuro che la maggior parte dei browser lo farà automaticamente converti qualsiasi cosa con 'https:' nella parte frontale per leggere nel formato corretto). Questo sembrerebbe:
string urlToImage = String.Join("/","websiteUrl", String.Join("/", "folder1", "folder2", "folder3", "item").Replace("//","/"));
Ci sono molte risposte qui che gestiranno tutto quanto sopra, ma nel mio caso, ne avevo bisogno solo una volta in una posizione e non avrò bisogno di fare molto affidamento su di esso. Inoltre, è davvero facile vedere cosa sta succedendo qui.
Vedi: https://docs.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8
Uso:
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);
}
Ha il vantaggio di comportarsi esattamente come Path.Combine
.
Ecco il mio approccio e lo userò anche per me stesso:
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);
}
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);
}
}
Per quello che vale, ecco un paio di metodi di estensione. Il primo combina i percorsi e il secondo aggiunge i parametri all'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();
}
Come si trova in altre risposte, nuove Uri()
o TryCreate()
possono fare il segno di spunta. Tuttavia, la base Uri deve finire /
e il parente NON deve iniziare /
; in caso contrario rimuoverà la parte finale dell'URL di base
Penso che questo sia fatto meglio come metodo di estensione, cioè
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);
}
e per usarlo:
var baseUri = new Uri("http://test.com/test/");
var combinedUri = baseUri.Append("/Do/Something");
In termini di prestazioni, ciò consuma più risorse del necessario, a causa della classe Uri che esegue molte analisi e convalide; una profilatura molto approssimativa (Debug) ha fatto un milione di operazioni in circa 2 secondi. Funzionerà per la maggior parte degli scenari, tuttavia per essere più efficiente, è meglio manipolare tutto come stringhe, ciò richiede 125 millisecondi per 1 milione di operazioni. ie
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;
}
E se desideri comunque restituire un URI, sono necessari circa 600 millisecondi per 1 milione di operazioni.
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);
}
Spero che questo possa essere d'aiuto.
Penso che questo dovrebbe darti una maggiore flessibilità in quanto puoi gestire tutti i segmenti di percorso che desideri:
public static string UrlCombine(this string baseUrl, params string[] segments)
=> string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));
Url.Combine
metodo che fa proprio questo.