18

I use HTTP GET that downloads a zip file in a browser, something like https://example.com/up/DBID/a/rRID/eFID/vVID (not the exact url)

Now, when I try to do the same download in C# code(same GET method as above) for a desktop application, the zip file downloaded is not a valid archive file. When I opened this file in notepad, it was some HTML page.

I think I'm not setting some header correctly. I looked around for examples. I'd found several wrt uploads, but did not see anything for downloads.

Code:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.ContentType = "application/zip";
try
{
    HttpWebResponse res = (HttpWebResponse)request.GetResponse();
    using (StreamReader sr = new StreamReader(res.GetResponseStream(), System.Text.Encoding.Default))
    {
        StreamWriter oWriter = new StreamWriter(@"D:\Downloads\1.zip");
        oWriter.Write(sr.ReadToEnd());
        oWriter.Close();
    }
    res.Close();
}
catch (Exception ex)
{
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Merrin
  • 655
  • 2
  • 7
  • 18
  • 4
    This is an unguessable 'it doesn't work' question. Post code, document what you see when you open the file in a hex viewer. – Hans Passant Jan 22 '11 at 16:31

4 Answers4

43

It's mainly because you use a StreamWriter : TextWriter to handle a binary Zip file. A StreamWriter expects text and will apply an Encoding. And even the simple ASCII Encoder might try to 'fix' what it thinks are invalid line-endings.

You can replace all your code with:

  using (var client = new WebClient())
  {
    client.DownloadFile("http://something",  @"D:\Downloads\1.zip");
  }

Note that for new code you should look at HttpClient instead of WebClient.
And then don't use using( ) { }

H H
  • 263,252
  • 30
  • 330
  • 514
  • Oh yes, I can see the same problem in there. – Al Kepp Jan 22 '11 at 16:40
  • +1 beat me - @Al: I tested this with a zip file and it works just fine, are you sure the file itself is not corrupted already? – BrokenGlass Jan 22 '11 at 16:45
  • WebClient also created the same type of zip file. – Merrin Jan 22 '11 at 16:47
  • @Merrin, if you mean "the same faulty Zip file" then you need to give (a lot) more information. – H H Jan 22 '11 at 16:48
  • 1
    I think the issue I'm facing is authentication to the service. And then I could probably use the webclient to download the file. – Merrin Jan 22 '11 at 17:00
  • @Merrin did you sort this out as i am having the same HTML zip problem? – Ashley Staggs Oct 29 '11 at 12:47
  • @AshleyStaggs Yes, for me I was not authenticated when I attempted to download. – Merrin Feb 22 '12 at 14:03
  • 1
    @HenkHolterman Oh my dear god, this answer just saved me **so** much time. Many thanks to you and Google who brought me here. – Mike G Jun 29 '12 at 14:55
  • @HenkHolterman Hi, I am trying to post a zip file from my app (Android is the client) to a IIS server (using C#.net for server side code). But my saved zip file at the server side on opening says it's an corrupted archive. Any pointers of what's wrong? I suspect that the header's are written too but AFAIK I don't think that the `HTTP` POST method from my client app is sending any header(s) just a zip file instead. :| – beerBear Feb 01 '13 at 06:19
  • @codebreaker - SO is not a forum, if you can't find an exiting answer then post a new question. – H H Feb 01 '13 at 07:58
  • @HenkHolterman Please see [my ques](http://stackoverflow.com/questions/14642246/saved-zip-file-gets-corrupted-from-an-android-app-to-an-iis-server). Thanks :) – beerBear Feb 01 '13 at 08:25
  • 1
    @HenkHolterman thanks buddy. you saved my life. its working fine :) – Arul Sidthan Oct 19 '15 at 14:46
  • How to run it if proxy authentication is required? – Faizan Mubasher May 16 '18 at 10:49
  • Don't ask questions in comments. Search for it and post a new Question if necessary. – H H May 16 '18 at 16:29
8

You could just use WebClient for a 2-liner:

using(WebClient wc = new WebClient())
{
   wc.DownloadFile(url, @"D:\Downloads\1.zip");
}
Bek Raupov
  • 3,782
  • 3
  • 24
  • 42
BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
3

You can also use System.Net.Http.HttpClient

using (HttpClient client = new HttpClient())
{
        using (HttpResponseMessage response = await client.GetAsync(downloadURL))
        {
             using(var stream = await response.Content.ReadAsStreamAsync())
             {
                  using(Stream zip = FileManager.OpenWrite(ZIP_PATH))
                  {
                       stream.CopyTo(zip);
                  }
             }
        }
}
1

Expanding on Ruben's answer which uses HttpClient instead of WebClient, you can add as an extension method like this:

using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

public static class Extensions
{
    public static async Task DownloadFile (this HttpClient client, string address, string fileName) {
        using (var response = await client.GetAsync(address))
        using (var stream = await response.Content.ReadAsStreamAsync())
        using (var file = File.OpenWrite(fileName)) {
            stream.CopyTo(file);
        }
    }
}

And then use like this:

var archivePath = "https://api.github.com/repos/microsoft/winget-pkgs/zipball/";
using (var httpClient = new HttpClient())
{
    await httpClient.DownloadFile(archivePath, "./repo.zip");
}
KyleMit
  • 30,350
  • 66
  • 462
  • 664