Path.Combine est pratique, mais existe-t-il une fonction similaire dans le framework .NET pour RL ?
Je cherche une syntaxe comme celle-ci:
Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")
qui retournerait:
"http://MyUrl.com/Images/Image.jpg"
Il y a c'est un commentaire de Todd Menier ci-dessus que Flurl inclut un Url.Combine.
Plus de détails:
Url.Combine est fondamentalement un Path.Combine pour les URL, assurant un et un seul caractère séparateur entre les parties:
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"
Obtenez Flurl.Http sur NuGet :
PM> Install-Package Flurl.Http
Ou obtenez le générateur d'URL autonome sans les fonctionnalités HTTP:
PM> Flurl de paquet d'installation
Uri
a un constructeur qui devrait le faire pour vous: new Uri(Uri baseUri, string relativeUri)
Voici un exemple:
Uri baseUri = new Uri("http://www.contoso.com");
Uri myUri = new Uri(baseUri, "catalog/shownew.htm");
Note de l'éditeur: Attention, cette méthode ne fonctionne pas comme prévu. Cela peut couper une partie de baseUri dans certains cas. Voir les commentaires et autres réponses.
Vous utilisez 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);
}
Reviendra:
http://msdn.Microsoft.com/en-us/library/system.uri.trycreate.aspx
Cela peut être une solution assez simple:
public static string Combine(string uri1, string uri2)
{
uri1 = uri1.TrimEnd('/');
uri2 = uri2.TrimStart('/');
return string.Format("{0}/{1}", uri1, uri2);
}
Il y a déjà quelques bonnes réponses ici. Sur la base de la suggestion de mdsharpe, voici une méthode d’extension qui peut facilement être utilisée lorsque vous souhaitez traiter des instances 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('/'))));
}
}
Et exemple d'utilisation:
var url = new Uri("http://example.com/subpath/").Append("/part1/", "part2").AbsoluteUri;
Cela produira http://example.com/subpath/part1/part2
La réponse de Ryan Cook est proche de ce que je recherche et pourrait être plus appropriée pour d'autres développeurs. Cependant, il ajoute http: // au début de la chaîne et en général, il effectue un peu plus de formatage que ce que je suis après.
De plus, pour mes cas d'utilisation, la résolution des chemins relatifs n'est pas importante.
la réponse de mdsharp contient également le germe d'une bonne idée, bien que la mise en œuvre effective nécessite quelques précisions supplémentaires. Ceci est une tentative pour étoffer le tout (et j'utilise cela en production):
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
Ce code passe le test suivant, qui se trouve être 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
Sur la base de l'exemple URL que vous avez fourni, je suppose que vous souhaitez combiner des URL relatives à votre site.
Sur la base de cette hypothèse, je propose cette solution comme étant la réponse la plus appropriée à votre question: "Path.Combine est pratique, existe-t-il une fonction similaire (= /// =) dans le cadre des URL? "
Comme il existe une fonction similaire dans le cadre des URL, je propose que le correct soit: "VirtualPathUtility "Combiner". Voici le lien de référence MSDN: Méthode VirtualPathUtility.Combine
Il y a un inconvénient: je pense que cela ne fonctionne que pour les URL relatives à votre site (autrement dit, vous ne pouvez pas l'utiliser pour générer des liens vers un autre site Web. Par exemple, var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");
).
Path.Combine ne fonctionne pas pour moi car il peut y avoir des caractères comme "|" dans les arguments QueryString et donc l'URL, ce qui entraînera une exception ArgumentException.
J'ai d'abord essayé la nouvelle approche Uri(Uri baseUri, string relativeUri)
, qui a échoué pour moi à cause d'URI tels que http://www.mediawiki.org/wiki/Special:SpecialPages
:
new Uri(new Uri("http://www.mediawiki.org/wiki/"), "Special:SpecialPages")
se traduira par Special: SpecialPages, en raison du signe deux-points après Special
qui indique un schéma.
J'ai donc finalement dû prendre la route mdsharpe/Brian MacKays et l'ai développée un peu plus loin pour travailler avec plusieurs parties d'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;
}
Utilisation: CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")
Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")
Je viens de mettre en place une petite méthode d'extension:
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('/');
}
Il peut être utilisé comme ceci:
"www.example.com/".UriCombine("/images").UriCombine("first.jpeg");
Exemple Witty, Ryan, pour terminer avec un lien vers la fonction. Bien joué.
Une recommandation Brian: si vous intégrez ce code dans une fonction, vous pouvez utiliser un UriBuilder pour envelopper l'URL de base avant l'appel à TryCreate.
Sinon, l'URL de base DOIT inclure le schéma (où UriBuilder assumera http: //). Juste une pensée:
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");
}
Combiner plusieurs parties d'une URL peut être un peu délicat. Vous pouvez utiliser le constructeur à deux paramètres Uri(baseUri, relativeUri)
ou la fonction utilitaire Uri.TryCreate()
.
Dans les deux cas, vous risquez de renvoyer un résultat incorrect car ces méthodes continuent à tronquer les parties relatives du premier paramètre baseUri
, c’est-à-dire de quelque chose comme http://google.com/some/thing
à http://google.com
.
Pour pouvoir combiner plusieurs parties dans une URL finale, vous pouvez copier les deux fonctions ci-dessous:
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;
}
Le code complet avec des tests unitaires pour démontrer l'utilisation peut être trouvé à https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs
J'ai des tests unitaires pour couvrir les trois cas les plus courants:
Un moyen facile de les combiner et de s’assurer qu’il est toujours correct est:
string.Format("{0}/{1}", Url1.Trim('/'), Url2);
J'ai trouvé que UriBuilder
fonctionnait vraiment bien pour ce genre de chose:
UriBuilder urlb = new UriBuilder("http", _serverAddress, _webPort, _filePath);
Uri url = urlb.Uri;
return url.AbsoluteUri;
Voir riBuilder Class - MSDN pour plus de constructeurs et de documentation.
Voici la méthode de Microsoft (OfficeDev PnP) rlUtility.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);
}
Source: GitHub
J'ai créé cette fonction qui vous facilitera la vie:
/// <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;
}
Cela fonctionne aussi bien pour les URL que pour les chemins normaux.
Usage:
// 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
Ma solution générique:
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;
}
Je trouve le suivant utile et a les caractéristiques suivantes:
params
pour plusieurs segments d'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);
}
Tests
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
Règles lors de la combinaison d'URL avec un URI
Pour éviter tout comportement étrange, il y a une règle à suivre:
string.Empty
supprimera également le répertoire relatif de l'URL!Si vous suivez les règles ci-dessus, vous pouvez combiner des URL avec le code ci-dessous. Selon votre situation, vous pouvez ajouter plusieurs parties de "répertoire" à l'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 vous ne souhaitez pas ajouter de dépendance tierce telle que Flurl ou créer une méthode d'extension personnalisée, dans ASP.NET Core (également disponible dans Microsoft.Owin), vous pouvez utiliser PathString
qui est destiné à la but de construire des chemins URI. Vous pouvez ensuite créer votre URI complet en utilisant une combinaison de ceci, Uri
et UriBuilder
.
Dans ce cas, ce serait:
new Uri(new UriBuilder("http", "MyUrl.com").Uri, new PathString("/Images").Add("/Image.jpg").ToString())
Cela vous donne toutes les pièces constitutives sans avoir à spécifier les séparateurs dans l'URL de base. Malheureusement, PathString
nécessite que /
soit ajouté à chaque chaîne, sinon il lance un ArgumentException
! Mais au moins, vous pouvez construire votre URI de manière déterministe de manière facilement testable.
Pour ce que cela vaut, voici quelques méthodes d’extension. Le premier combine les chemins et le second ajoute des paramètres à l'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();
}
J'ai trouvé que le constructeur Uri
transforme '\' en '/'. Vous pouvez donc aussi utiliser Path.Combine
, avec le constructeur Uri
.
Uri baseUri = new Uri("http://MyUrl.com");
string path = Path.Combine("Images", "Image.jpg");
Uri myUri = new Uri(baseUri, path);
Pourquoi ne pas simplement utiliser ce qui suit.
System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/")
Utilisation:
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);
}
Il a l'avantage de se comporter exactement comme Path.Combine
.
Utilisez ceci:
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);
}
}
Voici mon approche et je vais l'utiliser pour moi aussi:
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);
}
Eh bien, je viens de concaténer deux chaînes et d’utiliser des expressions régulières pour effectuer le nettoyage.
public class UriTool
{
public static Uri Join(string path1, string path2)
{
string url = path1 + "/" + path2;
url = Regex.Replace(url, "(?<!http:)/{2,}", "/");
return new Uri(url);
}
}
Donc, vous pouvez l'utiliser comme ceci:
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"
J'ai combiné toutes les réponses précédentes:
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);
}
J'ai utilisé ce code pour résoudre le problème:
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]);
}
}
}
Les deux fonctionnent:
Uri final = new Uri(Regex.Replace(baseUrl + "/" + relativePath, "(?<!http:)/{2,}", "/"));
Ou
Uri final =new Uri(string.Format("{0}/{1}", baseUrl.ToString().TrimEnd('/'), relativePath.ToString().TrimStart('/')));
C'est à dire. si
baseUrl = "http://tesrurl.test.com/Int18"
et
relativePath = "To_Folder"
output = http://tesrurl.test.com/Int18/To_Folder
Quelques erreurs apparaîtront pour le code ci-dessous:
// If you use the below code, some issues will be there in the final URI
Uri final = new Uri(baseUrl, relativePath);
Nous utilisons la méthode d'assistance simple suivante pour joindre un nombre arbitraire de parties d'URL:
public static string JoinUrlParts(params string[] urlParts)
{
return string.Join("/", urlParts.Where(up => !string.IsNullOrEmpty(up)).ToList().Select(up => up.Trim('/')).ToArray());
}
Notez qu'il ne supporte pas les URL relatives ../../something/page.htm'-style!
Un simple paquebot:
public static string Combine(this string uri1, string uri2) => $"{uri1.TrimEnd('/')}/{uri2.TrimStart('/')}";
Inspiré par la réponse de @Matt Sharpe.