3

I have the following code:

static void Main(string[] args)
{
    moHost = new Host(
        APIServerType.Simulator,
        "T4Example",
        "112A04B0-5AAF-42F4-994E-FA7CB959C60B",
        "CTS",
        "myUser",
        "myPass");  //automated login

    moHost = Host.Login(
        APIServerType.Simulator,
        "T4Example",
        "112A04B0-5AAF-42F4-994E-FA7CB959C60B"); //manual login window
    moAccounts = moHost.Accounts;

    System.Console.WriteLine(moAccounts.ToString());
}

Where I know that the first automated login is an asynchronous request sent that I need to "wait" for.

And the login success would trigger:

public event Host.LoginSuccessEventHandler LoginSuccess

While a login failure would trigger:

public event Host.LoginFailureEventHandler LoginFailure

And a generic notification would be triggered by:

public event Host.NotificationEventHandler Notification

How do I go about handling this and properly waiting for my login success or failure?

The first automated login attempt does not show me as connected while the second manual login window indeed succeeds (therefore I am okay to think my credentials are fine and now its just that the code didn't properly 'wait').

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
jason m
  • 6,519
  • 20
  • 69
  • 122
  • 2
    http://stackoverflow.com/questions/12858501/is-it-possible-to-await-an-event-instead-of-another-async-method Does this solve your problem? I think it does. – usr Jun 22 '14 at 16:30
  • @usr sorry to do this, but would you mind painting the picture a little more for me? i am unsure exactly how to implement what is recommended. – jason m Jun 22 '14 at 16:44

1 Answers1

6

I would use a TaskCompletionSource<T> to wrap the events that can trigger from Host.Login, and use it as an Extension Method around the Host type:

public static class HostExtensions
{
    public static Task<bool> LoginAsync(this Host host, APIServerType serverType, string name, string id)
    {
        var tcs = new TaskCompletionSource<bool>();
        try
        {
            host.LoginSuccess += (object obj, LoginSuccessEventHandler e) =>
            {
                tcs.SetResult(true);
            }
            
            host.LoginFailure += (object obj, LoginFailureEventHandler e) =>
            {
                tcs.SetResult(false);
            }
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
        
        host.Login(serverType, name, id);
        return tcs.Task;
    }
}

If the notification message is important, you can create a LoginDetails sort of type an use it as the return type of the TaskCompletionSource:

public class LoginDetails
{
    public bool IsSuccess { get; set; }
    public string Notification { get; set; }
}

and use it like this:

public static Task<LoginDetails> LoginAsync(this Host host, APIServerType serverType, string name, string id)
{
    var tcs = new TaskCompletionSource<LoginDetails>();
    var loginDetails = new LoginDetails();
    try
    {
        host.LoginSuccess += (object obj, LoginSuccessEventHandler e) =>
        {
            loginDetails.IsSuccess = true;
            tcs.SetResult(loginDetails);
        }
        
        host.LoginFailure += (object obj, LoginFailureEventHandler e) =>
        {
            loginDetails.IsSuccess = false;
            tcs.SetResult(loginDetails);
        }
        
        host.Notification += (object obj, NotificationEventHandler e) =>
        {
            loginDetails.Notificaiton = e.Notification // I assume it would look something like this
            tcs.SetResult(loginDetails);
        }
    }
    catch (Exception e)
    {
        tcs.SetException(e);
    }
    
    host.Login(serverType, name, id);
    return tcs.Task;
}

And now you can use await on LoginAsync.

var login = await host.LoginAsync(APIServerType.Simulator, "T4Example", "112A04B0-5AAF-42F4-994E-FA7CB959C60B");

On a side note, if you use this inside a Console application you would have to use Result which will block rather than await (which yields control back to the caller) inside Main, which is a bit of a shame since it would be missing the whole point of asynchronous calls:

var login = host.LoginAsync(APIServerType.Simulator, "T4Example", "112A04B0-5AAF-42F4-994E-FA7CB959C60B").Result;
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321