0

My workflow: Constructor -> Calls async Method 1 -> Calls async Method 2 -> Calls async Method 3

Constructor:

public MyConstructor() {
    Method1();
}

Method1:

private async void Method1() {
    //do some stuff
    await Method2();
    //do some more stuff
}

Method 2:

protected internal async Task Method2() {
    //do some stuff
    var x = await Method3("someParams");
    //do some more stuff
}

Method 3:

public async Task<List<string>> Method3(string someParams) {
    Debug.WriteLine("I am here"); //Breakpoint doesn't get hit, no output "I am here"
}

Yeah I know, you probably wonder why I am using so many different async methods.. But there is some more stuff going on (but nothing that influences the problem!). The problem is, Debug.WriteLine("I am here"); does not get hit, and no exception is thrown.

What am I doing wrong?

Ben
  • 76
  • 2
  • 8
  • Doesn't get hit as in you've put a breakpoint and it's not hit, or not hit as you don't see output from `Debug.WriteLine`? – Brandon Oct 17 '16 at 13:39
  • Both.. Breakpoint does not get hitted, and I also dont see any output.. – hans meyer Oct 17 '16 at 13:39
  • 1
    Tested this code and its working for me, probably your problem somewhere else – tym32167 Oct 17 '16 at 13:41
  • 2
    You are not awaiting your call of `Method1`, so maybe the execution stops before `Method3` gets called. – fknx Oct 17 '16 at 13:42
  • Do you see `Method1` and `Method2` get hit? – Brandon Oct 17 '16 at 13:42
  • @fknx Makes a good point. If this is a console app or there's no other thread running, it's possible that the app terminates before it can get to `Method3` – Brandon Oct 17 '16 at 13:43
  • @fknx yeah, maybe.. But I cant use async await in a constructor.. Brandon: yeah, I also added a breakpoint in Method2 (var x = await...) and it it gets executed. But the things below var x = await Method3(...) don't get executed – hans meyer Oct 17 '16 at 13:45
  • 1
    True, you can't use `async await` in the constructor. See [this](http://stackoverflow.com/questions/23048285/call-asynchronous-method-in-constructor) for possible workarounds. It links to this [blog post](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html) which introduces a factory pattern that might be useful. – fknx Oct 17 '16 at 13:51
  • @Fabio any idea how to debug this? – hans meyer Oct 17 '16 at 13:52
  • 6
    @hansmeyer: Every `async` method *begins* executing synchronously. The code you posted does not have any actual asynchronous work, so it will always synchronously print the debug line. Try to develop a minimal, complete, reproducible example and then post it (as it currently stands, the problem is not reproducible). – Stephen Cleary Oct 17 '16 at 13:59
  • You declare Method 3 async, so I assume there is an await above the Debug.WriteLine() that you are not showing. In which case - as Stephen says - all the initial sync parts of all your methods are executing, but on the await I refer to execution returns all the way back up to your constructor, which exits. The Debug.WriteLine() will eventually execute, but I'm guessing that in the scope you're in (perhaps a unit-test or console app that exits at that point), it is not seen. – sellotape Oct 17 '16 at 15:06
  • [Avoid async void](https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void). – Theodor Zoulias May 22 '20 at 16:46

1 Answers1

1

In a nutshell: yes, as @fknx mentioned in a comment, the problem is that the code executes asynchronously and is not awaited, therefore the app exits before reaching the line in question.

There are a couple of bad practices in your example:

async void method

It is not a good idea to create such things as you loose track of the task. Please always define Task as the return value, it does not cost anything and it will help you write a correct API.

asynchronous call in a constructor

This is not a good design either, because (as you mentioned) you cannot await this method in a constructor so you will just fire up the task and loose it. Please consider using an async Init method instead.

So instead of this:

public class MyCustomClass
{
    public MyCustomClass()
    {
        // BAD CODE, do not do this
        Method1();
    }

    private async Task Method1()
    {
        //do some stuff
        await Method2();
        //do some more stuff
    }
}

You could do this:

class Program
{
    static void Main(string[] args)
    {
        var m = new MyCustomClass();

        m.InitializeAsync().Wait();

        Console.WriteLine("Before exit...");
    }
}

public class MyCustomClass
{
    public MyCustomClass()
    {
        // in a constructor you should not do anything async
    }

    public async Task InitializeAsync()
    {
        await Method1();
    }

    private async Task Method1()
    {
        //do some stuff
        await Method2();
        //do some more stuff
    }
}

It is absolutely OK to Wait for an async method in the Main method, or to be precise your console app should have only one Wait (or WaitAll, or whatever) method in the main method (and nowhere else) if you want to create a truly async app.

Community
  • 1
  • 1
Miklós Tóth
  • 1,460
  • 11
  • 19