クライアントのデータをローカルマシンに(プログラムで)ダウンロードしようとしていますが、Webサーバーが非常に遅いため、WebClient
オブジェクトでタイムアウトが発生しています。
ここに私のコードがあります:
WebClient webClient = new WebClient();
webClient.Encoding = Encoding.UTF8;
webClient.DownloadFile(downloadUrl, downloadFile);
このオブジェクトに無限のタイムアウトを設定する方法はありますか?または、そうでない場合、誰かがこれを行う別の方法の例で私を助けることができますか?
ブラウザでURLは正常に機能します-表示するのに約3分かかります。
次の例のように、タイムアウトを延長できます。元のWebClientクラスを継承し、webrequestゲッターをオーバーライドして独自のタイムアウトを設定します。
私の場合、MyWebClientはプライベートクラスでした。
private class MyWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest w = base.GetWebRequest(uri);
w.Timeout = 20 * 60 * 1000;
return w;
}
}
最初の解決策は私にとってはうまくいきませんでしたが、私にとってはうまくいくコードがいくつかあります。
private class WebClient : System.Net.WebClient
{
public int Timeout { get; set; }
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest lWebRequest = base.GetWebRequest(uri);
lWebRequest.Timeout = Timeout;
((HttpWebRequest)lWebRequest).ReadWriteTimeout = Timeout;
return lWebRequest;
}
}
private string GetRequest(string aURL)
{
using (var lWebClient = new WebClient())
{
lWebClient.Timeout = 600 * 60 * 1000;
return lWebClient.DownloadString(aURL);
}
}
HttpWebRequest
ではなくWebClient
を使用する必要がありますが、WebClient
にタイムアウトを設定することはできません(HttpWebRequest
を使用している場合でも)。代わりにHttpWebRequest
を使用すると、タイムアウトを設定できます。
ネットワークケーブルを抜いたときにw.Timeoutコードを取得できませんでした。タイムアウトしなかったため、HttpWebRequestを使用するようになりました。
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(downloadUrl);
request.Timeout = 10000;
request.ReadWriteTimeout = 10000;
var wresp = (HttpWebResponse)request.GetResponse();
using (Stream file = File.OpenWrite(downloadFile))
{
wresp.GetResponseStream().CopyTo(file);
}
完全を期すために、ここにkispのソリューションをVBに移植しました(コードをコメントに追加できません)
Namespace Utils
''' <summary>
''' Subclass of WebClient to provide access to the timeout property
''' </summary>
Public Class WebClient
Inherits System.Net.WebClient
Private _TimeoutMS As Integer = 0
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal TimeoutMS As Integer)
MyBase.New()
_TimeoutMS = TimeoutMS
End Sub
''' <summary>
''' Set the web call timeout in Milliseconds
''' </summary>
''' <value></value>
Public WriteOnly Property setTimeout() As Integer
Set(ByVal value As Integer)
_TimeoutMS = value
End Set
End Property
Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
Dim w As System.Net.WebRequest = MyBase.GetWebRequest(address)
If _TimeoutMS <> 0 Then
w.Timeout = _TimeoutMS
End If
Return w
End Function
End Class
End Namespace
'CORRECTED VERSION OF LAST FUNCTION IN VISUAL BASIC BY GLENNG
Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
Dim w As System.Net.WebRequest = MyBase.GetWebRequest(address)
If _TimeoutMS <> 0 Then
w.Timeout = _TimeoutMS
End If
Return w '<<< NOTICE: MyBase.GetWebRequest(address) DOES NOT WORK >>>
End Function
Sohneeが言うように、 System.Net.HttpWebRequest
を使用して、System.Net.WebClient
を使用する代わりにTimeout
プロパティを設定します。
ただし、無限のタイムアウト値を設定することはできません(サポートされていないため、そうしようとするとArgumentOutOfRangeException
がスローされます)。
最初に HEAD HTTP リクエストを実行し、返されたContent-Length
ヘッダー値を調べてダウンロードしているファイルのバイト数を判断し、その後のGET
リクエストまたは単にリクエストのタイムアウト値を設定することをお勧めします超過するとは思わない非常に長いタイムアウト値を指定します。
使用法:
using (var client = new TimeoutWebClient(TimeSpan.FromSeconds(10)))
{
return await client.DownloadStringTaskAsync(url);
}
クラス:
using System;
using System.Net;
namespace Utilities
{
public class TimeoutWebClient : WebClient
{
public TimeSpan Timeout { get; set; }
public TimeoutWebClient(TimeSpan timeout)
{
Timeout = timeout;
}
protected override WebRequest GetWebRequest(Uri uri)
{
var request = base.GetWebRequest(uri);
if (request == null)
{
return null;
}
var timeoutInMilliseconds = (int) Timeout.TotalMilliseconds;
request.Timeout = timeoutInMilliseconds;
if (request is HttpWebRequest httpWebRequest)
{
httpWebRequest.ReadWriteTimeout = timeoutInMilliseconds;
}
return request;
}
}
}