2013-08-01 7 views
15

Seit einiger Zeit suche ich nach einer Path.Combine-Methode, die auf URLs funktioniert. Dies ist vergleichbar mit Path.Combine for URLs? mit einem großen Unterschied.Path.Combine für URLs (Teil 2)

Ich werde mit einem Beispiel veranschaulichen. Angenommen, wir haben eine Basis-URL: http://example.com/somefolder und eine Datei: foo.txt. Somit wäre der vollständige Pfad: http://example.com/somefolder/foo.txt. Klingt einfach, oder? Ha.

Ich versuchte die Uri-Klasse: Uri.TryCreate(new Uri("http://example.com/somefolder"), "foo.txt", out x);, die "http://example.com/foo.txt" ergab.

Dann versuchte ich Pfad: System.IO.Path.Combine("http://example.com/somefolder", "foo.txt");, was in "http://example.com/somefolder\foo.txt" ergab ... Näher, aber immer noch nicht.

Für Tritte habe ich dann versucht: System.IO.Path.Combine("http://example.com/somefolder/", "foo.txt"), die "http://example.com/somefolder/foo.txt" ergab.

Die letzte funktionierte, aber es ist im Grunde String-Verkettung an diesem Punkt.

Also ich denke, ich habe zwei Möglichkeiten:

  • Verwenden Path.Combine und ersetzen Sie alle \ mit/
  • Verwenden Grund String-Verkettung

Bin ich ein fehlt im Rahmen Methode gebaut für Dies?

UPDATE: Der Anwendungsfall, den ich habe, ist zum Herunterladen einer Reihe von Dateien. Mein Code sieht wie folgt aus:

public void Download() 
    { 
     var folder = "http://example.com/somefolder"; 
     var filenames = getFileNames(folder); 

     foreach (var name in filenames) 
     { 
      downloadFile(new Uri(folder + "/" + name)); 
     } 
    } 

Ich bin verstimmt an, die Zeichenfolge Concat in Uri-Konstruktor zu verwenden, als auch mit überprüfen, ob der Schrägstrich benötigt wird (was ich im Code weggelassen).

Es scheint mir, dass was ich versuche zu tun, würde viel kommen, da die Uri-Klasse eine Menge anderer Protokolle außer http behandelt.

Antwort

15

Flurl [Offenlegung: Ich bin der Autor] ist eine kleine URL Builder-Bibliothek, die die Lücke mit seiner Url.Combine Methode füllen kann:

string url = Url.Combine("http://www.foo.com/", "/too/", "/many/", "/slashes/", "too", "few"); 
// result: "http://www.foo.com/too/many/slashes/too/few" 

Sie es über NuGet bekommen können: Install-Package Flurl.

Ich wollte auch darauf hinweisen, dass Sie die Effizienz Ihres Codes dramatisch verbessern können, indem Sie die Dateien parallel herunterladen. Es gibt ein paar Möglichkeiten, das zu tun. Wenn Sie auf .NET 4.5 sind oder oben und downloadFile als Asynchron-Methode neu schreiben können, dann die beste Wahl wäre, um Ihre for Schleife mit so etwas zu ersetzen:

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

Andernfalls, wenn Sie auf stecken .NET 4, können Sie Parallelität erreichen leicht durch Parallel.ForEach mit:

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

Tatsächlich habe ich die Downloads mit ForEach parallelisiert. Ich habe es nur gekürzt, weil es für die Frage nicht relevant war. Interessanter Link. Ich werde es überprüfen und möglicherweise die angenommene Antwort ändern. – Xcelled194

+0

In welcher Lizenz ist der Code enthalten? kann ich es auf meinem proprietären Code verwenden? – Jack

+1

Absolut. [MIT-Lizenz] (http://choosealicense.com/licenses/mit/), also ist es ungefähr so ​​freizügig wie es nur geht. Du kannst mich einfach nicht verklagen. :) –

6

So funktioniert die Uri-Klasse.

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

Im Grunde tun sie über String-Manipulation einfachste und tun

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

Wenn Sie mehr erfahren möchten. Beitrag Check out C# Url Builder Class

aktualisiert Antwort

Bei Verweisen auf Basis uri wird es immer sein http://example.com/ etwas nach rechts ist gerade Weg.

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

Leider ist der Link (und Beispiele) Sie auf dem Laufenden nicht tun, was ich will. Ich möchte einfach einen Basis-URI-Pfad verwenden und einen Dateinamen anhängen. Ich verwende eine einfache String-Verkettung, aber ich kann nicht glauben, dass solch eine einfache (allgemeine) Verwendung von der URI-Klasse nicht unterstützt wird. Ich werde den Post mit einer Beispielverwendung und einigen Moordetails aktualisieren. – Xcelled194

+0

Die uri Klassenabsicht ist einfach nicht das, wonach Sie suchen. Die Antworten wurden aktualisiert, damit Sie das erreichen, was Sie möchten. – defong

+0

Scheint wie ein großes Loch im Rahmen fehlt ... Vielleicht hat JonSkeet etwas gemacht, um es zu stecken ... – Xcelled194

1

ich habe eine statische Methode für diesen Zweck:

// 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

Hier ist eine LINQ-Version von etwas, das der obigen Antwort nahe kommt.

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

Sie brauchen nicht all das Trimmen ... 'Trim ('', '/')' wird es tun. –

+0

Das würde für Leerzeichen funktionieren und/Es ist nicht identisch mit dem vorherigen Code, da Trim mit allen Leerzeichen und nicht nur Leerzeichen behandelt. Aber ich mag es und für eine URL sollte es gut funktionieren. – GenuineRex

0

Omg, warum schreiben Sie alle so komplexen Code? Es ist sehr einfach:

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

Beispiel:

var methodUrl = CombineUrl("http://something.com", "/task/status/", "dfgd/", "/111", "qqq"); 

Ergebnis url ist "http://something.com/task/status/dfgd/111/qqq"

+1

Was ist, wenn die URL mit einem Schrägstrich endet? Beispiel: 'CombineUrl ("http://example.com", "/ task/status /"); 'gibt' http: // example.com/task/status' anstelle von 'http://example.com zurück/Aufgabe/Status/'wie man es erwarten würde. – styfle