When my .NET code returned a Task, it wasn't doing the expected outcome. Changing it to async/await, fixed...












1















I have some pretty stock standard code for a typical .NET Core 2+ program.cs. I'm mainly setting up Logging.



With the code below, it's not async/await and the following happens:




  • Logging occurs during the startup process 100%.

  • the CloseAndFlush(); occurs nearly instantly, before the rest of the app does stuff.

  • No logging occurs in any controllers.


This is in part due to how Serilog works but that's not really the important bit, AFAIK.



The code steps right over return CreateWebHostBuilder(args).Build().RunAsync(); .. when I thought this is the part where it would be awaited by the caller? When I debug my app, it does await (hang) on that line ... until the app has completed starting up. Once it's ready to accept connections, it then returns back here ... and runs through .. which means it calls Log.CloseAndFlush() and then return Task.CompletedTask.



Buggy Code:



public static Task Main(string args)
{
Log.Logger = new LoggerConfiguration()....CreateLogger();

try
{
// awaits here until the app has 100% started, then continues.
return CreateWebHostBuilder(args).Build().RunAsync();
}
catch (Exception exception)
{
Log.Logger.Fatal(exception, "Host terminated unexpectantly. Sadness :~(");
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
Log.CloseAndFlush();
}

return Task.CompletedTask;
}


Now changing this to async/await fixes everything. The code does correctly await on return CreateWebHostBuilder(args).Build().RunAsync(); .. and then the CloseAndFlush() is called when the app is closing/terminating.



    public static async Task Main<T>(string args) where T : class
{
Log.Logger = new LoggerConfiguration()....CreateLogger();

try
{
// Correctly waits here until the app explodes or ctrl-c has been pressed.
await CreateWebHostBuilder<T>(args).Build().RunAsync();
}
catch (Exception exception)
{
Log.Error(exception, "Stopped program because of an exception.");
}

Log.Debug("Finished shutting down app.");

// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
Log.CloseAndFlush();
}


Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?










share|improve this question























  • Generally speaking, yes, passing through a task only makes sense if your other method code doesn't depend on the outcome of the task which often will be the end of the method. However, you need to keep in mind that exceptions will only be raised when the task is awaited. Thus, if a task is passed through methods A and B, and only method C awaits, the exception stack trace will not contain A and B which might complicate debugging.

    – ckuri
    Nov 23 '18 at 8:18


















1















I have some pretty stock standard code for a typical .NET Core 2+ program.cs. I'm mainly setting up Logging.



With the code below, it's not async/await and the following happens:




  • Logging occurs during the startup process 100%.

  • the CloseAndFlush(); occurs nearly instantly, before the rest of the app does stuff.

  • No logging occurs in any controllers.


This is in part due to how Serilog works but that's not really the important bit, AFAIK.



The code steps right over return CreateWebHostBuilder(args).Build().RunAsync(); .. when I thought this is the part where it would be awaited by the caller? When I debug my app, it does await (hang) on that line ... until the app has completed starting up. Once it's ready to accept connections, it then returns back here ... and runs through .. which means it calls Log.CloseAndFlush() and then return Task.CompletedTask.



Buggy Code:



public static Task Main(string args)
{
Log.Logger = new LoggerConfiguration()....CreateLogger();

try
{
// awaits here until the app has 100% started, then continues.
return CreateWebHostBuilder(args).Build().RunAsync();
}
catch (Exception exception)
{
Log.Logger.Fatal(exception, "Host terminated unexpectantly. Sadness :~(");
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
Log.CloseAndFlush();
}

return Task.CompletedTask;
}


Now changing this to async/await fixes everything. The code does correctly await on return CreateWebHostBuilder(args).Build().RunAsync(); .. and then the CloseAndFlush() is called when the app is closing/terminating.



    public static async Task Main<T>(string args) where T : class
{
Log.Logger = new LoggerConfiguration()....CreateLogger();

try
{
// Correctly waits here until the app explodes or ctrl-c has been pressed.
await CreateWebHostBuilder<T>(args).Build().RunAsync();
}
catch (Exception exception)
{
Log.Error(exception, "Stopped program because of an exception.");
}

Log.Debug("Finished shutting down app.");

// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
Log.CloseAndFlush();
}


Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?










share|improve this question























  • Generally speaking, yes, passing through a task only makes sense if your other method code doesn't depend on the outcome of the task which often will be the end of the method. However, you need to keep in mind that exceptions will only be raised when the task is awaited. Thus, if a task is passed through methods A and B, and only method C awaits, the exception stack trace will not contain A and B which might complicate debugging.

    – ckuri
    Nov 23 '18 at 8:18
















1












1








1








I have some pretty stock standard code for a typical .NET Core 2+ program.cs. I'm mainly setting up Logging.



With the code below, it's not async/await and the following happens:




  • Logging occurs during the startup process 100%.

  • the CloseAndFlush(); occurs nearly instantly, before the rest of the app does stuff.

  • No logging occurs in any controllers.


This is in part due to how Serilog works but that's not really the important bit, AFAIK.



