2

I am implementing System.Web.UI.IPostBackEventHandler on one of my classes and in the body of my implementation of void RaisePostBackEvent(string eventArgument)I am calling a method using theasync...await` syntax. E.g.

public void RaisePostBackEvent(string eventArgument)
{
    if (eventArgument.Equals("deq1"))
    {
        Result result = await SaveDataAsync();
        OnSaved();
    }
}

However, it produces the error:

CS4033 - The 'await' operator can only be used within an async method

CS4033 - The 'await' operator can only be used within an async method

The question: Making interface implementations async describes an almost identical problem to mine, with the key difference being that the interface implemented by the OP was under his control, and the accepted answer was to change void DoSomething() on the interface to Task DoSomething(). However, I cannot change the IPostBackEventHandler as it is part of the .NET Framework.

Any suggestions on how to solve this in a safe way?

Community
  • 1
  • 1
Ɖiamond ǤeezeƦ
  • 3,223
  • 3
  • 28
  • 40

2 Answers2

3

You can add the async modifier even if it is not defined in the interface.
Just take into account that RaisePostBackEvent must return void, so it will work as a "fire and forget" call. If that is not a problem just add the async modifier to the signature.

public async void RaisePostBackEvent(string eventArgument)
{
    if (eventArgument.Equals("deq1"))
    {
        Result result = await SaveDataAsync();
        OnSaved();
    }
}
pomber
  • 23,132
  • 10
  • 81
  • 94
  • What happens if an exception occurs during the save process? How could I handle it? – Ɖiamond ǤeezeƦ May 06 '16 at 22:00
  • You want to handle it in the same method? Just put a try catch. You can use await inside of the try. – pomber May 06 '16 at 22:01
  • 1
    Calling OnSaved() is not a good idea. See Stephen Cleary answer in [this](http://stackoverflow.com/questions/19415646/should-i-avoid-async-void-event-handlers) SO question and [this](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx) MSDN page. – Jeroen Heier May 07 '16 at 06:44
  • Unfortunately this is legacy code that requires the `RaisePostBackEvent` to be async due to a method deep down being async (call to put a command on a message bus using MassTransit 3). `OnSaved()` is a virtual method. As this code is part of a web control, I've modified `RaisePostBackEvent` to `Page.RegisterAsyncTask(new PageAsyncTask(() => RaisePostBackEventAsync(eventArgument)));` and put the original code into a new method called `RaisePostBackEventAsync(string eventArgument)` – Ɖiamond ǤeezeƦ May 13 '16 at 08:22
1

If your method implementation is NOT async, then you cannot "await" inside it. You can make your method implementation async void even if the interface you're implementing doesn't have async. You cannot make your method implementation async Task, as that changes the return value which is bad.

The outcome of making your method implementation async void is that the caller will not wait for the method to complete before returning. try:

public async void RaisePostBackEvent(string eventArgument)
{
    if (eventArgument.Equals("deq1"))
    {
        Result result = await SaveDataAsync();
        OnSaved();
    }
}
Peter pete
  • 704
  • 1
  • 7
  • 17