开发者

Building workaround for HttpWebRequest timeout issue

I'm using the HTTP Web Request class to call a RESTful web service. I need to pass data and receive data开发者_如何学运维 and it all seems to work very well. Today I attempted to configure the time-out of the class because there is a high likelihood of the server running the service being offline and I don't want to waste time waiting. I configured it all but it seemed to make no difference. The call still waited over 10 seconds before failing.

On looking into it I found that the time-out only deals with the processing of the call and that the DNS lookup beforehand is not included. As this would be the problem it would make sense as to why the time-out wasn't working as I'd expected.

Further reading suggested using the HttpWebRequest class in an asynchronous style instead. I've had a look at the code to do so but don't understand how to retrieve the callback in my code which is effectively synchronous.

The code I have as follows is as so:

HttpWebRequest _serviceRequest = (HttpWebRequest)WebRequest.Create(new Uri("http://mywebservice.com"));
_serviceRequest.Timeout = 3000;

HttpWebResponse response = (HttpWebResponse)_serviceRequest.GetResponse();
XmlReader reader = XmlReader.Create(response.GetResponseStream(), set);

The code I have to call asynchronously ends with the following line, but I'm not sure as to what I should do to get the response object.

IAsyncResult result = (IAsyncResult)req.BeginGetResponse(new AsyncCallback(RespCallback), reqState);

I'm also concerned about a half baked asynchronous solution such as this. Is it good practice to use an asynchronous method through a synchronous piece of code.

Any helpers appreciated...


The response would be available when the callback function RespCallback is invoked. I don't know what reqState has, but I assume it contains a reference to the original HttpWebRequest object. If this is the case, this would be a simple implementation of the RespCallback method:

void RespCallback(IAsyncResult asyncResult)
{
   ReqState reqState = (ReqState)asyncResult.AsyncState;
   HttpWebResponse resp = (HttpWebResponse)reqState.Request.EndGetResponse(asyncResult);
   // do what you need with the response.
}

Update: more info as asked in the comment

If you want the response in the same method where you did the Begin call, you can have an event which will be set when the callback is received, and you can wait on that event after the Begin call, like in the example below

class ReqState {
    public HttpWebRequest Request { get; set; }
    public HttpWebResponse Response { get; set; }
    public AutoResetEvent Evt { get; set; }
}

void RespCallback(IAsyncResult asyncResult) {
    ReqState reqState = (ReqState)asyncResult.AsyncState;
    reqState.Response = (HttpWebResponse)reqState.Request.EndGetResponse(asyncResult);
    reqState.Evt.Set();
}

void CallMethod() {
    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(...);
    // set properties on req
    ReqState state = new ReqState();
    state.Request = req;
    state.Evt = new ManualResetEvent(false);
    req.BeginGetResponse(RespCallback, state);
    state.Evt.WaitOne(TimeSpan.FromSeconds(30)); // wait for 30 seconds
    // access response via state.Response
}

Now notice that you're essentially doing a synchronous call in an asynchronous way. That gives you more control over the timeout, but with the price of code complexity. Another thing, this will not work on platforms such as Silverlight (and Windows Phone, IIRC), where synchronous calls (even those dressed up as asynchronous) are forbidden.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