1

I have an application (WinForms). It simply grabs some data, does some work on it, then uploads the result to some cloud storage. I'm now using some third party code which handles the authentication with the cloud storage for me. This code will create a WinForm, which hosts a browser control, which pops up if the user has not already provided credentials and permission for the application to use the cloud storage. Before my program goes and does its thing, I want to make sure I'm already authenticated, hence in the Main() loop of the program (Program.cs), I want to use the third party library to authenticate with the cloud storage and block my actual code (//myCode) executing until it is done. 'Unfortunately' the library is asynchronous, and I've spent the best part of today trying to get the behavior I've just described - my question is effectively a "make async function synchronous", but the general answers I've seen around don't seem to work for me.

So I have something like this

static void Main(string[] args)
{
OAuth.LoginAuthAsync("clientID", "client_secret", ...) 
//Don't want to get here until LoginAuthAsync is done 
application.run(myForm); //myCode
}

But this will popup the web browser and run my code, which I want to happen only after the web OAuth.LoginAuthAsync has completed.

I'm no expert with the whole TPL libraries, but I've spent a while playing around with things I believe should work but don't. I've tried:

I've tried

        Task.Run(async () =>
            {
                OAuth.LoginAuthAsync("123456", "asdasd", ...));
    ).Wait();

Which throws an error in the third party library

System.Threading.ThreadStateException: ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment. at System.Windows.Forms.WebBrowserBase..ctor(String clsidString) at System.Windows.Forms.WebBrowser..ctor()

So then I tried

        Thread tx = new Thread(() => OAuth.LoginAuthAsync("123456","asdasd", ……..));
        tx.SetApartmentState(ApartmentState.STA);
        tx.Start();
        tx.Join();

but that just pops up the window and it disappears instantly, and //myCode executes.

Any body have any ideas what I can do here. I tried moving the method inside of myForm _Load event (that's myForm invoked from the application.run), but I have the same problem.

Many Thanks

P.S. I don't want to use any further third party libraries.

friartuck
  • 2,954
  • 4
  • 33
  • 67
  • When you "complete" the login, can you catch that event and throw it back and then call the join? Also maybe put this in the application start-up before it calls application.run(yourForm) – Ryan Ternier Feb 23 '15 at 03:09
  • Check [this](http://stackoverflow.com/q/20876645/1768303). – noseratio Feb 23 '15 at 03:32

1 Answers1

1

You can block and wait for the code to complete using the Wait() method on the Task returned from OAuth.LoginAuthAsync. This works in a console app but may cause a deadlock in a GUI/ASP app.

static void Main(string[] args)
{
    OAuth.LoginAuthAsync("clientID", "client_secret", ...).Wait();

    //Don't want to get here until LoginAuthAsync is done 
    application.run(myForm); //myCode
}

For GUI apps it is best to make the relevant method async and then await the call to OAuth.LoginAuthAsync however Main can't be async. If you move the method inside the myForm_Load method you should be able to do await the call:

public async void myForm_Load(object o, EventArgs e)
{ 
     await OAuth.LoginAuthAsync("clientID", "client_secret", ...);
}

In my opinion that is the better solution.

svick
  • 236,525
  • 50
  • 385
  • 514
NeddySpaghetti
  • 13,187
  • 5
  • 32
  • 61
  • Thanks for the reply. Unfortunately the first method results in the GUI deadlocking (just a blank form with a wait cursor). The second method doesn't work either - execution continues as normal alongside opening up the login window (rather than the dialogue behavior I'm after) – friartuck Feb 23 '15 at 03:33
  • What about popping up a dialog and then in the `Load` event handler for that dialog calling `OAuth.LoginAuthAsync`? – NeddySpaghetti Feb 23 '15 at 03:47