【发布时间】:2013-08-07 07:34:05
【问题描述】:
我们有一个应用程序,它使用 HttpWebRequest 类调用远程网址,我们通过 WebRequest.Create 方法获得。
这是我们的实际代码:
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);
现在以一种不确定的方式(找不到重现它的模式)我们得到以下错误:
System.InvalidCastException
无法将“System.Net.HttpWebResponse”类型的对象转换为“System.Exception”类型。
使用此堆栈跟踪:
在 System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
在 System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult)
在 System.Net.LazyAsyncResult.Complete(IntPtr userToken)
在 System.Net.ContextAwareResult.CaptureOrComplete(ExecutionContext& cachedContext, Boolean returnContext)
在 System.Net.ContextAwareResult.FinishPostingAsyncOp()
在 System.Net.HttpWebRequest.BeginGetResponse(AsyncCallback 回调,对象状态)
有关此方法的文档报告了几个可以抛出的异常,但InvalidCastException 不是其中之一,这意味着它在 microsoft 方法中未处理。
我开始挖掘 .Net 资源,我想我找到了罪魁祸首。在 HttpWebResponse.EndGetResponseStream 方法中,有这样一行:
throw (Exception) lazyAsyncResult.Result;
这是此方法中唯一的 Exception 强制转换,所以一定是这样。现在该方法的实现方式是仅当连接流为空时才会到达该行,因此lazyasyncresult.Result 属性应该包含一个异常。然而,在我的情况下,到达了分支,但lazyasyncresult.Result 包含HttpWebResponse,因此装箱失败,我得到了那个错误。现在我有两个考虑:
- 如果
lazyasyncresult.Result的内容是正确的,它无论如何都会抛出(因为该行以抛出开始)但这将是一个有意义的错误; - 与上一点有关,我认为如果我有一个 HttpWebResponse,则无论如何都不应到达抛出的代码分支
现在我的问题很简单:如何防止这种情况发生?我在我的代码中做错了什么,或者这是 MS 方法中的一个普通错误?
以下是该方法的 MS 来源,以供参考。我在犯罪线上添加了一些 cmets。
感谢大家的宝贵时间。
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;
}
}
}
【问题讨论】:
-
你找到这个错误的原因了吗?
标签: c# exception casting httpwebrequest