2012-12-12 23 views
8

Bên trong Thư viện lớp di động, tôi có phương pháp sau đây đăng dữ liệu lên một Url cụ thể. Phương pháp này hoạt động rất tốt. Tuy nhiên tôi muốn chỉ định thời gian chờ tích cực hơn (mặc định là 100 giây).Cách xác định thời gian chờ tích cực hơn cho HttpWebRequest?

Xem xét không có thuộc tính Thời gian chờ trên lớp HttpWebRequest từ Thư viện lớp di động, làm cách nào để đảm bảo cuộc gọi bị hủy nếu mất hơn một vài giây?

public async Task<HttpResponse> PostAsync(Uri uri, string data) 
{ 
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); 
    request.Method = "POST"; 
    request.ContentType = "application/x-www-form-urlencoded"; 

    using (Stream requestStream = await request.GetRequestStreamAsync()) 
    { 
     byte[] postBytes = Encoding.UTF8.GetBytes(data); 
     requestStream.Write(postBytes, 0, postBytes.Length); 
    } 

    HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync(); 
    return new HttpResponse(response.StatusCode, await new StreamReader(response.GetResponseStream()).ReadToEndAsync()); 
} 
+0

HttpWebRequest.Timeout = 20000; ? điều này là đủ thông minh? –

Trả lời

20

Mã dưới đây hoặc sẽ trả về một HttpWebResponse hoặc null nếu hết thời gian chờ.

HttpWebResponse response = await TaskWithTimeout(request.GetResponseAsync(), 100); 
if(response != null) 
{ 
    .... 
} 

Task<HttpWebResponse> TaskWithTimeout(Task<WebResponse> task, int duration) 
{ 
    return Task.Factory.StartNew(() => 
    { 
     bool b = task.Wait(duration); 
     if (b) return (HttpWebResponse)task.Result; 
     return null; 
    }); 
} 

--EDIT--

Tạo một phương pháp mở rộng sẽ tốt hơn

public static class SOExtensions 
{ 
    public static Task<T> WithTimeout<T>(this Task<T> task, int duration) 
    { 
     return Task.Factory.StartNew(() => 
     { 
      bool b = task.Wait(duration); 
      if (b) return task.Result; 
      return default(T); 
     }); 
    } 
} 

Cách sử dụng sẽ là:

var response = (HttpWebResponse)await request.GetResponseAsync().WithTimeout(1000); 

--edit 2--

Một cách khác để làm việc đó

public async static Task<T> WithTimeout<T>(this Task<T> task, int duration) 
{ 
    var retTask = await Task.WhenAny(task, Task.Delay(duration)) 
          .ConfigureAwait(false); 

    if (retTask is Task<T>) return task.Result; 
    return default(T); 
} 
+0

Chà! Ý tưởng thú vị! Tôi thích nó vì nó thanh lịch và tương đối dễ hiểu. Nhưng tôi tự hỏi, nếu task.Wait là một hoạt động chặn (tức là một thread sẽ được giữ cho đến khi nó trả về). – Martin

+1

@Martin Có nó là một hoạt động chặn, nhưng nó được thực hiện trong một nhiệm vụ khác (xem: 'Task.Factory.StartNew') và sẽ không khác với việc gọi 'await request.GetResponseAsync()' –

+0

Tôi đồng ý! Nó chỉ là một chủ đề nữa trên ThreadPool. Tôi tự hỏi nếu chúng ta có thể làm cho nó không bị chặn. Chặn hay không, đây là một giải pháp rất thông minh. – Martin

0
// Abort the request if the timer fires. 
private static void TimeoutCallback(object state, bool timedOut) { 
    if (timedOut) { 
     HttpWebRequest request = state as HttpWebRequest; 
      if (request != null) { 
       request.Abort(); 
     } 
    } 
} 

Có nó là trách nhiệm của các ứng dụng client để thực hiện cơ chế time-out riêng của mình. Bạn có thể thực hiện điều này từ mã ở trên để đặt thời gian chờ và sử dụng phương thức ThreadPool.RegisterWaitForSingleObject. Xem http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort.aspx để biết chi tiết đầy đủ. Về cơ bản, nó bị hủy bỏ khỏi GetResponse, BeginGetResponse, EndGetResponse, GetRequestStream, BeginGetRequestStream hoặc EndGetRequestStream.

Các vấn đề liên quan