Implementing Timeout Property in Stream Read

I am getting a stream from HttpWebResponse.GetResponseStream()

where I read the data. Now I want to implement a property Timeout

. The easiest way to do this is: stream.ReadTimeout = timeout

but this calls InvalidOperationException -> Timeouts are not supported on this stream

.

With that in mind, I'm trying to implement the timeout property myself, but I'm stuck with it. This is what I got so far:

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

      

The problem with this code is that it gets thrown after that TimeoutException

, which is properly handled. It throws an exception on _src.Read(buffer, offset, count)

, saying that the _src stream has been removed.

Is there a way to reverse the ThreadPool method, or is there a better approach and which one?

thank

EDIT

As @JotaBe asked, there was code where I get the stream from the 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);
    }

      

+3


source to share


2 answers


I ended up using Nomad101's suggestion and surrounding the reading with try / catch.



-1


source


If you are trying to get the timeout if you have not received and responded to the web server, you are trying to do it in the wrong place.

To get a response, you usually make a request:

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

      

This is an operation that can be timed out. You have to call it in a different way using the Begin / End asynchronous pattern.

Here is a complete example of this MSDN doc for the HttpWebRequest.BeginGetResponse method



This example uses a callback function. However, there are many different ways to use Begin / End. For example, you can use the WaitHandle available in IAsyncResult like this:

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

      

It will take 15 seconds. If the answer achieves this, completion is true. If not, the completion will be false. Then you can use the method HttpWebRequest.Abort()

to cancel the request.

The Begin / End sample is responsible for managing the required flows.

+2


source







All Articles