Depuis quelque temps, je cherchais une méthode Path.Combine qui fonctionne sur les URL. Ceci est similaire à Path.Combine pour les URL? avec une grande différence.
Je vais illustrer par un exemple. Disons que nous avons une URL de base: http://example.com/somefolder
et un fichier: foo.txt
. Ainsi, le chemin complet serait: http://example.com/somefolder/foo.txt
. Cela semble simple, non? Ha.
J'ai essayé la classe Uri: Uri.TryCreate(new Uri("http://example.com/somefolder"), "foo.txt", out x);
qui a donné "http://example.com/foo.txt"
.
Ensuite, j'ai essayé Path: System.IO.Path.Combine("http://example.com/somefolder", "foo.txt");
qui a donné "http://example.com/somefolder\foo.txt"
... Plus près, mais toujours pas.
Pour les coups de pied, j’ai alors essayé: System.IO.Path.Combine("http://example.com/somefolder/", "foo.txt")
qui a donné "http://example.com/somefolder/foo.txt"
.
Le dernier a fonctionné, mais il s'agit essentiellement d'une concaténation de chaînes à ce stade.
Donc, je pense avoir deux options:
Me manque-t-il une méthode de cadre intégré pour cela?
UPDATE: Le cas d'utilisation que j'ai est pour télécharger un tas de fichiers. Mon code ressemble à ceci:
public void Download()
{
var folder = "http://example.com/somefolder";
var filenames = getFileNames(folder);
foreach (var name in filenames)
{
downloadFile(new Uri(folder + "/" + name));
}
}
Je suis fâché de devoir utiliser concatte chaîne dans le constructeur Uri, ainsi que de vérifier si la barre oblique est nécessaire (ce que j'ai omis dans le code).
Il me semble que ce que j'essaie de faire vaudrait beaucoup, car la classe Uri gère beaucoup d'autres protocoles en plus de http.
Flurl [divulgation: je suis l'auteur] est une petite bibliothèque de constructeur d'URL pouvant combler le vide avec sa méthode Url.Combine
:
string url = Url.Combine("http://www.foo.com/", "/too/", "/many/", "/slashes/", "too", "few");
// result: "http://www.foo.com/too/many/slashes/too/few"
Vous pouvez l'obtenir via NuGet: Install-Package Flurl
.
Je souhaitais également souligner que vous pouvez améliorer considérablement l'efficacité de votre code en téléchargeant les fichiers en parallèle. Il y a plusieurs façons de le faire. Si vous utilisez .NET 4.5 ou une version ultérieure et que vous pouvez réécrire downloadFile
en tant que méthode asynchrone, votre meilleure option serait de remplacer votre boucle for
par quelque chose comme ceci:
var tasks = filenames.Select(f => downloadFileAsync(Url.Combine(folder, f)));
await Task.WhenAll(tasks);
Sinon, si vous êtes bloqué sur .NET 4, vous pouvez toujours réaliser facilement le parallélisme en utilisant Parallel.ForEach :
Parallel.ForEach(filenames, f => downloadFile(Url.Combine(folder, f)));
Voici comment fonctionne la classe Uri.
var otherUri = new Uri("http://example.com/somefolder"));
// somefolder is just a path
var somefolder = otherUri.GetComponents(UriComponents.PathAndQuery, UriFormat.UriEscaped);
// example one
var baseUri = new Uri("http://example.com/");
var relativeUri = new Uri("somefolder/file.txt",UriKind.Relative);
var fullUri = new Uri(baseUri, relativeUri);
// example two
var baseUri = new Uri("http://example.com/somefolder");
var relativeUri = new Uri("somefolder/file.txt",UriKind.Relative);
var fullUri = new Uri(baseUri, relativeUri);
// example three
var baseUri = new Uri("http://example.com/");
var fullUri = new Uri(baseUri, "somefolder/file.txt");
Fondamentalement, le faire via la manipulation de chaîne plus simple et faire
var isValid = Uri.TryCreate(..., out myUri);
Si vous voulez en savoir plus . Découvrez ce post Classe C # Url Builder Builder
Réponse mise à jour
Lorsque vous vous référez à la base uri, ce sera toujours http://example.com/ tout ce qui se trouve à droite est simplement chemin.
void Main()
{
var ub = new UriBuilder("http://example.com/somefolder");
ub.AddPath("file.txt");
var fullUri = ub.Uri;
}
public static class MyExtensions
{
public static UriBuilder AddPath(this UriBuilder builder, string pathValue)
{
var path = builder.Path;
if (path.EndsWith("/") == false)
{
path = path + "/";
}
path += Uri.EscapeDataString(pathValue);
builder.Path = path;
}
}
Voici une version LINQ de quelque chose proche de la réponse ci-dessus.
public static string UrlCombine( this string root, params string[] parts)
{
return parts
.Select(part => part.Trim().TrimEnd('/').TrimStart('/').Trim())
.Aggregate(root, (current, path) => current + ("/" + path));
}
var x = "http://domain.com";
var p = "path";
var u = x.UrlCombine(p, "test.html"); // http://domain.com/path/test.html
J'ai une méthode statique à cet effet:
// Combines urls like System.IO.Path.Combine
// Usage: this.Literal1.Text = CommonCode.UrlCombine("http://stackoverflow.com/", "/questions ", " 372865", "path-combine-for-urls");
public static string UrlCombine(params string[] urls) {
string retVal = string.Empty;
foreach (string url in urls)
{
var path = url.Trim().TrimEnd('/').TrimStart('/').Trim();
retVal = string.IsNullOrWhiteSpace(retVal) ? path : new System.Uri(new System.Uri(retVal + "/"), path).ToString();
}
return retVal;
}
Omg, pourquoi écrivez-vous tous un code aussi complexe? C'est très simple:
private string CombineUrl(params string[] urls)
{
string result = "";
foreach (var url in urls)
{
if (result.Length > 0 && url.Length > 0)
result += '/';
result += url.Trim('/');
}
return result;
}
Exemple d'utilisation:
var methodUrl = CombineUrl("http://something.com", "/task/status/", "dfgd/", "/111", "qqq");
L'URL de résultat est " http://something.com/task/status/dfgd/111/qqq "