Ver código fonte

Add Exception Middleware

crobibero 5 anos atrás
pai
commit
1175ce3f97

+ 14 - 0
Jellyfin.Api/Models/ExceptionDtos/ExceptionDto.cs

@@ -0,0 +1,14 @@
+namespace Jellyfin.Api.Models.ExceptionDtos
+{
+    /// <summary>
+    /// Exception Dto.
+    /// Used for graceful handling of API exceptions.
+    /// </summary>
+    public class ExceptionDto
+    {
+        /// <summary>
+        /// Gets or sets exception message.
+        /// </summary>
+        public string Message { get; set; }
+    }
+}

+ 11 - 0
Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs

@@ -1,3 +1,4 @@
+using Jellyfin.Server.Middleware;
 using Microsoft.AspNetCore.Builder;
 
 namespace Jellyfin.Server.Extensions
@@ -23,5 +24,15 @@ namespace Jellyfin.Server.Extensions
                 c.SwaggerEndpoint("/swagger/v1/swagger.json", "Jellyfin API V1");
             });
         }
+
+        /// <summary>
+        /// Adds exception middleware to the application pipeline.
+        /// </summary>
+        /// <param name="applicationBuilder">The application builder.</param>
+        /// <returns>The updated application builder.</returns>
+        public static IApplicationBuilder UseExceptionMiddleware(this IApplicationBuilder applicationBuilder)
+        {
+            return applicationBuilder.UseMiddleware<ExceptionMiddleware>();
+        }
     }
 }

+ 60 - 0
Jellyfin.Server/Middleware/ExceptionMiddleware.cs

@@ -0,0 +1,60 @@
+using System;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Jellyfin.Api.Models.ExceptionDtos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Server.Middleware
+{
+    /// <summary>
+    /// Exception Middleware.
+    /// </summary>
+    public class ExceptionMiddleware
+    {
+        private readonly RequestDelegate _next;
+        private readonly ILogger<ExceptionMiddleware> _logger;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ExceptionMiddleware"/> class.
+        /// </summary>
+        /// <param name="next">Next request delegate.</param>
+        /// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
+        public ExceptionMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
+        {
+            _next = next ?? throw new ArgumentNullException(nameof(next));
+            _logger = loggerFactory.CreateLogger<ExceptionMiddleware>() ??
+                      throw new ArgumentNullException(nameof(loggerFactory));
+        }
+
+        /// <summary>
+        /// Invoke request.
+        /// </summary>
+        /// <param name="context">Request context.</param>
+        /// <returns>Task.</returns>
+        public async Task Invoke(HttpContext context)
+        {
+            try
+            {
+                await _next(context).ConfigureAwait(false);
+            }
+            catch (Exception ex)
+            {
+                if (context.Response.HasStarted)
+                {
+                    _logger.LogWarning("The response has already started, the exception middleware will not be executed.");
+                    throw;
+                }
+
+                var exceptionBody = new ExceptionDto { Message = ex.Message };
+                var exceptionJson = JsonSerializer.Serialize(exceptionBody);
+
+                context.Response.Clear();
+                context.Response.StatusCode = StatusCodes.Status500InternalServerError;
+                // TODO switch between PascalCase and camelCase
+                context.Response.ContentType = "application/json";
+                await context.Response.WriteAsync(exceptionJson).ConfigureAwait(false);
+            }
+        }
+    }
+}

+ 2 - 0
Jellyfin.Server/Startup.cs

@@ -58,6 +58,8 @@ namespace Jellyfin.Server
                 app.UseDeveloperExceptionPage();
             }
 
+            app.UseExceptionMiddleware();
+
             app.UseWebSockets();
 
             app.UseResponseCompression();