Добавить тайм-аут в живой код?

#c# #visual-studio-2010 #windows-phone-7 #live-tile

#c# #visual-studio-2010 #windows-phone-7 #живая плитка

Вопрос:

Первый пост здесь, извините, что начал с вопросов.

В моем приложении для Windows Phone 7 у меня есть рабочий livetile, который запускается фоновым агентом. Но как я могу изменить код, чтобы тайм-ауты httpwebrequest истекали через 10 секунд?

Заранее спасибо.

 protected override void OnInvoke(ScheduledTask task)
    {
        //TODO: Add code to perform your task in background

        var request = (HttpWebRequest)WebRequest.Create(
        new Uri("site.com"));

        request.BeginGetResponse(r =>
        {
            var httpRequest = (HttpWebRequest)r.AsyncState;
            var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);
            using (var reader = new StreamReader(httpResponse.GetResponseStream()))
            {
                var response = reader.ReadToEnd();

                Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                {
                    string strResult = response;


                    /// If application uses both PeriodicTask and ResourceIntensiveTask
                    if (task is PeriodicTask)
                    {
                        // Execute periodic task actions here.
                        ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("TileID=2"));
                        if (TileToFind != null)
                        {

                            StandardTileData NewTileData = new StandardTileData
                            {
                                BackgroundImage = new Uri("Pin-to-start.png", UriKind.Relative),
                                Title = strResult,
                                Count = null
                            };
                            TileToFind.Update(NewTileData);
                        }
                    }
                    else
                    {
                        // Execute resource-intensive task actions here.
                    }

                    NotifyComplete();
                }));
            }
        }, request);
    }
  

Ответ №1:

Вот копирование / вставка из кода, который я использую в одном из своих приложений. Соединение будет прервано через 60 секунд.

     private static void DoWebRequest(string uri)
    {
        string id = "my_request";

        Timer t = null;
        int timeout = 60; // in seconds

        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            request.Accept = "*/*";
            request.AllowAutoRedirect = true;

            // disable caching.
            request.Headers["Cache-Control"] = "no-cache";
            request.Headers["Pragma"] = "no-cache";

            t = new Timer(
                state =>
                {
                    if (string.Compare(state.ToString(), id, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        logger.Write("Timeout reached for connection [{0}], aborting download.", id);

                        request.Abort();
                        t.Dispose();
                    }
                },
                id,
                timeout * 1000,
                0);

            request.BeginGetResponse(
                r =>
                {
                    try
                    {
                        if (t != null)
                        {
                            t.Dispose();
                        }

                        // your code for processing the results

                    }
                    catch
                    {
                        // error handling.
                    }
                },
                request);
        }
        catch
        {
        }
    }
  

Комментарии:

1. Спасибо! Должен ли я добавить весь синтаксический анализ, а также фрагменты в «запрос. BeginGetResponse(…»?

2. да, вы можете просто оставить его там, но убедитесь, что вы утилизируете t (таймер) в начале BeginGetResponse .

3. Хорошо, итак, я беру ваш код и заменяю свой код до тех пор, пока «запрос. Начало ответа»? Я новичок, поэтому прошу прощения за основные вопросы 🙂 Я пытался это сделать, но получаю следующие ошибки: имя ‘timeout’ не существует в текущем контексте Имя ‘t’ не существует в текущем контексте

4. Хорошо, я опубликую более подробный пример через секунду. подождите.

5. Большое вам спасибо! Я использовал ваш код как своего рода оболочку, а затем добавил весь свой старый код после t.Dispose() . Сейчас я тестирую и думаю, что это работает. Я проверю после того, как мой телефон будет переведен в режим ожидания на ночь, если обновление живой плитки продолжится. Куда я должен поместить вызов NotifyComplete()?

Ответ №2:

Но как я могу изменить код, чтобы тайм-ауты httpwebrequest истекали через 10 секунд?

Вы имеете в виду, что он будет вызываться NotifyComplete() независимо от тайм-аутов?-) Проблема в том, что через 15 секунд задача завершается и отключается до тех пор, пока пользователь не запустит ее повторно (внутри вашего приложения).

Я бы рекомендовал использовать TPL для Silverlight и использовать возможность использовать задачи для установки времени ожидания.

Что-то вроде:

 protected override void OnInvoke(ScheduledTask task)
{
    var fetchTask = FetchData(TimeSpan.FromSeconds(10));
    fetchTask.ContinueWith(x =>
    {
        Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
        {
            string strResult = x.Resu< // mind you, x.Result will be "null" when a timeout occours.

            ...

            NotifyComplete();
        }));
    });
}

private Task<string> FetchData(TimeSpan timeout)
{ 
    var tcs = new TaskCompletionSource<string>();
    var request = (HttpWebRequest)WebRequest.Create(new Uri("site.com"));

    Timer timer = null;
    timer = new Timer(sender =>
    {
        tcs.TrySetResult(null);
        timer.Dispose();
    }, null, (int)timeout.TotalMilliseconds, Timeout.Infinite);

    request.BeginGetResponse(r =>
    {
        var httpRequest = (HttpWebRequest)r.AsyncState;
        var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);
        using (var reader = new StreamReader(httpResponse.GetResponseStream()))
        {
            var response = reader.ReadToEnd();
            tcs.TrySetResult(response);
        }
    });

    return tcs.Task;
}
  

Комментарии:

1. еще один отличный ответ от Клауса. Превосходит мой комментарий / ответ. Спасибо! TPL довольно потрясающий. не думал об этом.

2. Клаус, это лучшее решение? Я использовал первый ответ в этой теме и добавил NotifyComplete в часть кода для тайм-аута, а также добавил NotifyComplete, где устанавливается плитка. Таким образом, NotifyComplete следует вызывать независимо от того, истек ли тайм-аут httpwebrequest или нет? Всю ночь мой телефон работал в режиме flightmode, и сегодня утром живая плитка снова начала обновляться.

3. Ответ Клауса в основном лучше, потому что он использует существующую инфраструктуру TPL для достижения того же, что и я, но с гораздо меньшим количеством кода и, следовательно, менее подвержен ошибкам. Но моя реализация работает так же хорошо, как и его.

4. Хорошо, круто! Спасибо вам обоим! Так замечательно получить помощь, когда вы застряли.

5. Ну, это другое решение. Я думаю, что invalidusername также предоставил хорошее решение. Мне просто было скучно на работе, когда я писал это 😉