Use of Async/Await for EventHandlers












9














I have a MVC WinForms application. I am using Dependency Injection with Ninject as the IoC container.



public class SqlObjectExplorerController : ToolController, ISqlObjectExplorerController
{
private ISqlObjectExplorerView view = null;
private SqlServerStructureProvider structureProvider;
private IProgress<IProgressInfo> progress;

public SqlObjectExplorerController(ISqlObjectExplorerView view)
{
if (view == null)
throw new ArgumentNullException("view");

this.view = view;
InitializeEventHandlers();
...
}

private void InitializeEventHandlers()
{
(view as ToolView).Initialize += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
view.OnAddServerInstanceClicked += new EventHandler(async (s, e) => await AddServerInstanceAsync());
view.OnNewSqlQueryClicked += new EventHandler<NewSqlQueryRequestEventArgs>((s, e) => OpenNewSqlQueryDocument(e));
view.OnExpandRequested += new EventHandler<BeforeExpandEventArgs>((s, e) => BuildSubStructureForDatabaseNode(e));
}

private async Task RefreshObjectExplorerAsync()
{
await InitializeObjectExplorerAsync();
view.InitializeObjectExplorer(ServerCache);
}

... // Lots more code.


My question concerns the use of async/await in setting up the likes of += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());. There are some tasks I need to do on a background thread, so I am using async/await, my questions are about my understanding:




  1. In doing async (s, e) => await SomeMethodAsync() I am merely setting up an event handler equivalent to private async void SomeMethodAsync(object s, EventArgs e) { ... }. Which I think is fine in this case of the fire-and-forget Task I want to undertake, is it?


  2. I don't think there are any problems in setting this up these async handlers in the ctor of the controller, am I right?



The code seems to work fine, but is there something I am not seeing?










