1+ using PostSharp . Aspects ;
2+ using PostSharp . Extensibility ;
3+ using PostSharp . Serialization ;
4+ using System ;
5+ using System . Data ;
6+ using System . Linq ;
7+ using System . Net ;
8+ using System . Threading . Tasks ;
9+
10+ namespace PostSharp . Samples . AutoRetry . Aspects
11+ {
12+ /// <summary>
13+ /// Aspect that, when applied to a method, causes invocations of this method to be retried if the method ends with
14+ /// specified exceptions.
15+ /// </summary>
16+ [ PSerializable ]
17+ [ LinesOfCodeAvoided ( 5 ) ]
18+ [ MulticastAttributeUsage ( MulticastTargets . Method ) ]
19+ public sealed class AutoRetryAttribute : MethodInterceptionAspect
20+ {
21+ /// <summary>
22+ /// Initializes a new <see cref="AutoRetryAttribute" /> with default values.
23+ /// </summary>
24+ public AutoRetryAttribute ( )
25+ {
26+ // Set the default values for properties.
27+ MaxRetries = 5 ;
28+ Delay = 3 ;
29+ HandledExceptions = new [ ] { typeof ( WebException ) , typeof ( DataException ) } ;
30+ }
31+
32+ /// <summary>
33+ /// Gets or sets the maximum number of retries. The default value is 5.
34+ /// </summary>
35+ public int MaxRetries
36+ {
37+ get ; set ;
38+ }
39+
40+ /// <summary>
41+ /// Gets or sets the delay before retrying, in seconds. The default value is 3.
42+ /// </summary>
43+ public float Delay
44+ {
45+ get ; set ;
46+ }
47+
48+ /// <summary>
49+ /// Gets or sets the type of exceptions that cause the method invocation to be retried. The default value is
50+ /// <see cref="WebException" /> and <see cref="DataException" />.
51+ /// </summary>
52+ public Type [ ] HandledExceptions
53+ {
54+ get ; set ;
55+ }
56+
57+ public override async Task OnInvokeAsync ( MethodInterceptionArgs args )
58+ {
59+ for ( var i = 0 ; ; i ++ )
60+ {
61+ try
62+ {
63+ // Invoke the intercepted method.
64+ await args . ProceedAsync ( ) ;
65+
66+ // If we get here, it means the execution was successful.
67+ return ;
68+ }
69+ catch ( Exception e )
70+ {
71+ // The intercepted method threw an exception. Figure out if we can retry the method.
72+
73+ if ( CanRetry ( i , e ) )
74+ {
75+ // Yes, we can retry. Write some message and wait a bit.
76+
77+ Console . WriteLine (
78+ $ "Method failed with exception { e . GetType ( ) . Name } '{ e . Message } '. Sleeping { Delay } s and retrying. This was our attempt #{ i + 1 } .") ;
79+
80+ if ( Delay > 0 )
81+ {
82+ await Task . Delay ( TimeSpan . FromSeconds ( Delay ) ) ;
83+ }
84+
85+ // Continue to the next iteration.
86+ }
87+ else
88+ {
89+ // No, we cannot retry. Rethrow the exception.
90+ throw ;
91+ }
92+ }
93+ }
94+ }
95+
96+ private bool CanRetry ( int attempt , Exception e )
97+ {
98+ return attempt < MaxRetries &&
99+ ( HandledExceptions == null || HandledExceptions . Any ( type => type . IsInstanceOfType ( e ) ) ) ;
100+ }
101+ }
102+ }
0 commit comments