diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..4fd5271 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,3 @@ +{ + "image": "mcr.microsoft.com/devcontainers/dotnet" +} \ No newline at end of file diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 3aed081..0f2b6ec 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -38,9 +38,8 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.x - 7.x 8.x + 9.x - name: Build run: dotnet build -c ${{ env.BUILD_CONFIGURATION }} @@ -60,9 +59,8 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.x - 7.x 8.x + 9.x - uses: dotnet/nbgv@master with: diff --git a/Directory.Build.props b/Directory.Build.props index 2a1e7a6..2190e9e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,7 +6,7 @@ git true Latest - net6.0;net7.0;net8.0 + net8.0;net9.0 $(FETargetFrameworks) diff --git a/README.md b/README.md index 21851bd..b6b1182 100644 --- a/README.md +++ b/README.md @@ -291,6 +291,12 @@ The prerelease CI builds are packaged and hosted at [feedz.io](feedz.io), thanks # Release notes +## 4.0 + +- Remove support for .NET 6 and .NET 7 +- Add support for .NET 9 +- Remove dependency on ForEvolve.Core library which means the base exception is now `Exception` instead of `ForEvolve.Exception`. + ## 3.0 Version 3 of ExceptionMapper is a major rewrite that simplifies the codebase and usage of the library. Here are a few important changes: diff --git a/samples/WebApi.Minimal/Program.cs b/samples/WebApi.Minimal/Program.cs index c811bfb..78c8382 100644 --- a/samples/WebApi.Minimal/Program.cs +++ b/samples/WebApi.Minimal/Program.cs @@ -9,15 +9,9 @@ var builder = WebApplication.CreateBuilder(args); #if CHANGE_PROPERTY_NAME_POLICY -#if NET8_0_OR_GREATER builder.Services.ConfigureHttpJsonOptions(options => { options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseUpper; }); -#else -builder.Services.Configure(options => { - options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; -}); -#endif #endif builder.AddExceptionMapper(builder => { @@ -74,9 +68,7 @@ "---[Others]---", "/fallback", "/a-url-that-does-not-exist", -#if NET7_0_OR_GREATER "/fluent-validation?name=&description=&range=0", -#endif }); app.MapGet("/BadRequestException", context => throw new BadRequestException()); app.MapGet("/ConflictException", context => throw new ConflictException()); @@ -96,7 +88,6 @@ app.MapGet("/MyUnauthorizedException", context => throw new MyUnauthorizedException(Random.Shared.Next(100) % 2 == 0 ? "John" : "Jane")); app.MapGet("/fallback", context => throw new Exception("An error that gets handled by the fallback handler.")); -#if NET7_0_OR_GREATER app.MapGet("/fluent-validation", ([AsParameters] Entity entity) => { var validator = new EntityValidator(); @@ -107,7 +98,6 @@ } return TypedResults.Ok(entity); }); -#endif app.Run(); diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrorException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrorException.cs index 8e11789..cef5fc5 100644 --- a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrorException.cs +++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrorException.cs @@ -4,7 +4,7 @@ /// Client error responses (400 – 499) ///

See also /// -public abstract class ClientErrorException : ForEvolveException +public abstract class ClientErrorException : Exception { public ClientErrorException() { diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrorException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrorException.cs index 4c84abf..9a95824 100644 --- a/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrorException.cs +++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrorException.cs @@ -4,7 +4,7 @@ /// Server error responses (500 – 599) ///

