mosquito87
mosquito87

Reputation: 4440

Use actions inside AsyncCallback

My class does the following (simplified):

public void Startup(Action myAction)
{
    _myAction = myAction;
}

private void EstablishApplicationEndpoint()
{
    ...
    ApplicationEndpoint.BeginEstablish(OnApplicationEndpointEstablishCompleted, null);
}

private void OnApplicationEndpointEstablishCompleted(IAsyncResult result)
{
    try
    {
        ...
        _myAction();
    }
    catch (Exception exception)
    {
        Console.WriteLine(exception);
    }
}

The BeginEstablish method takes an AsyncCallback as first parameter.

However myAction is never executed (I use the class from a console application). The action should output something to the console and read a line, but the console is closed immediately.

My console application:

static void Main(string[] args)
{
    StartPlatform();
}

private static void StartPlatform()
{
    ...
    _platformController.Startup(SendContext);
}

private static void SendContext()
{
    Console.WriteLine("Press ENTER to send context");
    Console.ReadLine();
    ...
}

As the console can't know that a ReadLine- call will come at some time it closes automatically. How can I prevent to do so?

Upvotes: 1

Views: 388

Answers (1)

Chamila Chulatunga
Chamila Chulatunga

Reputation: 4914

You are using the 'Asynchronous Programming Model (APM)' pattern: https://msdn.microsoft.com/en-us/library/ms228963(v=vs.110).aspx

This model is typified by the use of Begin and End methods.

Note that when a Begin method (such as your BeginEstablish) is invoked, the work denoted by the callback method is scheduled to occur on a separate (background) thread, and program control is returned immediately in the main thread.

The assumption is that other computation can occur on the main thread, at some point the callback will have completed on the background thread, and the results of the background thread will then be re-joined to the main thread.

The mechanism for re-joining is a call to a corresponding End method (so in your case, a call to EndEstablish). As such, to prevent your console application from exiting due to the immediate return of control from the call to BeginEstablish, you need to do the following:

  • Maintain a reference to the the IAsyncResult object that is returned from the Begin call
  • At some point in the code path following the call to Begin, call the corresponding End, passing in the IAsyncResult object obtained from the call to Begin
  • Optionally use the second parameter to the Begin call to manage state

What this might look like is:

private IAsyncResult EstablishApplicationEndpoint()
{
    ...
    return ApplicationEndpoint.BeginEstablish(OnApplicationEndpointEstablishCompleted, null);
}

...

private static void StartPlatform()
{
    ...
    _platformController.Startup(SendContext);
    var asyncResult = _platformController.EstablishApplicationEndpoint();

    // Do other things

    // Re-join the callback
    ApplicationEndpoint.EndEstablish(asyncResult);
}

Keep in mind that if the callback has not yet completed by the time End is called, End will at that point block and wait for the callback to complete.

Since your callback is interacting with the Console, I suspect this will mean the call to End will be blocking in your case.

Upvotes: 2

Related Questions