[转载]WebClient的超时问题及解决
Webclient在下载请求时无法设置请求超时时间和请求读写超时时间。WebClient在异步下载时遇到网络不通等问题时没有响应超时造成app挂起。
1.Webclient请求超时设置
重写Webclient的GetWebRequest方法,为HttpWebRequest添加请求超时及读写超时
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.Timeout = 1000 * Timeout;
request.ReadWriteTimeout = 1000 * Timeout;
return request;
}
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.Timeout = 1000 * Timeout;
request.ReadWriteTimeout = 1000 * Timeout;
return request;
}
2.WebClient在异步下载
创建计时器监视响应情况,过期则取消下载
public class Calculagraph
{
/// <summary>
/// 时间到事件
/// </summary>
public event TimeoutCaller TimeOver;
/// <summary>
/// 开始时间
/// </summary>
private DateTime _startTime;
private TimeSpan _timeout = new TimeSpan(0, 0, 10);
private bool _hasStarted = false;
object _userdata;
/// <summary>
/// 计时器构造方法
/// </summary>
/// <param name="userdata">计时结束时回调的用户数据</param>
public Calculagraph(object userdata)
{
TimeOver += new TimeoutCaller(OnTimeOver);
_userdata = userdata;
}
/// <summary>
/// 超时退出
/// </summary>
/// <param name="userdata"></param>
public virtual void OnTimeOver(object userdata)
{
Stop();
}
/// <summary>
/// 过期时间(秒)
/// </summary>
public int Timeout
{
get
{
return _timeout.Seconds;
}
set
{
if (value <= 0)
return;
_timeout = new TimeSpan(0, 0, value);
}
}
/// <summary>
/// 是否已经开始计时
/// </summary>
public bool HasStarted
{
get
{
return _hasStarted;
}
}
/// <summary>
/// 开始计时
/// </summary>
public void Start()
{
Reset();
_hasStarted = true;
Thread th = new Thread(WaitCall);
th.IsBackground = true;
th.Start();
}
/// <summary>
/// 重置
/// </summary>
public void Reset()
{
_startTime = DateTime.Now;
}
/// <summary>
/// 停止计时
/// </summary>
public void Stop()
{
_hasStarted = false;
}
/// <summary>
/// 检查是否过期
/// </summary>
/// <returns></returns>
private bool checkTimeout()
{
return (DateTime.Now - _startTime).Seconds >= Timeout;
}
private void WaitCall()
{
try
{
//循环检测是否过期
while (_hasStarted && !checkTimeout())
{
Thread.Sleep(1000);
}
if (TimeOver != null)
TimeOver(_userdata);
}
catch (Exception)
{
Stop();
}
}
}
/// <summary>
/// 过期时回调委托
/// </summary>
/// <param name="userdata"></param>
public delegate void TimeoutCaller(object userdata);
{
/// <summary>
/// 时间到事件
/// </summary>
public event TimeoutCaller TimeOver;
/// <summary>
/// 开始时间
/// </summary>
private DateTime _startTime;
private TimeSpan _timeout = new TimeSpan(0, 0, 10);
private bool _hasStarted = false;
object _userdata;
/// <summary>
/// 计时器构造方法
/// </summary>
/// <param name="userdata">计时结束时回调的用户数据</param>
public Calculagraph(object userdata)
{
TimeOver += new TimeoutCaller(OnTimeOver);
_userdata = userdata;
}
/// <summary>
/// 超时退出
/// </summary>
/// <param name="userdata"></param>
public virtual void OnTimeOver(object userdata)
{
Stop();
}
/// <summary>
/// 过期时间(秒)
/// </summary>
public int Timeout
{
get
{
return _timeout.Seconds;
}
set
{
if (value <= 0)
return;
_timeout = new TimeSpan(0, 0, value);
}
}
/// <summary>
/// 是否已经开始计时
/// </summary>
public bool HasStarted
{
get
{
return _hasStarted;
}
}
/// <summary>
/// 开始计时
/// </summary>
public void Start()
{
Reset();
_hasStarted = true;
Thread th = new Thread(WaitCall);
th.IsBackground = true;
th.Start();
}
/// <summary>
/// 重置
/// </summary>
public void Reset()
{
_startTime = DateTime.Now;
}
/// <summary>
/// 停止计时
/// </summary>
public void Stop()
{
_hasStarted = false;
}
/// <summary>
/// 检查是否过期
/// </summary>
/// <returns></returns>
private bool checkTimeout()
{
return (DateTime.Now - _startTime).Seconds >= Timeout;
}
private void WaitCall()
{
try
{
//循环检测是否过期
while (_hasStarted && !checkTimeout())
{
Thread.Sleep(1000);
}
if (TimeOver != null)
TimeOver(_userdata);
}
catch (Exception)
{
Stop();
}
}
}
/// <summary>
/// 过期时回调委托
/// </summary>
/// <param name="userdata"></param>
public delegate void TimeoutCaller(object userdata);
public class CNNWebClient : WebClient
{
private Calculagraph _timer;
private int _timeOut = 10;
/// <summary>
/// 过期时间
/// </summary>
public int Timeout
{
get
{
return _timeOut;
}
set
{
if (value <= 0)
_timeOut = 10;
_timeOut = value;
}
}
/// <summary>
/// 重写GetWebRequest,添加WebRequest对象超时时间
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.Timeout = 1000 * Timeout;
request.ReadWriteTimeout = 1000 * Timeout;
return request;
}
/// <summary>
/// 带过期计时的下载
/// </summary>
public void DownloadFileAsyncWithTimeout(Uri address, string fileName, object userToken)
{
if (_timer == null)
{
_timer = new Calculagraph(this);
_timer.Timeout = Timeout;
_timer.TimeOver += new TimeoutCaller(_timer_TimeOver);
this.DownloadProgressChanged += new DownloadProgressChangedEventHandler(CNNWebClient_DownloadProgressChanged);
}
DownloadFileAsync(address, fileName, userToken);
_timer.Start();
}
/// <summary>
/// WebClient下载过程事件,接收到数据时引发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void CNNWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
_timer.Reset();//重置计时器
}
/// <summary>
/// 计时器过期
/// </summary>
/// <param name="userdata"></param>
void _timer_TimeOver(object userdata)
{
this.CancelAsync();//取消下载
}
}
{
private Calculagraph _timer;
private int _timeOut = 10;
/// <summary>
/// 过期时间
/// </summary>
public int Timeout
{
get
{
return _timeOut;
}
set
{
if (value <= 0)
_timeOut = 10;
_timeOut = value;
}
}
/// <summary>
/// 重写GetWebRequest,添加WebRequest对象超时时间
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.Timeout = 1000 * Timeout;
request.ReadWriteTimeout = 1000 * Timeout;
return request;
}
/// <summary>
/// 带过期计时的下载
/// </summary>
public void DownloadFileAsyncWithTimeout(Uri address, string fileName, object userToken)
{
if (_timer == null)
{
_timer = new Calculagraph(this);
_timer.Timeout = Timeout;
_timer.TimeOver += new TimeoutCaller(_timer_TimeOver);
this.DownloadProgressChanged += new DownloadProgressChangedEventHandler(CNNWebClient_DownloadProgressChanged);
}
DownloadFileAsync(address, fileName, userToken);
_timer.Start();
}
/// <summary>
/// WebClient下载过程事件,接收到数据时引发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void CNNWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
_timer.Reset();//重置计时器
}
/// <summary>
/// 计时器过期
/// </summary>
/// <param name="userdata"></param>
void _timer_TimeOver(object userdata)
{
this.CancelAsync();//取消下载
}
}
作者:陈 锋
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。