我有一个尝试获取网页的方法。我想尝试多次,所以我在它周围构建了一个包装器来重试几次。在名为I catch的方法中,然后忽略返回null的异常。因此,在第一次尝试之后将发生重试。这是被调用的方法:
internal static async Task<string> WebClientAsync(string URI, NetworkCredential Creds = null, Dictionary.FantasySite Site = Dictionary.FantasySite.Other)
{
if (Creds == null)
{
try
{ //attempt to get the web page
HttpClient client = new HttpClient(); //create client
HttpResponseMessage response = await client.GetAsync(URI); //get response
response.EnsureSuccessStatusCode(); //ensure the response is good (or throw Exception)
return await response.Content.ReadAsStringAsync(); //return the string back
}
catch (HttpRequestException)
{
//MessageBox.Show(string.Format("\nHttpRequestException Caught!\nMessage :{0} for URI {1}.", e.Message, URI));
return null; //Catch the exception because we wrapped this and are trying again (null is the indicator it didn't work)
}
catch (Exception)
{
//MessageBox.Show(string.Format("\nException Caught!\nMessage :{0} for URI {1}.", e.Message, URI)); //TODO - THis hasn't happened, but remove it for production
return null; //Catch the exception because we wrapped this and are trying again (null is the indicator it didn't work)
}
}
}
如果在所有重试之后仍然失败,那么我想抛出异常,但是因为我扔了它,我不能。这是调用方法。
internal static async Task<string> WebClientRetryAsync(string URI, NetworkCredential Creds = null, Dictionary.FantasySite Site = Dictionary.FantasySite.Other)
{
string webPage = null;
for (int i = 0; i < Dictionary.WEB_PAGE_ATTEMPTS; i++) //Attempt to get the webpage x times
{
System.Diagnostics.Debug.Print(string.Format("WebClientRetryAsync attempt {0} for {1}", i + 1, URI));
//wait some time before retrying just in case we are too busy
//Start wait at 0 for first time and multiply with each successive failure to slow down process by multiplying by i squared
Thread.Sleep(Wait.Next(i * i * Dictionary.RETRY_WAIT_MS));
webPage = await WebClientAsync(URI, Creds, Site);
if (webPage != null) { break; } //don't attempt again if success
}
/*TODO - If webPage is null we didn't have success and need to throw an exception.
* This is done in the calls to this method and should be done here, move code over */
return webPage;
}
有人可以建议,如果这是一个糟糕的方法,我怎么能重构代码以在失败多次后抛出异常?我应该将异常传递给调用方法并在重试用完之前忽略它吗?
答案 0 :(得分:3)
烨。你不应该抛弃你想要重新抛出的异常。一种可能的方法如下(尝试对当前代码进行少量修改):
internal static async Task<string> WebClientAsync(string URI, NetworkCredential Creds = null, Dictionary.FantasySite Site = Dictionary.FantasySite.Other)
{
// If (Creds == null) removed, you must return a task or throw an exception.
//attempt to get the web page
HttpClient client = new HttpClient(); //create client
HttpResponseMessage response = await client.GetAsync(URI); //get response
response.EnsureSuccessStatusCode(); //ensure the response is good (or throw Exception)
return await response.Content.ReadAsStringAsync(); //return the string back
}
internal static async Task<string> WebClientRetryAsync(string URI, NetworkCredential Creds = null, Dictionary.FantasySite Site = Dictionary.FantasySite.Other)
{
// assumes you have .NET 4.5, otherwise save exception.
// uses System.Runtime.ExceptionServices;
ExceptionDispatchInfo exceptionDispatchInfo = null;
for (int i = 0; i < Dictionary.WEB_PAGE_ATTEMPTS; i++) //Attempt to get the webpage x times
{
System.Diagnostics.Debug.Print(string.Format("WebClientRetryAsync attempt {0} for {1}", i + 1, URI));
try
{
var webPage = await WebClientAsync(URI, Creds, Site);
return webPage;
}
catch (Exception ex)
{
// save exception so it can be rethrown.
exceptionDispatchInfo = ExceptionDispatchInfo.Capture(ex);
}
// Edit: also need to do an async wait (no thread.sleep):
if (i < Dictionary.WEB_PAGE_ATTEMPTS - 1)
{
//wait some time before retrying just in case we are too busy
//Start wait at 0 for first time and multiply with each successive failure to slow down process by multiplying by i squared
await Task.Delay(Wait.Next(i * i * Dictionary.RETRY_WAIT_MS));
}
}
Debug.Assert(exceptionDispatchInfo != null); // shouldn't be null if we get here.
exceptionDispatchInfo.Throw();
}