-2

This might be answered somewhere but want to understand the detailed execution for this scenario. Today, I came across MVC action(synchronous) method which is calling an asynchronous method. I don't want this execution to wait synchronously or asynchronously. So, I haven't used the await keyword or wait method. But the outcome has surprised me a lot. Async method got executed some portion and some just skipped the execution. I have reproduced the same scenario and which is also behaving the same. Now, I got the execution but want to understand why this async and method behaving random execution inside the synchronous method. I have pasted the code snippet and output this code.

    internal async Task<int> Method1Async()
    {
        //await Task.Delay(1000);
        Console.WriteLine("Inside Method 1 : Before Calling await");
        await Task.FromResult(5);
        //await Task.Delay(1000);
        Console.WriteLine("Inside Method 1 : After Calling await");
        return await Task.FromResult(1);
    }

    internal async Task<int> Method2Async()
    {
        //await Task.Delay(1000);
        Console.WriteLine("Inside Method 2 : Before Calling await");
        var res = await Method1Async();
        await Task.Delay(1000);
        Console.WriteLine("Inside Method 2 : After Calling await");
        return res;
    }

    internal async Task<int> Method3Async()
    {
        //await Task.Delay(1000);
        Console.WriteLine("Inside Method 3 : Before Calling await");
        var res = await Method2Async();
        await Task.Delay(1000);
        Console.WriteLine("Inside Method 3 : After Calling await");
        return res;
    }

    internal void Method4()
    {
        Method3Async();
    }

    public static void Main()
    {
        Console.WriteLine("Inside Main : Before calling Method4");
        var demo =  new Demo();
        demo.Method4();
        Console.WriteLine("Inside Main : After calling Method4");
    }

enter image description here

Ravindra Sinare
  • 675
  • 1
  • 9
  • 25
  • @mjwills Console.Writeline statements from Method 2 and 3 did not executed. – Ravindra Sinare Jul 17 '21 at 13:49
  • Somewhere I feel CLR should be responsible to execute these remaining portion of code. – Ravindra Sinare Jul 17 '21 at 13:52
  • 2
    You reached the end of your `Main` method. The program closed - it _stopped running_. You want to _not_ wait for the async code to execute, but you also want the console to be written to. You can't have both. Pick one. – mjwills Jul 17 '21 at 13:53
  • There _was_ a warning in the IDE. You ignored it. `CS4014 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.`. – mjwills Jul 17 '21 at 13:58
  • 1
    If you missed I came across this in web app only and then tried to reproduce it in console app. – Ravindra Sinare Jul 17 '21 at 14:08
  • 1
    I have checked this answer and this all looks like console app and feel reasonable but what for web app? – Ravindra Sinare Jul 17 '21 at 14:21

1 Answers1

2

I don't want this execution to wait synchronously or asynchronously. So, I haven't used the await keyword or wait method.

"Fire and forget" on ASP.NET is dangerous, as you have discovered.

Technically, "fire and forget" means "forget". If you fire off a task without waiting synchronously or asynchronously, then your code is explicitly saying it doesn't care when that task completes, or how it completes, or if it completes.

Async method got executed some portion and some just skipped the execution... Now, I got the execution but want to understand why this async and method behaving random execution inside the synchronous method.

The bottom line is that shutdowns are normal. If you send a response to an HTTP request, then as far as ASP.NET knows, that request has been handled; and if there are no other requests, then it is safe to shut down. Fire-and-forget code is request-extrinsic (outside the scope of an HTTP request), so ASP.NET isn't even aware that that code exists.

I feel CLR should be responsible to execute these remaining portion of code.

Nope. The CLR can't do this because that would prevent some use cases regarding Task.WhenAny.

If you need to return early, the proper solution is:

  1. Add a durable queue to your architecture. E.g., an Azure Queue.
  2. Add a separate background processor to your architecture. E.g., an Azure Function.

Then, when your ASP.NET app wants to return early, it should serialize the work it needs to do into a message and write that to the durable queue, and then return. The separate background processor should read messages from the queue and do the actual work.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • I agree with whatever you explained and thanks for the clarification. Somehow still not convinced with warning message. I feel it should have been updated. – Ravindra Sinare Jul 17 '21 at 14:57
  • `I feel it should have been updated` How would you have updated it? It specifically tells you the issue and how to avoid it. – mjwills Jul 18 '21 at 00:08