The code steps right over return CreateWebHostBuilder(args).Build().RunAsync(); .. when I thought this is the part where it would be awaited by the caller? When I debug my app, it does await (hang) on that line ... until the app has completed starting up. Once it's ready to accept connections, it then returns back here ... and runs through .. which means it calls Log.CloseAndFlush() and then return Task.CompletedTask.



Buggy Code:



public static Task Main(string args)
{
Log.Logger = new LoggerConfiguration()....CreateLogger();

try
{
// awaits here until the app has 100% started, then continues.
return CreateWebHostBuilder(args).Build().RunAsync();
}
catch (Exception exception)
{
Log.Logger.Fatal(exception, "Host terminated unexpectantly. Sadness :~(");
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
Log.CloseAndFlush();
}

return Task.CompletedTask;
}


Now changing this to async/await fixes everything. The code does correctly await on return CreateWebHostBuilder(args).Build().RunAsync(); .. and then the CloseAndFlush() is called when the app is closing/terminating.



    public static async Task Main<T>(string args) where T : class
{
Log.Logger = new LoggerConfiguration()....CreateLogger();

try
{
// Correctly waits here until the app explodes or ctrl-c has been pressed.
await CreateWebHostBuilder<T>(args).Build().RunAsync();
}
catch (Exception exception)
{
Log.Error(exception, "Stopped program because of an exception.");
}

Log.Debug("Finished shutting down app.");

// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
Log.CloseAndFlush();
}


Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?










share|improve this question














I have some pretty stock standard code for a typical .NET Core 2+ program.cs. I'm mainly setting up Logging.



With the code below, it's not async/await and the following happens:




  • Logging occurs during the startup process 100%.

  • the CloseAndFlush(); occurs nearly instantly, before the rest of the app does stuff.

  • No logging occurs in any controllers.


This is in part due to how Serilog works but that's not really the important bit, AFAIK.



The code steps right over return CreateWebHostBuilder(args).Build().RunAsync(); .. when I thought this is the part where it would be awaited by the caller? When I debug my app, it does await (hang) on that line ... until the app has completed starting up. Once it's ready to accept connections, it then returns back here ... and runs through .. which means it calls Log.CloseAndFlush() and then return Task.CompletedTask.



Buggy Code:



public static Task Main(string args)
{
Log.Logger = new LoggerConfiguration()....CreateLogger();

try
{
// awaits here until the app has 100% started, then continues.
return CreateWebHostBuilder(args).Build().RunAsync();
}
catch (Exception exception)
{
Log.Logger.Fatal(exception, "Host terminated unexpectantly. Sadness :~(");
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
Log.CloseAndFlush();
}

return Task.CompletedTask;
}


Now changing this to async/await fixes everything. The code does correctly await on return CreateWebHostBuilder(args).Build().RunAsync(); .. and then the CloseAndFlush() is called when the app is closing/terminating.



    public static async Task Main<T>(string args) where T : class
{
Log.Logger = new LoggerConfiguration()....CreateLogger();

try
{
// Correctly waits here until the app explodes or ctrl-c has been pressed.
await CreateWebHostBuilder<T>(args).Build().RunAsync();
}
catch (Exception exception)
{
Log.Error(exception, "Stopped program because of an exception.");
}

Log.Debug("Finished shutting down app.");

// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
Log.CloseAndFlush();
}


Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?







c# .net asynchronous async-await






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 23 '18 at 8:08









Pure.KromePure.Krome

44.9k90317522




44.9k90317522













  • Generally speaking, yes, passing through a task only makes sense if your other method code doesn't depend on the outcome of the task which often will be the end of the method. However, you need to keep in mind that exceptions will only be raised when the task is awaited. Thus, if a task is passed through methods A and B, and only method C awaits, the exception stack trace will not contain A and B which might complicate debugging.

    – ckuri
    Nov 23 '18 at 8:18





















  • Generally speaking, yes, passing through a task only makes sense if your other method code doesn't depend on the outcome of the task which often will be the end of the method. However, you need to keep in mind that exceptions will only be raised when the task is awaited. Thus, if a task is passed through methods A and B, and only method C awaits, the exception stack trace will not contain A and B which might complicate debugging.

    – ckuri
    Nov 23 '18 at 8:18



















Generally speaking, yes, passing through a task only makes sense if your other method code doesn't depend on the outcome of the task which often will be the end of the method. However, you need to keep in mind that exceptions will only be raised when the task is awaited. Thus, if a task is passed through methods A and B, and only method C awaits, the exception stack trace will not contain A and B which might complicate debugging.

– ckuri
Nov 23 '18 at 8:18







Generally speaking, yes, passing through a task only makes sense if your other method code doesn't depend on the outcome of the task which often will be the end of the method. However, you need to keep in mind that exceptions will only be raised when the task is awaited. Thus, if a task is passed through methods A and B, and only method C awaits, the exception stack trace will not contain A and B which might complicate debugging.

– ckuri
Nov 23 '18 at 8:18














2 Answers
2






active

oldest

votes


















2














Returning a Task1 instead of awaiting it is your way of saying "there's nothing left for this method to do here"2.



