1
1
using System ;
2
2
using CoffeeCard . Common . Errors ;
3
+ using Microsoft . AspNetCore . Hosting ;
3
4
using Microsoft . AspNetCore . Http ;
4
5
using Microsoft . AspNetCore . Mvc ;
5
6
using Microsoft . AspNetCore . Mvc . Filters ;
6
- using Serilog ;
7
+ using Microsoft . Extensions . Hosting ;
8
+ using Microsoft . Extensions . Logging ;
7
9
8
10
namespace CoffeeCard . WebApi . Helpers
9
11
{
10
12
/// <summary>
11
13
/// Exception filter for handling API exceptions and returning appropriate HTTP status codes and error messages.
12
14
/// </summary>
13
- public class ApiExceptionFilter : ExceptionFilterAttribute
15
+ public class ApiExceptionFilter ( IWebHostEnvironment environment , ILogger < ApiExceptionFilter > logger )
16
+ : ExceptionFilterAttribute
14
17
{
18
+ private readonly ILogger < ApiExceptionFilter > _logger = logger ;
19
+ private readonly IWebHostEnvironment _environment = environment ;
20
+
15
21
/// <inheritdoc/>
16
22
public override void OnException ( ExceptionContext context )
17
23
{
18
- ApiError apiError ;
19
- switch ( context . Exception )
20
- {
21
- case ConflictException exception :
22
- apiError = new ApiError ( exception . Message ) ;
23
- context . HttpContext . Response . StatusCode = StatusCodes . Status409Conflict ;
24
- break ;
25
- case ApiException exception :
26
- {
27
- apiError = new ApiError ( exception . Message ) ;
28
- context . HttpContext . Response . StatusCode = exception . StatusCode ;
29
- break ;
30
- }
31
- case UnauthorizedAccessException _:
32
- apiError = new ApiError ( "Unauthorized Access" ) ;
33
- context . HttpContext . Response . StatusCode = StatusCodes . Status401Unauthorized ;
34
- break ;
35
- default :
36
- {
37
- Log . Error ( context . Exception , "Unhandled exception caught" ) ;
38
-
39
- #if ! DEBUG
40
- var msg = "An unhandled error occurred." ;
41
- #else
42
- var msg = context . Exception . GetBaseException ( ) . Message ;
43
- #endif
44
-
45
- apiError = new ApiError ( msg ) ;
46
- context . HttpContext . Response . StatusCode = StatusCodes . Status500InternalServerError ;
47
- break ;
48
- }
49
- }
24
+ var exception = context . Exception ;
25
+
26
+ var responseMessage = GetResponseMessage ( exception ) ;
27
+ var apiError = new ApiError ( responseMessage ) ;
28
+ context . HttpContext . Response . StatusCode = GetStatusCode ( exception ) ;
29
+ LogException ( exception ) ;
50
30
51
31
// always return a JSON result
52
32
context . Result = new JsonResult ( apiError ) ;
33
+ context . ExceptionHandled = true ;
53
34
54
35
base . OnException ( context ) ;
55
36
}
37
+
38
+ private string GetResponseMessage ( Exception exception )
39
+ {
40
+ return exception switch
41
+ {
42
+ // We consider our own exceptions fine for sending to users
43
+ ApiException apiException => apiException . Message ,
44
+ // To avoid leaking internal errors, we only show the exception message in dev
45
+ _ => _environment . IsDevelopment ( )
46
+ ? exception . GetBaseException ( ) . Message
47
+ : "Unhandled exception caught"
48
+ } ;
49
+ }
50
+
51
+ private int GetStatusCode ( Exception exception )
52
+ {
53
+ return exception switch
54
+ {
55
+ ApiException apiException => apiException . StatusCode ,
56
+ _ => StatusCodes . Status500InternalServerError
57
+ } ;
58
+ }
59
+
60
+ private void LogException ( Exception exception )
61
+ {
62
+ if ( exception is ApiException apiException )
63
+ {
64
+ _logger . LogWarning ( apiException , "Unintended user flow occured" ) ;
65
+ }
66
+ else
67
+ {
68
+ _logger . LogError ( exception , "Unhandled exception caught" ) ;
69
+ }
70
+ }
56
71
}
57
72
}
0 commit comments