我对WebClient有疑问,我希望有人可以帮助我。我知道这个问题被问过几次,但我找不到一个好的答案。
我有两种不同的场景需要调用URL。 a)我不需要从URL(Fire& Forget)回复任何回复。 b)URL返回一个JSON,所以我需要等待在服务器上完成处理才能获取我的数据。
我有一些问题a)我不知道我所做的事情是否有意义。为了实现Fire& Forget,我将WebClient超时设置为“小”数,500毫秒(代码如下)。 我的问题是:
a)这是一个好方法还是毫无意义? b)等待500ms甚至有意义吗?我可以将超时设置为零吗? c)这种方法安全吗?我不关心处理完成所需的时间,但我想确保我能够启动Web服务。下面的代码是否保证将触发Web服务,如果没有,我将得到一个不是Timneout的异常?
非常感谢!
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;
}
}
}
答案 0 :(得分:3)
将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;
}
}
}
答案 1 :(得分:2)
我建议你再次使用线程池线程进行IO绑定工作,根本没有必要,因为线程将花费大部分时间来阻止http请求。
更重要的是,在没有注册yhem的情况下剥离ASP.NET中的新线程是危险的,并且可能导致您的线程在应用程序池回收期间意外终止。
我建议您查看HttpClient
类以及使用`async-await。
在大多数情况下,我还建议不再使用火灾并忘记。如果请求失败或抛出异常会发生什么?不应该至少记录下来吗?
我会选择这样的事情:
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
关键字将使线程返回到线程池以处理更多请求,直到方法完成,并且还将传播抛出到等待线路的任何异常。