share|improve this question



























    9














    I have a MVC WinForms application. I am using Dependency Injection with Ninject as the IoC container.



    public class SqlObjectExplorerController : ToolController, ISqlObjectExplorerController
    {
    private ISqlObjectExplorerView view = null;
    private SqlServerStructureProvider structureProvider;
    private IProgress<IProgressInfo> progress;

    public SqlObjectExplorerController(ISqlObjectExplorerView view)
    {
    if (view == null)
    throw new ArgumentNullException("view");

    this.view = view;
    InitializeEventHandlers();
    ...
    }

    private void InitializeEventHandlers()
    {
    (view as ToolView).Initialize += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
    view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
    view.OnAddServerInstanceClicked += new EventHandler(async (s, e) => await AddServerInstanceAsync());
    view.OnNewSqlQueryClicked += new EventHandler<NewSqlQueryRequestEventArgs>((s, e) => OpenNewSqlQueryDocument(e));
    view.OnExpandRequested += new EventHandler<BeforeExpandEventArgs>((s, e) => BuildSubStructureForDatabaseNode(e));
    }

    private async Task RefreshObjectExplorerAsync()
    {
    await InitializeObjectExplorerAsync();
    view.InitializeObjectExplorer(ServerCache);
    }

    ... // Lots more code.


    My question concerns the use of async/await in setting up the likes of += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());. There are some tasks I need to do on a background thread, so I am using async/await, my questions are about my understanding:




    1. In doing async (s, e) => await SomeMethodAsync() I am merely setting up an event handler equivalent to private async void SomeMethodAsync(object s, EventArgs e) { ... }. Which I think is fine in this case of the fire-and-forget Task I want to undertake, is it?


    2. I don't think there are any problems in setting this up these async handlers in the ctor of the controller, am I right?



    The code seems to work fine, but is there something I am not seeing?










    share|improve this question

























      9












      9








      9







      I have a MVC WinForms application. I am using Dependency Injection with Ninject as the IoC container.



      public class SqlObjectExplorerController : ToolController, ISqlObjectExplorerController
      {
      private ISqlObjectExplorerView view = null;
      private SqlServerStructureProvider structureProvider;
      private IProgress<IProgressInfo> progress;

      public SqlObjectExplorerController(ISqlObjectExplorerView view)
      {
      if (view == null)
      throw new ArgumentNullException("view");

      this.view = view;
      InitializeEventHandlers();
      ...
      }

      private void InitializeEventHandlers()
      {
      (view as ToolView).Initialize += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
      view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
      view.OnAddServerInstanceClicked += new EventHandler(async (s, e) => await AddServerInstanceAsync());
      view.OnNewSqlQueryClicked += new EventHandler<NewSqlQueryRequestEventArgs>((s, e) => OpenNewSqlQueryDocument(e));
      view.OnExpandRequested += new EventHandler<BeforeExpandEventArgs>((s, e) => BuildSubStructureForDatabaseNode(e));
      }

      private async Task RefreshObjectExplorerAsync()
      {
      await InitializeObjectExplorerAsync();
      view.InitializeObjectExplorer(ServerCache);
      }

      ... // Lots more code.


      My question concerns the use of async/await in setting up the likes of += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());. There are some tasks I need to do on a background thread, so I am using async/await, my questions are about my understanding:




      1. In doing async (s, e) => await SomeMethodAsync() I am merely setting up an event handler equivalent to private async void SomeMethodAsync(object s, EventArgs e) { ... }. Which I think is fine in this case of the fire-and-forget Task I want to undertake, is it?


      2. I don't think there are any problems in setting this up these async handlers in the ctor of the controller, am I right?



      The code seems to work fine, but is there something I am not seeing?










      share|improve this question













      I have a MVC WinForms application. I am using Dependency Injection with Ninject as the IoC container.



      public class SqlObjectExplorerController : ToolController, ISqlObjectExplorerController
      {
      private ISqlObjectExplorerView view = null;
      private SqlServerStructureProvider structureProvider;
      private IProgress<IProgressInfo> progress;

      public SqlObjectExplorerController(ISqlObjectExplorerView view)
      {
      if (view == null)
      throw new ArgumentNullException("view");

      this.view = view;
      InitializeEventHandlers();
      ...
      }

      private void InitializeEventHandlers()
      {
      (view as ToolView).Initialize += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
      view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
      view.OnAddServerInstanceClicked += new EventHandler(async (s, e) => await AddServerInstanceAsync());
      view.OnNewSqlQueryClicked += new EventHandler<NewSqlQueryRequestEventArgs>((s, e) => OpenNewSqlQueryDocument(e));
      view.OnExpandRequested += new EventHandler<BeforeExpandEventArgs>((s, e) => BuildSubStructureForDatabaseNode(e));
      }

      private async Task RefreshObjectExplorerAsync()
      {
      await InitializeObjectExplorerAsync();
      view.InitializeObjectExplorer(ServerCache);
      }

      ... // Lots more code.


      My question concerns the use of async/await in setting up the likes of += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());. There are some tasks I need to do on a background thread, so I am using async/await, my questions are about my understanding:




      1. In doing async (s, e) => await SomeMethodAsync() I am merely setting up an event handler equivalent to private async void SomeMethodAsync(object s, EventArgs e) { ... }. Which I think is fine in this case of the fire-and-forget Task I want to undertake, is it?


      2. I don't think there are any problems in setting this up these async handlers in the ctor of the controller, am I right?



      The code seems to work fine, but is there something I am not seeing?







      c# event-handling winforms async-await






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jun 30 '16 at 10:18









      MoonKnight

      3421614




      3421614






















          2 Answers
          2






          active

          oldest

          votes


















          9














          The things to consider when it comes to async event handlers are:




          • Exceptions thrown for the handler might be rethrown on the UI SynchronizationContext, which usually crashes the application.

          • After you raise the event, the handlers won't be completed yet. The execution of a handler might be interleaved with the execution of the code after the raising and execution of multiple handlers can also be interleaved with each other.


          Assuming those caveats are acceptable for you, code like this should be fine.





          Also:



          view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());


          You should be able to simplify this to just:



          view.OnRefreshObjectExplorerClicked += async (s, e) => await RefreshObjectExplorerAsync();




          It seems you never unsubscribe the event handlers, are you sure that's okay?






          share|improve this answer























          • How do you unsubscribe from such an event handler? It's showing the warning Event unsubscription via anonymous delegate
            – Stephan
            Sep 27 '18 at 21:01










          • @Stephan Either you use a regular method instead of a lambda to both subscribe and unsubscribe or you store the delegate that represents the lambda in a variable and use that to subscribe and unsubscribe.
            – svick
            Sep 27 '18 at 21:47





















          0














          Here's one more way that worked for me using a method overload:



              public void StartWindowsService()
          {
          var interval = TimeSpan.FromSeconds(2).TotalMilliseconds;
          _someTimer = new Timer
          {
          Interval = interval,
          Enabled = true
          };
          _someTimer.Elapsed += OnTimedEvent;
          _someTimer.Start();
          }

          private void OnTimedEvent(object sender, ElapsedEventArgs e)
          {
          MyAsyncMethod().Wait();
          }

          private async Task MyAsyncMethod()
          {
          // do async stuff here . . .
          }





          share|improve this answer








          New contributor




          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.


















          • so is this code better because it requires fewer lines? if not, please edit and explain how this approach is better
            – Sᴀᴍ Onᴇᴌᴀ
            1 min ago











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          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: "196"
          };
          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: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          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%2fcodereview.stackexchange.com%2fquestions%2f133464%2fuse-of-async-await-for-eventhandlers%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









          9














          The things to consider when it comes to async event handlers are:




          • Exceptions thrown for the handler might be rethrown on the UI SynchronizationContext, which usually crashes the application.

          • After you raise the event, the handlers won't be completed yet. The execution of a handler might be interleaved with the execution of the code after the raising and execution of multiple handlers can also be interleaved with each other.


          Assuming those caveats are acceptable for you, code like this should be fine.





          Also:



          view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());


          You should be able to simplify this to just:



          view.OnRefreshObjectExplorerClicked += async (s, e) => await RefreshObjectExplorerAsync();




          It seems you never unsubscribe the event handlers, are you sure that's okay?






          share|improve this answer























          • How do you unsubscribe from such an event handler? It's showing the warning Event unsubscription via anonymous delegate
            – Stephan
            Sep 27 '18 at 21:01










          • @Stephan Either you use a regular method instead of a lambda to both subscribe and unsubscribe or you store the delegate that represents the lambda in a variable and use that to subscribe and unsubscribe.
            – svick
            Sep 27 '18 at 21:47


















          9














          The things to consider when it comes to async event handlers are:




          • Exceptions thrown for the handler might be rethrown on the UI SynchronizationContext, which usually crashes the application.

          • After you raise the event, the handlers won't be completed yet. The execution of a handler might be interleaved with the execution of the code after the raising and execution of multiple handlers can also be interleaved with each other.


          Assuming those caveats are acceptable for you, code like this should be fine.





          Also:



          view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());


          You should be able to simplify this to just:



          view.OnRefreshObjectExplorerClicked += async (s, e) => await RefreshObjectExplorerAsync();




          It seems you never unsubscribe the event handlers, are you sure that's okay?






          share|improve this answer























          • How do you unsubscribe from such an event handler? It's showing the warning Event unsubscription via anonymous delegate
            – Stephan
            Sep 27 '18 at 21:01










          • @Stephan Either you use a regular method instead of a lambda to both subscribe and unsubscribe or you store the delegate that represents the lambda in a variable and use that to subscribe and unsubscribe.
            – svick
            Sep 27 '18 at 21:47
















          9












          9








          9






          The things to consider when it comes to async event handlers are:




          • Exceptions thrown for the handler might be rethrown on the UI SynchronizationContext, which usually crashes the application.

          • After you raise the event, the handlers won't be completed yet. The execution of a handler might be interleaved with the execution of the code after the raising and execution of multiple handlers can also be interleaved with each other.


          Assuming those caveats are acceptable for you, code like this should be fine.





          Also:



          view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());


          You should be able to simplify this to just:



          view.OnRefreshObjectExplorerClicked += async (s, e) => await RefreshObjectExplorerAsync();




          It seems you never unsubscribe the event handlers, are you sure that's okay?






          share|improve this answer














          The things to consider when it comes to async event handlers are:




          • Exceptions thrown for the handler might be rethrown on the UI SynchronizationContext, which usually crashes the application.

          • After you raise the event, the handlers won't be completed yet. The execution of a handler might be interleaved with the execution of the code after the raising and execution of multiple handlers can also be interleaved with each other.


          Assuming those caveats are acceptable for you, code like this should be fine.





          Also:



          view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());


          You should be able to simplify this to just:



          view.OnRefreshObjectExplorerClicked += async (s, e) => await RefreshObjectExplorerAsync();




          It seems you never unsubscribe the event handlers, are you sure that's okay?







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Aug 5 '16 at 12:31

























          answered Jul 17 '16 at 21:33









          svick

          22.7k43778




          22.7k43778












          • How do you unsubscribe from such an event handler? It's showing the warning Event unsubscription via anonymous delegate
            – Stephan
            Sep 27 '18 at 21:01










          • @Stephan Either you use a regular method instead of a lambda to both subscribe and unsubscribe or you store the delegate that represents the lambda in a variable and use that to subscribe and unsubscribe.
            – svick
            Sep 27 '18 at 21:47




















          • How do you unsubscribe from such an event handler? It's showing the warning Event unsubscription via anonymous delegate
            – Stephan
            Sep 27 '18 at 21:01










          • @Stephan Either you use a regular method instead of a lambda to both subscribe and unsubscribe or you store the delegate that represents the lambda in a variable and use that to subscribe and unsubscribe.
            – svick
            Sep 27 '18 at 21:47


















          How do you unsubscribe from such an event handler? It's showing the warning Event unsubscription via anonymous delegate
          – Stephan
          Sep 27 '18 at 21:01




          How do you unsubscribe from such an event handler? It's showing the warning Event unsubscription via anonymous delegate
          – Stephan
          Sep 27 '18 at 21:01












          @Stephan Either you use a regular method instead of a lambda to both subscribe and unsubscribe or you store the delegate that represents the lambda in a variable and use that to subscribe and unsubscribe.
          – svick
          Sep 27 '18 at 21:47






          @Stephan Either you use a regular method instead of a lambda to both subscribe and unsubscribe or you store the delegate that represents the lambda in a variable and use that to subscribe and unsubscribe.
          – svick
          Sep 27 '18 at 21:47















          0














          Here's one more way that worked for me using a method overload:



              public void StartWindowsService()
          {
          var interval = TimeSpan.FromSeconds(2).TotalMilliseconds;
          _someTimer = new Timer
          {
          Interval = interval,
          Enabled = true
          };
          _someTimer.Elapsed += OnTimedEvent;
          _someTimer.Start();
          }

          private void OnTimedEvent(object sender, ElapsedEventArgs e)
          {
          MyAsyncMethod().Wait();
          }

          private async Task MyAsyncMethod()
          {
          // do async stuff here . . .
          }





          share|improve this answer








          New contributor




          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.


















          • so is this code better because it requires fewer lines? if not, please edit and explain how this approach is better
            – Sᴀᴍ Onᴇᴌᴀ
            1 min ago
















          0














          Here's one more way that worked for me using a method overload:



              public void StartWindowsService()
          {
          var interval = TimeSpan.FromSeconds(2).TotalMilliseconds;
          _someTimer = new Timer
          {
          Interval = interval,
          Enabled = true
          };
          _someTimer.Elapsed += OnTimedEvent;
          _someTimer.Start();
          }

          private void OnTimedEvent(object sender, ElapsedEventArgs e)
          {
          MyAsyncMethod().Wait();
          }

          private async Task MyAsyncMethod()
          {
          // do async stuff here . . .
          }





          share|improve this answer








          New contributor




          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.


















          • so is this code better because it requires fewer lines? if not, please edit and explain how this approach is better
            – Sᴀᴍ Onᴇᴌᴀ
            1 min ago














          0












          0








          0






          Here's one more way that worked for me using a method overload:



              public void StartWindowsService()
          {
          var interval = TimeSpan.FromSeconds(2).TotalMilliseconds;
          _someTimer = new Timer
          {
          Interval = interval,
          Enabled = true
          };
          _someTimer.Elapsed += OnTimedEvent;
          _someTimer.Start();
          }

          private void OnTimedEvent(object sender, ElapsedEventArgs e)
          {
          MyAsyncMethod().Wait();
          }

          private async Task MyAsyncMethod()
          {
          // do async stuff here . . .
          }





          share|improve this answer








          New contributor




          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          Here's one more way that worked for me using a method overload:



              public void StartWindowsService()
          {
          var interval = TimeSpan.FromSeconds(2).TotalMilliseconds;
          _someTimer = new Timer
          {
          Interval = interval,
          Enabled = true
          };
          _someTimer.Elapsed += OnTimedEvent;
          _someTimer.Start();
          }

          private void OnTimedEvent(object sender, ElapsedEventArgs e)
          {
          MyAsyncMethod().Wait();
          }

          private async Task MyAsyncMethod()
          {
          // do async stuff here . . .
          }






          share|improve this answer








          New contributor




          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          share|improve this answer



          share|improve this answer






          New contributor




          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          answered 24 mins ago









          daviesdoesit

          1




          1




          New contributor




          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.





          New contributor





          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.






          daviesdoesit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.












          • so is this code better because it requires fewer lines? if not, please edit and explain how this approach is better
            – Sᴀᴍ Onᴇᴌᴀ
            1 min ago


















          • so is this code better because it requires fewer lines? if not, please edit and explain how this approach is better
            – Sᴀᴍ Onᴇᴌᴀ
            1 min ago
















          so is this code better because it requires fewer lines? if not, please edit and explain how this approach is better
          – Sᴀᴍ Onᴇᴌᴀ
          1 min ago




          so is this code better because it requires fewer lines? if not, please edit and explain how this approach is better
          – Sᴀᴍ Onᴇᴌᴀ
          1 min ago


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • 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.


          Use MathJax to format equations. MathJax reference.


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





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • 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%2fcodereview.stackexchange.com%2fquestions%2f133464%2fuse-of-async-await-for-eventhandlers%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

          Morgemoulin

          Scott Moir

          Souastre