@@ -32,31 +32,32 @@ public async Task<TResponse> Handle(TRequest request, CancellationToken cancella
3232 catch ( Exception exception )
3333 {
3434 var state = new RequestExceptionHandlerState < TResponse > ( ) ;
35- Type ? exceptionType = null ;
3635
37- while ( ! state . Handled && exceptionType != typeof ( Exception ) )
36+ var exceptionTypes = GetExceptionTypes ( exception . GetType ( ) ) ;
37+
38+ var handlersForException = exceptionTypes
39+ . SelectMany ( exceptionType => GetHandlersForException ( exceptionType , request ) )
40+ . GroupBy ( handlerForException => handlerForException . Handler . GetType ( ) )
41+ . Select ( handlerForException => handlerForException . First ( ) )
42+ . Select ( handlerForException => ( MethodInfo : GetMethodInfoForHandler ( handlerForException . ExceptionType ) , handlerForException . Handler ) )
43+ . ToList ( ) ;
44+
45+ foreach ( var handlerForException in handlersForException )
3846 {
39- exceptionType = exceptionType == null ? exception . GetType ( ) : exceptionType . BaseType
40- ?? throw new InvalidOperationException ( "Could not determine exception base type." ) ;
41- var exceptionHandlers = GetExceptionHandlers ( request , exceptionType , out MethodInfo handleMethod ) ;
47+ try
48+ {
49+ await ( ( Task ) ( handlerForException . MethodInfo . Invoke ( handlerForException . Handler , new object [ ] { request , exception , state , cancellationToken } )
50+ ?? throw new InvalidOperationException ( "Did not return a Task from the exception handler." ) ) ) . ConfigureAwait ( false ) ;
51+ }
52+ catch ( TargetInvocationException invocationException ) when ( invocationException . InnerException != null )
53+ {
54+ // Unwrap invocation exception to throw the actual error
55+ ExceptionDispatchInfo . Capture ( invocationException . InnerException ) . Throw ( ) ;
56+ }
4257
43- foreach ( var exceptionHandler in exceptionHandlers )
58+ if ( state . Handled )
4459 {
45- try
46- {
47- await ( ( Task ) ( handleMethod . Invoke ( exceptionHandler , new object [ ] { request , exception , state , cancellationToken } )
48- ?? throw new InvalidOperationException ( "Did not return a Task from the exception handler." ) ) ) . ConfigureAwait ( false ) ;
49- }
50- catch ( TargetInvocationException invocationException ) when ( invocationException . InnerException != null )
51- {
52- // Unwrap invocation exception to throw the actual error
53- ExceptionDispatchInfo . Capture ( invocationException . InnerException ) . Throw ( ) ;
54- }
55-
56- if ( state . Handled )
57- {
58- break ;
59- }
60+ break ;
6061 }
6162 }
6263
@@ -73,16 +74,33 @@ public async Task<TResponse> Handle(TRequest request, CancellationToken cancella
7374 return state . Response ; //cannot be null if Handled
7475 }
7576 }
77+ private static IEnumerable < Type > GetExceptionTypes ( Type ? exceptionType )
78+ {
79+ while ( exceptionType != null && exceptionType != typeof ( object ) )
80+ {
81+ yield return exceptionType ;
82+ exceptionType = exceptionType . BaseType ;
83+ }
84+ }
7685
77- private IList < object > GetExceptionHandlers ( TRequest request , Type exceptionType , out MethodInfo handleMethodInfo )
86+ private IEnumerable < ( Type ExceptionType , object Handler ) > GetHandlersForException ( Type exceptionType , TRequest request )
7887 {
7988 var exceptionHandlerInterfaceType = typeof ( IRequestExceptionHandler < , , > ) . MakeGenericType ( typeof ( TRequest ) , typeof ( TResponse ) , exceptionType ) ;
8089 var enumerableExceptionHandlerInterfaceType = typeof ( IEnumerable < > ) . MakeGenericType ( exceptionHandlerInterfaceType ) ;
81- handleMethodInfo = exceptionHandlerInterfaceType . GetMethod ( nameof ( IRequestExceptionHandler < TRequest , TResponse , Exception > . Handle ) )
82- ?? throw new InvalidOperationException ( $ "Could not find method { nameof ( IRequestExceptionHandler < TRequest , TResponse , Exception > . Handle ) } on type { exceptionHandlerInterfaceType } ") ;
8390
84- var exceptionHandlers = ( IEnumerable < object > ) _serviceFactory . Invoke ( enumerableExceptionHandlerInterfaceType ) ;
91+ var exceptionHandlers = ( IEnumerable < object > ) _serviceFactory ( enumerableExceptionHandlerInterfaceType ) ;
92+
93+ return HandlersOrderer . Prioritize ( exceptionHandlers . ToList ( ) , request )
94+ . Select ( handler => ( exceptionType , action : handler ) ) ;
95+ }
96+
97+ private static MethodInfo GetMethodInfoForHandler ( Type exceptionType )
98+ {
99+ var exceptionHandlerInterfaceType = typeof ( IRequestExceptionHandler < , , > ) . MakeGenericType ( typeof ( TRequest ) , typeof ( TResponse ) , exceptionType ) ;
100+
101+ var handleMethodInfo = exceptionHandlerInterfaceType . GetMethod ( nameof ( IRequestExceptionHandler < TRequest , TResponse , Exception > . Handle ) )
102+ ?? throw new InvalidOperationException ( $ "Could not find method { nameof ( IRequestExceptionHandler < TRequest , TResponse , Exception > . Handle ) } on type { exceptionHandlerInterfaceType } ") ;
85103
86- return HandlersOrderer . Prioritize ( exceptionHandlers . ToList ( ) , request ) ;
104+ return handleMethodInfo ;
87105 }
88106}
0 commit comments