diff --git a/src/Ardalis.Result.AspNetCore/MinimalApiResultExtensions.cs b/src/Ardalis.Result.AspNetCore/MinimalApiResultExtensions.cs index ee62b3c..a080c78 100644 --- a/src/Ardalis.Result.AspNetCore/MinimalApiResultExtensions.cs +++ b/src/Ardalis.Result.AspNetCore/MinimalApiResultExtensions.cs @@ -6,6 +6,7 @@ #if NET7_0_OR_GREATER namespace Ardalis.Result.AspNetCore; + public static partial class ResultExtensions { /// @@ -33,14 +34,15 @@ internal static Microsoft.AspNetCore.Http.IResult ToMinimalApiResult(this IResul result.Status switch { ResultStatus.Ok => typeof(Result).IsInstanceOfType(result) - ? Results.Ok() - : Results.Ok(result.GetValue()), + ? Results.Ok() + : Results.Ok(result.GetValue()), ResultStatus.NotFound => NotFoundEntity(result), ResultStatus.Unauthorized => Results.Unauthorized(), ResultStatus.Forbidden => Results.Forbid(), ResultStatus.Invalid => Results.BadRequest(result.ValidationErrors), ResultStatus.Error => UnprocessableEntity(result), ResultStatus.Conflict => ConflictEntity(result), + ResultStatus.CriticalError => CriticalEntity(result), _ => throw new NotSupportedException($"Result {result.Status} conversion is not supported."), }; @@ -76,7 +78,7 @@ private static Microsoft.AspNetCore.Http.IResult NotFoundEntity(IResult result) return Results.NotFound(); } } - + private static Microsoft.AspNetCore.Http.IResult ConflictEntity(IResult result) { var details = new StringBuilder("Next error(s) occured:"); @@ -96,5 +98,26 @@ private static Microsoft.AspNetCore.Http.IResult ConflictEntity(IResult result) return Results.Conflict(); } } + + private static Microsoft.AspNetCore.Http.IResult CriticalEntity(IResult result) + { + var details = new StringBuilder("Next error(s) occured:"); + + if (result.Errors.Any()) + { + foreach (var error in result.Errors) details.Append("* ").Append(error).AppendLine(); + + return Results.Problem(new ProblemDetails() + { + Title = "Something went wrong.", + Detail = details.ToString(), + Status = StatusCodes.Status500InternalServerError + }); + } + else + { + return Results.StatusCode(StatusCodes.Status500InternalServerError); + } + } } #endif diff --git a/src/Ardalis.Result/Result.Void.cs b/src/Ardalis.Result/Result.Void.cs index 7c69e74..a0c2817 100644 --- a/src/Ardalis.Result/Result.Void.cs +++ b/src/Ardalis.Result/Result.Void.cs @@ -160,5 +160,17 @@ public static Result ErrorWithCorrelationId(string correlationId, params string[ { return new Result(ResultStatus.Conflict) { Errors = errorMessages }; } + + /// + /// Represents a critical error that occurred during the execution of the service. + /// Everything provided by the user was valid, but the service was unable to complete due to an exception. + /// See also HTTP 500 Internal Server Error: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors + /// + /// A list of string error messages. + /// A Result + public static Result CriticalError(params string[] errorMessages) + { + return new Result(ResultStatus.CriticalError) { Errors = errorMessages }; + } } } \ No newline at end of file diff --git a/tests/Ardalis.Result.UnitTests/ResultConstructor.cs b/tests/Ardalis.Result.UnitTests/ResultConstructor.cs index 029e6d2..deaed88 100644 --- a/tests/Ardalis.Result.UnitTests/ResultConstructor.cs +++ b/tests/Ardalis.Result.UnitTests/ResultConstructor.cs @@ -238,4 +238,12 @@ public void InitializedIsSuccessFalseForConflictFactoryCall() result.IsSuccess.Should().BeFalse(); } + + [Fact] + public void InitializedIsSuccessFalseForCriticalErrorFactoryCall() + { + var result = Result.CriticalError(); + + Assert.False(result.IsSuccess); + } } diff --git a/tests/Ardalis.Result.UnitTests/ResultMap.cs b/tests/Ardalis.Result.UnitTests/ResultMap.cs index 8f150a7..7552f8c 100644 --- a/tests/Ardalis.Result.UnitTests/ResultMap.cs +++ b/tests/Ardalis.Result.UnitTests/ResultMap.cs @@ -164,6 +164,18 @@ public void ShouldProduceConflictWithError() actual.Errors.Single().Should().Be(expectedMessage); } + [Fact] + public void ShouldProduceCriticalErrorWithError() + { + string expectedMessage = "Some critical error"; + var result = Result.CriticalError(expectedMessage); + + var actual = result.Map(val => val.ToString()); + + actual.Status.Should().Be(ResultStatus.CriticalError); + actual.Errors.Single().Should().Be(expectedMessage); + } + private record Foo(string Bar); private class FooDto diff --git a/tests/Ardalis.Result.UnitTests/ResultVoidConstructor.cs b/tests/Ardalis.Result.UnitTests/ResultVoidConstructor.cs index 0dcc839..7ca58d5 100644 --- a/tests/Ardalis.Result.UnitTests/ResultVoidConstructor.cs +++ b/tests/Ardalis.Result.UnitTests/ResultVoidConstructor.cs @@ -171,4 +171,15 @@ public void InitializesConflictResultWithFactoryMethodWithErrors() result.Status.Should().Be(ResultStatus.Conflict); result.Errors.Single().Should().Be(errorMessage); } + + [Fact] + public void InitializesCriticalErrorResultWithFactoryMethodWithErrors() + { + var errorMessage = "Some critical error"; + var result = Result.CriticalError(errorMessage); + + result.Value.Should().BeNull(); + result.Status.Should().Be(ResultStatus.CriticalError); + result.Errors.Single().Should().Be(errorMessage); + } } diff --git a/tests/Ardalis.Result.UnitTests/ResultVoidMap.cs b/tests/Ardalis.Result.UnitTests/ResultVoidMap.cs index aaaf8b7..7464400 100644 --- a/tests/Ardalis.Result.UnitTests/ResultVoidMap.cs +++ b/tests/Ardalis.Result.UnitTests/ResultVoidMap.cs @@ -92,5 +92,16 @@ public void ShouldProduceConflict() actual.Status.Should().Be(ResultStatus.Conflict); actual.Value.Should().BeNull(); } + + [Fact] + public void ShouldProduceCriticalError() + { + var result = Result.CriticalError(); + + var actual = result.Map(_ => "This should be ignored"); + + actual.Status.Should().Be(ResultStatus.CriticalError); + actual.Value.Should().BeNull(); + } } } diff --git a/tests/Ardalis.Result.UnitTests/ResultVoidToResultOfT.cs b/tests/Ardalis.Result.UnitTests/ResultVoidToResultOfT.cs index f596bdf..520428a 100644 --- a/tests/Ardalis.Result.UnitTests/ResultVoidToResultOfT.cs +++ b/tests/Ardalis.Result.UnitTests/ResultVoidToResultOfT.cs @@ -103,5 +103,14 @@ public void ConvertFromConflictResultOfUnit() result.Value.Should().BeNull(); } + [Fact] + public void ConvertFromCriticalErrorResultOfUnit() + { + var result = DoBusinessOperationExample(Result.CriticalError()); + + result.Status.Should().Be(ResultStatus.CriticalError); + result.Value.Should().BeNull(); + } + public Result DoBusinessOperationExample(Result testValue) => testValue; }