WebClient - синхронизировать ответ с большими данными - PullRequest
0 голосов
/ 02 апреля 2012

Я использую WebClient для получения некоторых данных JSON с сервера.И я хочу, чтобы это было синхронно (да, я знаю, что в WP все должно быть асинхронно, но мне нужна синхронизация по некоторым причинам).В моем классе у меня есть такой код:

    private WebClient _webClient;
    private string _acctualResponse;
    private AutoResetEvent _lock = new AutoResetEvent(false);

    void _webClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
    {
        _acctualResponse = e.Result;
        _lock.Set();
    }

    public string _message;
    public string SendString(string URL, string message)
    {
        _webClient.UploadStringAsync(new Uri(URL), message);
        _lock.WaitOne();
        return _acctualResponse;    
    }

В моей программе я использую его, чтобы получить несколько разных наборов данных.И все работает хорошо, в то время как возврат данных невелик.Когда мне нужно получить больше данных (3 img в base64), события не начинаются.НО!когда я удаляю _lock, событие всегда начинается через мгновение после завершения функции SendString.Я пытаюсь использовать некоторые другие механизмы для ожидания ответа, например, while loop:

    private void WaitForResponse()
    {
        _acctualRequestTime = 0;
        _acctualResponse = null;
        while (!_uploadComplet && _acctualRequestTime < Timeout)
        {
            int slepTime = 200;
            Thread.Sleep(slepTime);
            _acctualRequestTime += slepTime;
        }
        _uploadComplet = false;
    }

[конечно, если я установил _uploadComplete flag в true] Efect был тем же: ответ пришелчерез некоторое время, независимо от того, какой интервал был установлен.Я немного смущен этой ситуацией.Ты знаешь, что я делаю плохо?

Ответы [ 2 ]

1 голос
/ 02 апреля 2012

У меня тоже была эта проблема.

Вы можете использовать это:

public T Get<T>(string apiMethod) where T : class
        {
            T outputObject;
            lock (syncObj)
            {
                downloadHandle = new ManualResetEvent(false);

                ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod);
                downloadHandle.WaitOne();
                outputObject = JsonHelper.Parse<T>(result);
            }
            return outputObject;
        }

protected void DownloadAsync(object _uri)
        {
            try
            {
                var url = _uri as string;
                WebClient client = new WebClient();
                client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
                client.DownloadStringAsync(new Uri(GLOBALS.MAIN_API_URL + url, UriKind.Absolute));
            }
            catch (Exception ex)
            {
                downloadHandle.Set();
            }
        }

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            (sender as WebClient).DownloadStringCompleted -= client_DownloadStringCompleted;

            try
            {
                result = e.Result;
            }
            catch (Exception ex)
            {
                result = ex.Message;
            }
            finally
            {
                downloadHandle.Set();
            }
        }

Теперь вы можете использовать так:

public Song GetSong(int _id)
        {
            var wr = Get<SongInfoWrapper>("info/song/" + _id);
            if (wr != null)
            {
                if (wr.Error == null)
                {
                    return wr.Element;
                }
            }

            return null;
        }

Но убедитесь, что метод GetSong вызван не в потоке пользовательского интерфейса.

0 голосов
/ 02 апреля 2012

WebClient вызывает события в потоке пользовательского интерфейса, если запрос был запущен в потоке пользовательского интерфейса.Поэтому, если вы ожидаете в потоке пользовательского интерфейса и не управляете основным циклом событий, события будут поставлены в очередь и, следовательно, никогда не будут доставлены.

Поскольку WebClient выполняет всю обработку в потоке пользовательского интерфейсаMicrosoft и многие другие рекомендуют не использовать его.Вместо этого следует использовать WebRequest.Это может даже решить вашу проблему.(Хотя блокировка потока пользовательского интерфейса не совсем хорошая вещь.)

...