Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fix(errorHandling): adjust error handling to IExceptionFilter #1272

Merged
merged 3 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/framework/Framework.Async/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.Cors/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.DBAccess/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Service;
using Serilog.Context;
Expand All @@ -28,12 +29,12 @@

namespace Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Web;

public class GeneralHttpErrorHandler
public class GeneralHttpExceptionFilter(
ILogger<GeneralHttpExceptionFilter> logger,
IErrorMessageService errorMessageService)
: IExceptionFilter
{
private static readonly JsonSerializerOptions Options = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
private readonly RequestDelegate _next;
private readonly IErrorMessageService? _errorMessageService;
private readonly ILogger _logger;

private static readonly IReadOnlyDictionary<HttpStatusCode, MetaData> Metadata = ImmutableDictionary.CreateRange(new[]
{
Expand All @@ -57,7 +58,7 @@ public class GeneralHttpErrorHandler
(httpStatusCode,
messageFunc == null
? null
: (Exception e) => messageFunc.Invoke(e as T ?? throw new UnexpectedConditionException($"Exception type {e.GetType()} should always be of type {typeof(T)} here")),
: e => messageFunc.Invoke(e as T ?? throw new UnexpectedConditionException($"Exception type {e.GetType()} should always be of type {typeof(T)} here")),
logLevel));

private static readonly IReadOnlyDictionary<Type, (HttpStatusCode StatusCode, Func<Exception, (string?, IEnumerable<string>)>? MessageFunc, LogLevel LogLevel)> ErrorTypes = ImmutableDictionary.CreateRange(new[]
Expand All @@ -67,36 +68,26 @@ public class GeneralHttpErrorHandler
CreateErrorEntry<NotFoundException>(HttpStatusCode.NotFound),
CreateErrorEntry<ConflictException>(HttpStatusCode.Conflict),
CreateErrorEntry<ForbiddenException>(HttpStatusCode.Forbidden),
CreateErrorEntry<ServiceException>(HttpStatusCode.BadGateway, serviceException => (serviceException.Source, new[] { serviceException.StatusCode == null ? "remote service call failed" : $"remote service returned status code: {(int) serviceException.StatusCode} {serviceException.StatusCode}", serviceException.Message })),
CreateErrorEntry<ServiceException>(HttpStatusCode.BadGateway, serviceException => (serviceException.Source, new[] { serviceException.StatusCode == null ? "remote service call failed" : $"remote service returned status code: {(int)serviceException.StatusCode} {serviceException.StatusCode}", serviceException.Message })),
CreateErrorEntry<UnsupportedMediaTypeException>(HttpStatusCode.UnsupportedMediaType),
CreateErrorEntry<ConfigurationException>(HttpStatusCode.InternalServerError, configurationException => (configurationException.Source, new[] { $"Invalid service configuration: {configurationException.Message}" }))
});

public GeneralHttpErrorHandler(RequestDelegate next, ILogger<GeneralHttpErrorHandler> logger, IErrorMessageService? errorMessageService = null) //TODO make errorMessageService mandatory as soon all dependant services are adjusted accordingly
public void OnException(ExceptionContext context)
{
_next = next;
_logger = logger;
_errorMessageService = errorMessageService;
}

public async Task Invoke(HttpContext context)
{
try
var errorId = Guid.NewGuid().ToString();
var error = context.Exception;
var details = GetErrorDetails(error);
var message = GetErrorMessage(error);
LogErrorInformation(errorId, error);
var (statusCode, messageFunc, logLevel) = GetErrorInformation(error);
logger.Log(logLevel, error, "GeneralErrorHandler caught {Error} with errorId: {ErrorId} resulting in response status code {StatusCode}, message '{Message}'", error.GetType().Name, errorId, (int)statusCode, message);
context.Result = new ContentResult
{
await _next(context).ConfigureAwait(ConfigureAwaitOptions.None);
}
catch (Exception error)
{
var errorId = Guid.NewGuid().ToString();
var details = GetErrorDetails(error);
var message = GetErrorMessage(error);
LogErrorInformation(errorId, error);
var (statusCode, messageFunc, logLevel) = GetErrorInformation(error);
_logger.Log(logLevel, error, "GeneralErrorHandler caught {Error} with errorId: {ErrorId} resulting in response status code {StatusCode}, message '{Message}'", error.GetType().Name, errorId, (int)statusCode, message);
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)statusCode;
await context.Response.WriteAsync(JsonSerializer.Serialize(CreateErrorResponse(statusCode, error, errorId, message, details, messageFunc), Options)).ConfigureAwait(ConfigureAwaitOptions.None);
}
Content = JsonSerializer.Serialize(
CreateErrorResponse(statusCode, error, errorId, message, details, messageFunc), Options),
StatusCode = (int)statusCode
};
}

