2013-08-30 1 views
2

웹 페이지를 가져 오는 메서드가 있습니다. 몇 번 시도해보고 싶기 때문에 여러 번 다시 시도하기 위해 래퍼를 만들었습니다. 메서드에서 catch하고 null을 반환하는 예외를 무시합니다. 따라서 첫 번째 시도 후에 재 시도가 발생합니다. 다음은 호출 방법 :호출 된 메서드에서 예외를 catch하고 무시하지만 호출자에서 throw해야합니다.

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) 
     } 
    } 

}

모든 시도가 나는 예외를 throw 할 후에이 계속 실패하면,하지만 난 그것을 멀리 던졌다 때문에, 나는 할 수 없습니다. 다음은 호출하는 메소드입니다.

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

당신은 WebClientAsync에서 반환되는 사용자 정의 클래스/구조체를 할 수 : 한 가지 가능한 방법은 (현재의 코드를 수정 최소한의를 만들기 위해 노력하고) 다음과 같다 예외 및 웹 페이지 문자열 – andrewb

답변

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(); 
} 
+0

에 감사드립니다. 나는이 수업을 몰랐다. 호출하는 메소드에서 사용자 정의 클래스에서 다시 호출하는 이유가 있습니까? – Harrison

+1

@Harrison 그렇습니다. 실제로 예외를 처리하거나 아무 것도하지 않는 코드가 없기 때문에 예외를 잡아서는 안됩니다. "재시도"기능에서 그들을 잡아서, 그들은 저장 될 수있다, 당신은 당신이 재 시도 할 필요가있다 알고있다. 일반 조언 : 당신이 그들에게 행동하지 않으면 예외를 잡으려고하지 마십시오. – Alex

+0

그건 의미가 있습니다. 다시 한번 감사드립니다. 좋은 해결책 인 것 같습니다. – Harrison

관련 문제