Entwickler-Ecke

ASP.NET und Web - Webclient DownloadFileCompleted wird nicht aufgerufen


Sharpener - So 25.08.13 14:59
Titel: Webclient DownloadFileCompleted wird nicht aufgerufen
Hallo,
ich will einen HTML Parser programmieren. Dazu soll zuerst eine HTML Seite aus dem Netz geladen werden. Eigentlich eine simple Aufgabe aber das System soll warten bis die Seite wirklich ganz geladen ist, um Fehler zu vermeiden.
So sieht die vorläufige Methode aus:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
class Downloader
    {
        Boolean fertig = false;
        public void downloadFile(String address)
        {
            string pfad = @"c:\Greyhound";
            if(!Directory.Exists(pfad))
            {
                Directory.CreateDirectory(pfad);
            }
            WebClient down = new WebClient();
            down.DownloadFileCompleted += (sender, e) =>
                {
                    if (e.Error == null)
                    {
                        doSomeThing();
                    }
                };
            down.DownloadFileAsync(new Uri(address), @"c:\Greyhound\page.html");
        }
        public void doSomeThing()
        {
            MessageBox.Show("FERTIG");
        }

Und Aufgerufen wird die Methode von hier:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
public partial class MainWindow : Form
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void GoButton_Click(object sender, EventArgs e)
        {
            Downloader down = new Downloader();
            down.downloadFile(Convert.ToString(AddressBox.Text));
        }

    }

Ich bin schon im Debugger das Programm durchgegangen finde meinen Fehler aber nicht. Das Programm läuft durch... es downloaded die Seite komplett. Aber die (vorläufige) Messagebox wird nicht angezeigt.
Wo liegt der Fehler? Ich habe jetzt gefühlte Tage darüber geguckt und den Fehler nicht gefunden.


Christian S. - So 25.08.13 15:48

Ich bin gerade nicht sicher, ob die Instanz down nach dem Ende der Methode noch lange genug lebt, um das Event aufzurufen. Aber benutz' doch die neuen Async-Features von C# :-)


C#-Quelltext
1:
2:
3:
4:
5:
6:
        private async void button1_Click(object sender, EventArgs e)
        {
            var wc = new WebClient();
            string data = await wc.DownloadStringTaskAsync("http://www.entwickler-ecke.de");
            textBox1.Text = data;
        }


Sharpener - So 25.08.13 17:21

Stellt also...

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
public async void downloadFile(String address)
        {
            string pfad = @"c:\Greyhound";
            if(!Directory.Exists(pfad))
            {
                Directory.CreateDirectory(pfad);
            }
            WebClient down = new WebClient();
            await down.DownloadFileTaskAsync(new Uri(address), @"c:\Greyhound\page.html");
        }

...sicher, dass die Methode erst dann abschließt wenn der Download fertig ist? Hatte noch nicht viel mit async zu tun.


Christian S. - So 25.08.13 20:51

Ja, wenn Du die Methode mit await aufrufst.

Was bei Verwendung von await passiert: Die Methode, die mit await aufgerufen wird, wird in einem separaten Thread (als Task) aufgerufen. Damit bleibt zum Beispiel die GUI reaktionsfähig, weil der Hauptthread nicht blockiert ist. Wenn also bei Deinem Quelltext Zeile 9 erreicht ist, wird das Herunterladen gestartet und die Methode erst einmal verlassen. Sobald dies fertig ist, wird wieder in die Methode gesprungen und der Rest (bei Dir: nichts) abgearbeitet.

Wenn Du Deine Methode mit await aufrufst, wird ebenso verfahren. Deine Methode wird in einem separeten Thread abgearbeitet und alles, was danach kommt, wartet ohne zu blockieren.