private static (HttpStatusCode StatusCode, Func<Exception, (string?, IEnumerable<string>)>? MessageFunc, LogLevel LogLevel) GetErrorInformation(Exception error) =>
Expand Down Expand Up @@ -131,13 +122,13 @@ private ErrorResponse CreateErrorResponse(HttpStatusCode statusCode, Exception e
}

private string GetErrorMessage(Exception exception) =>
_errorMessageService is not null && exception is DetailException detail && detail.HasDetails
? detail.GetErrorMessage(_errorMessageService)
exception is DetailException { HasDetails: true } detail
? detail.GetErrorMessage(errorMessageService)
: exception.Message;

private IEnumerable<ErrorDetails> GetErrorDetails(Exception exception) =>
_errorMessageService is not null && exception is DetailException detail && detail.HasDetails
? detail.GetErrorDetails(_errorMessageService)
exception is DetailException { HasDetails: true } detail
? detail.GetErrorDetails(errorMessageService)
: Enumerable.Empty<ErrorDetails>();

private static void LogErrorInformation(string errorId, Exception exception)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.IO/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.Identity/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
59 changes: 59 additions & 0 deletions src/framework/Framework.Linq/AllOrNoneExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/********************************************************************************
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

namespace Org.Eclipse.TractusX.Portal.Backend.Framework.Linq;

public static class AllOrNoneExtension
{
public static bool AllOrNone<T>(this IEnumerable<T> items, Func<T, bool> predicate)
{
using var enumerator = items.GetEnumerator();
if (!enumerator.MoveNext())
{
return true;
}
var first = predicate(enumerator.Current);
while (enumerator.MoveNext())
{
if (first ^ predicate(enumerator.Current))
{
return false;
}
}
return true;
}

public static bool AllOrNone(this IEnumerable<bool> items)
{
using var enumerator = items.GetEnumerator();
if (!enumerator.MoveNext())
{
return true;
}
var first = enumerator.Current;
while (enumerator.MoveNext())
{
if (first ^ enumerator.Current)
{
return false;
}
}
return true;
}
}
2 changes: 1 addition & 1 deletion src/framework/Framework.Linq/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.Logging/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.Models/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.Seeding/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.Swagger/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.Token/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/framework/Framework.Web/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<Project>
<PropertyGroup>
<VersionPrefix>3.3.0</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
3 changes: 2 additions & 1 deletion src/framework/Framework.Web/StartupServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using Org.Eclipse.TractusX.Portal.Backend.Framework.Cors;
using Org.Eclipse.TractusX.Portal.Backend.Framework.DateTimeProvider.DependencyInjection;
using Org.Eclipse.TractusX.Portal.Backend.Framework.DependencyInjection;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Web;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Validation;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Swagger;
using System.IdentityModel.Tokens.Jwt;
Expand All @@ -43,7 +44,7 @@ public static IServiceCollection AddDefaultServices<TProgram>(this IServiceColle
options.IdleTimeout = TimeSpan.FromMinutes(10);
});

services.AddControllers()
services.AddControllers(options => options.Filters.Add<GeneralHttpExceptionFilter>())
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(allowIntegerValues: false));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Cors;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Web;
using Serilog;

namespace Org.Eclipse.TractusX.Portal.Backend.Framework.Web;
Expand Down Expand Up @@ -51,8 +50,6 @@ public static WebApplication CreateApp<TProgram>(this WebApplication app, string
app.UseSession();

app.UseCors(CorsExtensions.AllowSpecificOrigins);

app.UseMiddleware<GeneralHttpErrorHandler>();
app.UseAuthentication();
app.UseAuthorization();

Expand Down
Loading
Loading