-2

I am calling into this static login method with username and password. I want it to wait to return until the downloadstringasync has completed. For the freaking life of me I cant get it to wait though.

I tried the oldschool

while(wc.IsBusy){} //Which froze

also tried a variety of async crap that didnt even compile

    public static dbObj Login(String username, String password)
    {
        dbObj ret = new dbObj();
        String rawWebReturn = "";
        ret.propBag.Add(_BAGTYPE,returnTypes.Login.ToString());
        DateTime date = DateTime.Now;
        WebClient wc = new WebClient();
        wc.DownloadStringAsync(new Uri(baseLoginURI + "uname=" + username + "&pword=" + password + "&date=" + date.ToString()));   


        wc.DownloadStringCompleted  += (s,e) => {                                         
                                   if(e.Error!=null)
                                      rawWebReturn = e.Error.Message;
                                   else
                                      rawWebReturn = e.Result;
                                };
        return parseWebReturn(rawWebReturn,ret);            
    }
DotNetRussell
  • 9,716
  • 10
  • 56
  • 111

4 Answers4

3

First of all, you should never ever wait for an asynchronous operation to finish. Instead, continue with your execution after the function completes.

EDIT: You must add NuGet package Microsoft.Bcl.Async here.

Now, since you are using Windows Phone 8, you can safely use async here:

    public static async dbObj Login(String username, String password)
    {
        dbObj ret = new dbObj();
        String rawWebReturn = "";
        ret.propBag.Add(_BAGTYPE, returnTypes.Login.ToString());
        DateTime date = DateTime.Now;
        WebClient wc = new WebClient();
        try
        {
            var result = await wc.DownloadStringTaskAsync(new Uri(baseLoginURI + "uname=" + username + "&pword=" + password + "&date=" + date.ToString()));
            return parseWebReturn(result, ret);
        }
        catch (Exception e)
        {
            return parseWebReturn(e.Message, ret);
        }
    }

Async must compile because it just works. If you are having trouble with it, ask again with your code snippet here.

If you want to target Windows Phone 7, add the above mentioned NuGet package and you will be able to compile it without problems.

Toni Petrina
  • 7,014
  • 1
  • 25
  • 34
  • There is no Download String Task Ascync for windows phone in Web Client – DotNetRussell Aug 01 '13 at 11:02
  • 1
    Add reference to NuGet package **Microsoft.Bcl.Async**. – Toni Petrina Aug 01 '13 at 11:17
  • Thanks for the solid answer. I don't know why people downvoted this question when obviously so many people answered it with different solutions. It obviously has some value. Anyway good idea, saved me a huge hack (that I already implimented but now will be ripping out) – DotNetRussell Aug 01 '13 at 12:45
1

If you need to block the thread until an async operation is completed, you can use ManualResetEvent, like this:

ManualResetEvent wait = new ManualResetEvent(false);

wc.DownloadStringCompleted  += (s,e) => {                                         
    // ...

    // allow to proceed
    wait.Set();
};

// wait until Set
wait.WaitOne();

return parseWebReturn(rawWebReturn,ret); 

In general though, you don't want to block threads, but rather use callbacks. You can do that by providing an Action delegate instead of the return value:

public static void Login(String username, String password, Action<dbObj> callback)
{
    // ...

    wc.DownloadStringCompleted  += (s,e) => {                                         
                               if(e.Error!=null)
                                  rawWebReturn = e.Error.Message;
                               else
                                  rawWebReturn = e.Result;

                               Callback(parseWebReturn(rawWebReturn, ret););
                            };
}
McGarnagle
  • 101,349
  • 31
  • 229
  • 260
1

If you force a wait in the UI thread either by spinning a while loop or using ManualResetEvent.WaitOne then you are actually deadlocking your app. The network call at some point appears to need to touch the UI thread, but you've frozen it = deadlock.

Freezing the UI thread like this is also bad in lots of other ways (no touch events will be processed, no screen updates etc).

You would be better off using HttpClient for Windows Phone, and using the async/await pattern. You can download this from NuGet as the Microsoft.Net.Http package.

Paul Annetts
  • 9,554
  • 1
  • 27
  • 43
1

You can rewrite the existing WebClient method with the help of Async and Await method something like this

public Task<string> GetRssFeed(string feedUrl)
{
       var tcs = new TaskCompletionSource<string>();
       var client = new WebClient();
       client.DownloadStringCompleted += (s, e) =>
       {
             if (e.Error == null)
             {
                  tcs.SetResult(e.Result);
             }
             else
             {
                  tcs.SetException(e.Error);
             }
        };

        client.DownloadStringAsync(new Uri(feedUrl));
        return tcs.Task;

}

So from doing so you can await your call until the callback come back. This is the most effective and latest way to achieve your functionality

Rakesh R Nair
  • 1,736
  • 2
  • 12
  • 30
  • 2
    Yes that is the best way to achieve the functionality. – Nitha Paul Aug 01 '13 at 10:41
  • Except that this is windows phone and there is no Download String Completed – DotNetRussell Aug 01 '13 at 11:00
  • 2
    Yes there is: http://msdn.microsoft.com/en-us/library/system.net.webclient.downloadstringcompleted(v=vs.95).aspx. Supported in: Windows Phone OS 7.1, Windows Phone OS 7.0 – Toni Petrina Aug 01 '13 at 11:26
  • @RakeshRNair There is no Download String Completed in Windows Phone OS 8.0 which is what is targeted and tagged above – DotNetRussell Aug 01 '13 at 12:46
  • @RakeshRNair Here is what is available http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.net.webclient(v=vs.105).aspx – DotNetRussell Aug 01 '13 at 12:50
  • 1
    @AMR : Strange, You are asked for a solution to wait until the callback, And he guide in the right way too.. I don't know what is wrong with, You can go with TaskCompletion implementation in you current implementation too. – Stephan Ronald Aug 01 '13 at 13:28
  • @StephanRonald I don't know how many other ways to say this. This answer doens't work. It's not supported in windows phone 8. Look at the MSDN I linked. – DotNetRussell Aug 01 '13 at 13:35
  • 1
    @ARM : I didn't tried this in my computer, I only took Laurent's Blog as reference (http://geekswithblogs.net/lbugnion/archive/2013/01/27/using-asyncawait-with-webclient-in-windows-phone-8-or-taskcompletionsource.aspx). The issue you are facing is not because of missing the DownloadCompleted event, It is present in windows phone 8 instead the real reason is "the callback of the WebClient is executed on the main thread, which cannot happen since you're blocking it by calling task.Result" – Rakesh R Nair Aug 01 '13 at 14:04
  • 2
    Please find this thread for more detail : http://stackoverflow.com/questions/16708646/wp8-taskcompletionsource-not-getting-result – Rakesh R Nair Aug 01 '13 at 14:05