2016-04-16 52 views
1

HttpWebRequest.Timeoutの処理方法がわかりません。以前は、ソケットオブジェクトのタイムアウトを設定していましたが、これは簡単です。タイムアウトは、データのチャンクを送受信する最大時間を設定します。しかし、HttpWebRequest.TimeoutはHTTPリクエスト全体のタイムアウトを設定しているようです。要求が大きい場合(たとえば、HTTP PUTを使用して大きなファイルをアップロードしている場合など)には、数時間かかることがあります。これは、設定に私をリード:C#で大量のHTTPリクエストをHttpWebRequest.Timeoutに設定する方法

... 
request.Timeout = System.Threading.Timeout.Infinite; 
Stream requestStream = request.GetRequestStream(); 
for (something) 
{ 
    ... 
    requestStream.Write(b, 0, b.Length); 
} 

しかし、これは、サーバーとのネットワーク接続が立ち往生場合という意味ではありません、私はrequestStream.Writeは、「操作がタイムアウトした」例外をスローすることはありませんになってしまいますか?この場合、タイムアウトの概念は機能しません。

理想的には、.Timeout設定は1つのrequestStream.Writeにのみ影響します。それぞれが.Timeout値を超えることはないという条件で、必要なだけ多くのWrite()を持つことができます。

または、これを達成するために独自のソケットベースのメカニズムを実装する必要がありますか?

また、ブレークポイントを設定すると、requestStreamは実際には.Timeout = 300000(300秒)のConnectStreamインスタンスであることがわかりました。これは、Infiniteが実際に無限で300秒に制限されているわけではありませんか?ファイルが大きく、接続が遅い場合はかなり厳しい制限です。

答えて

2

を継承する独自のクラスを作成することです。 HttpWebRequest.TimeoutおよびHttpWebRequest.ReadWriteTimeoutの両方をとする必要があります。

HttpWebRequest.ReadWriteTimeout

まずは、HttpWebRequest.ReadWriteTimeoutに対処しましょう。 「ストリームバッファリングを無効にする」必要があります。この設定で

httpRequest.AllowWriteStreamBuffering = false; 

あなたは、あなたが(5分)既定値でそれらを残したり、それらを減らすことができますし、それらを希望としてあなたHttpWebRequest.ReadWriteTimeout値が魔法のように動作しますが、変更しました。私は60秒を使う。

この問題は、大きなファイルをアップロードするときに、.NETフレームワークによってデータがバッファされている場合、コードがアップロードが完了していないと判断し、HttpWebRequest.GetResponse()を呼び出す時間が早すぎるために発生します。

HttpWebRequest.Timeout

さて、HttpWebRequest.Timeoutに対処しましょう。

HttpWebRequest.Timeoutがアップロード全体に適用されるため、2番目の問題が発生します。 開始アップロードに

  1. 要求:アップロード・プロセスは、実際には3つのステップ(here's a great article that was my primary reference)から構成されています。
  2. バイトの書き込み。
  3. へのリクエストアップロードとサーバーからの応答を取得します。

アップロード全体に適用されるタイムアウトが1つの場合は、大きなファイルをアップロードするために大きな番号が必要ですが、タイムアウトが実際にタイムアウトするまでに時間がかかるという問題もあります。これは良い状況ではありません。代わりに、ステップ#1とステップ#3に適用するために短い時間(例えば30秒)が必要です。私たちは#2で全面的なタイムアウトを望んでいませんが、一定の期間バイトが書き込まれなくなると、アップロードが失敗することがあります。ありがたいことに、我々は既にHttpWebRequest.ReadWriteTimeoutで#2を扱っていますが、ちょうどHttpWebRequest.Timeoutの厄介な振る舞いを修正する必要があります。 GetRequestStreamGetResponseの非同期バージョンは、われわれが必要としているものとまったく同じものであることが判明しました。

ですから、このコードをしたい:

public static class AsyncExtensions 
{ 
    public static Task<T> WithTimeout<T>(this Task<T> task, TimeSpan timeout) 
    { 
     return Task.Factory.StartNew(() => 
     { 
      var b = task.Wait((int)timeout.TotalMilliseconds); 
      if (b) return task.Result; 
      throw new WebException("The operation has timed out", WebExceptionStatus.Timeout); 
     }); 
    } 
} 

、代わりのGetRequestStreamGetResponseを呼び出して、我々は非同期バージョンを呼び出します:応答のための

var uploadStream = httpRequest.GetRequestStreamAsync().WithTimeout(TimeSpan.FromSeconds(30)).Result; 

と同様:

var response = (HttpWebResponse)httpRequest.GetResponseAsync().WithTimeout(TimeSpan.FromSeconds(30)).Result; 

これですべてが必要です。今あなたのアップロードははるかに信頼性が高くなります。追加の確実性のために、アップロード全体を再試行ループでラップするかもしれません。

0

最も簡単な方法は、大きなファイルのアップロードを処理する際に、私たちを悩ませて2つのタイムアウトがありますWebRequestクラス

public class MyRequest : WebRequest 
    { 
     public MyRequest() 
     { 
      this.Timeout = 1234; 
     } 
    } 
+0

ありがとうございます。しかし、私はまだそれがどのように役立つのか分かりません。今のところ、.NET CLRには、HttpWebRequest.ReadWriteTimeoutとStreamを作るhttp://stackoverflow.com/questions/2679192/httpwebrequest-readwritetimeout-ignored-in-net-works-in-monoのバグがあるようです。 WriteTimeoutは役に立たない。あなたのソリューションはこれをどのように克服するのに役立ちますか? – Alex

+0

マネージャーC#では、これらのプロパティにアクセスすることはできません。 MyRequestを使用して、コードをクラスに追加します。それほど難しくありません。 – jdweng

+0

私はHttpWebRequest.Timeoutを設定することができます。子孫クラスで同じプロパティを直接設定する目的は何ですか?効果はどのように違うでしょうか? – Alex

関連する問題