wake-up-neo.com

Datei mit WebClient oder HttpClient herunterladen?

Ich versuche, die Datei von einer URL herunterzuladen, und ich muss zwischen WebClient und HttpClient wählen. Ich habe diesen Artikel und mehrere andere Artikel im Internet referenziert. Überall wird empfohlen, sich für HttpClient aufgrund der hervorragenden Unterstützung für async und andere .Net 4.5-Berechtigungen zu entscheiden. Aber ich bin noch nicht ganz überzeugt und brauche mehr Inputs. 

Ich verwende den folgenden Code zum Herunterladen von Dateien aus dem Internet:

WebClient:

WebClient client = new WebClient();
client.DownloadFile(downloadUrl, filePath);

HttpClient:

using (HttpClient client = new HttpClient())
{        
    using (HttpResponseMessage response = await client.GetAsync(url))
    using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
    {
    }
}

Aus meiner Sicht sehe ich nur einen Nachteil bei der Verwendung von WebClient, nämlich den nicht asynchronen Aufruf, der den aufrufenden Thread blockiert. Was aber, wenn ich mir keine Sorgen über das Blockieren von Threads mache oder client.DownloadFileAsync() benutze, um die async-Unterstützung zu nutzen? 

Wenn ich dagegen HttpClient verwende, lädt ich dann nicht jedes einzelne Byte einer Datei in den Speicher und schreibe es dann in eine lokale Datei? Wenn die Dateigröße zu groß ist, ist der Speicheraufwand nicht teuer? Dies könnte vermieden werden, wenn wir WebClient verwenden, da er direkt in lokale Dateien schreibt und keinen Systemspeicher beansprucht.

Welchen Ansatz sollte ich also zum Download verwenden, wenn Leistung meine absolute Priorität ist? Ich möchte klargestellt werden, ob meine oben genannte Annahme falsch ist, und ich bin auch offen für alternative Ansätze.

9
Saket

Hier ist mein Ansatz. 

Wenn Sie eine WebApi aufrufen, um eine Datei abzurufen, können Sie von einer Controller-Methode aus die HttpClient GET-Anforderung verwenden und den Dateistream mit dem Rückgabetyp FileStreamResult zurückgeben.

public async Task<ActionResult> GetAttachment(int FileID)
{
    UriBuilder uriBuilder = new UriBuilder();
    uriBuilder.Scheme = "https";
    uriBuilder.Host = "api.example.com";

    var Path = "/files/download";
    uriBuilder.Path = Path;
    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri(uriBuilder.ToString());
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Add("authorization", access_token); //if any
        client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
        HttpResponseMessage response = await client.GetAsync(uriBuilder.ToString());

            if (response.IsSuccessStatusCode)
            {
                System.Net.Http.HttpContent content = response.Content;
                var contentStream = await content.ReadAsStreamAsync(); // get the actual content stream
                return File(contentStream, content_type, filename);
            }
            else
            {
                throw new FileNotFoundException();
            }
    }
}
1
Ingale88s

Hier können Sie eine URL herunterladen und in einer Datei speichern: (Ich verwende Windows 7, daher steht mir kein WindowsRT zur Verfügung, daher verwende ich auch System.IO.)

public static class WebUtils
{
    private static Lazy<IWebProxy> proxy = new Lazy<IWebProxy>(() => string.IsNullOrEmpty(Settings.Default.WebProxyAddress) ? null : new WebProxy { Address = new Uri(Settings.Default.WebProxyAddress), UseDefaultCredentials = true });

    public static IWebProxy Proxy
    {
        get { return WebUtils.proxy.Value; }
    }

    public static Task DownloadAsync(string requestUri, string filename)
    {
        if (requestUri == null)
            throw new ArgumentNullException(“requestUri”);

        return DownloadAsync(new Uri(requestUri), filename);
    }

    public static async Task DownloadAsync(Uri requestUri, string filename)
    {
        if (filename == null)
            throw new ArgumentNullException(“filename”);

        if (Proxy != null)
            WebRequest.DefaultWebProxy = Proxy;

        using (var httpClient = new HttpClient())
        {
            using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
            {
                using (Stream contentStream = await (await httpClient.SendAsync(request)).Content.ReadAsStreamAsync(), stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, Constants.LargeBufferSize, true))
                {
                    await contentStream.CopyToAsync(stream);
                }
            }
        }
    }
} 

Beachten Sie, dass der Code die Adresse des von mir verwendeten Proxyservers (bei der Arbeit) in einer Einstellung speichert und diese verwendet, wenn eine solche Einstellung angegeben wird. Andernfalls sollten Sie alle erforderlichen Informationen zur Verwendung der HttpClient-Betaversion zum Herunterladen und Speichern einer Datei erhalten.

nach folgendem this link:

1
Nirzar

Mit .Net 4.5+ können Sie es nativ ausführen. Ich habe es auf Ihre Weise versucht, und dann habe ich in Intellisense einfach eine Methode gefunden, die sinnvoll erschien.

https://docs.Microsoft.com/en-us/dotnet/api/system.io.stream.copytoasync?view=netframework-4.7.2

uri = new Uri(generatePdfsRetrieveUrl + pdfGuid + ".pdf");
HttpClient client = new HttpClient();
var response = await client.GetAsync(uri);
using (var fs = new FileStream(
    HostingEnvironment.MapPath(string.Format("~/Downloads/{0}.pdf", pdfGuid)), 
    FileMode.CreateNew))
{
    await response.Content.CopyToAsync(fs);
}
0
Bluebaron

Wenn der Code wiederholt aufgerufen wird, möchten Sie nichtHttpClient in einen using -Block einfügen ( die hängenden Ports bleiben offen )

Zum Herunterladen einer Datei mit HttpClient habe ich diese Erweiterungsmethode gefunden, was mir als gute und zuverlässige Lösung erschien:

public static class HttpContentExtensions
{
    public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite)
    {
        string pathname = Path.GetFullPath(filename);
        if (!overwrite && File.Exists(filename))
        {
            throw new InvalidOperationException(string.Format("File {0} already exists.", pathname));
        }

        FileStream fileStream = null;
        try
        {
            fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None);
            return content.CopyToAsync(fileStream).ContinueWith(
                (copyTask) =>
                {
                    fileStream.Close();
                });
        }
        catch
        {
            if (fileStream != null)
            {
                fileStream.Close();
            }

            throw;
        }
    }
}
0
Thymine