From 7d2a239d21335d3e3da7893b774556bbeb8cfd70 Mon Sep 17 00:00:00 2001 From: apptade Date: Sat, 1 Aug 2026 18:37:20 +0300 Subject: [PATCH 1/8] Rename test folders --- .../CR.Exceptions.AspNet.Tests.csproj | 0 .../Component/CrExceptionHandlerTests.cs | 0 .../Component/LogLevelMapTests.cs | 0 .../Component/StatusCodeMapTests.cs | 0 .../TestNotFoundException.cs | 0 .../TestUnregisteredException.cs | 0 .../Unit/LogLevelMapBuilderTests.cs | 0 .../Unit/StatusCodeMapBuilderTests.cs | 0 .../CR.Exceptions.Tests.csproj | 0 .../Component/ErrorMapTests.cs | 0 .../Component/ExceptionFactoryTests.cs | 0 .../TestException.cs | 0 .../Unit/ErrorMapBuilderTests.cs | 0 .../Unit/ExceptionFactoryBuilderTests.cs | 0 CR.Exceptions.slnx | 4 ++-- 15 files changed, 2 insertions(+), 2 deletions(-) rename {CR.Exceptions.AspNet.UnitTests => CR.Exceptions.AspNet.Tests}/CR.Exceptions.AspNet.Tests.csproj (100%) rename {CR.Exceptions.AspNet.UnitTests => CR.Exceptions.AspNet.Tests}/Component/CrExceptionHandlerTests.cs (100%) rename {CR.Exceptions.AspNet.UnitTests => CR.Exceptions.AspNet.Tests}/Component/LogLevelMapTests.cs (100%) rename {CR.Exceptions.AspNet.UnitTests => CR.Exceptions.AspNet.Tests}/Component/StatusCodeMapTests.cs (100%) rename {CR.Exceptions.AspNet.UnitTests => CR.Exceptions.AspNet.Tests}/TestNotFoundException.cs (100%) rename {CR.Exceptions.AspNet.UnitTests => CR.Exceptions.AspNet.Tests}/TestUnregisteredException.cs (100%) rename {CR.Exceptions.AspNet.UnitTests => CR.Exceptions.AspNet.Tests}/Unit/LogLevelMapBuilderTests.cs (100%) rename {CR.Exceptions.AspNet.UnitTests => CR.Exceptions.AspNet.Tests}/Unit/StatusCodeMapBuilderTests.cs (100%) rename {CR.Exceptions.UnitTests => CR.Exceptions.Tests}/CR.Exceptions.Tests.csproj (100%) rename {CR.Exceptions.UnitTests => CR.Exceptions.Tests}/Component/ErrorMapTests.cs (100%) rename {CR.Exceptions.UnitTests => CR.Exceptions.Tests}/Component/ExceptionFactoryTests.cs (100%) rename {CR.Exceptions.UnitTests => CR.Exceptions.Tests}/TestException.cs (100%) rename {CR.Exceptions.UnitTests => CR.Exceptions.Tests}/Unit/ErrorMapBuilderTests.cs (100%) rename {CR.Exceptions.UnitTests => CR.Exceptions.Tests}/Unit/ExceptionFactoryBuilderTests.cs (100%) diff --git a/CR.Exceptions.AspNet.UnitTests/CR.Exceptions.AspNet.Tests.csproj b/CR.Exceptions.AspNet.Tests/CR.Exceptions.AspNet.Tests.csproj similarity index 100% rename from CR.Exceptions.AspNet.UnitTests/CR.Exceptions.AspNet.Tests.csproj rename to CR.Exceptions.AspNet.Tests/CR.Exceptions.AspNet.Tests.csproj diff --git a/CR.Exceptions.AspNet.UnitTests/Component/CrExceptionHandlerTests.cs b/CR.Exceptions.AspNet.Tests/Component/CrExceptionHandlerTests.cs similarity index 100% rename from CR.Exceptions.AspNet.UnitTests/Component/CrExceptionHandlerTests.cs rename to CR.Exceptions.AspNet.Tests/Component/CrExceptionHandlerTests.cs diff --git a/CR.Exceptions.AspNet.UnitTests/Component/LogLevelMapTests.cs b/CR.Exceptions.AspNet.Tests/Component/LogLevelMapTests.cs similarity index 100% rename from CR.Exceptions.AspNet.UnitTests/Component/LogLevelMapTests.cs rename to CR.Exceptions.AspNet.Tests/Component/LogLevelMapTests.cs diff --git a/CR.Exceptions.AspNet.UnitTests/Component/StatusCodeMapTests.cs b/CR.Exceptions.AspNet.Tests/Component/StatusCodeMapTests.cs similarity index 100% rename from CR.Exceptions.AspNet.UnitTests/Component/StatusCodeMapTests.cs rename to CR.Exceptions.AspNet.Tests/Component/StatusCodeMapTests.cs diff --git a/CR.Exceptions.AspNet.UnitTests/TestNotFoundException.cs b/CR.Exceptions.AspNet.Tests/TestNotFoundException.cs similarity index 100% rename from CR.Exceptions.AspNet.UnitTests/TestNotFoundException.cs rename to CR.Exceptions.AspNet.Tests/TestNotFoundException.cs diff --git a/CR.Exceptions.AspNet.UnitTests/TestUnregisteredException.cs b/CR.Exceptions.AspNet.Tests/TestUnregisteredException.cs similarity index 100% rename from CR.Exceptions.AspNet.UnitTests/TestUnregisteredException.cs rename to CR.Exceptions.AspNet.Tests/TestUnregisteredException.cs diff --git a/CR.Exceptions.AspNet.UnitTests/Unit/LogLevelMapBuilderTests.cs b/CR.Exceptions.AspNet.Tests/Unit/LogLevelMapBuilderTests.cs similarity index 100% rename from CR.Exceptions.AspNet.UnitTests/Unit/LogLevelMapBuilderTests.cs rename to CR.Exceptions.AspNet.Tests/Unit/LogLevelMapBuilderTests.cs diff --git a/CR.Exceptions.AspNet.UnitTests/Unit/StatusCodeMapBuilderTests.cs b/CR.Exceptions.AspNet.Tests/Unit/StatusCodeMapBuilderTests.cs similarity index 100% rename from CR.Exceptions.AspNet.UnitTests/Unit/StatusCodeMapBuilderTests.cs rename to CR.Exceptions.AspNet.Tests/Unit/StatusCodeMapBuilderTests.cs diff --git a/CR.Exceptions.UnitTests/CR.Exceptions.Tests.csproj b/CR.Exceptions.Tests/CR.Exceptions.Tests.csproj similarity index 100% rename from CR.Exceptions.UnitTests/CR.Exceptions.Tests.csproj rename to CR.Exceptions.Tests/CR.Exceptions.Tests.csproj diff --git a/CR.Exceptions.UnitTests/Component/ErrorMapTests.cs b/CR.Exceptions.Tests/Component/ErrorMapTests.cs similarity index 100% rename from CR.Exceptions.UnitTests/Component/ErrorMapTests.cs rename to CR.Exceptions.Tests/Component/ErrorMapTests.cs diff --git a/CR.Exceptions.UnitTests/Component/ExceptionFactoryTests.cs b/CR.Exceptions.Tests/Component/ExceptionFactoryTests.cs similarity index 100% rename from CR.Exceptions.UnitTests/Component/ExceptionFactoryTests.cs rename to CR.Exceptions.Tests/Component/ExceptionFactoryTests.cs diff --git a/CR.Exceptions.UnitTests/TestException.cs b/CR.Exceptions.Tests/TestException.cs similarity index 100% rename from CR.Exceptions.UnitTests/TestException.cs rename to CR.Exceptions.Tests/TestException.cs diff --git a/CR.Exceptions.UnitTests/Unit/ErrorMapBuilderTests.cs b/CR.Exceptions.Tests/Unit/ErrorMapBuilderTests.cs similarity index 100% rename from CR.Exceptions.UnitTests/Unit/ErrorMapBuilderTests.cs rename to CR.Exceptions.Tests/Unit/ErrorMapBuilderTests.cs diff --git a/CR.Exceptions.UnitTests/Unit/ExceptionFactoryBuilderTests.cs b/CR.Exceptions.Tests/Unit/ExceptionFactoryBuilderTests.cs similarity index 100% rename from CR.Exceptions.UnitTests/Unit/ExceptionFactoryBuilderTests.cs rename to CR.Exceptions.Tests/Unit/ExceptionFactoryBuilderTests.cs diff --git a/CR.Exceptions.slnx b/CR.Exceptions.slnx index 2d7e57f..34ade86 100644 --- a/CR.Exceptions.slnx +++ b/CR.Exceptions.slnx @@ -2,8 +2,8 @@ - + - + From 319d534713b1b9b5e969d959fb1139a6effe8f8c Mon Sep 17 00:00:00 2001 From: apptade Date: Sat, 1 Aug 2026 21:21:41 +0300 Subject: [PATCH 2/8] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 1eb1643..acb840f 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ A lightweight framework for defining application errors, creating typed exceptions, and exposing consistent error responses across application boundaries. -The repository contains the following modules: - ## Modules ### CR.Exceptions From ceb56acb79a02a7e2ed93499f9cd89922c9c3dc5 Mon Sep 17 00:00:00 2001 From: apptade Date: Sat, 1 Aug 2026 21:23:52 +0300 Subject: [PATCH 3/8] Update CR.Exceptions.csproj --- CR.Exceptions/CR.Exceptions.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CR.Exceptions/CR.Exceptions.csproj b/CR.Exceptions/CR.Exceptions.csproj index 21cbfe4..b40b4fb 100644 --- a/CR.Exceptions/CR.Exceptions.csproj +++ b/CR.Exceptions/CR.Exceptions.csproj @@ -10,7 +10,7 @@ Core .NET exception framework providing base error models, an exception factory, and error mapping. $(NuGetPackagePrefix).Exceptions - exceptions;exception-handling;error-handling;error-factory;error-mapping;domain-exceptions + exceptions;exception-handling;exception-factory;error-handling;error-factory;error-mapping; README.md From 7308c575bc365009edf82d08d948f945b18f9984 Mon Sep 17 00:00:00 2001 From: apptade Date: Sat, 1 Aug 2026 21:29:21 +0300 Subject: [PATCH 4/8] Update ImmutableArrayExtensions.cs --- CR.Exceptions/Extensions/ImmutableArrayExtensions.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CR.Exceptions/Extensions/ImmutableArrayExtensions.cs b/CR.Exceptions/Extensions/ImmutableArrayExtensions.cs index a3e99b7..3fa7157 100644 --- a/CR.Exceptions/Extensions/ImmutableArrayExtensions.cs +++ b/CR.Exceptions/Extensions/ImmutableArrayExtensions.cs @@ -1,23 +1,24 @@ using System.Collections.Immutable; +using System.Runtime.CompilerServices; namespace CR.Exceptions.Extensions; public static class ImmutableArrayExtensions { - extension(ImmutableArray source) where TSource : class? + extension(ImmutableArray source) { - public void ThrowIfEmptyOrContainsNull() + public void ThrowIfEmptyOrContainsNull([CallerArgumentExpression(nameof(source))] string? paramName = null) { if (source.IsDefaultOrEmpty) { - throw new ArgumentException("The array cannot be empty.", nameof(source)); + throw new ArgumentException("The array cannot be empty.", paramName); } for (var i = 0; i < source.Length; i++) { if (source[i] is null) { - throw new ArgumentNullException(nameof(source), $"The array element[{i}] is null."); + throw new ArgumentNullException(paramName, $"The array element[{i}] is null."); } } } From b14b8e778c30708b3557e0aeb4e4f01a8a7b9a5b Mon Sep 17 00:00:00 2001 From: apptade Date: Sat, 1 Aug 2026 21:41:32 +0300 Subject: [PATCH 5/8] Add MissingLogLevelMapping log --- CR.Exceptions.AspNet/CrExceptionHandler.cs | 7 ++++++- CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CR.Exceptions.AspNet/CrExceptionHandler.cs b/CR.Exceptions.AspNet/CrExceptionHandler.cs index 7cc15a8..9073323 100644 --- a/CR.Exceptions.AspNet/CrExceptionHandler.cs +++ b/CR.Exceptions.AspNet/CrExceptionHandler.cs @@ -60,7 +60,12 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e _logger.LogMissingHttpStatusMapping(exception, exceptionTypeName); } - var logLevel = _logLevelMap.TryFind(crException, out var level) ? level : LogLevel.Debug; + if (!_logLevelMap.TryFind(crException, out var logLevel)) + { + logLevel = LogLevel.Debug; + _logger.LogMissingLogLevelMapping(exceptionTypeName, logLevel); + } + _logger.LogApplicationException(logLevel, exception, exceptionTypeName); } else diff --git a/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs b/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs index a4f4e6f..44cb64c 100644 --- a/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs +++ b/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs @@ -14,6 +14,7 @@ private static class LogIds public const int ProblemDetailsExtensionOverwritten = BaseId + 4; public const int FailedToWriteProblemDetails = BaseId + 5; public const int ApplicationException = BaseId + 6; + public const int MissingLogLevelMapping = BaseId + 7; } [LoggerMessage( @@ -50,4 +51,10 @@ private static class LogIds EventId = LogIds.ApplicationException, Message = "Application exception of type '{ExceptionType}' occurred.")] public static partial void LogApplicationException(this ILogger logger, LogLevel level, Exception exception, string? exceptionType); + + [LoggerMessage( + EventId = LogIds.MissingLogLevelMapping, + Level = LogLevel.Information, + Message = "No log level mapping found for exception type '{ExceptionType}'. Using fallback log level '{FallbackLogLevel}'.")] + public static partial void LogMissingLogLevelMapping(this ILogger logger, string? exceptionType, LogLevel fallbackLogLevel); } \ No newline at end of file From 67021d141f825dccc905d3bbd141c4ee8709d681 Mon Sep 17 00:00:00 2001 From: apptade Date: Sat, 1 Aug 2026 21:42:54 +0300 Subject: [PATCH 6/8] Update CrExceptionHandler.cs --- CR.Exceptions.AspNet/CrExceptionHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CR.Exceptions.AspNet/CrExceptionHandler.cs b/CR.Exceptions.AspNet/CrExceptionHandler.cs index 9073323..ae501a7 100644 --- a/CR.Exceptions.AspNet/CrExceptionHandler.cs +++ b/CR.Exceptions.AspNet/CrExceptionHandler.cs @@ -86,6 +86,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Instance = httpContext.Request.Path }, }; + AddProblemDetailsExtension(problemDetailsContext.ProblemDetails, ProblemDetailsExtensionNames.Errors, errors); return await TryWriteResponseAsync(exception, problemDetailsContext); From 708b0be8d9b7eedb4f7171759a26067a6ab2e19b Mon Sep 17 00:00:00 2001 From: apptade Date: Sat, 1 Aug 2026 22:03:32 +0300 Subject: [PATCH 7/8] Update CrExceptionHandlerLogExtensions --- CR.Exceptions.AspNet/CrExceptionHandler.cs | 4 ++-- .../CrExceptionHandlerLogExtensions.cs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CR.Exceptions.AspNet/CrExceptionHandler.cs b/CR.Exceptions.AspNet/CrExceptionHandler.cs index ae501a7..2e21e36 100644 --- a/CR.Exceptions.AspNet/CrExceptionHandler.cs +++ b/CR.Exceptions.AspNet/CrExceptionHandler.cs @@ -66,11 +66,11 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e _logger.LogMissingLogLevelMapping(exceptionTypeName, logLevel); } - _logger.LogApplicationException(logLevel, exception, exceptionTypeName); + _logger.LogCrExceptionOccurred(logLevel, exception, exceptionTypeName); } else { - _logger.LogUnhandledException(exception, exceptionTypeName); + _logger.LogUnknownException(exception, exceptionTypeName); } httpContext.Response.StatusCode = statusCode; diff --git a/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs b/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs index 44cb64c..793063d 100644 --- a/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs +++ b/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs @@ -10,10 +10,10 @@ private static class LogIds public const int ResponseAlreadyStarted = BaseId + 1; public const int MissingHttpStatusMapping = BaseId + 2; - public const int UnhandledException = BaseId + 3; + public const int UnknownException = BaseId + 3; public const int ProblemDetailsExtensionOverwritten = BaseId + 4; public const int FailedToWriteProblemDetails = BaseId + 5; - public const int ApplicationException = BaseId + 6; + public const int CrExceptionOccurred = BaseId + 6; public const int MissingLogLevelMapping = BaseId + 7; } @@ -30,10 +30,10 @@ private static class LogIds public static partial void LogMissingHttpStatusMapping(this ILogger logger, Exception exception, string? exceptionType); [LoggerMessage( - EventId = LogIds.UnhandledException, + EventId = LogIds.UnknownException, Level = LogLevel.Error, - Message = "An unexpected exception of type '{ExceptionType}' occurred.")] - public static partial void LogUnhandledException(this ILogger logger, Exception exception, string? exceptionType); + Message = "Unknown exception of type '{ExceptionType}' occurred. Default internal errors will be used.")] + public static partial void LogUnknownException(this ILogger logger, Exception exception, string? exceptionType); [LoggerMessage( EventId = LogIds.ProblemDetailsExtensionOverwritten, @@ -48,9 +48,9 @@ private static class LogIds public static partial void LogFailedToWriteProblemDetails(this ILogger logger, Exception exception); [LoggerMessage( - EventId = LogIds.ApplicationException, - Message = "Application exception of type '{ExceptionType}' occurred.")] - public static partial void LogApplicationException(this ILogger logger, LogLevel level, Exception exception, string? exceptionType); + EventId = LogIds.CrExceptionOccurred, + Message = "CR exception of type '{ExceptionType}' occurred.")] + public static partial void LogCrExceptionOccurred(this ILogger logger, LogLevel level, Exception exception, string? exceptionType); [LoggerMessage( EventId = LogIds.MissingLogLevelMapping, From e3206eefcd195166c47e95aacb43f9f370daa028 Mon Sep 17 00:00:00 2001 From: apptade Date: Sat, 1 Aug 2026 22:25:25 +0300 Subject: [PATCH 8/8] Update CrExceptionHandlerLogExtensions.cs --- CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs b/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs index 793063d..a82a7d5 100644 --- a/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs +++ b/CR.Exceptions.AspNet/CrExceptionHandlerLogExtensions.cs @@ -2,7 +2,7 @@ namespace CR.Exceptions.AspNet; -public static partial class CrExceptionHandlerLogExtensions +internal static partial class CrExceptionHandlerLogExtensions { private static class LogIds { @@ -54,7 +54,7 @@ private static class LogIds [LoggerMessage( EventId = LogIds.MissingLogLevelMapping, - Level = LogLevel.Information, + Level = LogLevel.Debug, Message = "No log level mapping found for exception type '{ExceptionType}'. Using fallback log level '{FallbackLogLevel}'.")] public static partial void LogMissingLogLevelMapping(this ILogger logger, string? exceptionType, LogLevel fallbackLogLevel); } \ No newline at end of file