locked
HttpWebRequest timeout RRS feed

  • Question

  • I'm trying to do something that seems like it should be so simple, but has been causing me headaches for days now.

    I am making an HTTP request using the HttpWebRequest.BeginGetResponse function. I want it to timeout if it hasn't had a response within 30 seconds. How can I achieve this?

    The HttpWebRequest object has no timeout properties. I've tried starting another thread and getting it to abort the request, but I get a cross-thread access error. How else can I achieve this?

    Thanks!
    Wednesday, December 1, 2010 10:24 PM

Answers

  • The way I've implemented it is by putting a timer on my state object that get's passed around.

    using System.Net; 
    using System.Threading; 
     
    namespace xxxx.Communication 
        internal class xxxxHttpRequestState 
        { 
            public Timer TimeoutTimer; 
            public HttpWebRequest Request; 
            public HttpWebResponse Response; 
            public xxxxHttpResult HttpResult; 
            public xxxxHttpRequestCompleted InternalCallback; 
     
            public void RaiseInternalCallback() 
            { 
                if(InternalCallback != null
                { 
                    InternalCallback(HttpResult); 
                } 
            } 
        } 

            // TimeoutCallback fired if our httpResult isn't delivered in time 
            private void TimoutCallback(object stateObject) 
            { 
                var state = (xxxxHttpRequestState)stateObject; 
                state.HttpResult.FailureReason = "Time out"
                state.HttpResult.HttpResultStatus = xxxxHttpResult.Status.Failed; 
                state.Request.Abort(); 
                state.TimeoutTimer.Dispose(); 
            } 


            public void Get(xxxxHttpResult httpResult, xxxxHttpRequestCompleted internalCallback) 
            { 
                // Construct request 
                var request = (HttpWebRequest)WebRequest.Create(httpResult.RequestUri); 
                request.Method = "GET"
                request.CookieContainer = xxxxFactory.GetSettings().CookieContainer; // Use shared cookie container 
                request.AllowReadStreamBuffering = true
                request.AllowAutoRedirect = true
                httpResult.RequestHeaders = request.Headers; 
     
                // Create state for tracking httpResult 
                var state = new xxxxHttpRequestState { Request = request, HttpResult = httpResult, InternalCallback = internalCallback }; 
     
                // Set timeout 
                state.TimeoutTimer = new Timer(TimoutCallback, state, xxxxFactory.GetSettings().HttpRequestTimeoutPeriod, Timeout.Infinite); 
     
                // Get response from server 
                state.Request.BeginGetResponse(new AsyncCallback(ServerResponseReceived), state); 
            } 

    Thursday, December 2, 2010 12:23 AM
  • Hi Oenone,

    Hopefully this code will give you an idea on how to set the timeout:


    private HttpWebRequest request = null;
    private Stream requestStream = null;
    private ManualResetEvent requestStreamCreated;
    try
    {
    this.request.BeginGetRequestStream(this.GetRequestStreamAsyncCallback, null);
    if (!this.requestStreamCreated.WaitOne(this.timeout))
    {
    failed = true;
    this.request.Abort();
    }
    }
    catch (Exception e)
    {
    throw new IOException(String.Empty, e);
    }

    Thanks,

    ~Jonathan Tanner [MSFT]
    Thursday, December 2, 2010 12:40 AM

All replies

  • The way I've implemented it is by putting a timer on my state object that get's passed around.

    using System.Net; 
    using System.Threading; 
     
    namespace xxxx.Communication 
        internal class xxxxHttpRequestState 
        { 
            public Timer TimeoutTimer; 
            public HttpWebRequest Request; 
            public HttpWebResponse Response; 
            public xxxxHttpResult HttpResult; 
            public xxxxHttpRequestCompleted InternalCallback; 
     
            public void RaiseInternalCallback() 
            { 
                if(InternalCallback != null
                { 
                    InternalCallback(HttpResult); 
                } 
            } 
        } 

            // TimeoutCallback fired if our httpResult isn't delivered in time 
            private void TimoutCallback(object stateObject) 
            { 
                var state = (xxxxHttpRequestState)stateObject; 
                state.HttpResult.FailureReason = "Time out"
                state.HttpResult.HttpResultStatus = xxxxHttpResult.Status.Failed; 
                state.Request.Abort(); 
                state.TimeoutTimer.Dispose(); 
            } 


            public void Get(xxxxHttpResult httpResult, xxxxHttpRequestCompleted internalCallback) 
            { 
                // Construct request 
                var request = (HttpWebRequest)WebRequest.Create(httpResult.RequestUri); 
                request.Method = "GET"
                request.CookieContainer = xxxxFactory.GetSettings().CookieContainer; // Use shared cookie container 
                request.AllowReadStreamBuffering = true
                request.AllowAutoRedirect = true
                httpResult.RequestHeaders = request.Headers; 
     
                // Create state for tracking httpResult 
                var state = new xxxxHttpRequestState { Request = request, HttpResult = httpResult, InternalCallback = internalCallback }; 
     
                // Set timeout 
                state.TimeoutTimer = new Timer(TimoutCallback, state, xxxxFactory.GetSettings().HttpRequestTimeoutPeriod, Timeout.Infinite); 
     
                // Get response from server 
                state.Request.BeginGetResponse(new AsyncCallback(ServerResponseReceived), state); 
            } 

    Thursday, December 2, 2010 12:23 AM
  • Hi Oenone,

    Hopefully this code will give you an idea on how to set the timeout:


    private HttpWebRequest request = null;
    private Stream requestStream = null;
    private ManualResetEvent requestStreamCreated;
    try
    {
    this.request.BeginGetRequestStream(this.GetRequestStreamAsyncCallback, null);
    if (!this.requestStreamCreated.WaitOne(this.timeout))
    {
    failed = true;
    this.request.Abort();
    }
    }
    catch (Exception e)
    {
    throw new IOException(String.Empty, e);
    }

    Thanks,

    ~Jonathan Tanner [MSFT]
    Thursday, December 2, 2010 12:40 AM
  • Thank you both for your answers, I have this working perfectly now. :-)
    Thursday, December 2, 2010 11:18 PM
  • For the record, the WebClient interface does provide a timeout parameter in many of its methods.
    Friday, December 3, 2010 3:54 PM
  • Hi Jonathan,

    Could you please describe what is happening in that code snippet you provided?

    I thought the WaitOne would block the current thread? I.e. Whatever thread initiates the WebRequest would then block on the WaitOne call.

    Cheers,

    Tyler
    Sunday, March 13, 2011 7:56 AM