Sto sviluppando un'applicazione WPF 4.0 in cui otteniamo i dati da un servizio Web remoto. Il servizio web espone circa 120 metodi ai suoi clienti. Se una chiamata al servizio web dalla mia applicazione WPF fallisce, ho bisogno di riprovare n volte che è configurabile tramite App.Config. Come implementarlo? Ci sono schemi di progettazione che affrontano questo problema?Come implementare di nuovo n volte in caso di eccezione in C#?
risposta
static T TryNTimes<T>(Func<T> func, int times)
{
while (times>0)
{
try
{
return func();
}
catch(Exception e)
{
if (--times <= 0)
throw;
}
}
}
Dovrebbe essere chiamato TryNTimes, non ExecuteNTimes. –
Dovrebbe, lo modificherò. Grazie. –
Ho scritto questo codice non molto tempo fa per fare qualcosa di simile a quello che vuoi. Può essere modificato per adattarsi alle tue esigenze. È un metodo di attesa generico. Passare una funzione e se il risultato atteso non viene restituito, attendere quindi riprovare e uscire dopo il numero X di tentativi.
/// <summary>
/// Wait for the result of func to return the expeceted result
/// </summary>
/// <param name="func">Function to execute each cycle</param>
/// <param name="result">Desired result returned by func</param>
/// <param name="waitInterval">How long to wait (ms) per cycle </param>
/// <param name="cycles">How many times to execute func before failing</param>
/// <returns>True if desired result was attained. False if specified time runs out before desired result is returned by func</returns>
protected static bool WaitForEvent(Func<bool> func, bool result, int waitInterval, int cycles)
{
int waitCount = 0;
while (func() != result)
{
if (waitCount++ < cycles)
{
Thread.Sleep(waitInterval);
}
else
{
return false;
}
}
return true;
}
Stava per scrivere la stessa cosa. Ben fatto :-) –
Potrebbe essere una buona idea aumentare l'intervallo di attesa ad ogni tentativo. – CodesInChaos
thats if (waitCount ++
while(retries < maxTries)
try
{
//retryable code here
break;
}
catch(Exception ex)
{
if(++retries == maxTries)
throw;
continue;
}
Certamente niente di particolare, ma sarà ottenere il lavoro fatto. Il modello principale, che sarebbe comune a quasi tutte le implementazioni, è un costrutto di loop che contiene e in qualche modo controllato da un try-catch; che può essere una chiamata ricorsiva o un loop iterativo come il ciclo while sopra. Assicurati di uscire correttamente dal ciclo dopo un tentativo riuscito e tieni traccia dei tentativi; l'incapacità di fare causa causerà un ciclo infinito.
E se lo inserisce in una funzione, ha un punto centrale per le chiamate al metodo 120+. –
L'intervallo di attesa non sembra definito – NotMe
L'attesa non è sempre necessaria; dipende da cosa esattamente stai cercando di fare nel blocco try. Se è necessario accertarsi che un computer remoto abbia completato la pulizia dopo un tentativo fallito, attendere con ogni mezzo. Tuttavia, ThreadSleep() deve essere utilizzato con attenzione o causerà l'interruzione della risposta dell'app; che allarga la portata di ciò che devi fare per implementare qualcosa di simile in modo pulito. – KeithS
while(true)
{
try
{
Method();
break;
}
catch(Exception ex)
{
i++;
if(i == n) throw ex;
}
}
Ecco un codice simile che avvolge IO violazione di condivisione. E 'la stessa idea: abbiamo un delegato e un metodo statico involucro:
/// <summary>
/// Defines a sharing violation wrapper delegate.
/// </summary>
public delegate void WrapSharingViolationsCallback();
/// <summary>
/// Wraps sharing violations that could occur on a file IO operation.
/// </summary>
/// <param name="action">The action to execute. May not be null.</param>
/// <param name="exceptionsCallback">The exceptions callback. May be null.</param>
/// <param name="retryCount">The retry count.</param>
/// <param name="waitTime">The wait time in milliseconds.</param>
public static void WrapSharingViolations(WrapSharingViolationsCallback action, WrapSharingViolationsExceptionsCallback exceptionsCallback, int retryCount, int waitTime)
{
if (action == null)
throw new ArgumentNullException("action");
for (int i = 0; i < retryCount; i++)
{
try
{
action();
return;
}
catch (IOException ioe)
{
if ((IsSharingViolation(ioe)) && (i < (retryCount - 1)))
{
bool wait = true;
if (exceptionsCallback != null)
{
wait = exceptionsCallback(ioe, i, retryCount, waitTime);
}
if (wait)
{
Thread.Sleep(waitTime);
}
}
else
{
throw;
}
}
}
}
E poi, noi lo chiamiamo in questo modo (si adatta espressione lambda perfettamente qui):
WrapSharingViolations(() => DoWhatever(...));
è possibile utilizzare una funzionalità approccio a questo:
class Program
{
static T Retry<T, TException>(Func<T> thingToTry, int timesToRetry)
where TException : Exception
{
// Start at 1 instead of 0 to allow for final attempt
for (int i = 1; i < timesToRetry; i++)
{
try
{
return thingToTry();
}
catch (TException)
{
// Maybe: Trace.WriteLine("Failed attempt...");
}
}
return thingToTry(); // Final attempt, let exception bubble up
}
static int ServiceCall()
{
if (DateTime.Now.Ticks % 2 == 0)
{
throw new InvalidOperationException("Randomly not working");
}
return DateTime.Now.Second;
}
static void Main()
{
int s = Retry<int, InvalidOperationException>(ServiceCall, 10);
}
}
È possibile utilizzarlo per rilevare eccezioni specifiche (aggiungere ulteriori parametri generici TException se necessario).
Perché utilizzare ricorsivo? Ci saranno problemi di prestazioni e di memoria, per non menzionare (come hai sottolineato) una possibilità di overflow dello stack. Buona prova, ma pessimo design IMO. –
Buon punto. Ultimamente sto facendo troppa codifica funzionale. Fisso. –
Sebbene sia necessario riprovare molto prima che si verifichino problemi di prestazioni e memoria. –
Potreste essere in grado di fare questo con un GOTO
(gasp)
int count = 0;
try
{
TryAgain:
// Do something with your web service
}
catch(Exception e)
{
if(count < numberOfAttemptsAllowed)
{
count++;
goto TryAgain;
}
}
Sono sicuro che ci potrebbe essere un modo migliore, ma questo potrebbe fare quello che ti serve.
- 1. C# in caso di eccezione
- 2. Ciclo senza confronto n volte in C
- 3. Java vs Objective C in caso di eccezione nullpointer
- 4. Prevent Task.ContinueWith in caso di eccezione
- 5. Eccezione nel caso di Overriding
- 6. Come implementare eccezione concatenamento in PHP
- 7. eccezione di registrazione in C#
- 8. Come implementare la relazione n: m in Java?
- 9. Nuovo thread più volte
- 10. Ripetere la creazione n volte in Jenkins
- 11. Avvia una shell IPython in caso di eccezione
- 12. eccezione di lancio dal costruttore in C++
- 13. Ho davvero bisogno di implementare iteratore in quel caso?
- 14. Il client Jersey chiude la connessione in caso di eccezione?
- 15. GetPrintJobInfoCollection() Eccezione a volte
- 16. Generazione di numeri casuali da -n a n in C
- 17. Posso dire la dimensione di una matrice creata con "nuovo tipo [n]" in C++?
- 18. Come implementare la funzione di "ottimizzazione" di R in C++?
- 19. Avvertimento in caso di perdita di dati C++/C
- 20. Come per ripetere una serie n-volte in Google SpreadSheet
- 21. Come implementare la funzionalità di Excel Solver in C#?
- 22. Riprovare un'attività più volte in base all'input dell'utente in caso di un'eccezione nell'attività
- 23. Come implementare il pattern Observer in C++
- 24. Come implementare la trasmissione di video in diretta in C#?
- 25. Come implementare la serializzazione in C++
- 26. eccezione aritmetica in C#
- 27. MATLAB: duplicazione vettore 'n' volte
- 28. Creazione di nuova eccezione in C++
- 29. Come implementare una matrice enorme in C
- 30. Ignora eccezione in C#
Si noti che questo modello non si integra bene con se stesso. Se una funzione che tenta quattro volte chiama una funzione che tenta quattro volte, e che chiama una funzione che prova quattro volte, allora l'ultima operazione viene ripetuta 64 volte. Se attende 30 secondi tra i tentativi, l'utente rimane lì per mezz'ora in attesa del messaggio di errore. Consiglio vivamente contro questo modello. Quando qualcosa non va a buon fine, fermati * immediatamente *, informa l'utente e lascia che decidano se riprovare o se andare a vedere se il router è scollegato. –
Ofcourse per le app WPF, il numero di tentativi non sarà alto! Tuttavia, questo è molto utile per le applicazioni console che eseguono operazioni in background. – funwithcoding
Cosa hai finito per fare? Non dimenticare di segnare una risposta? –