メソッドを介して取得する HttpWebRequest クラスを使用してリモート Web アドレスを呼び出すアプリケーションがあります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& コンテキスト) で
System.Net.HttpWebRequest.EndGetRequestStream (IAsyncResult asyncResult) で
System.Net.LazyAsyncResult.Complete (IntPtr userToken) で
System.Net.ContextAwareResult.CaptureOrComplete (ExecutionContext& cachedContext、ブール値の returnContext) で
System.Net.ContextAwareResult.FinishPostingAsyncOp() で
System.Net.HttpWebRequest.BeginGetResponse (AsyncCallback コールバック、オブジェクトの状態) で
このメソッドに関するドキュメントでは、スローされる可能性のあるいくつかの例外が報告されていますがInvalidCastException
、それらの 1 つではありません。つまり、Microsoft メソッドでは処理されません。.Net ソースを掘り下げ始めたところ、犯人が見つかったと思います。HttpWebResponse.EndGetResponseStream メソッドには、次の行があります。
throw (Exception) lazyAsyncResult.Result;
これが、このメソッドに存在する Exception への唯一のキャストであるため、これに違いありません。メソッドは、接続ストリームが null の場合にのみこの行に到達するように実装されているため、lazyasyncresult.Result
プロパティには例外が含まれている必要があります。ただし、私の場合、ブランチに到達しましたが、がlazyasyncresult.Result
含まれているHttpWebResponse
ため、ボクシングが失敗し、そのエラーが発生します。今、私は2つの考慮事項があります:
- の内容
lazyasyncresult.Result
が正しければ、とにかくスローされます (行がスローで始まるため) が、意味のあるエラーになります。 - 前のポイントに関連して、HttpWebResponse がある場合、スローするコード ブランチにとにかく到達するべきではないと思います
私の質問は非常に単純です。どうすればこれが起こらないようにできますか? コードで何か間違ったことをしているのですか、それとも MS メソッドの単純なバグですか?
参考までに、メソッドの MS ソースを以下に示します。非難された行にいくつかのコメントを追加しました。
お時間をいただきありがとうございます。
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;
}
}
}