Matteo Mosca
Matteo Mosca

Reputation: 7448

HttpWebRequest unhandled "invalidcastexception" casting HttpWebResponse to System.Exception

we have an application that makes calls to a remote web address using the HttpWebRequest class, which we get through the WebRequest.Create method.

This is our actual code:

var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "HEAD";
request.Timeout = this.connectionTimeout;

if (this.usePipelinedConnection)
{
     request.KeepAlive = true;
     request.Pipelined = true;
}

request.BeginGetResponse(cb => logService.EndGetRequestStream(cb), null);

Now in a non-deterministic way (can't find a pattern to reproduce it) we get the following error:

System.InvalidCastException

Unable to cast object of type 'System.Net.HttpWebResponse' to type 'System.Exception'.

with this stack trace:

at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)

at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult)

at System.Net.LazyAsyncResult.Complete(IntPtr userToken)

at System.Net.ContextAwareResult.CaptureOrComplete(ExecutionContext& cachedContext, Boolean returnContext)

at System.Net.ContextAwareResult.FinishPostingAsyncOp()

at System.Net.HttpWebRequest.BeginGetResponse(AsyncCallback callback, Object state)

Documentation about this method reports several exceptions that can be thrown, but InvalidCastException is not one of those, meaning that it is unhandled in microsoft method. I started digging in .Net sources, and I think I found the culprit. In the HttpWebResponse.EndGetResponseStream method, there's this line:

throw (Exception) lazyAsyncResult.Result;

That's the only cast to Exception present in this method, so that must be it. Now the method is implemented in a way that it will reach this line only if the connectionstream is null, so the lazyasyncresult.Result property should contain an exception. In my case however, the branch is reached but lazyasyncresult.Result contains an HttpWebResponse, thus the boxing fails and I get that error. Now I have two considerations:

Now my questions is plain simple: how do I prevent this from happening? I'm doing something wrong in my code or it's a plain bug in MS method?

Here follows, for reference, the MS source of the method. I added some comments on the incriminated line.

Thanks everyone for your time.

public Stream EndGetRequestStream(IAsyncResult asyncResult, out TransportContext context)
    {
      if (Logging.On)
        Logging.Enter(Logging.Web, (object) this, "EndGetRequestStream", "");
      context = (TransportContext) null;
      if (asyncResult == null)
        throw new ArgumentNullException("asyncResult");
      LazyAsyncResult lazyAsyncResult = asyncResult as LazyAsyncResult;
      if (lazyAsyncResult == null || lazyAsyncResult.AsyncObject != this)
        throw new ArgumentException(SR.GetString("net_io_invalidasyncresult"), "asyncResult");
      if (lazyAsyncResult.EndCalled)
      {
        throw new InvalidOperationException(SR.GetString("net_io_invalidendcall", new object[1]
        {
          (object) "EndGetRequestStream"
        }));
      }
      else
      {
        ConnectStream connectStream = lazyAsyncResult.InternalWaitForCompletion() as ConnectStream;
        lazyAsyncResult.EndCalled = true;
        if (connectStream == null)
        {
          if (Logging.On)
            Logging.Exception(Logging.Web, (object) this, "EndGetRequestStream", lazyAsyncResult.Result as Exception);

// Here result contains HttpWebResponse so the cast to Exception fails. 
// It would throw anyway (since there' a throw) but I think, since result contains a response
// that the code shouldn't be hitting this if branch.
          throw (Exception) lazyAsyncResult.Result;
        }
        else
        {
          context = (TransportContext) new ConnectStreamContext(connectStream);
          if (Logging.On)
            Logging.Exit(Logging.Web, (object) this, "EndGetRequestStream", (object) connectStream);
          return (Stream) connectStream;
        }
      }
    }

Upvotes: 2

Views: 1159

Answers (1)

feroze
feroze

Reputation: 7594

I have not used this async task library ever, and forgive me if this is a naive question. But.. arent you calling the wrong EndGetXXX function?

request.BeginGetResponse(cb => logService.EndGetRequestStream(cb), null);

I dont know what that logService variable is, but shouldnt it be invoking EndGetResponse() instead?

Upvotes: 3

Related Questions