See also /// -public abstract class ServerErrorException : ForEvolveException +public abstract class ServerErrorException : Exception { public ServerErrorException() { diff --git a/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionExtensions.cs b/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionExtensions.cs index 3972fe1..775978c 100644 --- a/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionExtensions.cs @@ -53,23 +53,16 @@ public static WebApplicationBuilder AddExceptionMapper(this WebApplicationBuilde private static void AddSerializationHandler(this IServiceCollection services, IConfiguration configuration) { -#if NET7_0_OR_GREATER services.ConfigureHttpJsonOptions(options => { options.SerializerOptions.DictionaryKeyPolicy = options.SerializerOptions.PropertyNamingPolicy; }); -#endif services .AddOptions() .Bind(configuration.GetSection("ExceptionMapper:ProblemDetailsSerialization")) .ValidateOnStart() ; services.AddSingleton(sp => sp.GetRequiredService>().Value); -#if NET7_0_OR_GREATER services.AddProblemDetails(); -#endif - // Workaround: binding a local copy of the DefaultProblemDetailsFactory because the .NET class is internal. - // Moreover, the only way to add the class is by calling the AddMvcCore method, which add way more services. - // So until we can add the DefaultProblemDetailsFactory services.TryAddSingleton(); services.TryAddSingleton(); } diff --git a/src/ForEvolve.ExceptionMapper/ForEvolve.ExceptionMapper.csproj b/src/ForEvolve.ExceptionMapper/ForEvolve.ExceptionMapper.csproj index c9822a9..c15c5ef 100644 --- a/src/ForEvolve.ExceptionMapper/ForEvolve.ExceptionMapper.csproj +++ b/src/ForEvolve.ExceptionMapper/ForEvolve.ExceptionMapper.csproj @@ -7,10 +7,13 @@ - - - + + + + + + diff --git a/src/ForEvolve.ExceptionMapper/Serialization/DefaultProblemDetailsFactory.cs b/src/ForEvolve.ExceptionMapper/Serialization/DefaultProblemDetailsFactory.cs index b61f82f..1629bf3 100644 --- a/src/ForEvolve.ExceptionMapper/Serialization/DefaultProblemDetailsFactory.cs +++ b/src/ForEvolve.ExceptionMapper/Serialization/DefaultProblemDetailsFactory.cs @@ -1,4 +1,6 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Load this only for .NET 8. +#if !NET9_0_OR_GREATER +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Http; @@ -100,43 +102,4 @@ private void ApplyProblemDetailsDefaults(HttpContext httpContext, ProblemDetails _configure?.Invoke(new() { HttpContext = httpContext!, ProblemDetails = problemDetails }); } } - -#if NET6_0 -public class ProblemDetailsOptions -{ - /// - /// The operation that customizes the current instance. - /// - public Action? CustomizeProblemDetails { get; set; } -} - -public class ProblemDetailsContext -{ - private ProblemDetails? _problemDetails; - - /// - /// The associated with the current request being processed by the filter. - /// - public HttpContext? HttpContext { get; init; } - - /// - /// A collection of additional arbitrary metadata associated with the current request endpoint. - /// - public EndpointMetadataCollection? AdditionalMetadata { get; init; } - - /// - /// An instance of that will be - /// used during the response payload generation. - /// - public ProblemDetails ProblemDetails - { - get => _problemDetails ??= new ProblemDetails(); - set => _problemDetails = value; - } - - /// - /// The exception causing the problem or null if no exception information is available. - /// - public Exception? Exception { get; init; } -} -#endif \ No newline at end of file +#endif diff --git a/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationHandler.cs b/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationHandler.cs index e35b369..7c91d37 100644 --- a/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationHandler.cs +++ b/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationHandler.cs @@ -17,15 +17,11 @@ public class ProblemDetailsSerializationHandler : IExceptionSerializer private readonly ProblemDetailsFactory _problemDetailsFactory; private readonly IHostEnvironment _hostEnvironment; private readonly ProblemDetailsSerializationOptions _options; -#if NET7_0_OR_GREATER private readonly IProblemDetailsService _problemDetailsService; -#endif private readonly JsonSerializerOptions _jsonSerializerOptions; public ProblemDetailsSerializationHandler( -#if NET7_0_OR_GREATER IProblemDetailsService problemDetailsService, -#endif ProblemDetailsFactory problemDetailsFactory, IHostEnvironment hostEnvironment, ProblemDetailsSerializationOptions options, @@ -34,9 +30,7 @@ public ProblemDetailsSerializationHandler( _problemDetailsFactory = problemDetailsFactory ?? throw new ArgumentNullException(nameof(problemDetailsFactory)); _hostEnvironment = hostEnvironment ?? throw new ArgumentNullException(nameof(hostEnvironment)); _options = options ?? throw new ArgumentNullException(nameof(options)); -#if NET7_0_OR_GREATER _problemDetailsService = problemDetailsService ?? throw new ArgumentNullException(nameof(problemDetailsService)); -#endif _jsonSerializerOptions = jsonOptions.Value.SerializerOptions ?? throw new ArgumentNullException(nameof(jsonOptions)); } @@ -113,27 +107,13 @@ public async Task ExecuteAsync(ExceptionHandlingContext ctx) } // Output the problem details -#if NET7_0_OR_GREATER var problemDetailsContext = new ProblemDetailsContext { HttpContext = ctx.HttpContext, -#if NET8_0_OR_GREATER Exception = ctx.Error, -#endif ProblemDetails = problemDetails, }; await _problemDetailsService.WriteAsync(problemDetailsContext); -#else -#pragma warning disable CS0618 // Type or member is obsolete - ctx.HttpContext.Response.ContentType = _options.ContentType; - await JsonSerializer.SerializeAsync( - ctx.HttpContext.Response.Body, - problemDetails, - _jsonSerializerOptions, - cancellationToken: ctx.HttpContext.RequestAborted - ); -#pragma warning restore CS0618 // Type or member is obsolete -#endif } private string FormatName(string name) diff --git a/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationOptions.cs b/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationOptions.cs index b9bbd10..f33a9b6 100644 --- a/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationOptions.cs +++ b/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationOptions.cs @@ -6,10 +6,4 @@ public class ProblemDetailsSerializationOptions { public bool SerializeExceptions { get; set; } = true; public Func DisplayDebugInformation { get; set; } = (ExceptionHandlingContext ctx) => false; -#if NET6_0 - private const string _obsoleteMessage = "This property was removed when targeting .NET 7+. The library now leverages the `IProblemDetailsService` interface instead."; - - [Obsolete(_obsoleteMessage)] - public string ContentType { get; set; } = "application/problem+json; charset=utf-8"; -#endif } diff --git a/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlerTest.cs index 9c188ec..2d2db65 100644 --- a/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlerTest.cs +++ b/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlerTest.cs @@ -60,7 +60,7 @@ await sut.ExecuteAsync(new ExceptionHandlingContext( Assert.Equal( sut.StatusCode, - _httpContextHelper.HttpResponse.StatusCode + _httpContextHelper.HttpResponseFake.StatusCode ); } diff --git a/test/ForEvolve.ExceptionMapper.Tests/ForEvolve.ExceptionMapper.Tests.csproj b/test/ForEvolve.ExceptionMapper.Tests/ForEvolve.ExceptionMapper.Tests.csproj index cb9333e..1091a70 100644 --- a/test/ForEvolve.ExceptionMapper.Tests/ForEvolve.ExceptionMapper.Tests.csproj +++ b/test/ForEvolve.ExceptionMapper.Tests/ForEvolve.ExceptionMapper.Tests.csproj @@ -12,4 +12,19 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/version.json b/version.json index 8d459ea..bc85e5f 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "3.0", + "version": "4.0", "publicReleaseRefSpec": [ "^refs/heads/master$" ],