火,忘记使用WebClient设置timeout
本文关键字:WebClient 设置 timeout 忘记 | 更新日期: 2023-09-27 18:17:30
我有一个关于WebClient的问题,我希望有人能帮助我。我知道这个问题已经被问过几次了,但是我找不到一个好的答案。
我有两个不同的场景,我需要调用一个URL。a)我不需要URL的任何响应(Fire&Forget)。b) URL返回一个JSON,所以我需要等待处理在服务器上完成,以便获得我的数据。
我对a)有一些问题,我不知道我所做的是否有意义。为了实现Fire&Forget,我将WebClient超时设置为一个"小"数,500毫秒(代码如下)。我的问题是:
a)这是一个好方法还是毫无意义?b)等待500毫秒有意义吗?我能把超时设置为0吗?c)这种方法安全吗?我不关心处理完成需要多长时间,但我想确保能够启动web服务。下面的代码是否保证web服务将被触发,如果没有,我将得到一个异常,不是超时?
谢谢你!
public static void SubmitUrl(string url)
{
using (WebClient webClient = new WebClientEx(500))
{
try
{
Logger.Log(string.Format("Start Invoking URL: {0}", url));
var response = webClient.OpenRead(url);
response.Close();
Logger.Log(string.Format("End Invoking URL: {0}", url));
}
catch (System.Net.WebException ex)
{
if (ex.Status != WebExceptionStatus.Timeout)
{
Logger.Log(string.Format("Exception Invoking URL: {0} 'n {1}", url, ex.ToString()));
throw;
}
}
catch (System.Exception ex)
{
Logger.Log(string.Format("Exception Invoking URL: {0} 'n {1}", url, ex.ToString()));
throw;
}
}
}
public class WebClientEx : WebClient
{
// Timeout in milliseconds
public int timeout { get; set; }
public WebClientEx(int timeout)
: base()
{
this.timeout = timeout;
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest wr = base.GetWebRequest(address);
wr.Timeout = this.timeout;
return wr;
}
}
}
将WebClient调用放在不同的线程中,这样它就不会阻塞主应用程序流中的任何内容。在这种情况下,Logger必须是非常线程安全的。
public static void SubmitUrl(string url)
{
Task.Factory.StartNew(() => SubmitUrlPrivate(url));
}
private static void SubmitUrlPrivate(string url)
{
using (var webClient = new WebClient())
{
try
{
Logger.Log(string.Format("Start Invoking URL: {0}", url));
using (webClient.OpenRead(url))
{
Logger.Log(string.Format("End Invoking URL: {0}", url));
}
}
catch (WebException ex)
{
if (ex.Status != WebExceptionStatus.Timeout)
{
Logger.Log(string.Format("Exception Invoking URL: {0} 'n {1}", url, ex.ToString()));
throw;
}
}
catch (Exception ex)
{
Logger.Log(string.Format("Exception Invoking URL: {0} 'n {1}", url, ex.ToString()));
throw;
}
}
}
我建议您不要使用线程池线程来做io绑定的工作,因为根本没有必要,因为线程将花费大部分时间阻塞HTTP请求。
此外,在ASP中启动新线程。. NET不注册它们是危险的,可能会导致你的线程在应用程序池回收期间意外终止。
我建议你看看HttpClient
类和使用' async-await。
我还建议在大多数情况下不要使用fire and forget。如果请求失败或抛出异常会发生什么?难道不应该至少记录一下吗?
我会这样写:
private static async Task SubmitUrlAsync(string url)
{
try
{
var httpClient = new HttpClient();
Logger.Log(string.Format("Start Invoking URL: {0}", url));
await httpClient.GetAsync(url);
Logger.Log(string.Format("End Invoking URL: {0}", url));
}
catch (WebException ex)
{
if (ex.Status != WebExceptionStatus.Timeout)
{
Logger.Log(string.Format("Exception Invoking URL:
{0} 'n {1}", url, ex.ToString()));
throw;
}
}
catch (Exception ex)
{
Logger.Log(string.Format("Exception Invoking URL:
{0} 'n {1}", url, ex.ToString()));
throw;
}
}
await
关键字将使线程返回到线程池处理更多的请求,直到该方法完成,并且还将抛出任何异常到等待行。