| | | 1 | | using Microsoft.Extensions.DependencyInjection; |
| | | 2 | | using Microsoft.Extensions.DependencyInjection.Extensions; |
| | | 3 | | |
| | | 4 | | namespace ZhEaIsNsAaBn.Utilities.APIExceptionHandlers; |
| | | 5 | | |
| | | 6 | | /// <summary>Records the extra handlers; <see cref="Build"/> registers everything in the fixed order.</summary> |
| | | 7 | | internal sealed class ExceptionHandlersBuilder : IExceptionHandlersBuilder |
| | | 8 | | { |
| | | 9 | | // Registered first, in this order, by every Build(); the fallback always goes last. |
| | 7 | 10 | | private static readonly Type[] BuiltIns = |
| | 7 | 11 | | [ typeof( JsonExceptionHandler ), typeof( ValidationExceptionHandler ), typeof( BusinessExceptionHandler ), type |
| | | 12 | | |
| | 116 | 13 | | private readonly List<Action<IServiceCollection>> _extras = []; |
| | 116 | 14 | | private readonly HashSet<Type> _types = [ ..BuiltIns, typeof( FallbackExceptionHandler ) ]; |
| | | 15 | | private readonly IServiceCollection _services; |
| | | 16 | | private bool _built; |
| | | 17 | | |
| | | 18 | | |
| | 116 | 19 | | internal ExceptionHandlersBuilder( IServiceCollection services ) |
| | | 20 | | { |
| | 116 | 21 | | ArgumentNullException.ThrowIfNull( services ); |
| | | 22 | | |
| | 116 | 23 | | _services = services; |
| | 116 | 24 | | } |
| | | 25 | | |
| | | 26 | | |
| | | 27 | | public IExceptionHandlersBuilder WithHandler< THandler >() |
| | | 28 | | where THandler : class, IExceptionHandler |
| | | 29 | | { |
| | | 30 | | // After Build() the fallback is already registered; a late handler would run after it, i.e. never. |
| | 98 | 31 | | if ( _built ) { throw new InvalidOperationException( $"{typeof( THandler ).Name} was recorded after Build(); rec |
| | | 32 | | |
| | 168 | 33 | | if ( _types.Add( typeof( THandler ) ) ) { _extras.Add( services => services.AddExceptionHandler<THandler>() ); } |
| | | 34 | | |
| | 90 | 35 | | return this; |
| | | 36 | | } |
| | | 37 | | |
| | | 38 | | public IServiceCollection Build() |
| | | 39 | | { |
| | 120 | 40 | | if ( _built ) { return _services; } |
| | | 41 | | |
| | 112 | 42 | | _built = true; |
| | | 43 | | |
| | | 44 | | |
| | 112 | 45 | | _services.AddAPIResponses(); |
| | | 46 | | |
| | 112 | 47 | | _services.AddExceptionHandler<JsonExceptionHandler>(); |
| | 112 | 48 | | _services.AddExceptionHandler<ValidationExceptionHandler>(); |
| | 112 | 49 | | _services.AddExceptionHandler<BusinessExceptionHandler>(); |
| | 112 | 50 | | _services.AddExceptionHandler<ExternalServiceExceptionHandler>(); |
| | | 51 | | |
| | 434 | 52 | | foreach ( var extra in _extras ) { extra( _services ); } |
| | | 53 | | |
| | 112 | 54 | | _services.AddExceptionHandler<FallbackExceptionHandler>(); |
| | | 55 | | |
| | | 56 | | |
| | | 57 | | // Before AddProblemDetails, so it is asked ahead of the default writer. |
| | 112 | 58 | | _services.TryAddEnumerable( ServiceDescriptor.Singleton<IProblemDetailsWriter, BaseResponseProblemDetailsWriter> |
| | 112 | 59 | | _services.AddProblemDetails(); |
| | | 60 | | |
| | | 61 | | |
| | 112 | 62 | | return _services; |
| | | 63 | | } |
| | | 64 | | } |