Ожидание и возврат результата с помощью DownloadStringAsync WP8

Я делаю веб-запрос с DownloadStringAsync(), но мне нужно вернуть результат только тогда, когда было вызвано событие DownloadStringCompleted. После метода downloadasync мне нужно дождаться результата, а затем я могу вернуть его в строковом свойстве. Итак, я реализовал while(Result == ""), но не знаю, что там делать. Я уже пробовал Thread.sleep(500), но, похоже, загрузка так и не завершилась. А код остается в то время навсегда.

  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;
        }
    }

ИНТЕРФЕЙС КОД

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);
    }

    }

}

статический класс ServerFunction

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;
    }

person Paul Martinez    schedule 07.02.2014    source источник
comment
Вы видели этот ТАК вопрос? Мне кажется, это твоя проблема, не так ли?   -  person Timothée Bourguignon    schedule 07.02.2014
comment
да, я уже видел этот вопрос, но он мне не помог, потому что мне нужно вернуть результат тем же методом, который вызывал метод DownloadStringAsync(): метод Query()... результат будет обработан другим класс... Я также пытался использовать DownloadStringTaskAsync, но, похоже, у меня возникла тупиковая ситуация. Я разместил вопрос об этом здесь ссылка   -  person Paul Martinez    schedule 07.02.2014


Ответы (1)


Нет ничего хорошего в блокировании основного пользовательского интерфейса (если вам действительно это не нужно). Но если вы хотите дождаться своего результата, вы можете использовать async-await и TaskCompletitionSource — вы можете найти подробнее в этом блоге и как использовать TCS в этом ответе:

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;
}

(Я не пробовал этот код, могут быть некоторые ошибки, но он должен работать)
На основе этого кода вы также можете расширить свой WebClient ожидаемой версией строки загрузки.

person Romasz    schedule 07.02.2014
comment
дело в том, что мне нужно, чтобы метод query() возвращал мой результат, потому что я вызываю этот метод в другом классе, в котором я обрабатываю результат. в вашем примере возврат метода Query недействителен... - person Paul Martinez; 07.02.2014
comment
@PaulMartinez, вы можете изменить его по своему усмотрению (на мой взгляд, этот метод Query больше не нужен - вы можете вызвать myDonload прямо из своего класса). Помните, что этот метод асинхронный, и если вы хотите дождаться его, вы должны сделать mystring = await Query(); - person Romasz; 07.02.2014
comment
Итак, я попробовал ваш код и столкнулся с той же проблемой, что и здесь /a> Mydownloadstring возвращает задачу, и ее статус — Ожидание активации. Таким образом, в режиме отладки, когда mydownloadString завершается и код возвращается в методе Query, пользовательский интерфейс моего приложения всплывает и остается заблокированным. Ошибка не возникает. .. - person Paul Martinez; 07.02.2014
comment
@PaulMartinez, можете ли вы показать какой-нибудь код с вашим пользовательским интерфейсом - где вы вызываете эти методы? И вы хотите, чтобы интерфейс был заблокирован или нет? - person Romasz; 07.02.2014
comment
На данный момент не имеет значения, заблокирован ли пользовательский интерфейс с помощью метода синхронизации или ожидания завершения асинхронного метода... Я просто хочу получить строковое значение в возврате метода GetXml()... Я отредактировал код благодарю вас - person Paul Martinez; 07.02.2014
comment
@PaulMartinez Когда я смотрю на ваш код, я думаю, что ваши GetXml(), GetDocLibs() также должны быть асинхронными Task‹› — у вас есть метод внутри, который должен ждать результата. Без ожидания - xmlResult=requesteur.Query(dataRequestParam); будет выполняться асинхронно и метод не будет ждать результата - будет обрабатываться дальше, а вы там вернете xmlResult. Что будет возвращено, если загрузка не была завершена? С другой стороны, вы проверили, работает ли загрузка строки из этого Uri (по отдельному простому методу)? - person Romasz; 07.02.2014
comment
ОК, большое спасибо ... вы были правы, все мои методы должны дождаться результата ... У меня сейчас ошибка, но теперь кажется, что я могу вернуть xmldata ... так что большое спасибо за ваше время .. .;) - person Paul Martinez; 07.02.2014