rudimenter
rudimenter

Reputation: 3460

Is marking an interface method as async the right thing todo in my case

I am working with a custom framework wich is used for a long time within my company. I want to use the new async feature within my code.

In order todo this i have to mark the "ProcessRequestMessage" of "MyClass" as async. I can't change the interface "IFramework" and class "FrameworkBase".

The Framework expects already that "ProcessRequestMessage" finishes asynchronously so i don't have to use "Wait()" on the End of the method. A call to "SetResponseCode" signalizes to the framework to finalize the instance of "MyClass"

Question: I read in the documentation of the async feature that only void Events should be marked as async for Entry into the async workflow (Task does not apply here). My code requires that i mark the implementation of a void interface method as Entry point.

So can i do this:

interface IFramework
{
    void ProcessRequestMessage()

    void SetResponseCode(int code)
}

public abstract class FrameworkBase: IFramework
{
    abstract void ProcessRequestMessage()

    public void SetResponseCode(int code)
    {
        //internal implementation
    }
}

public class MyClass: FrameworkBase
{

    protected override async void ProcessRequestMessage()
    {
        //await something

        SetResponseCode(0);
    }
}

Upvotes: 1

Views: 518

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456887

There are two major reasons why you should avoid async void:

  1. The calling code assumes the method has completed when it has returned.
  2. How it handles exceptions.

In your particular case, the calling code does not assume the operation has completed when ProcessRequestMessage returns, so you can use async void but you must be very careful with your exceptions. (I prefer using task continuations instead of async void).

I recommend writing a FrameworkTaskBase just for this:

public class FrameworkTestBase: FrameworkBase
{
  protected abstract Task ProcessRequestMessageAsync();
  protected override sealed void ProcessRequestMessage()
  {
    ProcessRequestMessageAsync().ContinueWith(t =>
    {
      if (t.IsFaulted || t.IsCanceled)
        SetResponseCode(-1);
      else
        SetResponseCode(0);
    });
  }
}

public class MyClass: FrameworkBase
{
  protected override async Task ProcessRequestMessageAsync()
  {
    //await something
  }
}

Alternatively (using async void):

public class FrameworkTestBase: FrameworkBase
{
  protected abstract Task ProcessRequestMessageAsync();
  protected override sealed async void ProcessRequestMessage()
  {
    try
    {
      await ProcessRequestMessageAsync();
      SetResponseCode(0);
    }
    catch
    {
      SetResponseCode(-1);
    }
  }
}

Upvotes: 3

Related Questions