의 시간 제한을 변경하는 방법.NET WebClient 개체
클라이언트의 데이터를 로컬 컴퓨터에 (프로그램적으로) 다운로드하려고 하는데 웹 서버가 매우 느려서 시간이 초과되었습니다.WebClient
물건.
내 코드는 다음과 같습니다.
WebClient webClient = new WebClient();
webClient.Encoding = Encoding.UTF8;
webClient.DownloadFile(downloadUrl, downloadFile);
이 개체에 무한 제한 시간을 설정할 수 있는 방법이 있습니까?아니면 다른 방법으로 이 작업을 수행할 수 있는 예를 들어보겠습니다.
URL은 브라우저에서 잘 작동합니다. 표시하는 데 약 3분 정도 걸립니다.
시간 초과를 확장할 수 있습니다. 즉, 원래 WebClient 클래스를 상속하고 웹 요청 getter를 재정의하여 다음 예제와 같이 사용자 자신의 시간 초과를 설정할 수 있습니다.
My WebClient는 제 경우 개인 클래스였습니다.
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
대신 시간 초과를 설정할 수 있습니다.
비동기/작업 방법에 사용할 수 있는 시간 제한이 있는 WebClient가 필요한 사용자는 제안된 솔루션이 작동하지 않습니다.다음과 같은 기능을 제공합니다.
public class WebClientWithTimeout : WebClient
{
//10 secs default
public int Timeout { get; set; } = 10000;
//for sync requests
protected override WebRequest GetWebRequest(Uri uri)
{
var w = base.GetWebRequest(uri);
w.Timeout = Timeout; //10 seconds timeout
return w;
}
//the above will not work for async requests :(
//let's create a workaround by hiding the method
//and creating our own version of DownloadStringTaskAsync
public new async Task<string> DownloadStringTaskAsync(Uri address)
{
var t = base.DownloadStringTaskAsync(address);
if(await Task.WhenAny(t, Task.Delay(Timeout)) != t) //time out!
{
CancelAsync();
}
return await t;
}
}
여기에 대한 전체 해결 방법에 대해 블로그에 올렸습니다.
W를 가져올 수 없습니다.네트워크 케이블을 꺼냈을 때 작동할 시간 초과 코드입니다. 시간 초과가 아니라 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
Sohnee의 말처럼, 사용하고 설정합니다.Timeout
사용하는 대신 자산System.Net.WebClient
.
그러나 무한 제한 시간 값을 설정할 수는 없습니다(지원되지 않으며 이를 시도하면ArgumentOutOfRangeException
).
먼저 HEAD HTTP 요청을 수행하고 다음을 검토하는 것이 좋습니다.Content-Length
다운로드 중인 파일의 바이트 수를 결정하고 그에 따라 다음에 대한 시간 초과 값을 설정하기 위해 반환되는 헤더 값GET
요청하거나 단순히 초과하지 않을 것으로 예상되는 매우 긴 시간 제한 값을 지정합니다.
'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
용도:
using (var client = new TimeoutWebClient(TimeSpan.FromSeconds(10)))
{
return await client.DownloadStringTaskAsync(url).ConfigureAwait(false);
}
클래스:
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;
}
}
}
하지만 좀 더 현대적인 솔루션을 추천합니다.
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public static async Task<string> ReadGetRequestDataAsync(Uri uri, TimeSpan? timeout = null, CancellationToken cancellationToken = default)
{
using var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
if (timeout != null)
{
source.CancelAfter(timeout.Value);
}
using var client = new HttpClient();
using var response = await client.GetAsync(uri, source.Token).ConfigureAwait(false);
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
그것은 던져질 것입니다.OperationCanceledException
잠시 후에
저는 어제 이 문제로 싸워야 했고, 커스텀 익스텐션 클래스도 쓰게 되었습니다.
아래 코드를 보고 수락된 답변과 비교해 보면 알 수 있듯이, 좀 더 다재다능한 클래스를 갖기 위해 제안을 조금 더 수정하려고 했습니다. 이렇게 하면 개체를 인스턴스화할 때나 내부를 사용하는 메서드를 사용하기 직전에 정확한 시간 제한을 설정할 수 있습니다.WebRequest
핸들러
using System;
using System.Net;
namespace Ryadel.Components.Web
{
/// <summary>
/// An extension of the standard System.Net.WebClient
/// featuring a customizable constructor and [Timeout] property.
/// </summary>
public class RyadelWebClient : WebClient
{
/// <summary>
/// Default constructor (30000 ms timeout)
/// NOTE: timeout can be changed later on using the [Timeout] property.
/// </summary>
public RyadelWebClient() : this(30000) { }
/// <summary>
/// Constructor with customizable timeout
/// </summary>
/// <param name="timeout">
/// Web request timeout (in milliseconds)
/// </param>
public RyadelWebClient(int timeout)
{
Timeout = timeout;
}
#region Methods
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest w = base.GetWebRequest(uri);
w.Timeout = Timeout;
((HttpWebRequest)w).ReadWriteTimeout = Timeout;
return w;
}
#endregion
/// <summary>
/// Web request timeout (in milliseconds)
/// </summary>
public int Timeout { get; set; }
}
}
제가 그곳에 있는 동안, 저는 또한 기본값을 낮추는 기회를 잡았습니다.Timeout
에 가치를 두는.30
(초 로단위초로로 지정100
내겐 너무 과분해 보였습니다.
이 수업이나 사용법에 대한 추가 정보가 필요한 경우, 제가 블로그에 쓴 이 게시물을 확인하세요.
kisp 솔루션에 따르면 이것은 비동기식으로 작동하는 편집된 버전입니다.
클래스 WebConnection.cs
internal class WebConnection : WebClient
{
internal int Timeout { get; set; }
protected override WebRequest GetWebRequest(Uri Address)
{
WebRequest WebReq = base.GetWebRequest(Address);
WebReq.Timeout = Timeout * 1000 // Seconds
return WebReq;
}
}
비동기 작업
private async Task GetDataAsyncWithTimeout()
{
await Task.Run(() =>
{
using (WebConnection webClient = new WebConnection())
{
webClient.Timeout = 5; // Five seconds (the multiplication is in the override)
webClient.DownloadData("https://www.yourwebsite.com");
}
});
} // await GetDataAsyncWithTimeout()
또는 비동기를 사용하지 않으려면 다음을 수행합니다.
private void GetDataSyncWithTimeout()
{
using (WebConnection webClient = new WebConnection())
{
webClient.Timeout = 5; // Five seconds (the multiplication is in the override)
webClient.DownloadData("https://www.yourwebsite.com");
}
} // GetDataSyncWithTimeout()
경우에 따라 헤더에 사용자 에이전트를 추가해야 합니다.
WebClient myWebClient = new WebClient();
myWebClient.DownloadFile(myStringWebResource, fileName);
myWebClient.Headers["User-Agent"] = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
이것이 제 사건의 해결책이었습니다.
신용:
http://genjurosdojo.blogspot.com/2012/10/the-remote-server-returned-error-504.html
언급URL : https://stackoverflow.com/questions/1789627/how-to-change-the-timeout-on-a-net-webclient-object
'programing' 카테고리의 다른 글
npm 패키지의 로컬 설치를 위한 사용자 지정 위치를 설정하는 방법은 무엇입니까? (0) | 2023.05.09 |
---|---|
Swift를 사용하여 키보드로 보기 이동 (0) | 2023.05.04 |
Excel에서 UDF를 사용하여 워크시트 업데이트 (0) | 2023.05.04 |
Git 커밋을 아직 오리진에 푸시하지 않은 목록 (0) | 2023.05.04 |
Git remote에서 풀링할 때 원격 변경을 사용하여 충돌 해결 (0) | 2023.05.04 |