1

I have tried to load a web page into my program using Get web page using HtmlAgilityPack.NETCore . The problem is that debugging jumps directly off the first Using statement, so the code and the second using are not called at all. No Exception or something else is thrown. Program ends with exit code 0 What am I doing wrong? I am working with .net Core 2.2

HttpClient client = new HttpClient();
List<string> htmlContent = new List<string>();
using (var response = await client.GetAsync(URL))
{
    using (var content = response.Content)
    {
        var result = await content.ReadAsStringAsync();
        var document = new HtmlDocument();
        document.LoadHtml(result);
        foreach (HtmlNode node in document.DocumentNode.SelectNodes("//text()"))
        {
            htmlContent.Add(node.InnerText);
        }
    }
}
H H
  • 263,252
  • 30
  • 330
  • 514
Florian Falk
  • 214
  • 4
  • 17
  • 1
    *"debugging jumps directly off the first Using statement"* - It's not clear what you mean by that. Is an exception thrown? Something else? – David May 01 '19 at 18:36
  • @David no. Nothing happens. No exception, nothing. It just runs to the end until exit code 0. – Florian Falk May 01 '19 at 18:43
  • @EdPlunkett what do you mean? ARM. Or not? – Florian Falk May 01 '19 at 18:44
  • @EdPlunkett yes. maybe your question was a little imprecise ;) . As I said. ARM (Automatic Resource Management) – Florian Falk May 01 '19 at 18:48
  • 5
    Is your Main method also async? Seems to me like what you are seeing is the normal early return from async/await (the whole point of async is so the thread can do something else while waiting, and from the viewpoint of synchronous code that looks like an early return) and then your app is not waiting for the asynchronous operation to complete before exiting. – Tadmas May 01 '19 at 18:51
  • I'd put a breakpoint between the first and the second using and if its not hit, try surrounding everything with a try catch :) – Jannik May 01 '19 at 18:54
  • use the "sync" answer in the linked question if you don't have something to make your app wait for the async code to finish: https://stackoverflow.com/a/43368205/674326 – Brandon May 01 '19 at 18:54
  • @EdPlunkett I have learned that "using" in C# is the same as ARM in Java. So the object that is created in the round brackets of using is closed automatically after the usingblock is closed. Like e.g. a scanner. – Florian Falk May 01 '19 at 18:55
  • @Tadmas yeah. That's was a good tip! Asynchronous programming is still completely new for me. I haven't found the right "must know" on google yet. – Florian Falk May 01 '19 at 19:05
  • @FlorianFalk Ahhh, Java. Anyhow, I had forgotten that Task implements IDisposable, so never mind all that. – 15ee8f99-57ff-4f92-890c-b56153 May 01 '19 at 19:08
  • @FlorianFalk It sound like you could be debugging with compiler optimizations on – johnny 5 May 01 '19 at 19:34
  • 3
    @EdPlunkett: That's relevant though, but in an odd way. Normally the practice is to always wrap a disposable with a using, but in the case of Task, the opposite is true. Read Stephen Toub's great article on this: https://devblogs.microsoft.com/pfxteam/do-i-need-to-dispose-of-tasks/ – Eric Lippert May 01 '19 at 19:43
  • 2
    @FlorianFalk: As noted in the previous comment, remove the `using` from the task creation. That's unlikely to be the source of your problem though. Can you say what the *caller* of the method containing the code fragment you've created does with the task that the method returns, if any? What's the signature of the method? – Eric Lippert May 01 '19 at 19:45

1 Answers1

6

Program ends with exit code 0

Two rules when first learning async:

  1. Avoid async void; use async Task instead.
  2. await all your tasks. So if you call a method that returns a Task, be sure to await it.

As you grow in async, both of these rules can be bent somewhat. But it's a lot easier to learn async by following the rules above.

So, the code you posted should be in an async Task method. The calling method should await that task, and in turn is an async Task method, etc. All the way back to Main, which should be an async Task Main method. Note that this is a C# 7.1 language feature, so if you created this project using VS2017 instead of VS2019, you will need to set the language version, e.g., to latest.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thank you for the explanation! During my research yesterday I read that you should use async with void only if you need events. As @Tadmas said in the upper comment, and you also said, the main method must be async too. However, I have found code examples where this is not the case and async is used. As far as I understand, this works as long as the asynchronous task is finished before the main is finished. But depending on the todos of this task, I can only estimate it badly. Can you then say as a rule of thumb that as soon as you work with asynchronc, the main should also be asychronous? – Florian Falk May 02 '19 at 06:35
  • 1
    "Can you then say as a rule of thumb that as soon as you work with asynchronc, the main should also be asychronous?" Yes. – Stephen Cleary May 02 '19 at 09:35