();
- });
- }
-}
diff --git a/samples/WebApi.Mvc/Properties/launchSettings.json b/samples/WebApi.Mvc/Properties/launchSettings.json
deleted file mode 100644
index 6e1ad3b..0000000
--- a/samples/WebApi.Mvc/Properties/launchSettings.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "profiles": {
- "WebApi.HttpMiddleware (watch)": {
- "executablePath": "dotnet.exe",
- "workingDirectory": "$(ProjectDir)",
- "commandLineArgs": "watch run",
- "applicationUrl": "https://localhost:9327;http://localhost:9326",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "WebApi.HttpMiddleware": {
- "commandName": "Project",
- "launchBrowser": true,
- "applicationUrl": "https://localhost:9327;http://localhost:9326",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "WebApi.HttpMiddleware (Production)": {
- "commandName": "Project",
- "launchBrowser": true,
- "applicationUrl": "https://localhost:9327;http://localhost:9326",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Production"
- }
- }
- }
-}
diff --git a/samples/WebApi.Mvc/Startup.cs b/samples/WebApi.Mvc/Startup.cs
deleted file mode 100644
index 1d06f73..0000000
--- a/samples/WebApi.Mvc/Startup.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-
-namespace WebApi.Mvc
-{
- public class Startup
- {
- // This method gets called by the runtime. Use this method to add services to the container.
- // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
- public void ConfigureServices(IServiceCollection services)
- {
- //services.AddExceptionMapper(builder => builder
- // .MapCommonMvcExceptions()
- //);
- }
-
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapGet("/", async context =>
- {
- await context.Response.WriteAsync("Hello World!");
- });
- });
- }
- }
-}
diff --git a/samples/WebApi.Mvc/WebApi.Mvc.csproj b/samples/WebApi.Mvc/WebApi.Mvc.csproj
deleted file mode 100644
index 2e6c72a..0000000
--- a/samples/WebApi.Mvc/WebApi.Mvc.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- net5.0;net6.0
-
-
-
-
-
-
-
-
diff --git a/samples/WebApi.Mvc/appsettings.Development.json b/samples/WebApi.Mvc/appsettings.Development.json
deleted file mode 100644
index 8983e0f..0000000
--- a/samples/WebApi.Mvc/appsettings.Development.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
- }
- }
-}
diff --git a/samples/WebApi.Shared/DroidNotFoundException.cs b/samples/WebApi.Shared/DroidNotFoundException.cs
new file mode 100644
index 0000000..f79aa74
--- /dev/null
+++ b/samples/WebApi.Shared/DroidNotFoundException.cs
@@ -0,0 +1,12 @@
+using ForEvolve.ExceptionMapper;
+
+namespace WebApi.Shared;
+
+public class DroidNotFoundException : NotFoundException
+{
+ public DroidNotFoundException()
+ : base("These aren't the droids we're looking for.")
+ {
+
+ }
+}
diff --git a/samples/WebApi.Shared/GoneException.cs b/samples/WebApi.Shared/GoneException.cs
deleted file mode 100644
index 906b291..0000000
--- a/samples/WebApi.Shared/GoneException.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using System;
-
-namespace WebApi.Shared
-{
- public class GoneException : Exception
- {
- }
-}
diff --git a/samples/WebApi.Shared/ImATeapotException.cs b/samples/WebApi.Shared/ImATeapotException.cs
index d7f880e..2bd5923 100644
--- a/samples/WebApi.Shared/ImATeapotException.cs
+++ b/samples/WebApi.Shared/ImATeapotException.cs
@@ -1,9 +1,8 @@
using System;
-namespace WebApi.Shared
+namespace WebApi.Shared;
+
+public class ImATeapotException : Exception
{
- public class ImATeapotException : Exception
- {
- }
}
diff --git a/samples/WebApi.Shared/ImATeapotExceptionHandler.cs b/samples/WebApi.Shared/ImATeapotExceptionHandler.cs
deleted file mode 100644
index 1383a00..0000000
--- a/samples/WebApi.Shared/ImATeapotExceptionHandler.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using ForEvolve.ExceptionMapper;
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Threading.Tasks;
-
-namespace WebApi.Shared
-{
- public class ImATeapotExceptionHandler : IExceptionHandler
- {
- public int Order => HandlerOrder.DefaultOrder;
-
- public async Task ExecuteAsync(ExceptionHandlingContext context)
- {
- var response = context.HttpContext.Response;
- response.StatusCode = StatusCodes.Status418ImATeapot;
- response.ContentType = "text/html";
- context.Result = new ExceptionHandledResult(context.Error);
- await response.WriteAsync("");
- await response.WriteAsync(@" ;,'
- _o_ ;:;'
- ,-.'---`.__ ;
-((j`=====',-'
- `-\ /
- `-=-' hjw
-Source: https://www.asciiart.eu/food-and-drinks/coffee-and-tea");
- await response.WriteAsync("
");
- }
-
- public Task KnowHowToHandleAsync(Exception exception)
- {
- return Task.FromResult(exception is ImATeapotException);
- }
- }
-}
diff --git a/samples/WebApi.Shared/MyForbiddenException.cs b/samples/WebApi.Shared/MyForbiddenException.cs
index 9e8e63f..d66530a 100644
--- a/samples/WebApi.Shared/MyForbiddenException.cs
+++ b/samples/WebApi.Shared/MyForbiddenException.cs
@@ -1,9 +1,18 @@
using System;
+using System.Text.Json.Serialization;
-namespace WebApi.Shared
+namespace WebApi.Shared;
+
+public class MyForbiddenException : Exception
{
- public class MyForbiddenException : Exception
+ public MyForbiddenException()
+ : base("Accessing this resource is forbidden.")
{
-
+
}
+
+ public string CustomProperty1 => "Lorem Ipsum 1";
+
+ [JsonIgnore]
+ public string CustomProperty2 => "Lorem Ipsum 2";
}
diff --git a/samples/WebApi.Shared/MyForbiddenExceptionHandler.cs b/samples/WebApi.Shared/MyForbiddenExceptionHandler.cs
index 14507e5..6684444 100644
--- a/samples/WebApi.Shared/MyForbiddenExceptionHandler.cs
+++ b/samples/WebApi.Shared/MyForbiddenExceptionHandler.cs
@@ -1,10 +1,9 @@
using ForEvolve.ExceptionMapper;
using Microsoft.AspNetCore.Http;
-namespace WebApi.Shared
+namespace WebApi.Shared;
+
+public class MyForbiddenExceptionHandler : ExceptionHandler
{
- public class MyForbiddenExceptionHandler : ExceptionHandler
- {
- public override int StatusCode => StatusCodes.Status403Forbidden;
- }
+ public override int StatusCode => StatusCodes.Status403Forbidden;
}
diff --git a/samples/WebApi.Shared/MyNotFoundException.cs b/samples/WebApi.Shared/MyNotFoundException.cs
deleted file mode 100644
index 3880d2a..0000000
--- a/samples/WebApi.Shared/MyNotFoundException.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using ForEvolve.ExceptionMapper;
-
-namespace WebApi.Shared
-{
- public class MyNotFoundException : NotFoundException
- {
- }
-}
diff --git a/samples/WebApi.Shared/MyUnauthorizedException.cs b/samples/WebApi.Shared/MyUnauthorizedException.cs
index 0f63270..d462866 100644
--- a/samples/WebApi.Shared/MyUnauthorizedException.cs
+++ b/samples/WebApi.Shared/MyUnauthorizedException.cs
@@ -1,8 +1,12 @@
-using System;
+using ForEvolve.ExceptionMapper;
-namespace WebApi.Shared
+namespace WebApi.Shared;
+
+public class MyUnauthorizedException : UnauthorizedException
{
- public class MyUnauthorizedException : Exception
+ public MyUnauthorizedException(string name)
+ : base($"Sorry {name}, you can't access this page.")
{
+
}
}
diff --git a/samples/WebApi.Shared/WebApi.Shared.csproj b/samples/WebApi.Shared/WebApi.Shared.csproj
index e42da42..1e6ab37 100644
--- a/samples/WebApi.Shared/WebApi.Shared.csproj
+++ b/samples/WebApi.Shared/WebApi.Shared.csproj
@@ -1,12 +1,12 @@
-
+
- net5.0;net6.0
- False
+ $(FETestsTargetFrameworks)
+ False
-
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 35115d1..33a40bc 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -12,11 +12,13 @@
true
True
snupkg
+ enable
+ enable
-
+
- 3.2.31
+ 3.6.133
all
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrorException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrorException.cs
deleted file mode 100644
index 4f4f73c..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrorException.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public abstract class ClientErrorException : ForEvolveException
- {
- public ClientErrorException()
- {
- }
-
- public ClientErrorException(string message) : base(message)
- {
- }
-
- public ClientErrorException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/BadRequestException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/BadRequestException.cs
deleted file mode 100644
index 4c56393..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/BadRequestException.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class BadRequestException : Exception
- {
- public BadRequestException()
- {
- }
-
- public BadRequestException(string message) : base(message)
- {
- }
-
- public BadRequestException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ConflictException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ConflictException.cs
deleted file mode 100644
index 61bfd5b..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ConflictException.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ConflictException : ClientErrorException
- {
- public ConflictException()
- {
- }
-
- public ConflictException(string message) : base(message)
- {
- }
-
- public ConflictException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ForbiddenException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ForbiddenException.cs
deleted file mode 100644
index c79cd49..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ForbiddenException.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ForbiddenException : Exception
- {
- public ForbiddenException()
- {
- }
-
- public ForbiddenException(string message) : base(message)
- {
- }
-
- public ForbiddenException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/NotFoundException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/NotFoundException.cs
deleted file mode 100644
index a4f672f..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/NotFoundException.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class NotFoundException : ClientErrorException
- {
- public NotFoundException()
- {
- }
-
- public NotFoundException(string message) : base(message)
- {
- }
-
- public NotFoundException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ResourceNotFoundException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ResourceNotFoundException.cs
deleted file mode 100644
index a965bdc..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/ResourceNotFoundException.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Extensions;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ResourceNotFoundException : NotFoundException
- {
- public ResourceNotFoundException(HttpContext context)
- : base($"No resource were found at '{context.Request.GetDisplayUrl()}'.")
- {
-
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/UnauthorizedException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/UnauthorizedException.cs
deleted file mode 100644
index 7f380a2..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ClientErrors/UnauthorizedException.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class UnauthorizedException : Exception
- {
- public UnauthorizedException()
- {
- }
-
- public UnauthorizedException(string message) : base(message)
- {
- }
-
- public UnauthorizedException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ForEvolve.ExceptionMapper.CommonExceptions.csproj b/src/ForEvolve.ExceptionMapper.CommonExceptions/ForEvolve.ExceptionMapper.CommonExceptions.csproj
deleted file mode 100644
index 3ede149..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ForEvolve.ExceptionMapper.CommonExceptions.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- netstandard2.0
- ForEvolve.ExceptionMapper
-
-
-
-
-
-
-
-
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ServerErrorException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ServerErrorException.cs
deleted file mode 100644
index 3b7dda1..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ServerErrorException.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public abstract class ServerErrorException : ForEvolveException
- {
- public ServerErrorException()
- {
- }
-
- public ServerErrorException(string message) : base(message)
- {
- }
-
- public ServerErrorException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonExceptions/ServerErrors/InternalServerErrorException.cs b/src/ForEvolve.ExceptionMapper.CommonExceptions/ServerErrors/InternalServerErrorException.cs
deleted file mode 100644
index e90ce30..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonExceptions/ServerErrors/InternalServerErrorException.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class InternalServerErrorException : ServerErrorException
- {
- public InternalServerErrorException(Exception innerException)
- : base(innerException.Message, innerException)
- {
-
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/CommonExceptionsMappingBuilderExtensions.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/CommonExceptionsMappingBuilderExtensions.cs
deleted file mode 100644
index 5a07bc7..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/CommonExceptionsMappingBuilderExtensions.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using ForEvolve.ExceptionMapper;
-using ForEvolve.ExceptionMapper.Handlers;
-using ForEvolve.ExceptionMapper.Handlers.Fallback;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- public static class CommonHttpExceptionHandlersMappingBuilderExtensions
- {
- ///
- /// Registers all found in the assembly
- /// with singleton lifetime.
- ///
- public static IExceptionMappingBuilder MapCommonHttpExceptions(this IExceptionMappingBuilder builder)
- {
- return builder.ScanHandlersFrom(
- s => s
- .FromAssembliesOf(typeof(CommonHttpExceptionHandlersMappingBuilderExtensions))
- .AddClasses(x => x.InExactNamespaceOf()),
- ServiceLifetime.Singleton
- );
- }
-
- ///
- /// Registers all found in the assembly
- /// with singleton lifetime.
- ///
- public static IExceptionMappingBuilder MapHttpFallback(this IExceptionMappingBuilder builder, Action setup = null)
- {
- if (setup != null) { builder.Services.Configure(setup); }
- return builder.AddExceptionHandler();
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandler.cs
deleted file mode 100644
index 80dc502..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandler.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Options;
-using System;
-using System.Threading.Tasks;
-
-namespace ForEvolve.ExceptionMapper.Handlers.Fallback
-{
- public class FallbackExceptionHandler : IExceptionHandler
- {
- public int Order => HandlerOrder.FallbackOrder;
-
- private readonly FallbackExceptionHandlerOptions _options;
- public FallbackExceptionHandler(IOptionsMonitor options)
- {
- _options = options.CurrentValue;
- }
-
- public Task KnowHowToHandleAsync(Exception exception)
- {
- if (_options.Strategy == FallbackStrategy.Handle)
- {
- return Task.FromResult(true);
- }
- return Task.FromResult(false);
- }
-
- public Task ExecuteAsync(ExceptionHandlingContext context)
- {
- if (_options.Strategy == FallbackStrategy.Handle)
- {
- if (!context.Result.ExceptionHandled)
- {
- context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
- context.Result = new ExceptionHandledResult(context.Error);
- }
- }
- return Task.CompletedTask;
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerOptions.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerOptions.cs
deleted file mode 100644
index bd2e315..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerOptions.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace ForEvolve.ExceptionMapper.Handlers.Fallback
-{
- public class FallbackExceptionHandlerOptions
- {
- public FallbackStrategy Strategy { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackStrategy.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackStrategy.cs
deleted file mode 100644
index 13e2e83..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Fallback/FallbackStrategy.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace ForEvolve.ExceptionMapper.Handlers.Fallback
-{
- public enum FallbackStrategy
- {
- Ignore = 0,
- Handle = 1
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.csproj b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.csproj
deleted file mode 100644
index 61e3287..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- netstandard2.0
-
-
-
-
-
-
-
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/BadRequestExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/BadRequestExceptionHandler.cs
deleted file mode 100644
index 571baf6..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/BadRequestExceptionHandler.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class BadRequestExceptionHandler : ExceptionHandler
- {
- public override int StatusCode => StatusCodes.Status400BadRequest;
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/ConflictExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/ConflictExceptionHandler.cs
deleted file mode 100644
index 2e86912..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/ConflictExceptionHandler.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class ConflictExceptionHandler : ExceptionHandler
- {
- public override int StatusCode => StatusCodes.Status409Conflict;
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/ForbiddenExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/ForbiddenExceptionHandler.cs
deleted file mode 100644
index cca6651..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/ForbiddenExceptionHandler.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Microsoft.AspNetCore.Http;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class ForbiddenExceptionHandler : ExceptionHandler
- {
- public override int StatusCode => StatusCodes.Status403Forbidden;
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/InternalServerErrorExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/InternalServerErrorExceptionHandler.cs
deleted file mode 100644
index 24c48aa..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/InternalServerErrorExceptionHandler.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Microsoft.AspNetCore.Http;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class InternalServerErrorExceptionHandler : ExceptionHandler
- {
- public override int StatusCode => StatusCodes.Status500InternalServerError;
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/NotFoundExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/NotFoundExceptionHandler.cs
deleted file mode 100644
index 4571e3a..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/NotFoundExceptionHandler.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Microsoft.AspNetCore.Http;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class NotFoundExceptionHandler : ExceptionHandler
- {
- public override int StatusCode => StatusCodes.Status404NotFound;
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/NotImplementedExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/NotImplementedExceptionHandler.cs
deleted file mode 100644
index 95c9e56..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/NotImplementedExceptionHandler.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class NotImplementedExceptionHandler : ExceptionHandler
- {
- public override int StatusCode => StatusCodes.Status501NotImplemented;
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/UnauthorizedExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/UnauthorizedExceptionHandler.cs
deleted file mode 100644
index 2be796d..0000000
--- a/src/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers/Handlers/UnauthorizedExceptionHandler.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Microsoft.AspNetCore.Http;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class UnauthorizedExceptionHandler : ExceptionHandler
- {
- public override int StatusCode => StatusCodes.Status401Unauthorized;
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ExceptionMappingBuilderExtensions.cs b/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ExceptionMappingBuilderExtensions.cs
deleted file mode 100644
index 765780b..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ExceptionMappingBuilderExtensions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using ForEvolve.ExceptionMapper;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- public static class ExceptionMappingBuilderExtensions
- {
- public static IExceptionMappingBuilder AddExceptionHandler(this IExceptionMappingBuilder builder)
- where THandler : class, IExceptionHandler
- {
- builder.Services.AddSingleton();
- return builder;
- }
-
- public static IExceptionMappingBuilder AddExceptionHandler(this IExceptionMappingBuilder builder, THandler handler)
- where THandler : class, IExceptionHandler
- {
- builder.Services.AddSingleton(handler);
- return builder;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/IExceptionMappingBuilder.cs b/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/IExceptionMappingBuilder.cs
deleted file mode 100644
index 397880c..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/IExceptionMappingBuilder.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Microsoft.Extensions.DependencyInjection
-{
- public interface IExceptionMappingBuilder
- {
- IServiceCollection Services { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ServiceCollectionExtensions.cs b/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ServiceCollectionExtensions.cs
deleted file mode 100644
index 371f1a7..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using ForEvolve.ExceptionMapper;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Extensions.Options;
-using System;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- public static class ServiceCollectionExceptionFiltersExtensions
- {
- public static IServiceCollection AddExceptionMapper(this IServiceCollection services, Action exceptionMappingBuilder = null)
- {
- services.AddLogging();
- exceptionMappingBuilder?.Invoke(new ServiceCollectionWrapper(services));
- services.TryAddSingleton();
- return services;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ServiceCollectionWrapper.cs b/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ServiceCollectionWrapper.cs
deleted file mode 100644
index f707b10..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/DependencyInjection/ServiceCollectionWrapper.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- public class ServiceCollectionWrapper : IExceptionMappingBuilder
- {
- public ServiceCollectionWrapper(IServiceCollection services)
- {
- Services = services ?? throw new ArgumentNullException(nameof(services));
- }
-
- public IServiceCollection Services { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/ExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.Core/ExceptionHandler.cs
deleted file mode 100644
index 653d3a1..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/ExceptionHandler.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Threading.Tasks;
-namespace ForEvolve.ExceptionMapper
-{
- public abstract class ExceptionHandler : IExceptionHandler
- where TException : Exception
- {
- public abstract int StatusCode { get; }
- public virtual int Order => HandlerOrder.DefaultOrder;
-
- public virtual Task KnowHowToHandleAsync(Exception exception)
- {
- return Task.FromResult(exception is TException);
- }
-
- public virtual Task ExecuteAsync(ExceptionHandlingContext context)
- {
- context.HttpContext.Response.StatusCode = StatusCode;
- context.Result = new ExceptionHandledResult(context.Error);
- return ExecuteCoreAsync(new ExceptionHandlingContext(context));
- }
-
- protected virtual Task ExecuteCoreAsync(ExceptionHandlingContext context)
- {
- return Task.CompletedTask;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/ExceptionHandlingManager.cs b/src/ForEvolve.ExceptionMapper.Core/ExceptionHandlingManager.cs
deleted file mode 100644
index e629d7b..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/ExceptionHandlingManager.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-using Microsoft.AspNetCore.Diagnostics;
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Threading.Tasks;
-namespace ForEvolve.ExceptionMapper
-{
- public class ExceptionHandlingManager : IExceptionHandlingManager
- {
- private readonly List _handlers;
-
- public ExceptionHandlingManager(IEnumerable handlers)
- {
- if (handlers == null) { throw new ArgumentNullException(nameof(handlers)); }
-
- _handlers = handlers
- .OrderBy(x => x.Order)
- .ToList();
- }
-
- public IReadOnlyCollection Handlers
- => new ReadOnlyCollection(_handlers);
-
- public async Task HandleAsync(HttpContext httpContext)
- {
- var exceptionHandlerPathFeature = httpContext.Features.Get();
- if (exceptionHandlerPathFeature == null)
- {
- return new ExceptionHandlerFeatureNotSupportedResult();
- }
-
- var exception = exceptionHandlerPathFeature.Error;
- if (exception == null)
- {
- return new NoExceptionResult();
- }
-
- var context = new ExceptionHandlingContext(httpContext, exception, new ExceptionNotHandledResult(exception));
- foreach (var handler in _handlers)
- {
- if (await handler.KnowHowToHandleAsync(exception))
- {
- await handler.ExecuteAsync(context);
- }
- }
-
- return context.Result;
- }
- }
-
- public class ExceptionHandlingContext
- where TException : Exception
- {
- public ExceptionHandlingContext(ExceptionHandlingContext previous)
- : this(previous.HttpContext, previous.Error as TException, previous.Result)
- {
- }
-
- public ExceptionHandlingContext(ExceptionHandlingContext previous)
- : this(previous.HttpContext, previous.Error, previous.Result)
- {
- }
-
- public ExceptionHandlingContext(HttpContext httpContext, TException error, IExceptionHandlingResult initialResult)
- {
- HttpContext = httpContext ?? throw new ArgumentNullException(nameof(httpContext));
- Error = error ?? throw new ArgumentNullException(nameof(error));
- Result = initialResult;
- }
-
- public HttpContext HttpContext { get; }
- public TException Error { get; }
- public IExceptionHandlingResult Result { get; set; }
- }
-
- public class ExceptionHandlingContext : ExceptionHandlingContext
- {
- public ExceptionHandlingContext(ExceptionHandlingContext previous)
- : base(previous)
- {
- }
-
- public ExceptionHandlingContext(HttpContext httpContext, Exception error, IExceptionHandlingResult initialResult)
- : base(httpContext, error, initialResult)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/ForEvolve.ExceptionMapper.Core.csproj b/src/ForEvolve.ExceptionMapper.Core/ForEvolve.ExceptionMapper.Core.csproj
deleted file mode 100644
index 2649f0d..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/ForEvolve.ExceptionMapper.Core.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- netstandard2.0
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/ForEvolve.ExceptionMapper.Core/HandlerOrder.cs b/src/ForEvolve.ExceptionMapper.Core/HandlerOrder.cs
deleted file mode 100644
index e39b5cf..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/HandlerOrder.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ForEvolve.ExceptionMapper
-{
- public sealed class HandlerOrder
- {
- public const int DefaultOrder = 1;
- public const int FallbackOrder = 50;
- public const int SerializerOrder = 100;
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.Core/IExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.Core/IExceptionHandler.cs
deleted file mode 100644
index 42b8086..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/IExceptionHandler.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Threading.Tasks;
-
-namespace ForEvolve.ExceptionMapper
-{
- public interface IExceptionHandler
- {
- int Order { get; }
- Task KnowHowToHandleAsync(Exception exception);
- Task ExecuteAsync(ExceptionHandlingContext context);
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/IExceptionHandlingManager.cs b/src/ForEvolve.ExceptionMapper.Core/IExceptionHandlingManager.cs
deleted file mode 100644
index 24c5149..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/IExceptionHandlingManager.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System.Threading.Tasks;
-namespace ForEvolve.ExceptionMapper
-{
- public interface IExceptionHandlingManager
- {
- Task HandleAsync(HttpContext context);
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionHandledResult.cs b/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionHandledResult.cs
deleted file mode 100644
index ea0212d..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionHandledResult.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ExceptionHandledResult : IExceptionHandlingResult
- {
- public ExceptionHandledResult(Exception error)
- {
- Error = error ?? throw new ArgumentNullException(nameof(error));
- ExceptionHandled = true;
- ExceptionHandlerFeatureSupported = true;
- }
-
- public bool ExceptionHandled { get; }
- public Exception Error { get; }
- public bool ExceptionHandlerFeatureSupported { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionHandlerFeatureNotSupportedResult.cs b/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionHandlerFeatureNotSupportedResult.cs
deleted file mode 100644
index 2100b06..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionHandlerFeatureNotSupportedResult.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public sealed class ExceptionHandlerFeatureNotSupportedResult : IExceptionHandlingResult
- {
- public bool ExceptionHandled { get; }
- public Exception Error { get; }
- public bool ExceptionHandlerFeatureSupported => false;
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionNotHandledResult.cs b/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionNotHandledResult.cs
deleted file mode 100644
index cf08590..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/Results/ExceptionNotHandledResult.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ExceptionNotHandledResult : IExceptionHandlingResult
- {
- public ExceptionNotHandledResult(Exception error)
- {
- Error = error ?? throw new ArgumentNullException(nameof(error));
- ExceptionHandlerFeatureSupported = true;
- }
-
- public bool ExceptionHandled { get; }
- public Exception Error { get; }
- public bool ExceptionHandlerFeatureSupported { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/Results/IExceptionHandlingResult.cs b/src/ForEvolve.ExceptionMapper.Core/Results/IExceptionHandlingResult.cs
deleted file mode 100644
index 5c105fe..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/Results/IExceptionHandlingResult.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public interface IExceptionHandlingResult
- {
- bool ExceptionHandled { get; }
- Exception Error { get; }
- bool ExceptionHandlerFeatureSupported { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Core/Results/NoExceptionResult.cs b/src/ForEvolve.ExceptionMapper.Core/Results/NoExceptionResult.cs
deleted file mode 100644
index 8c2eaa7..0000000
--- a/src/ForEvolve.ExceptionMapper.Core/Results/NoExceptionResult.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class NoExceptionResult : IExceptionHandlingResult
- {
- public NoExceptionResult()
- {
- ExceptionHandlerFeatureSupported = true;
- }
-
- public bool ExceptionHandled { get; }
- public Exception Error { get; }
- public bool ExceptionHandlerFeatureSupported { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentExceptionHandler.cs b/src/ForEvolve.ExceptionMapper.FluentMapper/FluentExceptionHandler.cs
deleted file mode 100644
index eb8a7ea..0000000
--- a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentExceptionHandler.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using ForEvolve.ExceptionMapper;
-using System;
-using System.Threading.Tasks;
-
-namespace ForEvolve.ExceptionMapper.FluentMapper
-{
- public class FluentExceptionHandler : IExceptionHandler
- where TException : Exception
- {
- public int Order { get; set; } = HandlerOrder.DefaultOrder;
- private Func _handler;
-
- public Task ExecuteAsync(ExceptionHandlingContext context)
- {
- if (_handler == null)
- {
- return Task.CompletedTask;
- }
- var task = _handler?.Invoke(context);
- if (!context.Result.ExceptionHandled)
- {
- context.Result = new ExceptionHandledResult(context.Error);
- }
- return task;
- }
-
- public Task KnowHowToHandleAsync(Exception exception)
- {
- return Task.FromResult(exception is TException);
- }
-
- public void AppendHandler(Func handler)
- {
- if (handler == null) { throw new ArgumentNullException(nameof(handler)); }
- if (_handler == null)
- {
- _handler = handler;
- return;
- }
- _handler = (context) =>
- {
- var task1 = _handler.Invoke(context);
- var task2 = handler.Invoke(context);
- return Task.WhenAll(task1, task2);
- };
- }
-
- public void PrependHandler(Func handler)
- {
- if (handler == null) { throw new ArgumentNullException(nameof(handler)); }
- if (_handler == null)
- {
- _handler = handler;
- return;
- }
- _handler = (context) =>
- {
- var task1 = handler.Invoke(context);
- var task2 = _handler.Invoke(context);
- return Task.WhenAll(task1, task2);
- };
- }
-
- public void ReplaceHandler(Func handler)
- {
- _handler = handler ?? throw new ArgumentNullException(nameof(handler));
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentHandlerStrategy.cs b/src/ForEvolve.ExceptionMapper.FluentMapper/FluentHandlerStrategy.cs
deleted file mode 100644
index 5406a71..0000000
--- a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentHandlerStrategy.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace ForEvolve.ExceptionMapper.FluentMapper
-{
- public enum FluentHandlerStrategy
- {
- Append,
- Prepend,
- Replace
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperBuilder.cs b/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperBuilder.cs
deleted file mode 100644
index 72ef875..0000000
--- a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperBuilder.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-using System;
-
-namespace ForEvolve.ExceptionMapper.FluentMapper
-{
- public class FluentMapperBuilder
- where TException : Exception
- {
- public FluentMapperBuilder(IExceptionMappingBuilder builder, FluentExceptionHandler handler)
- {
- Builder = builder ?? throw new ArgumentNullException(nameof(builder));
- Handler = handler ?? throw new ArgumentNullException(nameof(handler));
- }
-
- public IExceptionMappingBuilder Builder { get; }
-
- public IServiceCollection Services => Builder.Services;
-
- public FluentExceptionHandler Handler { get; }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperBuilderExtensions.cs b/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperBuilderExtensions.cs
deleted file mode 100644
index f6f0ab1..0000000
--- a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperBuilderExtensions.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using ForEvolve.ExceptionMapper;
-using ForEvolve.ExceptionMapper.FluentMapper;
-using System;
-using System.Threading.Tasks;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- public static class FluentMapperBuilderExtensions
- {
- public static FluentMapperBuilder ToStatusCode(this FluentMapperBuilder fluentBuilder, int expectedStatusCode, FluentHandlerStrategy strategy = FluentHandlerStrategy.Replace)
- where TException : Exception
- {
- return fluentBuilder.To(
- context => StatusCodeHandler(context, expectedStatusCode),
- strategy
- );
-
- static Task StatusCodeHandler(ExceptionHandlingContext context, int statusCode)
- {
- context.HttpContext.Response.StatusCode = statusCode;
- return Task.CompletedTask;
- }
- }
-
- public static FluentMapperBuilder To(this FluentMapperBuilder fluentBuilder, Func handler, FluentHandlerStrategy strategy = FluentHandlerStrategy.Replace)
- where TException : Exception
- {
- switch (strategy)
- {
- case FluentHandlerStrategy.Append:
- fluentBuilder.Handler.AppendHandler(handler);
- break;
- case FluentHandlerStrategy.Prepend:
- fluentBuilder.Handler.PrependHandler(handler);
- break;
- case FluentHandlerStrategy.Replace:
- fluentBuilder.Handler.ReplaceHandler(handler);
- break;
- default:
- throw new NotSupportedException($"The strategy '{strategy}' is not supported.");
- }
- return fluentBuilder;
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperExceptionMappingBuilderExtensions.cs b/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperExceptionMappingBuilderExtensions.cs
deleted file mode 100644
index 6d1a382..0000000
--- a/src/ForEvolve.ExceptionMapper.FluentMapper/FluentMapperExceptionMappingBuilderExtensions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using ForEvolve.ExceptionMapper.FluentMapper;
-using System;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- public static class FluentMapperExceptionMappingBuilderExtensions
- {
- public static IExceptionMappingBuilder Map(this IExceptionMappingBuilder builder, Action> mapperAction)
- where TException : Exception
- {
- if (mapperAction == null) { throw new ArgumentNullException(nameof(mapperAction)); }
-
- var handler = new FluentExceptionHandler();
- var fluentMapper = new FluentMapperBuilder(builder, handler);
- builder.AddExceptionHandler(handler);
- mapperAction.Invoke(fluentMapper);
- return builder;
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.FluentMapper/ForEvolve.ExceptionMapper.FluentMapper.csproj b/src/ForEvolve.ExceptionMapper.FluentMapper/ForEvolve.ExceptionMapper.FluentMapper.csproj
deleted file mode 100644
index 2a2dbc7..0000000
--- a/src/ForEvolve.ExceptionMapper.FluentMapper/ForEvolve.ExceptionMapper.FluentMapper.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- netstandard2.0
-
-
-
-
-
-
-
diff --git a/src/ForEvolve.ExceptionMapper.HttpMiddleware/ApplicationBuilderExtensions.cs b/src/ForEvolve.ExceptionMapper.HttpMiddleware/ApplicationBuilderExtensions.cs
deleted file mode 100644
index 7238f06..0000000
--- a/src/ForEvolve.ExceptionMapper.HttpMiddleware/ApplicationBuilderExtensions.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using ForEvolve.ExceptionMapper;
-namespace Microsoft.AspNetCore.Builder
-{
- public static class ApplicationBuilderExtensions
- {
- public static IApplicationBuilder UseExceptionMapper(this IApplicationBuilder app)
- {
- app.UseExceptionHandler(errorApp =>
- {
- errorApp.UseMiddleware();
- });
- app.UseMiddleware();
- return app;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.HttpMiddleware/ForEvolve.ExceptionMapper.HttpMiddleware.csproj b/src/ForEvolve.ExceptionMapper.HttpMiddleware/ForEvolve.ExceptionMapper.HttpMiddleware.csproj
deleted file mode 100644
index 1d73bd0..0000000
--- a/src/ForEvolve.ExceptionMapper.HttpMiddleware/ForEvolve.ExceptionMapper.HttpMiddleware.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- netstandard2.0
-
-
-
-
-
-
-
-
diff --git a/src/ForEvolve.ExceptionMapper.HttpMiddleware/HttpExceptionHandlingMiddleware.cs b/src/ForEvolve.ExceptionMapper.HttpMiddleware/HttpExceptionHandlingMiddleware.cs
deleted file mode 100644
index 8acb2ac..0000000
--- a/src/ForEvolve.ExceptionMapper.HttpMiddleware/HttpExceptionHandlingMiddleware.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Threading.Tasks;
-namespace ForEvolve.ExceptionMapper
-{
- public class HttpExceptionHandlingMiddleware
- {
- private readonly RequestDelegate _next;
- private readonly IExceptionHandlingManager _exceptionHandlingManager;
-
- public HttpExceptionHandlingMiddleware(IExceptionHandlingManager exceptionHandlingManager, RequestDelegate next)
- {
- _exceptionHandlingManager = exceptionHandlingManager ?? throw new ArgumentNullException(nameof(exceptionHandlingManager));
- _next = next;
- }
-
- public async Task InvokeAsync(HttpContext context)
- {
- var result = await _exceptionHandlingManager.HandleAsync(context);
- if (result.ExceptionHandled)
- {
- return;
- }
- await _next(context);
- }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.HttpMiddleware/UnhandledStatusCodeException.cs b/src/ForEvolve.ExceptionMapper.HttpMiddleware/UnhandledStatusCodeException.cs
deleted file mode 100644
index ed0bc13..0000000
--- a/src/ForEvolve.ExceptionMapper.HttpMiddleware/UnhandledStatusCodeException.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System;
-namespace ForEvolve.ExceptionMapper
-{
- public class UnhandledStatusCodeException : Exception
- {
- public UnhandledStatusCodeException()
- : base($"An unhandled error occured.") { }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.HttpMiddleware/UnhandledStatusCodeMiddleware.cs b/src/ForEvolve.ExceptionMapper.HttpMiddleware/UnhandledStatusCodeMiddleware.cs
deleted file mode 100644
index f0fc1d1..0000000
--- a/src/ForEvolve.ExceptionMapper.HttpMiddleware/UnhandledStatusCodeMiddleware.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Threading.Tasks;
-namespace ForEvolve.ExceptionMapper
-{
- public class UnhandledStatusCodeMiddleware
- {
- private readonly RequestDelegate _next;
-
- public UnhandledStatusCodeMiddleware(RequestDelegate next) => _next = next;
-
- public async Task InvokeAsync(HttpContext context)
- {
- await _next(context);
-
- if (context.Response.HasStarted)
- {
- return;
- }
-
- // Client errors (400–499)
- // Server errors (500–599)
- if (context.Response.StatusCode >= 400)
- {
- switch (context.Response.StatusCode)
- {
- case StatusCodes.Status400BadRequest:
- throw new BadRequestException();
- case StatusCodes.Status401Unauthorized:
- throw new UnauthorizedException();
- case StatusCodes.Status403Forbidden:
- throw new ForbiddenException();
- case StatusCodes.Status404NotFound:
- throw new ResourceNotFoundException(context);
- case StatusCodes.Status409Conflict:
- throw new ConflictException();
- case StatusCodes.Status500InternalServerError:
- throw new InternalServerErrorException(new UnhandledStatusCodeException());
- case StatusCodes.Status501NotImplemented:
- throw new NotImplementedException();
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper.Mvc/Class1.cs b/src/ForEvolve.ExceptionMapper.Mvc/Class1.cs
deleted file mode 100644
index d6143e6..0000000
--- a/src/ForEvolve.ExceptionMapper.Mvc/Class1.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using System;
-
-namespace ForEvolve.ExceptionMapper.Mvc
-{
- public class Class1
- {
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.Mvc/ForEvolve.ExceptionMapper.Mvc.csproj b/src/ForEvolve.ExceptionMapper.Mvc/ForEvolve.ExceptionMapper.Mvc.csproj
deleted file mode 100644
index 7599bbf..0000000
--- a/src/ForEvolve.ExceptionMapper.Mvc/ForEvolve.ExceptionMapper.Mvc.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- netstandard2.0
- False
-
-
-
-
-
-
-
diff --git a/src/ForEvolve.ExceptionMapper.Scrutor/AspNetExceptionMappingBuilderExtensions.cs b/src/ForEvolve.ExceptionMapper.Scrutor/AspNetExceptionMappingBuilderExtensions.cs
deleted file mode 100644
index ff00407..0000000
--- a/src/ForEvolve.ExceptionMapper.Scrutor/AspNetExceptionMappingBuilderExtensions.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using ForEvolve.ExceptionMapper;
-using Scrutor;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- public static class AspNetExceptionMappingBuilderExtensions
- {
- /// The type in which assembly that should be scanned.
- public static IExceptionMappingBuilder ScanHandlersFromAssemblyOf(this IExceptionMappingBuilder builder, ServiceLifetime lifetime = ServiceLifetime.Singleton)
- {
- return builder.ScanHandlersFrom(s => s.FromAssemblyOf(), lifetime);
- }
-
- public static IExceptionMappingBuilder ScanHandlersFrom(this IExceptionMappingBuilder builder, Func typeSelector, ServiceLifetime lifetime = ServiceLifetime.Singleton)
- {
- if (typeSelector == null) { throw new ArgumentNullException(nameof(typeSelector)); }
-
- builder.Services.Scan(s => typeSelector(s)
- .AddClasses(f => f.AssignableTo())
- .As()
- .WithLifetime(lifetime)
- );
- return builder;
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.Scrutor/ForEvolve.ExceptionMapper.Scrutor.csproj b/src/ForEvolve.ExceptionMapper.Scrutor/ForEvolve.ExceptionMapper.Scrutor.csproj
deleted file mode 100644
index f69062f..0000000
--- a/src/ForEvolve.ExceptionMapper.Scrutor/ForEvolve.ExceptionMapper.Scrutor.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- netstandard2.0
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/ForEvolve.ExceptionMapper.Serialization.Json/ForEvolve.ExceptionMapper.Serialization.Json.csproj b/src/ForEvolve.ExceptionMapper.Serialization.Json/ForEvolve.ExceptionMapper.Serialization.Json.csproj
deleted file mode 100644
index 02d4dc3..0000000
--- a/src/ForEvolve.ExceptionMapper.Serialization.Json/ForEvolve.ExceptionMapper.Serialization.Json.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- netcoreapp3.1;net5.0;net6.0
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/ForEvolve.ExceptionMapper.Serialization.Json/ProblemDetailsSerializationHandler.cs b/src/ForEvolve.ExceptionMapper.Serialization.Json/ProblemDetailsSerializationHandler.cs
deleted file mode 100644
index e79e953..0000000
--- a/src/ForEvolve.ExceptionMapper.Serialization.Json/ProblemDetailsSerializationHandler.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System;
-using System.Text.Json;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Options;
-
-namespace ForEvolve.ExceptionMapper.Serialization.Json
-{
- public class ProblemDetailsSerializationHandler : IExceptionHandler
- {
- private readonly ProblemDetailsFactory _problemDetailsFactory;
- private readonly IHostEnvironment _hostEnvironment;
- private readonly ProblemDetailsSerializationOptions _options;
-
- public ProblemDetailsSerializationHandler(ProblemDetailsFactory problemDetailsFactory, IHostEnvironment hostEnvironment, ProblemDetailsSerializationOptions options)
- {
- _problemDetailsFactory = problemDetailsFactory ?? throw new ArgumentNullException(nameof(problemDetailsFactory));
- _hostEnvironment = hostEnvironment ?? throw new ArgumentNullException(nameof(hostEnvironment));
- _options = options ?? throw new ArgumentNullException(nameof(options));
- }
-
- public int Order => HandlerOrder.SerializerOrder;
-
- public async Task ExecuteAsync(ExceptionHandlingContext ctx)
- {
- var problemDetails = _problemDetailsFactory.CreateProblemDetails(
- ctx.HttpContext,
- title: ctx.Error.Message,
- statusCode: ctx.HttpContext.Response.StatusCode
- );
-
- var displayDebugInformation = _options.DisplayDebugInformation?.Invoke() ?? false;
- if (displayDebugInformation || _hostEnvironment.IsDevelopment())
- {
- var errorType = ctx.Error.GetType();
- problemDetails.Extensions.Add(
- "debug",
- new {
- type = new {
- name = errorType.Name,
- fullName = errorType.FullName,
- },
- stackTrace = ctx.Error.StackTrace,
- }
- );
- }
-
- ctx.HttpContext.Response.ContentType = _options.ContentType;
- if(_options.JsonSerializerOptions is null)
- {
- await JsonSerializer.SerializeAsync(
- ctx.HttpContext.Response.Body,
- problemDetails
- );
- }
- else
- {
- await JsonSerializer.SerializeAsync(
- ctx.HttpContext.Response.Body,
- problemDetails,
- _options.JsonSerializerOptions
- );
- }
- }
-
- public Task KnowHowToHandleAsync(Exception exception)
- {
- return Task.FromResult(_options.SerializeExceptions);
- }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.Serialization.Json/ProblemDetailsSerializationOptions.cs b/src/ForEvolve.ExceptionMapper.Serialization.Json/ProblemDetailsSerializationOptions.cs
deleted file mode 100644
index 2de1ad0..0000000
--- a/src/ForEvolve.ExceptionMapper.Serialization.Json/ProblemDetailsSerializationOptions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Microsoft.Extensions.Options;
-using System;
-using System.Text.Json;
-
-namespace ForEvolve.ExceptionMapper.Serialization.Json
-{
- public class ProblemDetailsSerializationOptions
- {
- public ProblemDetailsSerializationOptions()
- {
- SerializeExceptions = true;
- DisplayDebugInformation = () => false;
- ContentType = "application/problem+json; charset=utf-8";
- }
-
- public bool SerializeExceptions { get; set; }
- public Func DisplayDebugInformation { get; set; }
- public string ContentType { get; set; }
- public JsonSerializerOptions JsonSerializerOptions { get; set; }
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper.Serialization.Json/SerializationJsonExtensions.cs b/src/ForEvolve.ExceptionMapper.Serialization.Json/SerializationJsonExtensions.cs
deleted file mode 100644
index 3086730..0000000
--- a/src/ForEvolve.ExceptionMapper.Serialization.Json/SerializationJsonExtensions.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
-
-namespace ForEvolve.ExceptionMapper.Serialization.Json
-{
- public static class SerializationJsonExtensions
- {
- public static IExceptionMappingBuilder SerializeAsProblemDetails(this IExceptionMappingBuilder builder)
- => SerializeAsProblemDetails(builder, new ProblemDetailsSerializationOptions());
-
- public static IExceptionMappingBuilder SerializeAsProblemDetails(this IExceptionMappingBuilder builder, ProblemDetailsSerializationOptions options)
- {
- builder.Services.AddSingleton(options);
- return builder.SerializeAsProblemDetailsCore();
- }
-
- public static IExceptionMappingBuilder SerializeAsProblemDetails(this IExceptionMappingBuilder builder, IConfiguration configuration)
- {
- builder.Services
- .Configure(configuration)
- .AddSingleton(ctx => ctx.GetService>().CurrentValue)
- ;
- return builder.SerializeAsProblemDetailsCore();
- }
-
- private static IExceptionMappingBuilder SerializeAsProblemDetailsCore(this IExceptionMappingBuilder builder)
- {
- builder.Services.AddMvcCore(); // Workaround
- return builder.AddExceptionHandler();
- }
-
- }
-}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrorException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrorException.cs
new file mode 100644
index 0000000..8e11789
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrorException.cs
@@ -0,0 +1,20 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// Client error responses (400 – 499)
+///
See also
+///
+public abstract class ClientErrorException : ForEvolveException
+{
+ public ClientErrorException()
+ {
+ }
+
+ public ClientErrorException(string message) : base(message)
+ {
+ }
+
+ public ClientErrorException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/BadRequestException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/BadRequestException.cs
new file mode 100644
index 0000000..05c2979
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/BadRequestException.cs
@@ -0,0 +1,22 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
+///
See also
+///
+/// 400 Bad Request
+public class BadRequestException : ClientErrorException
+{
+ public BadRequestException()
+ : base("The server can not process the request due to a client error. Resolve the issue and try again.")
+ {
+ }
+
+ public BadRequestException(string message) : base(message)
+ {
+ }
+
+ public BadRequestException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ConflictException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ConflictException.cs
new file mode 100644
index 0000000..1df3694
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ConflictException.cs
@@ -0,0 +1,22 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// This response is sent when a request conflicts with the current state of the server.
+///
See also
+///
+/// 409 Conflict
+public class ConflictException : ClientErrorException
+{
+ public ConflictException()
+ : base("The request conflicts with the current state of the server.")
+ {
+ }
+
+ public ConflictException(string message) : base(message)
+ {
+ }
+
+ public ConflictException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ForbiddenException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ForbiddenException.cs
new file mode 100644
index 0000000..aab0bef
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ForbiddenException.cs
@@ -0,0 +1,22 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// The client does not have access rights to the content; that is, it is unauthorized, so the server is refusing to give the requested resource. Unlike 401 Unauthorized, the client's identity is known to the server.
+///
See also
+///
+/// 403 Forbidden
+public class ForbiddenException : ClientErrorException
+{
+ public ForbiddenException()
+ : base("You do not have access rights to the content.")
+ {
+ }
+
+ public ForbiddenException(string message) : base(message)
+ {
+ }
+
+ public ForbiddenException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/GoneException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/GoneException.cs
new file mode 100644
index 0000000..23a5343
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/GoneException.cs
@@ -0,0 +1,22 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// This response is sent when the requested content has been permanently deleted from server, with no forwarding address. Clients are expected to remove their caches and links to the resource. The HTTP specification intends this status code to be used for "limited-time, promotional services". APIs should not feel compelled to indicate resources that have been deleted with this status code.
+///
See also
+///
+/// 410 Gone
+public class GoneException : ClientErrorException
+{
+ public GoneException()
+ : base("The requested content has been permanently deleted from server.")
+ {
+ }
+
+ public GoneException(string message) : base(message)
+ {
+ }
+
+ public GoneException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/NotFoundException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/NotFoundException.cs
new file mode 100644
index 0000000..5ab1ffd
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/NotFoundException.cs
@@ -0,0 +1,22 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// The server cannot find the requested resource. In the browser, this means the URL is not recognized. In an API, this can also mean that the endpoint is valid but the resource itself does not exist. Servers may also send this response instead of 403 Forbidden to hide the existence of a resource from an unauthorized client. This response code is probably the most well known due to its frequent occurrence on the web.
+///
See also
+///
+/// 404 Not Found
+public class NotFoundException : ClientErrorException
+{
+ public NotFoundException()
+ : base("The server cannot find the requested resource.")
+ {
+ }
+
+ public NotFoundException(string message) : base(message)
+ {
+ }
+
+ public NotFoundException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ResourceNotFoundException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ResourceNotFoundException.cs
new file mode 100644
index 0000000..c59a37b
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/ResourceNotFoundException.cs
@@ -0,0 +1,18 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Extensions;
+
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// The server cannot find the requested resource. In the browser, this means the URL is not recognized. In an API, this can also mean that the endpoint is valid but the resource itself does not exist.
+///
See also
+///
+/// 404 Not Found
A default error message is created using the requested URL.
+public class ResourceNotFoundException : NotFoundException
+{
+ public ResourceNotFoundException(HttpContext context)
+ : base($"The server cannot find the following resource: '{context.Request.GetDisplayUrl()}'.")
+ {
+
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/UnauthorizedException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/UnauthorizedException.cs
new file mode 100644
index 0000000..28489ea
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ClientErrors/UnauthorizedException.cs
@@ -0,0 +1,22 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// Although the HTTP standard specifies "unauthorized", semantically this response means "unauthenticated". That is, the client must authenticate itself to get the requested response.
+///
See also
+///
+/// 401 Unauthorized
+public class UnauthorizedException : ClientErrorException
+{
+ public UnauthorizedException()
+ : base("You must be authenticated to access the requested resource.")
+ {
+ }
+
+ public UnauthorizedException(string message) : base(message)
+ {
+ }
+
+ public UnauthorizedException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrorException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrorException.cs
new file mode 100644
index 0000000..4c84abf
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrorException.cs
@@ -0,0 +1,20 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// Server error responses (500 – 599)
+///
See also
+///
+public abstract class ServerErrorException : ForEvolveException
+{
+ public ServerErrorException()
+ {
+ }
+
+ public ServerErrorException(string message) : base(message)
+ {
+ }
+
+ public ServerErrorException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/GatewayTimeoutException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/GatewayTimeoutException.cs
new file mode 100644
index 0000000..05615c0
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/GatewayTimeoutException.cs
@@ -0,0 +1,22 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// This error response is given when the server is acting as a gateway and cannot get a response in time.
+///
See also
+///
+/// 504 Gateway Timeout
+public class GatewayTimeoutException : ServerErrorException
+{
+ public GatewayTimeoutException()
+ : base("The server was not able to get the response in time.")
+ {
+ }
+
+ public GatewayTimeoutException(string message) : base(message)
+ {
+ }
+
+ public GatewayTimeoutException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/InternalServerErrorException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/InternalServerErrorException.cs
new file mode 100644
index 0000000..4dccde8
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/InternalServerErrorException.cs
@@ -0,0 +1,16 @@
+namespace ForEvolve.ExceptionMapper;
+
+
+///
+/// The server has encountered a situation it does not know how to handle.
+///
See also
+///
+/// 500 Internal Server Error
+public class InternalServerErrorException : ServerErrorException
+{
+ public InternalServerErrorException(Exception innerException)
+ : base(innerException.Message, innerException)
+ {
+
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/ServiceUnavailableException.cs b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/ServiceUnavailableException.cs
new file mode 100644
index 0000000..6b6cf4b
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonExceptions/ServerErrors/ServiceUnavailableException.cs
@@ -0,0 +1,22 @@
+namespace ForEvolve.ExceptionMapper;
+
+///
+/// The server is not ready to handle the request. Common causes are a server that is down for maintenance or that is overloaded. Note that together with this response, a user-friendly page explaining the problem should be sent. This response should be used for temporary conditions and the Retry-After HTTP header should, if possible, contain the estimated time before the recovery of the service. The webmaster must also take care about the caching-related headers that are sent along with this response, as these temporary condition responses should usually not be cached.
+///
See also
+///
+/// 503 Service Unavailable
+public class ServiceUnavailableException : ServerErrorException
+{
+ public ServiceUnavailableException()
+ : base("The server is not ready to handle the request.")
+ {
+ }
+
+ public ServiceUnavailableException(string message) : base(message)
+ {
+ }
+
+ public ServiceUnavailableException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandler.cs b/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandler.cs
new file mode 100644
index 0000000..2305f79
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandler.cs
@@ -0,0 +1,35 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+
+namespace ForEvolve.ExceptionMapper.Handlers.Fallback;
+
+public class FallbackExceptionHandler : IExceptionHandler
+{
+ private readonly FallbackExceptionHandlerOptions _options;
+ public FallbackExceptionHandler(IOptionsMonitor options)
+ {
+ _options = options.CurrentValue;
+ }
+
+ public Task CanHandle(Exception exception)
+ {
+ if (_options.Strategy == FallbackStrategy.Handle)
+ {
+ return Task.FromResult(true);
+ }
+ return Task.FromResult(false);
+ }
+
+ public Task ExecuteAsync(ExceptionHandlingContext context)
+ {
+ if (_options.Strategy == FallbackStrategy.Handle)
+ {
+ if (!context.Result.ExceptionHandled)
+ {
+ context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
+ context.Result = new ExceptionHandledResult(context.Error);
+ }
+ }
+ return Task.CompletedTask;
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerOptions.cs b/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerOptions.cs
new file mode 100644
index 0000000..fc2a438
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerOptions.cs
@@ -0,0 +1,6 @@
+namespace ForEvolve.ExceptionMapper.Handlers.Fallback;
+
+public class FallbackExceptionHandlerOptions
+{
+ public FallbackStrategy Strategy { get; set; } = FallbackStrategy.Handle;
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackStrategy.cs b/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackStrategy.cs
new file mode 100644
index 0000000..28874fd
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/CommonHttpExceptionHandlers/Fallback/FallbackStrategy.cs
@@ -0,0 +1,7 @@
+namespace ForEvolve.ExceptionMapper.Handlers.Fallback;
+
+public enum FallbackStrategy
+{
+ Ignore = 0,
+ Handle = 1
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/DependencyInjection/ApplicationBuilderExtensions.cs b/src/ForEvolve.ExceptionMapper/DependencyInjection/ApplicationBuilderExtensions.cs
new file mode 100644
index 0000000..d3eaeb4
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/DependencyInjection/ApplicationBuilderExtensions.cs
@@ -0,0 +1,15 @@
+using ForEvolve.ExceptionMapper;
+namespace Microsoft.AspNetCore.Builder;
+
+public static class ApplicationBuilderExtensions
+{
+ public static IApplicationBuilder UseExceptionMapper(this IApplicationBuilder app)
+ {
+ app.UseExceptionHandler(errorApp =>
+ {
+ errorApp.UseMiddleware();
+ });
+ app.UseMiddleware();
+ return app;
+ }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionExtensions.cs b/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000..3972fe1
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionExtensions.cs
@@ -0,0 +1,125 @@
+using ForEvolve.ExceptionMapper;
+using ForEvolve.ExceptionMapper.Handlers.Fallback;
+using ForEvolve.ExceptionMapper.Serialization;
+using ForEvolve.ExceptionMapper.Serialization.Json;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Options;
+
+namespace Microsoft.Extensions.DependencyInjection;
+
+public static class ServiceCollectionExceptionFiltersExtensions
+{
+ public static IServiceCollection AddExceptionMapper(this IServiceCollection services, IConfiguration configuration, Action? exceptionMappingBuilder = null)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.TryAddSingleton();
+ services.AddSerializationHandler(configuration);
+
+ var builder = new ExceptionMappingBuilder(services);
+ builder
+ // Common client exceptions
+ .Map().ToStatusCode(StatusCodes.Status400BadRequest)
+ .Map().ToStatusCode(StatusCodes.Status409Conflict)
+ .Map().ToStatusCode(StatusCodes.Status403Forbidden)
+ .Map().ToStatusCode(StatusCodes.Status410Gone)
+ .Map().ToStatusCode(StatusCodes.Status404NotFound)
+ .Map().ToStatusCode(StatusCodes.Status404NotFound)
+ .Map().ToStatusCode(StatusCodes.Status401Unauthorized)
+
+ // .NET exceptions
+ .Map().ToStatusCode(StatusCodes.Status400BadRequest)
+ .Map().ToStatusCode(StatusCodes.Status501NotImplemented)
+
+ // Common server exceptions
+ .Map().ToStatusCode(StatusCodes.Status504GatewayTimeout)
+ .Map().ToStatusCode(StatusCodes.Status500InternalServerError)
+ .Map().ToStatusCode(StatusCodes.Status503ServiceUnavailable)
+ ;
+ exceptionMappingBuilder?.Invoke(builder);
+ services.AddFallbackExceptionHandler(configuration, builder);
+ return services;
+ }
+
+ public static WebApplicationBuilder AddExceptionMapper(this WebApplicationBuilder builder, Action? exceptionMappingBuilder = null)
+ {
+ AddExceptionMapper(builder.Services, builder.Configuration, exceptionMappingBuilder);
+ return builder;
+ }
+
+ 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();
+ }
+
+ private static void AddFallbackExceptionHandler(this IServiceCollection services, IConfiguration configuration, IExceptionMappingBuilder builder)
+ {
+ services
+ .AddOptions()
+ .Bind(configuration.GetSection("ExceptionMapper:FallbackExceptionHandler"))
+ .ValidateOnStart()
+ ;
+ services.AddSingleton(sp => sp.GetRequiredService>().Value);
+ builder.AddExceptionHandler();
+ }
+
+ public static Map Map(this IExceptionMappingBuilder builder)
+ where TException : Exception
+ {
+ return new Map(builder);
+ }
+
+ public static IExceptionMappingBuilder ToStatusCode(this Map map, int expectedStatusCode)
+ where TException : Exception
+ {
+ map.Builder.Services.AddSingleton(new StatusCodeExceptionHandler(expectedStatusCode));
+ return map.Builder;
+ }
+
+ public static IExceptionMappingBuilder AddExceptionHandler(this IExceptionMappingBuilder builder)
+ where THandler : class, IExceptionHandler
+ {
+ builder.Services.AddSingleton();
+ return builder;
+ }
+
+ public static IExceptionMappingBuilder AddExceptionHandler(this IExceptionMappingBuilder builder, THandler handler)
+ where THandler : class, IExceptionHandler
+ {
+ builder.Services.AddSingleton(handler);
+ return builder;
+ }
+}
+
+public class Map
+ where TException : Exception
+{
+ public Map(IExceptionMappingBuilder builder)
+ {
+ Builder = builder;
+ }
+
+ public IExceptionMappingBuilder Builder { get; }
+}
diff --git a/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionWrapper.cs b/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionWrapper.cs
new file mode 100644
index 0000000..2abe008
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/DependencyInjection/ServiceCollectionWrapper.cs
@@ -0,0 +1,14 @@
+using ForEvolve.ExceptionMapper;
+
+namespace Microsoft.Extensions.DependencyInjection;
+
+public class ExceptionMappingBuilder : IExceptionMappingBuilder
+{
+ public ExceptionMappingBuilder(IServiceCollection services)
+ {
+ Services = services ?? throw new ArgumentNullException(nameof(services));
+ }
+
+ public IServiceCollection Services { get; }
+ public IList Handlers { get; } = new List();
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/ExceptionHandler.cs b/src/ForEvolve.ExceptionMapper/ExceptionHandler.cs
new file mode 100644
index 0000000..cec492f
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/ExceptionHandler.cs
@@ -0,0 +1,24 @@
+namespace ForEvolve.ExceptionMapper;
+
+public abstract class ExceptionHandler : IExceptionHandler
+ where TException : Exception
+{
+ public abstract int StatusCode { get; }
+
+ public virtual Task CanHandle(Exception exception)
+ {
+ return Task.FromResult(exception is TException);
+ }
+
+ public virtual Task ExecuteAsync(ExceptionHandlingContext context)
+ {
+ context.HttpContext.Response.StatusCode = StatusCode;
+ context.Result = new ExceptionHandledResult(context.Error);
+ return ExecuteCoreAsync(new ExceptionHandlingContext(context));
+ }
+
+ protected virtual Task ExecuteCoreAsync(ExceptionHandlingContext context)
+ {
+ return Task.CompletedTask;
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/ExceptionHandlerCollection.cs b/src/ForEvolve.ExceptionMapper/ExceptionHandlerCollection.cs
new file mode 100644
index 0000000..3dfc977
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/ExceptionHandlerCollection.cs
@@ -0,0 +1,69 @@
+using ForEvolve.ExceptionMapper;
+using System.Collections;
+
+namespace Microsoft.Extensions.DependencyInjection;
+
+public class ExceptionHandlerCollection : IList
+{
+ private List _exceptionHandlers = new();
+ public ExceptionHandlerCollection(IEnumerable exceptionHandlers)
+ {
+ _exceptionHandlers.AddRange(exceptionHandlers);
+ }
+
+ public IExceptionHandler this[int index] { get => ((IList)_exceptionHandlers)[index]; set => ((IList)_exceptionHandlers)[index] = value; }
+
+ public int Count => ((ICollection)_exceptionHandlers).Count;
+
+ public bool IsReadOnly => ((ICollection)_exceptionHandlers).IsReadOnly;
+
+ public void Add(IExceptionHandler item)
+ {
+ ((ICollection)_exceptionHandlers).Add(item);
+ }
+
+ public void Clear()
+ {
+ ((ICollection)_exceptionHandlers).Clear();
+ }
+
+ public bool Contains(IExceptionHandler item)
+ {
+ return ((ICollection)_exceptionHandlers).Contains(item);
+ }
+
+ public void CopyTo(IExceptionHandler[] array, int arrayIndex)
+ {
+ ((ICollection)_exceptionHandlers).CopyTo(array, arrayIndex);
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return ((IEnumerable)_exceptionHandlers).GetEnumerator();
+ }
+
+ public int IndexOf(IExceptionHandler item)
+ {
+ return ((IList)_exceptionHandlers).IndexOf(item);
+ }
+
+ public void Insert(int index, IExceptionHandler item)
+ {
+ ((IList)_exceptionHandlers).Insert(index, item);
+ }
+
+ public bool Remove(IExceptionHandler item)
+ {
+ return ((ICollection)_exceptionHandlers).Remove(item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ ((IList)_exceptionHandlers).RemoveAt(index);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)_exceptionHandlers).GetEnumerator();
+ }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/ExceptionHandlingManager.cs b/src/ForEvolve.ExceptionMapper/ExceptionHandlingManager.cs
new file mode 100644
index 0000000..9ce2a97
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/ExceptionHandlingManager.cs
@@ -0,0 +1,84 @@
+using Microsoft.AspNetCore.Diagnostics;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using System.Collections.ObjectModel;
+namespace ForEvolve.ExceptionMapper;
+
+public class ExceptionHandlingManager : IExceptionHandlingManager
+{
+ private readonly ExceptionMapperOptions _options;
+
+ public ExceptionHandlingManager(ExceptionMapperOptions options)
+ {
+ _options = options ?? throw new ArgumentNullException(nameof(options));
+ }
+
+ public IReadOnlyCollection Handlers
+ => new ReadOnlyCollection(_options.Handlers);
+
+ public async Task HandleAsync(HttpContext httpContext)
+ {
+ var exceptionHandlerPathFeature = httpContext.Features.Get();
+ if (exceptionHandlerPathFeature == null)
+ {
+ return new ExceptionHandlerFeatureNotSupportedResult();
+ }
+
+ var exception = exceptionHandlerPathFeature.Error;
+ if (exception == null)
+ {
+ return new NoExceptionResult();
+ }
+
+ var context = new ExceptionHandlingContext(httpContext, exception, new ExceptionNotHandledResult(exception));
+ foreach (var handler in _options.Handlers)
+ {
+ if (await handler.CanHandle(exception))
+ {
+ await handler.ExecuteAsync(context);
+ }
+ }
+
+ await _options.Serializer.ExecuteAsync(context);
+
+ return context.Result;
+ }
+}
+
+public class ExceptionHandlingContext
+ where TException : Exception
+{
+ public ExceptionHandlingContext(ExceptionHandlingContext previous)
+ : this(previous.HttpContext, previous.Error as TException, previous.Result)
+ {
+ }
+
+ public ExceptionHandlingContext(ExceptionHandlingContext previous)
+ : this(previous.HttpContext, previous.Error, previous.Result)
+ {
+ }
+
+ public ExceptionHandlingContext(HttpContext httpContext, TException? error, IExceptionHandlingResult initialResult)
+ {
+ HttpContext = httpContext ?? throw new ArgumentNullException(nameof(httpContext));
+ Error = error ?? throw new ArgumentNullException(nameof(error));
+ Result = initialResult;
+ }
+
+ public HttpContext HttpContext { get; }
+ public TException Error { get; }
+ public IExceptionHandlingResult Result { get; set; }
+}
+
+public class ExceptionHandlingContext : ExceptionHandlingContext
+{
+ public ExceptionHandlingContext(ExceptionHandlingContext previous)
+ : base(previous)
+ {
+ }
+
+ public ExceptionHandlingContext(HttpContext httpContext, Exception error, IExceptionHandlingResult initialResult)
+ : base(httpContext, error, initialResult)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/ExceptionMapperOptions.cs b/src/ForEvolve.ExceptionMapper/ExceptionMapperOptions.cs
new file mode 100644
index 0000000..cfbf8f4
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/ExceptionMapperOptions.cs
@@ -0,0 +1,15 @@
+using ForEvolve.ExceptionMapper;
+
+namespace Microsoft.Extensions.DependencyInjection;
+
+public class ExceptionMapperOptions
+{
+ public ExceptionMapperOptions(ExceptionHandlerCollection handlers, IExceptionSerializer serializer)
+ {
+ Handlers = handlers ?? throw new ArgumentNullException(nameof(handlers));
+ Serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
+ }
+
+ public ExceptionHandlerCollection Handlers { get; }
+ public IExceptionSerializer Serializer { get; }
+}
diff --git a/src/ForEvolve.ExceptionMapper/ForEvolve.ExceptionMapper.csproj b/src/ForEvolve.ExceptionMapper/ForEvolve.ExceptionMapper.csproj
index 89bdeca..23b5384 100644
--- a/src/ForEvolve.ExceptionMapper/ForEvolve.ExceptionMapper.csproj
+++ b/src/ForEvolve.ExceptionMapper/ForEvolve.ExceptionMapper.csproj
@@ -1,20 +1,11 @@
-
- netstandard2.0;net5.0;net6.0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ $(FETargetFrameworks)
+
+
+
+
+
+
diff --git a/src/ForEvolve.ExceptionMapper/HttpMiddleware/HttpExceptionHandlingMiddleware.cs b/src/ForEvolve.ExceptionMapper/HttpMiddleware/HttpExceptionHandlingMiddleware.cs
new file mode 100644
index 0000000..c3f205e
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/HttpMiddleware/HttpExceptionHandlingMiddleware.cs
@@ -0,0 +1,24 @@
+using Microsoft.AspNetCore.Http;
+namespace ForEvolve.ExceptionMapper;
+
+public class HttpExceptionHandlingMiddleware
+{
+ private readonly RequestDelegate _next;
+ private readonly IExceptionHandlingManager _exceptionHandlingManager;
+
+ public HttpExceptionHandlingMiddleware(IExceptionHandlingManager exceptionHandlingManager, RequestDelegate next)
+ {
+ _exceptionHandlingManager = exceptionHandlingManager ?? throw new ArgumentNullException(nameof(exceptionHandlingManager));
+ _next = next;
+ }
+
+ public async Task InvokeAsync(HttpContext context)
+ {
+ var result = await _exceptionHandlingManager.HandleAsync(context);
+ if (result.ExceptionHandled)
+ {
+ return;
+ }
+ await _next(context);
+ }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/HttpMiddleware/UnhandledStatusCodeException.cs b/src/ForEvolve.ExceptionMapper/HttpMiddleware/UnhandledStatusCodeException.cs
new file mode 100644
index 0000000..fb7d6c8
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/HttpMiddleware/UnhandledStatusCodeException.cs
@@ -0,0 +1,7 @@
+namespace ForEvolve.ExceptionMapper;
+
+public class UnhandledStatusCodeException : Exception
+{
+ public UnhandledStatusCodeException()
+ : base($"An unhandled error occurred.") { }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/HttpMiddleware/UnhandledStatusCodeMiddleware.cs b/src/ForEvolve.ExceptionMapper/HttpMiddleware/UnhandledStatusCodeMiddleware.cs
new file mode 100644
index 0000000..6a90231
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/HttpMiddleware/UnhandledStatusCodeMiddleware.cs
@@ -0,0 +1,42 @@
+using Microsoft.AspNetCore.Http;
+namespace ForEvolve.ExceptionMapper;
+
+public class UnhandledStatusCodeMiddleware
+{
+ private readonly RequestDelegate _next;
+
+ public UnhandledStatusCodeMiddleware(RequestDelegate next) => _next = next;
+
+ public async Task InvokeAsync(HttpContext context)
+ {
+ await _next(context);
+
+ if (context.Response.HasStarted)
+ {
+ return;
+ }
+
+ // Client errors (400–499)
+ // Server errors (500–599)
+ if (context.Response.StatusCode >= 400)
+ {
+ switch (context.Response.StatusCode)
+ {
+ case StatusCodes.Status400BadRequest:
+ throw new BadRequestException();
+ case StatusCodes.Status401Unauthorized:
+ throw new UnauthorizedException();
+ case StatusCodes.Status403Forbidden:
+ throw new ForbiddenException();
+ case StatusCodes.Status404NotFound:
+ throw new ResourceNotFoundException(context);
+ case StatusCodes.Status409Conflict:
+ throw new ConflictException();
+ case StatusCodes.Status500InternalServerError:
+ throw new InternalServerErrorException(new UnhandledStatusCodeException());
+ case StatusCodes.Status501NotImplemented:
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/IExceptionHandler.cs b/src/ForEvolve.ExceptionMapper/IExceptionHandler.cs
new file mode 100644
index 0000000..631f272
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/IExceptionHandler.cs
@@ -0,0 +1,7 @@
+namespace ForEvolve.ExceptionMapper;
+
+public interface IExceptionHandler
+{
+ Task CanHandle(Exception exception);
+ Task ExecuteAsync(ExceptionHandlingContext context);
+}
diff --git a/src/ForEvolve.ExceptionMapper/IExceptionHandlingManager.cs b/src/ForEvolve.ExceptionMapper/IExceptionHandlingManager.cs
new file mode 100644
index 0000000..f79ba3a
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/IExceptionHandlingManager.cs
@@ -0,0 +1,7 @@
+using Microsoft.AspNetCore.Http;
+namespace ForEvolve.ExceptionMapper;
+
+public interface IExceptionHandlingManager
+{
+ Task HandleAsync(HttpContext context);
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/IExceptionMappingBuilder.cs b/src/ForEvolve.ExceptionMapper/IExceptionMappingBuilder.cs
new file mode 100644
index 0000000..4e508dd
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/IExceptionMappingBuilder.cs
@@ -0,0 +1,7 @@
+namespace Microsoft.Extensions.DependencyInjection;
+
+public interface IExceptionMappingBuilder
+{
+ IServiceCollection Services { get; }
+ //IList Handlers { get; }
+}
diff --git a/src/ForEvolve.ExceptionMapper/IExceptionSerializer.cs b/src/ForEvolve.ExceptionMapper/IExceptionSerializer.cs
new file mode 100644
index 0000000..cc20880
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/IExceptionSerializer.cs
@@ -0,0 +1,6 @@
+namespace ForEvolve.ExceptionMapper;
+
+public interface IExceptionSerializer
+{
+ Task ExecuteAsync(ExceptionHandlingContext context);
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/Results/ExceptionHandledResult.cs b/src/ForEvolve.ExceptionMapper/Results/ExceptionHandledResult.cs
new file mode 100644
index 0000000..652e1bd
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/Results/ExceptionHandledResult.cs
@@ -0,0 +1,13 @@
+namespace ForEvolve.ExceptionMapper;
+
+public class ExceptionHandledResult : IExceptionHandlingResult
+{
+ public ExceptionHandledResult(Exception error)
+ {
+ Error = error ?? throw new ArgumentNullException(nameof(error));
+ ExceptionHandled = true;
+ }
+
+ public bool ExceptionHandled { get; }
+ public Exception Error { get; }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/Results/ExceptionHandlerFeatureNotSupportedResult.cs b/src/ForEvolve.ExceptionMapper/Results/ExceptionHandlerFeatureNotSupportedResult.cs
new file mode 100644
index 0000000..6a4a0c2
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/Results/ExceptionHandlerFeatureNotSupportedResult.cs
@@ -0,0 +1,7 @@
+namespace ForEvolve.ExceptionMapper;
+
+public sealed class ExceptionHandlerFeatureNotSupportedResult : IExceptionHandlingResult
+{
+ public bool ExceptionHandled { get; }
+ public Exception? Error { get; }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/Results/ExceptionNotHandledResult.cs b/src/ForEvolve.ExceptionMapper/Results/ExceptionNotHandledResult.cs
new file mode 100644
index 0000000..d2d02c3
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/Results/ExceptionNotHandledResult.cs
@@ -0,0 +1,12 @@
+namespace ForEvolve.ExceptionMapper;
+
+public class ExceptionNotHandledResult : IExceptionHandlingResult
+{
+ public ExceptionNotHandledResult(Exception error)
+ {
+ Error = error ?? throw new ArgumentNullException(nameof(error));
+ }
+
+ public bool ExceptionHandled { get; }
+ public Exception Error { get; }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/Results/IExceptionHandlingResult.cs b/src/ForEvolve.ExceptionMapper/Results/IExceptionHandlingResult.cs
new file mode 100644
index 0000000..f1a8ae5
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/Results/IExceptionHandlingResult.cs
@@ -0,0 +1,7 @@
+namespace ForEvolve.ExceptionMapper;
+
+public interface IExceptionHandlingResult
+{
+ bool ExceptionHandled { get; }
+ Exception? Error { get; }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/Results/NoExceptionResult.cs b/src/ForEvolve.ExceptionMapper/Results/NoExceptionResult.cs
new file mode 100644
index 0000000..9ef8bfc
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/Results/NoExceptionResult.cs
@@ -0,0 +1,7 @@
+namespace ForEvolve.ExceptionMapper;
+
+public class NoExceptionResult : IExceptionHandlingResult
+{
+ public bool ExceptionHandled { get; }
+ public Exception? Error { get; }
+}
\ No newline at end of file
diff --git a/src/ForEvolve.ExceptionMapper/Serialization/DefaultProblemDetailsFactory.cs b/src/ForEvolve.ExceptionMapper/Serialization/DefaultProblemDetailsFactory.cs
new file mode 100644
index 0000000..b61f82f
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/Serialization/DefaultProblemDetailsFactory.cs
@@ -0,0 +1,142 @@
+// 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;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.Extensions.Options;
+using System.Diagnostics;
+
+namespace ForEvolve.ExceptionMapper.Serialization;
+// Source: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Infrastructure/DefaultProblemDetailsFactory.cs
+// This is a workaround until (hopefully) the following issue get resolved: https://github.com/dotnet/aspnetcore/issues/49982
+
+internal sealed class DefaultProblemDetailsFactory : ProblemDetailsFactory
+{
+ private readonly ApiBehaviorOptions _options;
+ private readonly Action? _configure;
+
+ public DefaultProblemDetailsFactory(
+ IOptions options,
+ IOptions? problemDetailsOptions = null)
+ {
+ _options = options?.Value ?? throw new ArgumentNullException(nameof(options));
+ _configure = problemDetailsOptions?.Value?.CustomizeProblemDetails;
+ }
+
+ public override ProblemDetails CreateProblemDetails(
+ HttpContext httpContext,
+ int? statusCode = null,
+ string? title = null,
+ string? type = null,
+ string? detail = null,
+ string? instance = null)
+ {
+ statusCode ??= 500;
+
+ var problemDetails = new ProblemDetails
+ {
+ Status = statusCode,
+ Title = title,
+ Type = type,
+ Detail = detail,
+ Instance = instance,
+ };
+
+ ApplyProblemDetailsDefaults(httpContext, problemDetails, statusCode.Value);
+
+ return problemDetails;
+ }
+
+ public override ValidationProblemDetails CreateValidationProblemDetails(
+ HttpContext httpContext,
+ ModelStateDictionary modelStateDictionary,
+ int? statusCode = null,
+ string? title = null,
+ string? type = null,
+ string? detail = null,
+ string? instance = null)
+ {
+ ArgumentNullException.ThrowIfNull(modelStateDictionary);
+
+ statusCode ??= 400;
+
+ var problemDetails = new ValidationProblemDetails(modelStateDictionary)
+ {
+ Status = statusCode,
+ Type = type,
+ Detail = detail,
+ Instance = instance,
+ };
+
+ if (title != null)
+ {
+ // For validation problem details, don't overwrite the default title with null.
+ problemDetails.Title = title;
+ }
+
+ ApplyProblemDetailsDefaults(httpContext, problemDetails, statusCode.Value);
+
+ return problemDetails;
+ }
+
+ private void ApplyProblemDetailsDefaults(HttpContext httpContext, ProblemDetails problemDetails, int statusCode)
+ {
+ problemDetails.Status ??= statusCode;
+
+ if (_options.ClientErrorMapping.TryGetValue(statusCode, out var clientErrorData))
+ {
+ problemDetails.Title ??= clientErrorData.Title;
+ problemDetails.Type ??= clientErrorData.Link;
+ }
+
+ var traceId = Activity.Current?.Id ?? httpContext?.TraceIdentifier;
+ if (traceId != null)
+ {
+ problemDetails.Extensions["traceId"] = traceId;
+ }
+
+ _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
diff --git a/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationHandler.cs b/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationHandler.cs
new file mode 100644
index 0000000..87dcd6c
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationHandler.cs
@@ -0,0 +1,146 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Json;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Options;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Net.Http;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace ForEvolve.ExceptionMapper.Serialization.Json;
+
+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,
+ IOptions jsonOptions)
+ {
+ _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));
+ }
+
+ public async Task ExecuteAsync(ExceptionHandlingContext ctx)
+ {
+ if (!_options.SerializeExceptions)
+ {
+ await ctx.HttpContext.Response.CompleteAsync();
+ return;
+ }
+
+ var problemDetails = _problemDetailsFactory.CreateProblemDetails(
+ ctx.HttpContext,
+ title: ctx.Error.Message,
+ statusCode: ctx.HttpContext.Response.StatusCode
+ );
+
+ // Add debug info
+ var displayDebugInformation = _options.DisplayDebugInformation?.Invoke(ctx) ?? false;
+ if (displayDebugInformation || _hostEnvironment.IsDevelopment())
+ {
+ var errorType = ctx.Error.GetType();
+ problemDetails.Extensions.Add(
+ FormatName("debug"),
+ new
+ {
+ type = new
+ {
+ name = errorType.Name,
+ fullName = errorType.FullName,
+ },
+ stackTrace = ctx.Error.StackTrace,
+ }
+ );
+ }
+
+ // Remove the default "traceId" property and
+ // add it back with a key that is in line with the JSON serializer options.
+ var traceId = Activity.Current?.Id ?? ctx.HttpContext.TraceIdentifier;
+ if (traceId != null)
+ {
+ var traceIdKey = "traceId";
+ problemDetails.Extensions.Remove(traceIdKey);
+ problemDetails.Extensions.Add(FormatName(traceIdKey), traceId);
+ }
+
+ // Transfer non-excluded and non-JsonIgnored properties to the problem details.
+ var properties = TypeDescriptor.GetProperties(ctx.Error);
+ var propertiesToExclude = new string[] {
+ nameof(Exception.StackTrace),
+ nameof(Exception.Data),
+ nameof(Exception.HResult),
+ nameof(Exception.TargetSite),
+ nameof(Exception.Message),
+ nameof(Exception.Source),
+ nameof(Exception.InnerException),
+ };
+ foreach (PropertyDescriptor property in properties)
+ {
+ if (propertiesToExclude.Contains(property.Name))
+ {
+ continue;
+ }
+ if (property.Attributes.OfType().Any())
+ {
+ continue;
+ }
+
+ var value = property.GetValue(ctx.Error);
+ if (value != null)
+ {
+ problemDetails.Extensions.Add(FormatName(property.Name), value);
+ }
+ }
+
+ // 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)
+ {
+ return _jsonSerializerOptions.PropertyNamingPolicy?.ConvertName(name) ?? FormatToCamelCase(name);
+
+ static string FormatToCamelCase(string name)
+ => string.Concat(name[0].ToString().ToLower(), name.AsSpan(1));
+ }
+}
diff --git a/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationOptions.cs b/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationOptions.cs
new file mode 100644
index 0000000..b9bbd10
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/Serialization/Json/ProblemDetailsSerializationOptions.cs
@@ -0,0 +1,15 @@
+using System.Text.Json;
+
+namespace ForEvolve.ExceptionMapper.Serialization.Json;
+
+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/src/ForEvolve.ExceptionMapper/StatusCodeExceptionHandler.cs b/src/ForEvolve.ExceptionMapper/StatusCodeExceptionHandler.cs
new file mode 100644
index 0000000..4515322
--- /dev/null
+++ b/src/ForEvolve.ExceptionMapper/StatusCodeExceptionHandler.cs
@@ -0,0 +1,11 @@
+namespace ForEvolve.ExceptionMapper;
+
+public class StatusCodeExceptionHandler : ExceptionHandler
+ where TException : Exception
+{
+ public StatusCodeExceptionHandler(int statusCode)
+ {
+ StatusCode = statusCode;
+ }
+ public override int StatusCode { get; }
+}
\ No newline at end of file
diff --git a/test/Directory.Build.props b/test/Directory.Build.props
index 3aae19f..4459169 100644
--- a/test/Directory.Build.props
+++ b/test/Directory.Build.props
@@ -6,10 +6,10 @@
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/test/ForEvolve.ExceptionMapper.CommonExceptions.Tests/ForEvolve.ExceptionMapper.CommonExceptions.Tests.csproj b/test/ForEvolve.ExceptionMapper.CommonExceptions.Tests/ForEvolve.ExceptionMapper.CommonExceptions.Tests.csproj
deleted file mode 100644
index a9269f0..0000000
--- a/test/ForEvolve.ExceptionMapper.CommonExceptions.Tests/ForEvolve.ExceptionMapper.CommonExceptions.Tests.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
- ForEvolve.ExceptionMapper.CommonExceptions
-
-
- ForEvolve.ExceptionMapper
-
-
-
- net5.0;net6.0
- false
-
-
-
-
-
-
-
diff --git a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Fallback/FallbackExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Fallback/FallbackExceptionHandlerTest.cs
deleted file mode 100644
index fa2dfdc..0000000
--- a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Fallback/FallbackExceptionHandlerTest.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-using ForEvolve.Testing.AspNetCore.Http;
-using Microsoft.Extensions.Options;
-using Moq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.Handlers.Fallback
-{
- public class FallbackExceptionHandlerTest
- {
- private readonly FallbackExceptionHandlerOptions _options;
- private readonly Mock> _optionsMonitorMock;
- private readonly FallbackExceptionHandler sut;
-
- public FallbackExceptionHandlerTest()
- {
- _options = new FallbackExceptionHandlerOptions();
- _optionsMonitorMock = new Mock>();
- _optionsMonitorMock.Setup(x => x.CurrentValue).Returns(_options);
- sut = new FallbackExceptionHandler(_optionsMonitorMock.Object);
- }
-
- public class Order : FallbackExceptionHandlerTest
- {
- [Fact]
- public void Should_be_equal_to_FallbackOrder()
- {
- Assert.Equal(HandlerOrder.FallbackOrder, sut.Order);
- }
- }
-
- public class KnowHowToHandleAsync : FallbackExceptionHandlerTest
- {
- [Fact]
- public async Task Should_return_true_when_FallbackStrategy_equals_Handle()
- {
- _options.Strategy = FallbackStrategy.Handle;
- var result = await sut.KnowHowToHandleAsync(new Exception());
- Assert.True(result);
- }
-
- [Fact]
- public async Task Should_return_false_when_FallbackStrategy_equals_Ignore()
- {
- _options.Strategy = FallbackStrategy.Ignore;
- var result = await sut.KnowHowToHandleAsync(new Exception());
- Assert.False(result);
- }
- }
-
- public class ExecuteAsync : FallbackExceptionHandlerTest
- {
- private readonly Exception _error;
- private readonly ExceptionHandlingContext _context;
- private readonly HttpContextHelper _httpContextHelper;
- private readonly ExceptionNotHandledResult _initialResult;
-
- public ExecuteAsync()
- {
- _error = new Exception();
- _initialResult = new ExceptionNotHandledResult(_error);
- _httpContextHelper = new HttpContextHelper();
- _context = new ExceptionHandlingContext(_httpContextHelper.HttpContext, _error, _initialResult);
- }
-
- [Fact]
- public async Task Should_handle_the_exception_when_FallbackStrategy_equals_Handle()
- {
- _options.Strategy = FallbackStrategy.Handle;
- await sut.ExecuteAsync(_context);
- Assert.IsType(_context.Result);
- }
-
- [Fact]
- public async Task Should_do_nothing_when_FallbackStrategy_equals_Ignore()
- {
- _options.Strategy = FallbackStrategy.Ignore;
- await sut.ExecuteAsync(_context);
- Assert.Same(_initialResult, _context.Result);
- }
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests.csproj b/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests.csproj
deleted file mode 100644
index 2dad928..0000000
--- a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers
-
-
-
- net5.0;net6.0
- false
-
-
-
-
-
-
-
diff --git a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/ConflictExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/ConflictExceptionHandlerTest.cs
deleted file mode 100644
index 520a967..0000000
--- a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/ConflictExceptionHandlerTest.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class ConflictExceptionHandlerTest
- {
- [Fact]
- public void StatusCode_should_equal_409()
- {
- var sut = new ConflictExceptionHandler();
- Assert.Equal(StatusCodes.Status409Conflict, sut.StatusCode);
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/InternalServerErrorExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/InternalServerErrorExceptionHandlerTest.cs
deleted file mode 100644
index dbd1fba..0000000
--- a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/InternalServerErrorExceptionHandlerTest.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class InternalServerErrorExceptionHandlerTest
- {
- [Fact]
- public void StatusCode_should_equal_500()
- {
- var sut = new InternalServerErrorExceptionHandler();
- Assert.Equal(StatusCodes.Status500InternalServerError, sut.StatusCode);
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/NotFoundExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/NotFoundExceptionHandlerTest.cs
deleted file mode 100644
index 65d767e..0000000
--- a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/NotFoundExceptionHandlerTest.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class NotFoundExceptionHandlerTest
- {
- [Fact]
- public void StatusCode_should_equal_404()
- {
- var sut = new NotFoundExceptionHandler();
- Assert.Equal(StatusCodes.Status404NotFound, sut.StatusCode);
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/NotImplementedExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/NotImplementedExceptionHandlerTest.cs
deleted file mode 100644
index c2b125e..0000000
--- a/test/ForEvolve.ExceptionMapper.CommonHttpExceptionHandlers.Tests/Handlers/NotImplementedExceptionHandlerTest.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.Handlers
-{
- public class NotImplementedExceptionHandlerTest
- {
- [Fact]
- public void StatusCode_should_equal_501()
- {
- var sut = new NotImplementedExceptionHandler();
- Assert.Equal(StatusCodes.Status501NotImplemented, sut.StatusCode);
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Core.Tests/ExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.Core.Tests/ExceptionHandlerTest.cs
deleted file mode 100644
index 54dc971..0000000
--- a/test/ForEvolve.ExceptionMapper.Core.Tests/ExceptionHandlerTest.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using ForEvolve.Testing.AspNetCore.Http;
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ExceptionHandlerTest
- {
- public class KnowHowToHandleAsync : ExceptionHandlerTest
- {
- public static TheoryData TrueResults = new TheoryData
- {
- new TestException(),
- new TestSubException()
- };
-
- public static TheoryData FalseResults = new TheoryData
- {
- new TestWrongException(),
- new Exception()
- };
-
- [Theory]
- [MemberData(nameof(TrueResults))]
- public async Task Should_return_true_when_the_exception_is_a_TException(TestException exception)
- {
- var sut = new ExceptionTestHandler();
- var result = await sut.KnowHowToHandleAsync(exception);
- Assert.True(result);
- }
-
- [Theory]
- [MemberData(nameof(FalseResults))]
- public async Task Should_return_false_when_the_exception_type_is_not_a_TException(Exception exception)
- {
- var sut = new ExceptionTestHandler();
- var result = await sut.KnowHowToHandleAsync(exception);
- Assert.False(result);
- }
-
- }
-
- public class ExecuteAsync : ExceptionHandlerTest
- {
- private HttpContextHelper _httpContextHelper = new HttpContextHelper();
-
- [Fact]
- public async Task Should_set_response_StatusCode_to_handler_StatusCode_value()
- {
- var sut = new ExceptionTestHandler();
- var exception = new TestException();
-
- await sut.ExecuteAsync(new ExceptionHandlingContext(
- _httpContextHelper.HttpContextMock.Object,
- exception,
- default
- ));
-
- Assert.Equal(
- sut.StatusCode,
- _httpContextHelper.HttpResponse.StatusCode
- );
- }
-
- [Fact]
- public async Task Should_call_ExecuteCoreAsync()
- {
- var sut = new ExceptionTestHandler();
- var exception = new TestException();
-
- await sut.ExecuteAsync(new ExceptionHandlingContext(
- _httpContextHelper.HttpContextMock.Object,
- exception,
- default
- ));
-
- Assert.True(sut.HandleCoreWasCalled);
- Assert.Same(exception, sut.Exception);
- Assert.Same(
- _httpContextHelper.HttpContextMock.Object,
- sut.HttpContext
- );
- }
- }
-
- private class ExceptionTestHandler : ExceptionHandler
- where TException : Exception
- {
- public override int StatusCode => 999;
-
- protected override Task ExecuteCoreAsync(ExceptionHandlingContext context)
- {
- HandleCoreWasCalled = true;
- HttpContext = context.HttpContext;
- Exception = context.Error;
- return base.ExecuteCoreAsync(context);
- }
-
- public bool HandleCoreWasCalled { get; private set; }
- public TException Exception { get; private set; }
- public HttpContext HttpContext { get; private set; }
- }
-
- public class TestException : Exception { }
- public class TestSubException : TestException { }
- public class TestWrongException : Exception { }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Core.Tests/ExceptionHandlingManagerTest.cs b/test/ForEvolve.ExceptionMapper.Core.Tests/ExceptionHandlingManagerTest.cs
deleted file mode 100644
index 54e1103..0000000
--- a/test/ForEvolve.ExceptionMapper.Core.Tests/ExceptionHandlingManagerTest.cs
+++ /dev/null
@@ -1,227 +0,0 @@
-using ForEvolve.Testing.AspNetCore.Http;
-using Microsoft.AspNetCore.Diagnostics;
-using Microsoft.AspNetCore.Http;
-using Moq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-using Xunit.Sdk;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ExceptionHandlingManagerTest
- {
- public class HandleAsync : ExceptionHandlingManagerTest
- {
- private readonly HttpContextHelper _httpContextHelper = new HttpContextHelper();
- private HttpContext HttpContext => _httpContextHelper.HttpContextMock.Object;
- private readonly List _handlers = new List();
-
- public class When_IExceptionHandlerFeature_is_null : HandleAsync
- {
- [Fact]
- public async Task Should_return_ExceptionHandlerFeatureNotSupportedResult()
- {
- // Arrange
- var sut = new ExceptionHandlingManager(_handlers);
- _httpContextHelper.FeaturesMock
- .Setup(x => x.Get())
- .Returns(default(IExceptionHandlerFeature));
-
- // Act
- var result = await sut.HandleAsync(HttpContext);
-
- // Assert
- Assert.IsType(result);
- }
- }
-
- public class When_IExceptionHandlerFeature_is_not_null : HandleAsync
- {
- private readonly Mock _exceptionHandlerFeatureMock;
-
- public When_IExceptionHandlerFeature_is_not_null()
- {
- _exceptionHandlerFeatureMock = new Mock();
- _httpContextHelper.FeaturesMock
- .Setup(x => x.Get())
- .Returns(_exceptionHandlerFeatureMock.Object);
- }
-
- public class And_has_no_Error : When_IExceptionHandlerFeature_is_not_null
- {
- [Fact]
- public async Task Should_return_NoExceptionResult()
- {
- // Arrange
- _exceptionHandlerFeatureMock
- .Setup(x => x.Error)
- .Returns(default(Exception));
- var sut = new ExceptionHandlingManager(_handlers);
-
- // Act
- var result = await sut.HandleAsync(HttpContext);
-
- // Assert
- Assert.IsType(result);
- }
- }
-
- public class And_has_an_Error : When_IExceptionHandlerFeature_is_not_null
- {
- private readonly Exception _exception;
- public And_has_an_Error()
- {
- _exception = new Exception();
- _exceptionHandlerFeatureMock
- .Setup(x => x.Error)
- .Returns(_exception);
- }
-
- public class And_the_Exception_was_handled : And_has_an_Error
- {
- [Fact]
- public async Task Should_return_ExceptionHandlingContext_Result()
- {
- // Arrange
- var handlerMock = new Mock();
- handlerMock
- .Setup(x => x.KnowHowToHandleAsync(_exception))
- .ReturnsAsync(true);
- handlerMock
- .Setup(x => x.ExecuteAsync(It.IsAny()))
- .Callback((ExceptionHandlingContext context) => context.Result = new TestResult())
- .Returns(Task.CompletedTask);
- _handlers.Add(handlerMock.Object);
- var sut = new ExceptionHandlingManager(_handlers);
-
- // Act
- var result = await sut.HandleAsync(HttpContext);
-
- // Assert
- Assert.IsType(result);
- }
-
- private class TestResult : IExceptionHandlingResult
- {
- public bool ExceptionHandled => throw new NotImplementedException();
-
- public Exception Error => throw new NotImplementedException();
-
- public bool ExceptionHandlerFeatureSupported => throw new NotImplementedException();
- }
- }
-
- public class And_the_Exception_was_not_handled_by_any_handler : And_has_an_Error
- {
- [Fact]
- public async Task Should_return_ExceptionNotHandledResult()
- {
- // Arrange
- var sut = new ExceptionHandlingManager(_handlers);
-
- // Act
- var result = await sut.HandleAsync(HttpContext);
-
- // Assert
- Assert.IsType(result);
- }
- }
- }
- }
- }
-
- public class Handlers : ExceptionHandlingManagerTest
- {
- private static readonly OrderableTestExceptionHandler _handlerOrder1 = new OrderableTestExceptionHandler { Order = 1 };
- private static readonly OrderableTestExceptionHandler _handlerOrder2 = new OrderableTestExceptionHandler { Order = 2 };
- private static readonly OrderableTestExceptionHandler _handlerOrder3 = new OrderableTestExceptionHandler { Order = 3 };
-
- private static readonly OrderableTestExceptionHandler _handlerOrder1Version1 = new OrderableTestExceptionHandler { Order = 1 };
- private static readonly OrderableTestExceptionHandler _handlerOrder1Version2 = new OrderableTestExceptionHandler { Order = 1 };
- private static readonly OrderableTestExceptionHandler _handlerOrder1Version3 = new OrderableTestExceptionHandler { Order = 1 };
-
- public static TheoryData, Action>> OrderTestsData = new TheoryData, Action>>
- {
- {
- "Should sort handlers using their Order property",
- new[] {
- _handlerOrder2,
- _handlerOrder1,
- _handlerOrder3,
- },
- orderedHandlers => Assert.Collection(orderedHandlers,
- handler => Assert.Same(_handlerOrder1, handler),
- handler => Assert.Same(_handlerOrder2, handler),
- handler => Assert.Same(_handlerOrder3, handler)
- )
- },
- {
- "Should sort handlers 'first in first out'",
- new[] {
- _handlerOrder1Version1,
- _handlerOrder2,
- _handlerOrder1,
- _handlerOrder3,
- _handlerOrder1Version2,
- _handlerOrder1Version3
- },
- orderedHandlers => Assert.Collection(orderedHandlers,
- handler => Assert.Same(_handlerOrder1Version1, handler),
- handler => Assert.Same(_handlerOrder1, handler),
- handler => Assert.Same(_handlerOrder1Version2, handler),
- handler => Assert.Same(_handlerOrder1Version3, handler),
- handler => Assert.Same(_handlerOrder2, handler),
- handler => Assert.Same(_handlerOrder3, handler)
- )
- }
- };
-
- [Theory]
- [MemberData(nameof(OrderTestsData))]
- public void Should_order_handlers(
- string errorMessage,
- IEnumerable input,
- Action> assert
- )
- {
- var sut = new ExceptionHandlingManager(input);
- var orderedHandlers = sut.Handlers;
- try
- {
- assert(orderedHandlers);
- }
- catch (XunitException ex)
- {
- throw new DescriptiveException(errorMessage, ex);
- }
- }
-
- public class OrderableTestExceptionHandler : IExceptionHandler
- {
- public int Order { get; set; }
-
- public Task ExecuteAsync(ExceptionHandlingContext context)
- {
- throw new NotImplementedException();
- }
-
- public Task KnowHowToHandleAsync(Exception exception)
- {
- throw new NotImplementedException();
- }
- }
-
- public class DescriptiveException : XunitException
- {
- public DescriptiveException(string userMessage, XunitException innerException)
- : base(userMessage, innerException)
- {
- }
- }
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Core.Tests/ForEvolve.ExceptionMapper.Core.Tests.csproj b/test/ForEvolve.ExceptionMapper.Core.Tests/ForEvolve.ExceptionMapper.Core.Tests.csproj
deleted file mode 100644
index b00e988..0000000
--- a/test/ForEvolve.ExceptionMapper.Core.Tests/ForEvolve.ExceptionMapper.Core.Tests.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- ForEvolve.ExceptionMapper.Core
-
-
-
- net5.0;net6.0
- false
-
-
-
-
-
-
-
diff --git a/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionHandledResultTest.cs b/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionHandledResultTest.cs
deleted file mode 100644
index 2d42735..0000000
--- a/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionHandledResultTest.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ExceptionHandledResultTest
- {
- [Fact]
- public void Should_set_the_expected_values()
- {
- // Arrange
- var exception = new Exception();
-
- // Act
- var result = new ExceptionHandledResult(exception);
-
- // Assert
- Assert.Equal(exception, result.Error);
- Assert.True(result.ExceptionHandled);
- Assert.True(result.ExceptionHandlerFeatureSupported);
- }
-
- [Fact]
- public void Should_guard_against_null()
- {
- Assert.Throws(
- "error",
- () => new ExceptionHandledResult(default)
- );
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionHandlerFeatureNotSupportedResultTest.cs b/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionHandlerFeatureNotSupportedResultTest.cs
deleted file mode 100644
index 65e8891..0000000
--- a/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionHandlerFeatureNotSupportedResultTest.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ExceptionHandlerFeatureNotSupportedResultTest
- {
- [Fact]
- public void Should_set_the_expected_values()
- {
- // Act
- var result = new ExceptionHandlerFeatureNotSupportedResult();
-
- // Assert
- Assert.Null(result.Error);
- Assert.False(result.ExceptionHandled);
- Assert.False(result.ExceptionHandlerFeatureSupported);
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionNotHandledResultTest.cs b/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionNotHandledResultTest.cs
deleted file mode 100644
index 43ac042..0000000
--- a/test/ForEvolve.ExceptionMapper.Core.Tests/Results/ExceptionNotHandledResultTest.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ExceptionNotHandledResultTest
- {
- [Fact]
- public void Should_set_the_expected_values()
- {
- // Arrange
- var exception = new Exception();
-
- // Act
- var result = new ExceptionNotHandledResult(exception);
-
- // Assert
- Assert.Equal(exception, result.Error);
- Assert.False(result.ExceptionHandled);
- Assert.True(result.ExceptionHandlerFeatureSupported);
- }
-
- [Fact]
- public void Should_guard_against_null()
- {
- Assert.Throws(
- "error",
- () => new ExceptionNotHandledResult(default)
- );
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Core.Tests/Results/NoExceptionResultTest.cs b/test/ForEvolve.ExceptionMapper.Core.Tests/Results/NoExceptionResultTest.cs
deleted file mode 100644
index c460d23..0000000
--- a/test/ForEvolve.ExceptionMapper.Core.Tests/Results/NoExceptionResultTest.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class NoExceptionResultTest
- {
- [Fact]
- public void Should_set_the_expected_values()
- {
- // Act
- var result = new NoExceptionResult();
-
- // Assert
- Assert.Null(result.Error);
- Assert.False(result.ExceptionHandled);
- Assert.True(result.ExceptionHandlerFeatureSupported);
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Core.Tests/ServiceCollectionExtensionsTest.cs b/test/ForEvolve.ExceptionMapper.Core.Tests/ServiceCollectionExtensionsTest.cs
deleted file mode 100644
index e5383cd..0000000
--- a/test/ForEvolve.ExceptionMapper.Core.Tests/ServiceCollectionExtensionsTest.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.DependencyInjection;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class ServiceCollectionExtensionsTest
- {
- [Fact]
- public void Should_register_all_dependencies()
- {
- // Arrange
- var services = new ServiceCollection();
- services.AddExceptionMapper();
- var serviceProvider = services.BuildServiceProvider();
-
- // Act
- var manager = serviceProvider
- .GetRequiredService();
-
- // Assert
- Assert.NotNull(manager);
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.FluentMapper.Tests/ForEvolve.ExceptionMapper.FluentMapper.Tests.csproj b/test/ForEvolve.ExceptionMapper.FluentMapper.Tests/ForEvolve.ExceptionMapper.FluentMapper.Tests.csproj
deleted file mode 100644
index 50428f3..0000000
--- a/test/ForEvolve.ExceptionMapper.FluentMapper.Tests/ForEvolve.ExceptionMapper.FluentMapper.Tests.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- ForEvolve.ExceptionMapper.FluentMapper
-
-
-
- net5.0;net6.0
- false
-
-
-
-
-
-
-
diff --git a/test/ForEvolve.ExceptionMapper.FluentMapper.Tests/UnitTest1.cs b/test/ForEvolve.ExceptionMapper.FluentMapper.Tests/UnitTest1.cs
deleted file mode 100644
index c73de6f..0000000
--- a/test/ForEvolve.ExceptionMapper.FluentMapper.Tests/UnitTest1.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.FluentMapper.Tests
-{
- public class UnitTest1
- {
- [Fact]
- public void Test1()
- {
-
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.HttpMiddleware.Tests/ForEvolve.ExceptionMapper.HttpMiddleware.Tests.csproj b/test/ForEvolve.ExceptionMapper.HttpMiddleware.Tests/ForEvolve.ExceptionMapper.HttpMiddleware.Tests.csproj
deleted file mode 100644
index bf24c7f..0000000
--- a/test/ForEvolve.ExceptionMapper.HttpMiddleware.Tests/ForEvolve.ExceptionMapper.HttpMiddleware.Tests.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- ForEvolve.ExceptionMapper.HttpMiddleware
-
-
-
- net5.0;net6.0
- false
-
-
-
-
-
-
-
diff --git a/test/ForEvolve.ExceptionMapper.HttpMiddleware.Tests/HttpExceptionHandlingMiddlewareTest.cs b/test/ForEvolve.ExceptionMapper.HttpMiddleware.Tests/HttpExceptionHandlingMiddlewareTest.cs
deleted file mode 100644
index 4803ab8..0000000
--- a/test/ForEvolve.ExceptionMapper.HttpMiddleware.Tests/HttpExceptionHandlingMiddlewareTest.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using ForEvolve.Testing.AspNetCore.Http;
-using Microsoft.AspNetCore.Http;
-using Moq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper
-{
- public class HttpExceptionHandlingMiddlewareTest
- {
- private readonly HttpContextHelper _httpContextHelper = new HttpContextHelper();
- private HttpContext HttpContext => _httpContextHelper.HttpContextMock.Object;
- private bool _nextWasCalled = false;
- private readonly HttpExceptionHandlingMiddleware sut;
- private readonly Mock _exceptionHandlingManagerMock;
-
- public HttpExceptionHandlingMiddlewareTest()
- {
- _exceptionHandlingManagerMock = new Mock();
- sut = new HttpExceptionHandlingMiddleware(
- _exceptionHandlingManagerMock.Object,
- Next
- );
- }
-
- [Fact]
- public async Task Should_not_call_next_when_exception_is_handled()
- {
- // Arrange
- var resultMock = new Mock();
- resultMock.Setup(x => x.ExceptionHandled).Returns(true);
- _exceptionHandlingManagerMock
- .Setup(x => x.HandleAsync(It.IsAny()))
- .ReturnsAsync(resultMock.Object)
- ;
-
- // Act
- await sut.InvokeAsync(HttpContext);
-
- // Assert
- Assert.False(_nextWasCalled);
- }
-
- [Fact]
- public async Task Should_call_next_when_exception_is_not_handled()
- {
- // Arrange
- var resultMock = new Mock();
- resultMock.Setup(x => x.ExceptionHandled).Returns(false);
- _exceptionHandlingManagerMock
- .Setup(x => x.HandleAsync(It.IsAny()))
- .ReturnsAsync(resultMock.Object)
- ;
-
- // Act
- await sut.InvokeAsync(HttpContext);
-
- // Assert
- Assert.True(_nextWasCalled);
- }
-
- private Task Next(HttpContext context)
- {
- _nextWasCalled = true;
- return Task.CompletedTask;
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Mvc.Tests/ForEvolve.ExceptionMapper.Mvc.Tests.csproj b/test/ForEvolve.ExceptionMapper.Mvc.Tests/ForEvolve.ExceptionMapper.Mvc.Tests.csproj
deleted file mode 100644
index 1e41f9d..0000000
--- a/test/ForEvolve.ExceptionMapper.Mvc.Tests/ForEvolve.ExceptionMapper.Mvc.Tests.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- ForEvolve.ExceptionMapper.Mvc
-
-
-
- net5.0;net6.0
- false
-
-
-
-
-
-
-
diff --git a/test/ForEvolve.ExceptionMapper.Mvc.Tests/UnitTest1.cs b/test/ForEvolve.ExceptionMapper.Mvc.Tests/UnitTest1.cs
deleted file mode 100644
index 138bab8..0000000
--- a/test/ForEvolve.ExceptionMapper.Mvc.Tests/UnitTest1.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.Mvc.Tests
-{
- public class UnitTest1
- {
- [Fact]
- public void Test1()
- {
-
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Scrutor.Tests/ForEvolve.ExceptionMapper.Scrutor.Tests.csproj b/test/ForEvolve.ExceptionMapper.Scrutor.Tests/ForEvolve.ExceptionMapper.Scrutor.Tests.csproj
deleted file mode 100644
index 175e3fa..0000000
--- a/test/ForEvolve.ExceptionMapper.Scrutor.Tests/ForEvolve.ExceptionMapper.Scrutor.Tests.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- ForEvolve.ExceptionMapper.Scrutor
-
-
-
- net5.0;net6.0
- false
-
-
-
-
-
-
-
diff --git a/test/ForEvolve.ExceptionMapper.Scrutor.Tests/UnitTest1.cs b/test/ForEvolve.ExceptionMapper.Scrutor.Tests/UnitTest1.cs
deleted file mode 100644
index e588bdc..0000000
--- a/test/ForEvolve.ExceptionMapper.Scrutor.Tests/UnitTest1.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.Scrutor.Tests
-{
- public class UnitTest1
- {
- [Fact]
- public void Test1()
- {
-
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Serialization.Json.Tests/ForEvolve.ExceptionMapper.Serialization.Json.Tests.csproj b/test/ForEvolve.ExceptionMapper.Serialization.Json.Tests/ForEvolve.ExceptionMapper.Serialization.Json.Tests.csproj
deleted file mode 100644
index 65ec58a..0000000
--- a/test/ForEvolve.ExceptionMapper.Serialization.Json.Tests/ForEvolve.ExceptionMapper.Serialization.Json.Tests.csproj
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
- ForEvolve.ExceptionMapper.Serialization.Json
-
-
-
- net5.0;net6.0
- false
-
-
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
-
-
-
-
-
-
diff --git a/test/ForEvolve.ExceptionMapper.Serialization.Json.Tests/UnitTest1.cs b/test/ForEvolve.ExceptionMapper.Serialization.Json.Tests/UnitTest1.cs
deleted file mode 100644
index 1f7c332..0000000
--- a/test/ForEvolve.ExceptionMapper.Serialization.Json.Tests/UnitTest1.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using Xunit;
-
-namespace ForEvolve.ExceptionMapper.Serialization.Json.Tests
-{
- public class UnitTest1
- {
- [Fact]
- public void Test1()
- {
-
- }
- }
-}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.Tests/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerTest.cs
new file mode 100644
index 0000000..9288a3e
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/CommonHttpExceptionHandlers/Fallback/FallbackExceptionHandlerTest.cs
@@ -0,0 +1,74 @@
+using ForEvolve.Testing.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using Moq;
+using System;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper.Handlers.Fallback;
+
+public class FallbackExceptionHandlerTest
+{
+ private readonly FallbackExceptionHandlerOptions _options;
+ private readonly Mock> _optionsMonitorMock;
+ private readonly FallbackExceptionHandler sut;
+
+ public FallbackExceptionHandlerTest()
+ {
+ _options = new FallbackExceptionHandlerOptions();
+ _optionsMonitorMock = new Mock>();
+ _optionsMonitorMock.Setup(x => x.CurrentValue).Returns(_options);
+ sut = new FallbackExceptionHandler(_optionsMonitorMock.Object);
+ }
+
+ public class KnowHowToHandleAsync : FallbackExceptionHandlerTest
+ {
+ [Fact]
+ public async Task Should_return_true_when_FallbackStrategy_equals_Handle()
+ {
+ _options.Strategy = FallbackStrategy.Handle;
+ var result = await sut.CanHandle(new Exception());
+ Assert.True(result);
+ }
+
+ [Fact]
+ public async Task Should_return_false_when_FallbackStrategy_equals_Ignore()
+ {
+ _options.Strategy = FallbackStrategy.Ignore;
+ var result = await sut.CanHandle(new Exception());
+ Assert.False(result);
+ }
+ }
+
+ public class ExecuteAsync : FallbackExceptionHandlerTest
+ {
+ private readonly Exception _error;
+ private readonly ExceptionHandlingContext _context;
+ private readonly HttpContextHelper _httpContextHelper;
+ private readonly ExceptionNotHandledResult _initialResult;
+
+ public ExecuteAsync()
+ {
+ _error = new Exception();
+ _initialResult = new ExceptionNotHandledResult(_error);
+ _httpContextHelper = new HttpContextHelper();
+ _context = new ExceptionHandlingContext(_httpContextHelper.HttpContext, _error, _initialResult);
+ }
+
+ [Fact]
+ public async Task Should_handle_the_exception_when_FallbackStrategy_equals_Handle()
+ {
+ _options.Strategy = FallbackStrategy.Handle;
+ await sut.ExecuteAsync(_context);
+ Assert.IsType(_context.Result);
+ }
+
+ [Fact]
+ public async Task Should_do_nothing_when_FallbackStrategy_equals_Ignore()
+ {
+ _options.Strategy = FallbackStrategy.Ignore;
+ await sut.ExecuteAsync(_context);
+ Assert.Same(_initialResult, _context.Result);
+ }
+ }
+}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/DependencyInjection/ServiceCollectionExtensionsTest.cs b/test/ForEvolve.ExceptionMapper.Tests/DependencyInjection/ServiceCollectionExtensionsTest.cs
new file mode 100644
index 0000000..119a91d
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/DependencyInjection/ServiceCollectionExtensionsTest.cs
@@ -0,0 +1,29 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Moq;
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper;
+
+public class ServiceCollectionExtensionsTest
+{
+ [Fact]
+ public void Should_register_all_dependencies()
+ {
+ // Arrange
+ var configuration = new ConfigurationBuilder().Build();
+ var hostEnvironmentMock = new Mock();
+ var services = new ServiceCollection();
+ services.AddSingleton(hostEnvironmentMock.Object);
+ services.AddExceptionMapper(configuration);
+ var serviceProvider = services.BuildServiceProvider();
+
+ // Act
+ var manager = serviceProvider
+ .GetRequiredService();
+
+ // Assert
+ Assert.NotNull(manager);
+ }
+}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlerTest.cs b/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlerTest.cs
new file mode 100644
index 0000000..9c188ec
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlerTest.cs
@@ -0,0 +1,109 @@
+using ForEvolve.Testing.AspNetCore.Http;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper;
+
+public class ExceptionHandlerTest
+{
+ public class KnowHowToHandleAsync : ExceptionHandlerTest
+ {
+ public static TheoryData TrueResults = new TheoryData
+ {
+ new TestException(),
+ new TestSubException()
+ };
+
+ public static TheoryData FalseResults = new TheoryData
+ {
+ new TestWrongException(),
+ new Exception()
+ };
+
+ [Theory]
+ [MemberData(nameof(TrueResults))]
+ public async Task Should_return_true_when_the_exception_is_a_TException(TestException exception)
+ {
+ var sut = new ExceptionTestHandler();
+ var result = await sut.CanHandle(exception);
+ Assert.True(result);
+ }
+
+ [Theory]
+ [MemberData(nameof(FalseResults))]
+ public async Task Should_return_false_when_the_exception_type_is_not_a_TException(Exception exception)
+ {
+ var sut = new ExceptionTestHandler();
+ var result = await sut.CanHandle(exception);
+ Assert.False(result);
+ }
+
+ }
+
+ public class ExecuteAsync : ExceptionHandlerTest
+ {
+ private HttpContextHelper _httpContextHelper = new HttpContextHelper();
+
+ [Fact]
+ public async Task Should_set_response_StatusCode_to_handler_StatusCode_value()
+ {
+ var sut = new ExceptionTestHandler();
+ var exception = new TestException();
+
+ await sut.ExecuteAsync(new ExceptionHandlingContext(
+ _httpContextHelper.HttpContextMock.Object,
+ exception,
+ default
+ ));
+
+ Assert.Equal(
+ sut.StatusCode,
+ _httpContextHelper.HttpResponse.StatusCode
+ );
+ }
+
+ [Fact]
+ public async Task Should_call_ExecuteCoreAsync()
+ {
+ var sut = new ExceptionTestHandler();
+ var exception = new TestException();
+
+ await sut.ExecuteAsync(new ExceptionHandlingContext(
+ _httpContextHelper.HttpContextMock.Object,
+ exception,
+ default
+ ));
+
+ Assert.True(sut.HandleCoreWasCalled);
+ Assert.Same(exception, sut.Exception);
+ Assert.Same(
+ _httpContextHelper.HttpContextMock.Object,
+ sut.HttpContext
+ );
+ }
+ }
+
+ private class ExceptionTestHandler : ExceptionHandler
+ where TException : Exception
+ {
+ public override int StatusCode => 999;
+
+ protected override Task ExecuteCoreAsync(ExceptionHandlingContext context)
+ {
+ HandleCoreWasCalled = true;
+ HttpContext = context.HttpContext;
+ Exception = context.Error;
+ return base.ExecuteCoreAsync(context);
+ }
+
+ public bool HandleCoreWasCalled { get; private set; }
+ public TException Exception { get; private set; }
+ public HttpContext HttpContext { get; private set; }
+ }
+
+ public class TestException : Exception { }
+ public class TestSubException : TestException { }
+ public class TestWrongException : Exception { }
+}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlingManagerTest.cs b/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlingManagerTest.cs
new file mode 100644
index 0000000..682467a
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/ExceptionHandlingManagerTest.cs
@@ -0,0 +1,134 @@
+using ForEvolve.Testing.AspNetCore.Http;
+using Microsoft.AspNetCore.Diagnostics;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Moq;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper;
+
+public class ExceptionHandlingManagerTest
+{
+ public class HandleAsync : ExceptionHandlingManagerTest
+ {
+ private readonly HttpContextHelper _httpContextHelper = new HttpContextHelper();
+ private HttpContext HttpContext => _httpContextHelper.HttpContextMock.Object;
+ private readonly List _handlers = new List();
+ private readonly Mock _serializer = new Mock();
+ private ExceptionMapperOptions Options => new(new ExceptionHandlerCollection(_handlers), _serializer.Object);
+
+ public class When_IExceptionHandlerFeature_is_null : HandleAsync
+ {
+ [Fact]
+ public async Task Should_return_ExceptionHandlerFeatureNotSupportedResult()
+ {
+ // Arrange
+ var sut = new ExceptionHandlingManager(Options);
+ _httpContextHelper.FeaturesMock
+ .Setup(x => x.Get())
+ .Returns(default(IExceptionHandlerFeature));
+
+ // Act
+ var result = await sut.HandleAsync(HttpContext);
+
+ // Assert
+ Assert.IsType(result);
+ }
+ }
+
+ public class When_IExceptionHandlerFeature_is_not_null : HandleAsync
+ {
+ private readonly Mock _exceptionHandlerFeatureMock;
+
+ public When_IExceptionHandlerFeature_is_not_null()
+ {
+ _exceptionHandlerFeatureMock = new Mock();
+ _httpContextHelper.FeaturesMock
+ .Setup(x => x.Get())
+ .Returns(_exceptionHandlerFeatureMock.Object);
+ }
+
+ public class And_has_no_Error : When_IExceptionHandlerFeature_is_not_null
+ {
+ [Fact]
+ public async Task Should_return_NoExceptionResult()
+ {
+ // Arrange
+ _exceptionHandlerFeatureMock
+ .Setup(x => x.Error)
+ .Returns(default(Exception));
+ var sut = new ExceptionHandlingManager(Options);
+
+ // Act
+ var result = await sut.HandleAsync(HttpContext);
+
+ // Assert
+ Assert.IsType(result);
+ }
+ }
+
+ public class And_has_an_Error : When_IExceptionHandlerFeature_is_not_null
+ {
+ private readonly Exception _exception;
+ public And_has_an_Error()
+ {
+ _exception = new Exception();
+ _exceptionHandlerFeatureMock
+ .Setup(x => x.Error)
+ .Returns(_exception);
+ }
+
+ public class And_the_Exception_was_handled : And_has_an_Error
+ {
+ [Fact]
+ public async Task Should_return_ExceptionHandlingContext_Result()
+ {
+ // Arrange
+ var handlerMock = new Mock();
+ handlerMock
+ .Setup(x => x.CanHandle(_exception))
+ .ReturnsAsync(true);
+ handlerMock
+ .Setup(x => x.ExecuteAsync(It.IsAny()))
+ .Callback((ExceptionHandlingContext context) => context.Result = new TestResult())
+ .Returns(Task.CompletedTask);
+ _handlers.Add(handlerMock.Object);
+ var sut = new ExceptionHandlingManager(Options);
+
+ // Act
+ var result = await sut.HandleAsync(HttpContext);
+
+ // Assert
+ Assert.IsType(result);
+ }
+
+ private class TestResult : IExceptionHandlingResult
+ {
+ public bool ExceptionHandled => throw new NotImplementedException();
+
+ public Exception Error => throw new NotImplementedException();
+ }
+ }
+
+ public class And_the_Exception_was_not_handled_by_any_handler : And_has_an_Error
+ {
+ [Fact]
+ public async Task Should_return_ExceptionNotHandledResult()
+ {
+ // Arrange
+ var sut = new ExceptionHandlingManager(Options);
+
+ // Act
+ var result = await sut.HandleAsync(HttpContext);
+
+ // Assert
+ Assert.IsType(result);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/ForEvolve.ExceptionMapper.Tests.csproj b/test/ForEvolve.ExceptionMapper.Tests/ForEvolve.ExceptionMapper.Tests.csproj
index 8c189d6..cb9333e 100644
--- a/test/ForEvolve.ExceptionMapper.Tests/ForEvolve.ExceptionMapper.Tests.csproj
+++ b/test/ForEvolve.ExceptionMapper.Tests/ForEvolve.ExceptionMapper.Tests.csproj
@@ -1,11 +1,11 @@
-
+
ForEvolve.ExceptionMapper
- net5.0;net6.0
- false
+ $(FETestsTargetFrameworks)
+ false
diff --git a/test/ForEvolve.ExceptionMapper.Tests/HttpMiddleware/HttpExceptionHandlingMiddlewareTest.cs b/test/ForEvolve.ExceptionMapper.Tests/HttpMiddleware/HttpExceptionHandlingMiddlewareTest.cs
new file mode 100644
index 0000000..9a822ff
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/HttpMiddleware/HttpExceptionHandlingMiddlewareTest.cs
@@ -0,0 +1,67 @@
+using ForEvolve.Testing.AspNetCore.Http;
+using Microsoft.AspNetCore.Http;
+using Moq;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper;
+
+public class HttpExceptionHandlingMiddlewareTest
+{
+ private readonly HttpContextHelper _httpContextHelper = new HttpContextHelper();
+ private HttpContext HttpContext => _httpContextHelper.HttpContextMock.Object;
+ private bool _nextWasCalled = false;
+ private readonly HttpExceptionHandlingMiddleware sut;
+ private readonly Mock _exceptionHandlingManagerMock;
+
+ public HttpExceptionHandlingMiddlewareTest()
+ {
+ _exceptionHandlingManagerMock = new Mock();
+ sut = new HttpExceptionHandlingMiddleware(
+ _exceptionHandlingManagerMock.Object,
+ Next
+ );
+ }
+
+ [Fact]
+ public async Task Should_not_call_next_when_exception_is_handled()
+ {
+ // Arrange
+ var resultMock = new Mock();
+ resultMock.Setup(x => x.ExceptionHandled).Returns(true);
+ _exceptionHandlingManagerMock
+ .Setup(x => x.HandleAsync(It.IsAny()))
+ .ReturnsAsync(resultMock.Object)
+ ;
+
+ // Act
+ await sut.InvokeAsync(HttpContext);
+
+ // Assert
+ Assert.False(_nextWasCalled);
+ }
+
+ [Fact]
+ public async Task Should_call_next_when_exception_is_not_handled()
+ {
+ // Arrange
+ var resultMock = new Mock();
+ resultMock.Setup(x => x.ExceptionHandled).Returns(false);
+ _exceptionHandlingManagerMock
+ .Setup(x => x.HandleAsync(It.IsAny()))
+ .ReturnsAsync(resultMock.Object)
+ ;
+
+ // Act
+ await sut.InvokeAsync(HttpContext);
+
+ // Assert
+ Assert.True(_nextWasCalled);
+ }
+
+ private Task Next(HttpContext context)
+ {
+ _nextWasCalled = true;
+ return Task.CompletedTask;
+ }
+}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionHandledResultTest.cs b/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionHandledResultTest.cs
new file mode 100644
index 0000000..9b1f9fb
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionHandledResultTest.cs
@@ -0,0 +1,30 @@
+using System;
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper;
+
+public class ExceptionHandledResultTest
+{
+ [Fact]
+ public void Should_set_the_expected_values()
+ {
+ // Arrange
+ var exception = new Exception();
+
+ // Act
+ var result = new ExceptionHandledResult(exception);
+
+ // Assert
+ Assert.Equal(exception, result.Error);
+ Assert.True(result.ExceptionHandled);
+ }
+
+ [Fact]
+ public void Should_guard_against_null()
+ {
+ Assert.Throws(
+ "error",
+ () => new ExceptionHandledResult(default)
+ );
+ }
+}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionHandlerFeatureNotSupportedResultTest.cs b/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionHandlerFeatureNotSupportedResultTest.cs
new file mode 100644
index 0000000..e65c5c2
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionHandlerFeatureNotSupportedResultTest.cs
@@ -0,0 +1,17 @@
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper;
+
+public class ExceptionHandlerFeatureNotSupportedResultTest
+{
+ [Fact]
+ public void Should_set_the_expected_values()
+ {
+ // Act
+ var result = new ExceptionHandlerFeatureNotSupportedResult();
+
+ // Assert
+ Assert.Null(result.Error);
+ Assert.False(result.ExceptionHandled);
+ }
+}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionNotHandledResultTest.cs b/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionNotHandledResultTest.cs
new file mode 100644
index 0000000..a3165dc
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/Results/ExceptionNotHandledResultTest.cs
@@ -0,0 +1,30 @@
+using System;
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper;
+
+public class ExceptionNotHandledResultTest
+{
+ [Fact]
+ public void Should_set_the_expected_values()
+ {
+ // Arrange
+ var exception = new Exception();
+
+ // Act
+ var result = new ExceptionNotHandledResult(exception);
+
+ // Assert
+ Assert.Equal(exception, result.Error);
+ Assert.False(result.ExceptionHandled);
+ }
+
+ [Fact]
+ public void Should_guard_against_null()
+ {
+ Assert.Throws(
+ "error",
+ () => new ExceptionNotHandledResult(default)
+ );
+ }
+}
diff --git a/test/ForEvolve.ExceptionMapper.Tests/Results/NoExceptionResultTest.cs b/test/ForEvolve.ExceptionMapper.Tests/Results/NoExceptionResultTest.cs
new file mode 100644
index 0000000..d8f5411
--- /dev/null
+++ b/test/ForEvolve.ExceptionMapper.Tests/Results/NoExceptionResultTest.cs
@@ -0,0 +1,17 @@
+using Xunit;
+
+namespace ForEvolve.ExceptionMapper;
+
+public class NoExceptionResultTest
+{
+ [Fact]
+ public void Should_set_the_expected_values()
+ {
+ // Act
+ var result = new NoExceptionResult();
+
+ // Assert
+ Assert.Null(result.Error);
+ Assert.False(result.ExceptionHandled);
+ }
+}
diff --git a/version.json b/version.json
index a1a0c87..8d459ea 100644
--- a/version.json
+++ b/version.json
@@ -1,10 +1,12 @@
{
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
- "version": "2.0",
- "publicReleaseRefSpec": ["^refs/heads/master$"],
+ "version": "3.0",
+ "publicReleaseRefSpec": [
+ "^refs/heads/master$"
+ ],
"cloudBuild": {
"buildNumber": {
"enabled": true
}
}
-}
+}
\ No newline at end of file