2011-09-10 48 views
0

我之前问过这个问题,但我要用提出的解决方案来完成问题,并提出另一个问题。在异步请求中使用超时回调

我使用这个类进行异步WebRequest

class HttpSocket 
{ 
    public static void MakeRequest(Uri uri, Action<RequestCallbackState> responseCallback) 
    { 
     WebRequest request = WebRequest.Create(uri); 
     request.Proxy = null; 

     Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null); 
     ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, 1000, true); 
     asyncTask.ContinueWith(task => 
      { 
       WebResponse response = task.Result; 
       Stream responseStream = response.GetResponseStream(); 
       responseCallback(new RequestCallbackState(response.GetResponseStream())); 
       responseStream.Close(); 
       response.Close(); 
      }); 
    } 

    private static void TimeoutCallback(object state, bool timedOut) 
    { 
     Console.WriteLine("Timeout: " + timedOut); 
     if (timedOut) 
     { 
      Console.WriteLine("Timeout"); 
      WebRequest request = (WebRequest)state; 
      if (state != null) 
      { 
       request.Abort(); 
      } 
     } 
    } 
} 

而且我这个代码测试的类:

class Program 
{ 
    static void Main(string[] args) 
    { 
     // Making a request to a nonexistent domain. 
     HttpSocket.MakeRequest(new Uri("http://www.google.comhklhlñ"), callbackState => 
      { 
       if (callbackState.Exception != null) 
        throw callbackState.Exception; 
       Console.WriteLine(GetResponseText(callbackState.ResponseStream)); 
      }); 
     Thread.Sleep(100000); 
    } 

    public static string GetResponseText(Stream responseStream) 
    { 
     using (var reader = new StreamReader(responseStream)) 
     { 
      return reader.ReadToEnd(); 
     } 
    } 
} 

一旦执行,则立即进入回调,显示“Timeout:false”并且没有更多的throws,所以超时不起作用。

这是在original thread中提出的解决方案,但正如您所看到的,代码适用于他。

我在做什么错了?

编辑:

class RequestCallbackState 
{ 
    public Stream ResponseStream { get; private set; } 
    public Exception Exception { get; private set; } 

    public RequestCallbackState(Stream responseStream) 
    { 
     ResponseStream = responseStream; 
    } 

    public RequestCallbackState(Exception exception) 
    { 
     Exception = exception; 
    } 
} 

class RequestState 
{ 
    public byte[] RequestBytes { get; set; } 
    public WebRequest Request { get; set; } 
    public Action<RequestCallbackState> ResponseCallback { get; set; } 
} 
+0

什么是RequestCallbackState? – BrokenGlass

+0

如果使用false调用回调,它应该表示该对象被发送信号。 –

+0

@BrokenGlass谢谢你的回答。我将这些类添加到了帖子 –

回答

6

此方法有效。我建议将其切换为显式处理异常(包括超时,但也包括错误的域名等),稍有不同。在这种情况下,我将它分解为一个单独的延续。

此外,为了使这个非常明确的,我已经缩短超时时间,放在一个“真实”的,但缓慢的领域,以及增加了一个明确的超时状态,你可以看到:

using System; 
using System.IO; 
using System.Net; 
using System.Threading; 
using System.Threading.Tasks; 

class HttpSocket 
{ 
    private const int TimeoutLength = 100; 

    public static void MakeRequest(Uri uri, Action<RequestCallbackState> responseCallback) 
    { 
     WebRequest request = WebRequest.Create(uri); 
     request.Proxy = null; 

     Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null); 
     ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, TimeoutLength, true); 
     asyncTask.ContinueWith(task => 
      { 
       WebResponse response = task.Result; 
       Stream responseStream = response.GetResponseStream(); 
       responseCallback(new RequestCallbackState(response.GetResponseStream())); 
       responseStream.Close(); 
       response.Close(); 
      }, TaskContinuationOptions.NotOnFaulted); 
     // Handle errors 
     asyncTask.ContinueWith(task => 
      { 
       var exception = task.Exception; 
       var webException = exception.InnerException; 

       // Track whether you cancelled or not... up to you... 
       responseCallback(new RequestCallbackState(exception.InnerException, webException.Message.Contains("The request was canceled."))); 
      }, TaskContinuationOptions.OnlyOnFaulted); 
    } 

    private static void TimeoutCallback(object state, bool timedOut) 
    { 
     Console.WriteLine("Timeout: " + timedOut); 
     if (timedOut) 
     { 
      Console.WriteLine("Timeout"); 
      WebRequest request = (WebRequest)state; 
      if (state != null) 
      { 
       request.Abort(); 
      } 
     } 
    } 
} 

class RequestCallbackState 
{ 
    public Stream ResponseStream { get; private set; } 
    public Exception Exception { get; private set; } 

    public bool RequestTimedOut { get; private set; } 

    public RequestCallbackState(Stream responseStream) 
    { 
     ResponseStream = responseStream; 
    } 

    public RequestCallbackState(Exception exception, bool timedOut = false) 
    { 
     Exception = exception; 
     RequestTimedOut = timedOut; 
    } 
} 

class RequestState 
{ 
    public byte[] RequestBytes { get; set; } 
    public WebRequest Request { get; set; } 
    public Action<RequestCallbackState> ResponseCallback { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     // Making a request to a nonexistent domain. 
     HttpSocket.MakeRequest(new Uri("http://www.tanzaniatouristboard.com/"), callbackState => 
      { 
       if (callbackState.RequestTimedOut) 
       { 
        Console.WriteLine("Timed out!"); 
       } 
       else if (callbackState.Exception != null) 
        throw callbackState.Exception; 
       else 
        Console.WriteLine(GetResponseText(callbackState.ResponseStream)); 
      }); 
     Thread.Sleep(100000); 
    } 

    public static string GetResponseText(Stream responseStream) 
    { 
     using (var reader = new StreamReader(responseStream)) 
     { 
      return reader.ReadToEnd(); 
     } 
    } 
} 

这将运行,并适当显示超时。

+0

非常感谢。现在所有的工作都很好;) –

1

使用2个不同类别:通过代码中使用其他类

class RequestCallbackException : Exception 
{ 
    public RequestCallbackException(Stream responseStream, Exception exception) : base(exception) 
    { 
    } 
} 

class RequestCallbackStream 
{ 
    public Stream ResponseStream { get; private set; } 

    public RequestCallbackState(Stream responseStream) 
    { 
     ResponseStream = responseStream; 
    } 
} 

你会发现,有时候的GetResponseStream()返回null ,立即引发例外

asyncTask.ContinueWith() --> 

GetResponseText(callbackState.ResponseStream)--> 

using (var reader = new StreamReader(responseStream)) // responseStream is null 
{ 
} 
+0

我应该在哪里放置异常回调?无论如何,这不是超时问题的解决方案,对吧? –