Skip to content

Remove dependency on ForEvolve.Core #14

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 18, 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
3 changes: 3 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"image": "mcr.microsoft.com/devcontainers/dotnet"
}
6 changes: 2 additions & 4 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand All @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<RepositoryType>git</RepositoryType>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<LangVersion>Latest</LangVersion>
<FETargetFrameworks>net6.0;net7.0;net8.0</FETargetFrameworks>
<FETargetFrameworks>net8.0;net9.0</FETargetFrameworks>
<FETestsTargetFrameworks>$(FETargetFrameworks)</FETestsTargetFrameworks>
</PropertyGroup>

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 0 additions & 10 deletions samples/WebApi.Minimal/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<JsonOptions>(options => {
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
#endif
#endif
builder.AddExceptionMapper(builder =>
{
Expand Down Expand Up @@ -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());
Expand All @@ -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();
Expand All @@ -107,7 +98,6 @@
}
return TypedResults.Ok(entity);
});
#endif
app.Run();


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/// Client error responses (400 – 499)
/// <br /><br />See also <seealso cref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses"/>
/// </summary>
public abstract class ClientErrorException : ForEvolveException
public abstract class ClientErrorException : Exception
{
public ClientErrorException()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/// Server error responses (500 – 599)
/// <br /><br />See also <seealso cref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#server_error_responses"/>
/// </summary>
public abstract class ServerErrorException : ForEvolveException
public abstract class ServerErrorException : Exception
{
public ServerErrorException()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ProblemDetailsSerializationOptions>()
.Bind(configuration.GetSection("ExceptionMapper:ProblemDetailsSerialization"))
.ValidateOnStart()
;
services.AddSingleton(sp => sp.GetRequiredService<IOptions<ProblemDetailsSerializationOptions>>().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<ProblemDetailsFactory, DefaultProblemDetailsFactory>();
services.TryAddSingleton<IExceptionSerializer, ProblemDetailsSerializationHandler>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="ForEvolve.Core" Version="2.3.5" />
</ItemGroup>
<ItemGroup>
<None Include="../../README.md" Pack="true" PackagePath="\"/>
<None Include="../../LICENSE" Pack="true" PackagePath="\"/>
<None Include="../../README.md" Pack="true" PackagePath="\" />
<None Include="../../LICENSE" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.115" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -100,43 +102,4 @@ private void ApplyProblemDetailsDefaults(HttpContext httpContext, ProblemDetails
_configure?.Invoke(new() { HttpContext = httpContext!, ProblemDetails = problemDetails });
}
}

#if NET6_0
public class ProblemDetailsOptions
{
/// <summary>
/// The operation that customizes the current <see cref="Mvc.ProblemDetails"/> instance.
/// </summary>
public Action<ProblemDetailsContext>? CustomizeProblemDetails { get; set; }
}

public class ProblemDetailsContext
{
private ProblemDetails? _problemDetails;

/// <summary>
/// The <see cref="HttpContext"/> associated with the current request being processed by the filter.
/// </summary>
public HttpContext? HttpContext { get; init; }

/// <summary>
/// A collection of additional arbitrary metadata associated with the current request endpoint.
/// </summary>
public EndpointMetadataCollection? AdditionalMetadata { get; init; }

/// <summary>
/// An instance of <see cref="ProblemDetails"/> that will be
/// used during the response payload generation.
/// </summary>
public ProblemDetails ProblemDetails
{
get => _problemDetails ??= new ProblemDetails();
set => _problemDetails = value;
}

/// <summary>
/// The exception causing the problem or <c>null</c> if no exception information is available.
/// </summary>
public Exception? Exception { get; init; }
}
#endif
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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));
}

Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,4 @@ public class ProblemDetailsSerializationOptions
{
public bool SerializeExceptions { get; set; } = true;
public Func<ExceptionHandlingContext, bool> 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
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ await sut.ExecuteAsync(new ExceptionHandlingContext(

Assert.Equal(
sut.StatusCode,
_httpContextHelper.HttpResponse.StatusCode
_httpContextHelper.HttpResponseFake.StatusCode
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,19 @@
<ProjectReference Include="..\..\src\ForEvolve.ExceptionMapper\ForEvolve.ExceptionMapper.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Update="ForEvolve.Testing.AspNetCore" Version="1.0.20" />
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Update="Moq" Version="4.20.72" />
<PackageReference Update="xunit" Version="2.9.3" />
<PackageReference Update="xunit.runner.visualstudio" Version="3.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -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$"
],
Expand Down