Реализация свойства тайм-аута в Stream Read - PullRequest
3 голосов
/ 21 марта 2012

Я получаю поток из HttpWebResponse.GetResponseStream(), откуда я читаю данные. Теперь я хочу реализовать свойство Timeout. Самый простой способ сделать это - stream.ReadTimeout = timeout, но это выдает InvalidOperationException -> Timeouts are not supported on this stream.

Учитывая это, я пытаюсь реализовать свойство timeout самостоятельно, но застрял на удалении. Вот что я получил до сих пор:

public class MyStream : Stream {
    private readonly Stream _src;
    public override int ReadTimeout { get; set; }

    public MyStream (Stream src, int timeout) {
       ReadTimeout = timeout;
       _src = src;
    }

    public override int Read(byte[] buffer, int offset, int count) {
        var timer = new AutoResetEvent(false);
        int read = 0;

        ThreadPool.QueueUserWorkItem(
            _ => {
                read = _src.Read(buffer, offset, count);
                timer.Set();
            });
        bool completed = timer.WaitOne(ReadTimeout);
        if (completed) {
            return read;
        }
        throw new TimeoutException(string.Format("waited {0} miliseconds", ReadTimeout));
    }

Проблема с этим кодом заключается в том, что после броска TimeoutException, где-то правильно обрабатывается. Выдает исключение для _src.Read(buffer, offset, count), говорящее о том, что поток _src был удален.

Есть ли способ отменить метод ThreadPool или я должен использовать лучший подход и какой?

Спасибо

EDIT

Как спросил @JotaBe, вот код, из которого я получаю поток из HttpWebResponse:

_httpRequest = WebRequest.CreateHttp(url);

_httpRequest.AllowReadStreamBuffering = false;
_httpRequest.BeginGetResponse(
    result =>
        {
            try {
                _httpResponse = (HttpWebResponse)_httpRequest.EndGetResponse(result);
                stream = _httpResponse.GetResponseStream();
            }
            catch (WebException) {
                downloadCompleted.Set();
                Abort();
            }
            finally {
                downloadCompleted.Set();
            }
        },
        null);

    bool completed = downloadCompleted.WaitOne(15 * 1000);
    if (completed) {
        return new MyStream(stream, 10000);
    }

Ответы [ 2 ]

2 голосов
/ 21 марта 2012

Если вы пытаетесь получить тайм-аут, если вы не получаете и не отвечаете с веб-сервера, вы пытаетесь сделать это не в том месте.

Чтобы получить ответ, вы обычно делаете запрос:

HttpWebResponse response = (HttpWebResponse)request.GetResponse ();

Это операция, которая может прерваться. Вы должны вызывать его по-другому, используя асинхронный шаблон Begin / End.

Существует полный пример этого в Документ MSDN для метода HttpWebRequest.BeginGetResponse

В этом примере используется функция обратного вызова. Тем не менее, есть много разных способов использования Begin / End. Например, вы можете использовать WaitHandle, доступный в IAsyncResult, например:

IAsyncResult ar = req.BeginGetResponse(yourCallback, null);
bool completed = ar.AsyncWaitHandle.WaitOne(15000 /*your timeout in miliseconds*/);

Это подождет 15 секунд. Если ответ прибудет до этого, выполнено будет верно. Если нет, выполнено будет ложным. Затем вы можете использовать метод HttpWebRequest.Abort(), чтобы отменить запрос.

Шаблон Begin / End отвечает за управление необходимыми потоками.

0 голосов
/ 26 марта 2012

Я использовал предложение Nomad101 и окружил чтение попыткой / уловом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...