2013-08-01 1 views
15

Depuis quelque temps, je recherche une méthode Path.Combine qui fonctionne sur les URL. Ceci est similaire à Path.Combine for URLs? avec une grande différence.Path.Combine pour les URL (partie 2)

Je vais illustrer avec un exemple. Supposons que nous ayons un 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 abouti à "http://example.com/foo.txt".

Ensuite, j'ai essayé chemin: System.IO.Path.Combine("http://example.com/somefolder", "foo.txt"); qui a abouti à "http://example.com/somefolder\foo.txt" ... plus proche, mais toujours pas. Pour les coups de pied, j'ai alors essayé: System.IO.Path.Combine("http://example.com/somefolder/", "foo.txt") qui s'est soldé par "http://example.com/somefolder/foo.txt".

Le dernier a fonctionné, mais il fait fondamentalement la concaténation de chaîne à ce point.

donc je pense avoir deux options:

  • Utilisez Path.Combine et remplacer tous les \ avec/
  • Utilisez concaténation de chaînes de base

Suis-je manque un construit dans la méthode de cadre ce?

MISE À JOUR: Le cas d'utilisation que j'ai est de 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 vexé d'avoir à utiliser concat chaîne dans le constructeur Uri, ainsi avoir à vérifier si la barre est nécessaire (que j'omis dans le code).

Il me semble que ce que j'essaie de faire serait beaucoup, car la classe Uri gère beaucoup d'autres protocoles en plus de http.

Répondre

15

Flurl [divulgation: Je suis l'auteur] est une petite bibliothèque de création d'URL qui peut combler l'écart 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 voulais é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 êtes sur 4,5 .NET ou ci-dessus et peut réécrire downloadFile comme une méthode async, votre meilleure option serait de remplacer votre boucle for avec quelque chose comme ceci:

var tasks = filenames.Select(f => downloadFileAsync(Url.Combine(folder, f))); 
await Task.WhenAll(tasks); 

Sinon, si vous êtes coincé sur .NET 4, vous pouvez toujours obtenir facilement le parallélisme en utilisant Parallel.ForEach:

Parallel.ForEach(filenames, f => downloadFile(Url.Combine(folder, f))); 
+0

En effet, j'ai parallélisé les téléchargements avec ForEach. Je l'ai juste coupé parce que ce n'était pas pertinent pour la question. Lien intéressant, cependant. Je vais vérifier et éventuellement changer la réponse acceptée. – Xcelled194

+0

Quelle est la licence sous le code? puis-je l'utiliser sur mon code propriétaire? – Jack

+1

Absolument. [Licence MIT] (http://choosealicense.com/licenses/mit/), donc c'est à peu près aussi permissif que possible. Vous ne pouvez pas me poursuivre en justice. :) –

6

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"); 

font essentiellement via simple et faire la manipulation de chaînes

var isValid = Uri.TryCreate(..., out myUri); 

Si vous voulez en savoir plus. Consultez ce post C# Url Builder Class

réponse Mise à jour

Lorsque vous faites référence à la base uri il sera toujours http://example.com/ quoi que ce soit à droite est le chemin juste.

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; 
    } 
} 
+0

Malheureusement, le lien (et des exemples) que vous avez posté ne fais pas ce que je veux. Je veux simplement prendre un chemin URI de base et y ajouter un nom de fichier. J'utilise une simple concaténation de chaînes, mais je ne peux pas croire qu'un tel usage (commun) ne soit pas supporté par la classe URI. Je mettrai à jour le post avec un exemple d'utilisation et quelques détails de mire. – Xcelled194

+0

L'intention de classe d'uri est tout simplement pas ce que vous recherchez. Mise à jour des réponses pour vous aider à réaliser ce que vous voulez. – defong

+0

On dirait qu'un gros trou manque dans le cadre ... Peut-être que JonSkeet a fait quelque chose pour le brancher ... – Xcelled194

1

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; 

} 
1

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 
+0

Vous n'avez pas besoin de tout ce découpage ... 'Trim ('', '/')' le fera. –

+0

Cela fonctionnerait pour les espaces et/Il n'est pas identique au code précédent car Trim traite tous les espaces blancs et pas seulement les espaces. Mais je l'aime et pour une URL devrait bien fonctionner. – GenuineRex

0

Omg, pourquoi vous écrivez tous un tel code complexe? Il 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"); 

url résultat est "http://something.com/task/status/dfgd/111/qqq"

+1

Qu'en est-il si l'URL se termine par une barre oblique? Par exemple, 'CombineUrl (" http://example.com ","/task/status/");' renvoie 'http: // example.com/task/status' au lieu de' http://example.com/task/status/'comme on s'y attendrait. – styfle