2012-12-12 18 views
8

ポータブルクラスライブラリの中で、私は特定のURLにデータを投稿する以下のメソッドを持っています。このメソッドは素晴らしいです。しかし、より積極的なタイムアウト(デフォルトは100秒)を指定したいと思います。HttpWebRequestのより積極的なタイムアウトを定義する方法は?

ポータブルクラスライブラリのHttpWebRequestクラスにタイムアウトプロパティがないことを考慮して、数秒以上かかると呼び出しが放棄されるようにするにはどうすればよいですか?

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; ?これは十分にスマートですか? –

答えて

20

タイムアウトした場合のいずれかHttpWebResponseのはnullを返します。

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--

でも良いだろう拡張メソッドを作成

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); 
     }); 
    } 
} 

使い方は次のようになります。

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

--edit 2--

それを行う別の方法

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

うわー!興味深いアイデア!私はそれがエレガントで比較的理解しやすいので好きです。しかし、私はtask.Waitがブロック操作であるかどうか疑問に思います(つまり、スレッドが復帰するまでスレッドが保留になる)。 – Martin

+1

@Martinはい、それはブロック操作ですが、それは別のタスクで実行される(参照: 'Task.Factory.StartNew')と'待つrequest.GetResponseAsync()私は同意 ' –

+0

を呼び出すと異なることがありません!これは、ThreadPool上のもう1つのスレッドです。私たちがそれをノンブロッキングにすることができるのだろうかと思います。ブロッキングであろうとなかろうと、これは非常に巧妙な解決策です。 – 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(); 
     } 
    } 
} 

はい、それ自身のタイムアウトメカニズムを実装するためのクライアントアプリケーションの責任です。上記のコードからタイムアウトを設定し、ThreadPool.RegisterWaitForSingleObjectメソッドを使用します。詳細については、http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort.aspxを参照してください。本質的に、GetResponse、BeginGetResponse、EndGetResponse、GetRequestStream、BeginGetRequestStream、またはEndGetRequestStreamから中止します。

コードの下
関連する問題