Ý tưởng ở đây rất đơn giản, nhưng việc triển khai có một số sắc thái thú vị. Đây là chữ ký của phương pháp mở rộng mà tôi muốn triển khai trong .NET 4.Phương thức mở rộng triển khai WebRequest.GetResponseAsync với sự hỗ trợ cho CancellationToken
public static Task<WebResponse> GetResponseAsync(this WebRequest request, CancellationToken token);
Đây là triển khai ban đầu của tôi. Từ những gì tôi đã đọc, yêu cầu web có thể cần phải là cancelled due to a timeout. Ngoài hỗ trợ được mô tả trên trang đó, tôi muốn gọi đúng số request.Abort()
nếu yêu cầu hủy qua 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();
}
}
Câu hỏi của tôi đơn giản nhưng đầy thử thách. Việc triển khai này có thực sự hoạt động như mong đợi khi được sử dụng với TPL không?
@ 280Z28 Thank - Tôi viết này mà không có VS, như vậy có thể không thực sự kiểm tra nó tất cả;) –
@ 280Z28 Yeah - Như tôi đã couldn'te kiểm tra nó, tôi đã không nhận ra rằng 'Abort' sẽ vẫn kích hoạt gọi lại (có nghĩa là nó làm). Điều đó sẽ chỉ khiến cho hành vi trở nên hơi lệch, nhưng vẫn hoạt động. (Bạn sẽ nhận được một WebException thay vì hủy bỏ thích hợp). –
Tôi đã chỉnh sửa bài đăng của bạn thành 1) mô tả đúng 2 lỗi chính trong câu hỏi ban đầu của tôi (bao gồm 1 lỗi mới), 2) chứa mã làm việc mới nhất và 3) chứa lớp kiểm tra cho thấy hành vi phù hợp trong trường hợp thành công và 3 trường hợp lỗi (hủy, hết thời gian chờ và lỗi 404). –