1

I do a webrequest with DownloadStringAsync() but I need to return the result only when the DownloadStringCompleted event has been called. After the downloadasync-method, I need to wait for the result and then I could return it in a string property. So I implemented a while(Result == "") but I don't know what to do there. I already tried Thread.sleep(500) but it seems the download never gets completed. And the code remains in the while forever.

  string Result = "";

    public String Query(DataRequestParam dataRequestParam)
    {    
        try
        {
            WebClient web = new WebClient();

            if (!string.IsNullOrEmpty(dataRequestParam.AuthentificationLogin))
            {
                System.Net.NetworkCredential account = new NetworkCredential(dataRequestParam.AuthentificationLogin, dataRequestParam.AuthentificationPassword);
                web.Credentials = account;
            }

            web.DownloadStringCompleted += OnDownloadStringCompleted;
            web.DownloadStringAsync(dataRequestParam.TargetUri);

            while (Result == "")
            {
                //What am i supposed to do here ?  
            }
            return Result;
        }    
        catch(WebException we)
        {
            MessageBox.Show(we.Message);
            return null;
        }
    }

    private void OnDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            //Error treating
        }
        else
        {
            Result = e.Result;
        }
    }

UI CODE

protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    base.OnNavigatedTo(e);


    if (e.NavigationMode != NavigationMode.Back)
    {

    ServerFunctions.SetUserProfil(User.UserLogin,User.UserPassword);

    this.listBoxGetDocsLibs.Clear();
    List<BdeskDocLib> list = new List<BdeskDocLib>();
    try
    {
         //HERE THE START OF THE DOWNLOAD 
         ServerFunctions.GetDocLibs(true);
    }
    catch (Exception ex)
    {
       //error
    }

    foreach (BdeskDocLib docLib in list)
    {
        this.listBoxGetDocsLibs.Add(docLib);
    }

    }

}

the ServerFunction static class

public static List<BdeskDocLib> GetDocLibs(bool onlyDocLibPerso)
    {
        string xmlContent = GetXml(URL_GETDOCLIBS);
        List<BdeskDocLib> result = BdeskDocLib.GetListFromXml(xmlContent, onlyDocLibPerso);
        return result;
    }

   private static String GetXml(string partialUrl)
    {

        string url = GenerateUrl(partialUrl);

        DataRequestParam dataRequestParam = new DataRequestParam();
        dataRequestParam.TargetUri = new Uri(url);
        dataRequestParam.UserAgent = "BSynchro";

        dataRequestParam.AuthentificationLogin = userLogin;
        dataRequestParam.AuthentificationPassword = userPwd;

      //HERE I START THE QUERY method
       // NEED QUERY RETURNS A STRING or Task<String>
        DataRequest requesteur = new DataRequest();
        xmlResult=requesteur.Query(dataRequestParam);


        if (CheckErrorConnexion(xmlResult) == false)
        {
            throw new Exception("Erreur du login ou mot de passe");
        }

        return xmlResult;
    }
Paul Martinez
  • 562
  • 1
  • 9
  • 19
  • 1
    Did you see [this SO question](http://stackoverflow.com/questions/5071076/downloadstringasync-wait-for-request-completion)? It sounds like your problem to me, isn't it? – Timothée Bourguignon Feb 07 '14 at 11:44
  • yes i already saw this question but it didn't help me because i need to make the return of the result in the same method who called the DownloadStringAsync(): the Query() method...the result will be treated in a different class...I also tried to use the DownloadStringTaskAsync but it seems i got a deadlock i posted a question about it here [link](http://stackoverflow.com/questions/21606017/task-status-waiting-for-activation-downloadstringtaskasync-wp8) – Paul Martinez Feb 07 '14 at 11:48

1 Answers1

0

There is nothing good in blocking main UI (unless you really need to). But if you want to wait for your result you can make some use of async-await and TaskCompletitionSource - you can find more about on this blog and how to use TCS in this answer:

public static Task<string> myDownloadString(DataRequestParam dataRequestParam)
{
    var tcs = new TaskCompletionSource<string>();
    var web = new WebClient();

    if (!string.IsNullOrEmpty(dataRequestParam.AuthentificationLogin))
    {
       System.Net.NetworkCredential account = new NetworkCredential(dataRequestParam.AuthentificationLogin, dataRequestParam.AuthentificationPassword);
        web.Credentials = account;
    }

    web.DownloadStringCompleted += (s, e) =>
    {
        if (e.Error != null) tcs.TrySetException(e.Error);
        else if (e.Cancelled) tcs.TrySetCanceled();
        else tcs.TrySetResult(e.Result);
    };

    web.DownloadStringAsync(dataRequestParam.TargetUri);
    return tcs.Task;
}



public async Task<string> Query(DataRequestParam dataRequestParam)
{
   string Result = "";
   try
   {
       Result = await myDownloadString(dataRequestParam);
   }
   catch (WebException we)
   {
       MessageBox.Show(we.Message);
       return null;
   }
   return Result;
}

(I've not tried this code, there maight be some mistakes, but it should work)
Basing on this code you can also extend your WebClient with awaitable version of download string.

Community
  • 1
  • 1
Romasz
  • 29,662
  • 13
  • 79
  • 154
  • the thing is i need that the query() method return my result because i call this method in another class in which i treat the result.in your example the Query mehtod return is void... – Paul Martinez Feb 07 '14 at 12:04
  • @PaulMartinez you can modify it how you wish (in my opinion this Query method is no longer needed - you can call myDonload directly from your class). Remember that this method is async and if you want to wait for it you should do mystring = await Query(); – Romasz Feb 07 '14 at 12:11
  • Ok so i tried your code and i encoutered the same issue that i posted here [LINK](http://stackoverflow.com/questions/21606017/task-status-waiting-for-activation-downloadstringtaskasync-wp8) The mydownloadstring return a task and its status is "Waiting for activation".So in debug mode when the mydownloadString finishes and the code returns in the Query method , the UI of my app pops up and remains blocked..No error is raised... – Paul Martinez Feb 07 '14 at 12:27
  • @PaulMartinez can you show some code with your UI - where you call these methods? And do you want UI to be blocked or not? – Romasz Feb 07 '14 at 12:45
  • It doesn't matter for now if the UI is blocked by using sync method or waiting async method to be finished...I just want to get a string value in the return of the GetXml() method...I edited the code thank you – Paul Martinez Feb 07 '14 at 13:02
  • 1
    @PaulMartinez As I look at your code I think your GetXml(), GetDocLibs() should also be async Task<> - you have a method inside which should await for the result. Without await - xmlResult=requesteur.Query(dataRequestParam); will be run asynchronously and the method won't wait for the result - will process further, and you have return xmlResult there. What will be returned as Downloading wasn't finished? On the other hand - have you checked if the downloading the string from this Uri works (on separate simple method)? – Romasz Feb 07 '14 at 13:22
  • OK thank you very much...you was right all my methods need to wait the result...Im having error now but it seems now that im able to return the xmldata...so thanks you very much for your time...;) – Paul Martinez Feb 07 '14 at 13:35