If that's not the case (as here, where you don't want your finally clause to run yet), you're not done. You need some way of running some code at a later point in time, but you've got nothing useful to do now. And that's precisely what await allows you to signal.





1As Jonas mentions, this is exactly true for non-Task returns too.



2I'm ignoring the case when you take a Task from elsewhere, add a ContinueWith and return the resulting Task, because there you're using a different mechanism to ensure you get to run code later and it's not precisely "this method" that runs in the continuation.






share|improve this answer































    2















    Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?




    Basically, yes. Returning the task as in your first snippet will let the finally block run as you leave the scope, just like any other return statement inside a try with an associated finally. And as commented by ckuri your catch block won't do what you want either, as it will not catch exceptions from the task, only from the setup in CreateWebHostBuilder itself.






    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53442791%2fwhen-my-net-code-returned-a-task-it-wasnt-doing-the-expected-outcome-changin%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2














      Returning a Task1 instead of awaiting it is your way of saying "there's nothing left for this method to do here"2.



      If that's not the case (as here, where you don't want your finally clause to run yet), you're not done. You need some way of running some code at a later point in time, but you've got nothing useful to do now. And that's precisely what await allows you to signal.





      1As Jonas mentions, this is exactly true for non-Task returns too.



      2I'm ignoring the case when you take a Task from elsewhere, add a ContinueWith and return the resulting Task, because there you're using a different mechanism to ensure you get to run code later and it's not precisely "this method" that runs in the continuation.






      share|improve this answer




























        2














        Returning a Task1 instead of awaiting it is your way of saying "there's nothing left for this method to do here"2.



        If that's not the case (as here, where you don't want your finally clause to run yet), you're not done. You need some way of running some code at a later point in time, but you've got nothing useful to do now. And that's precisely what await allows you to signal.





        1As Jonas mentions, this is exactly true for non-Task returns too.



        2I'm ignoring the case when you take a Task from elsewhere, add a ContinueWith and return the resulting Task, because there you're using a different mechanism to ensure you get to run code later and it's not precisely "this method" that runs in the continuation.






        share|improve this answer


























          2












          2








          2







          Returning a Task1 instead of awaiting it is your way of saying "there's nothing left for this method to do here"2.



          If that's not the case (as here, where you don't want your finally clause to run yet), you're not done. You need some way of running some code at a later point in time, but you've got nothing useful to do now. And that's precisely what await allows you to signal.





          1As Jonas mentions, this is exactly true for non-Task returns too.



          2I'm ignoring the case when you take a Task from elsewhere, add a ContinueWith and return the resulting Task, because there you're using a different mechanism to ensure you get to run code later and it's not precisely "this method" that runs in the continuation.






          share|improve this answer













          Returning a Task1 instead of awaiting it is your way of saying "there's nothing left for this method to do here"2.



          If that's not the case (as here, where you don't want your finally clause to run yet), you're not done. You need some way of running some code at a later point in time, but you've got nothing useful to do now. And that's precisely what await allows you to signal.





          1As Jonas mentions, this is exactly true for non-Task returns too.



          2I'm ignoring the case when you take a Task from elsewhere, add a ContinueWith and return the resulting Task, because there you're using a different mechanism to ensure you get to run code later and it's not precisely "this method" that runs in the continuation.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 23 '18 at 8:23









          Damien_The_UnbelieverDamien_The_Unbeliever

          195k17248335




          195k17248335

























              2















              Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?




              Basically, yes. Returning the task as in your first snippet will let the finally block run as you leave the scope, just like any other return statement inside a try with an associated finally. And as commented by ckuri your catch block won't do what you want either, as it will not catch exceptions from the task, only from the setup in CreateWebHostBuilder itself.






              share|improve this answer




























                2















                Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?




                Basically, yes. Returning the task as in your first snippet will let the finally block run as you leave the scope, just like any other return statement inside a try with an associated finally. And as commented by ckuri your catch block won't do what you want either, as it will not catch exceptions from the task, only from the setup in CreateWebHostBuilder itself.






                share|improve this answer


























                  2












                  2








                  2








                  Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?




                  Basically, yes. Returning the task as in your first snippet will let the finally block run as you leave the scope, just like any other return statement inside a try with an associated finally. And as commented by ckuri your catch block won't do what you want either, as it will not catch exceptions from the task, only from the setup in CreateWebHostBuilder itself.






                  share|improve this answer














                  Would returning a Task probably be only suitable if the method is only doing one async/await in it AND that is the last thing in the method?




                  Basically, yes. Returning the task as in your first snippet will let the finally block run as you leave the scope, just like any other return statement inside a try with an associated finally. And as commented by ckuri your catch block won't do what you want either, as it will not catch exceptions from the task, only from the setup in CreateWebHostBuilder itself.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 23 '18 at 8:20









                  Jonas HøghJonas Høgh

                  7,21311737




                  7,21311737






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53442791%2fwhen-my-net-code-returned-a-task-it-wasnt-doing-the-expected-outcome-changin%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Costa Masnaga

                      Fotorealismo

                      Sidney Franklin