ここでの考え方は単純ですが、実装にはいくつかの興味深いニュアンスがあります。これは、 .NET 4で実装したい拡張メソッドのシグネチャです。
public static Task<WebResponse> GetResponseAsync(this WebRequest request, CancellationToken token);
これが私の最初の実装です。私が読んだことから、タイムアウトのために Web リクエストをキャンセルする必要があるかもしれません。request.Abort()
そのページに書いてあるサポートに加えて、キャンセルの場合はちゃんと電話したいCancellationToken
。
public static Task<WebResponse> GetResponseAsync(this WebRequest request, CancellationToken token)
{
if (request == null)
throw new ArgumentNullException("request");
return Task.Factory.FromAsync<WebRequest, CancellationToken, WebResponse>(BeginGetResponse, request.EndGetResponse, request, token, null);
}
private static IAsyncResult BeginGetResponse(WebRequest request, CancellationToken token, AsyncCallback callback, object state)
{
IAsyncResult asyncResult = request.BeginGetResponse(callback, state);
if (!asyncResult.IsCompleted)
{
if (request.Timeout != Timeout.Infinite)
ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, WebRequestTimeoutCallback, request, request.Timeout, true);
if (token != CancellationToken.None)
ThreadPool.RegisterWaitForSingleObject(token.WaitHandle, WebRequestCancelledCallback, Tuple.Create(request, token), Timeout.Infinite, true);
}
return asyncResult;
}
private static void WebRequestTimeoutCallback(object state, bool timedOut)
{
if (timedOut)
{
WebRequest request = state as WebRequest;
if (request != null)
request.Abort();
}
}
private static void WebRequestCancelledCallback(object state, bool timedOut)
{
Tuple<WebRequest, CancellationToken> data = state as Tuple<WebRequest, CancellationToken>;
if (data != null && data.Item2.IsCancellationRequested)
{
data.Item1.Abort();
}
}
私の質問は単純ですが挑戦的です。この実装を TPL と共に使用した場合、実際に期待どおりに動作しますか?