CustomResultError 1.1.11
See the version list below for details.
dotnet add package CustomResultError --version 1.1.11
NuGet\Install-Package CustomResultError -Version 1.1.11
<PackageReference Include="CustomResultError" Version="1.1.11" />
paket add CustomResultError --version 1.1.11
#r "nuget: CustomResultError, 1.1.11"
// Install CustomResultError as a Cake Addin #addin nuget:?package=CustomResultError&version=1.1.11 // Install CustomResultError as a Cake Tool #tool nuget:?package=CustomResultError&version=1.1.11
CustomResultError
The modern Result Error types adjusted to modern AOT needs.
Combine the power of Results and Errors using a "discriminated union" approach.
How to install
Via tha Package Manager:
Install-Package CustomResultError
Via the .NET CLI
dotnet add package CustomResultError
Error
Generic Error<CodeType>
inherit from the Error
base class. The Error
class is an immutable object which contains the properties Message (string)
and Details (string[])
.
For the generic error, the CodeType
is the type of an additional Code
property. The errors are considered equal if their corresponding Code
properties are equal.
Error<int> e4 = new("mpe", code: 125);
Error<int> e5 = new("mpou", code: 125);
Console.WriteLine(e5); //will print the Message, i.e. "mpe"
Console.WriteLine(e4 == e5); //will print "True" because their codes are the same.
Error<string> e6 = new("mpa", "CODE1");
Error<string> e7 = new("mpampou", "CODE1"); //will return True because their codes are the same.
In the AOT world you cannot use the JsonSerializer
methods, because they use Reflection, which is not allowed. For this reason, the Error
objects have a ToJsonString
method which simplifies output especially in the case of Web endpoints.
The ToString()
overriden method returns only the Message
. Below are some examples that show how to export a full JSON string:
//the simplest case
Error<int> e4 = new("mpe", 125);
Console.WriteLine(e4.ToJsonString());
//we can add sub-errors/details by adding more arguments in the constructor (or by passing a string array)
Error<int> e4a = new("mpe", 125,"suberror1","suberror2");
Console.WriteLine(e4a.ToJsonString());
The first case will print:
{
"code" : 125,
"message" : "mpe"
}
The second case will print:
{
"code" : 125,
"message" : "mpe",
"details" : ["suberror1", "suberror2"]
}
ExceptionError
ExceptionError
is a special Error
object that inherit from Error<Exception>
. For convenience purposes it adds a domain (string)
before the name of the exception, in order to generate a domain-specific exception code (the domain
is optional).
The Message
property gets its value from the Exception.Message
property and the Details
array is populated from internal exception if they exist. The Code
property itself contains the Exception
object, so any stack information is preserved. For example:
Exception e = new InvalidOperationException("bamboo", new OperationCanceledException("mpeeee"));
ExceptionError error = new(e,domain:"MAIN");
Console.WriteLine(error.ToJsonString());
will print the following:
{
"code" : "MAIN.InvalidOperationException",
"message" : "bamboo",
"details" : ["mpeeee"]
}
Result
The Result class is designed in a way to behave like a union. A (very) simple example below, shows the implicit conversion from the result type, or the error to a Result
instance:
Result<int, Error<string>> result;
int a=5,b=6;
if (a < b)
result = Result.Ok(a+b);
else
result = Result.Fail(new Error<string>("This was a bad calc.","App.CalcError"));
//or (due to implicit conversions the code below is equivalent to the code above)
if (a < b)
result = a+b;
else
result = new Error<string>("This was a bad calc.","App.CalcError");
The Result
instance contains the Value
and Error
properties. A continuation of the previous result is the following:
IResult res;
if (result.IsSuccess)
res = Results.Ok(result.Value);
else
res = Results.BadRequest(result.Error);
There are 2 more compact ways to write the same statemens above, using the Match
function:
res = result.Match<IResult>( v => Results.Ok(v), e => Results.BadRequest(e));
//or
res = result.Match<IResult>(Results.Ok, Results.BadRequest);
//or (the IResult return type is implied from the return type of the functions)
res = result.Match(Results.Ok, Results.BadRequest);
The Match
function takes 2 functions (Func
) are arguments. The first is a function that gets the Value
and returns an IResult
and the second functions gets the Error
and returns a different IResult
.
The Switch
function is similar to the Match
function but takes as arguments functions that do not return any value aka Action
.
In the example below, the first Action
happens on success, while the second Action
happens on failure.
result.Switch(v => Console.WriteLine($"YES! The value is {v}"),
e=>Console.WriteLine($"NO! The error is {e}"));
Error parsing and AOT
But wait, what AOT compiling has to do with all these? The problem with AOT, is that reflection is not supported. Methods that support deserialization such as AsJsonAsync
, will not work. This Error
class supports parsing without the use of Reflection and therefore IS AOT compatible.
See the two examples below. The jsonString might come from the text response content of an HTTP call:
Error<int> e1 = new("messsad", 200, "sub1", "sub2");
string jsonString = e1.ToJsonString();
var e1_c = Error<int>.Parse(jsonString); //parsing does not use reflection here
Console.WriteLine(e1==e1_c);//will print True
Error<string> e2 = new(message:"messsad",code: "DSAD.asd", "sub1", "sub2");
jsonString = e2.ToJsonString();
var e2_c = Error<string>.Parse(jsonString); //parsing does not use reflection here
Console.WriteLine(e2 == e2_c); //will print True
The Validator static class
The CustomResultError.Validator
static class has some methods that combine the features of validation, logging and the Error
type. Aren't there other libraries that do validation stuff? Of course there are, however, they are NOT AOT friendly. For example, the FluentValidation
library uses Reflection heavily and therefore cannot be used in AOT apps.
In the following cases, it is practical to use the Validator
static members globally using the following statement:
using static CustomResultError.Validator;
//for convenience we add an alias for Errors with code as strings
using ErrorString = CustomResultError.Error<string>;
The Validate
function is a generic function that returns an Error only if the validation fails. If an ILogger
is passed to the Validate
function, then the errorMessageTemplate
message is logged. The message that is passed to the ILogger
is combined with the messageArgs
arguments to populate any interpolated values in the errorMessageTemplate
. The same error message, is also the Message
property of the ErrorString
returned instance. If the validation test is passed (based on the validateFunction
) then null
is returned. If the passed logger
is null
then no logging is done. Note that no logging happens if the value is successfully validated, to avoid verbose outputs.
static ErrorString? ValidateTaxValue(int valueInPerc, Microsoft.Extensions.Logging.ILogger? logger)
{
return Validate(
value: valueInPerc,
validateFunction: p => p >= 0 && p <= 100,
logger: logger,
errorCode: "App.InvalidTax",
errorMessageTemplate: "The tax value ({value}) is invalid.",
logTypeIfError: ValidatorLogTypeIfError.Error,
messageArgs: valueInPerc);
}
The same functionality can be done via the Fail
method. The above method is same to the method below. Note that the Fail
function returns a non-nullable Error
and also passes the error message to the logger
(if given):
static ErrorString? ValidateTaxValue2(int valueInPerc, Microsoft.Extensions.Logging.ILogger? logger)
{
if(valueInPerc < 0 || valueInPerc > 100)
return Fail(
logger: logger,
errorCode: "App.InvalidTax",
errorMessageTemplate: "The tax value ({value}) is invalid.",
logTypeIfError: ValidatorLogTypeIfError.Error,
messageArgs: valueInPerc);
return null;
}
MORE EXAMPLES TO FOLLOW
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.2.15 | 112 | 12/6/2024 |
1.2.14 | 212 | 7/20/2024 |
1.2.13 | 102 | 7/14/2024 |
1.2.12 | 122 | 5/4/2024 |
1.2.11 | 106 | 5/3/2024 |
1.2.10 | 101 | 5/3/2024 |
1.2.9 | 94 | 5/3/2024 |
1.2.8 | 91 | 5/3/2024 |
1.2.7 | 77 | 5/3/2024 |
1.2.6 | 84 | 5/3/2024 |
1.2.5 | 82 | 5/3/2024 |
1.2.4 | 79 | 5/3/2024 |
1.2.2 | 76 | 5/3/2024 |
1.2.1 | 78 | 5/3/2024 |
1.2.0 | 70 | 5/3/2024 |
1.1.15 | 130 | 3/28/2024 |
1.1.14 | 124 | 3/28/2024 |
1.1.13 | 126 | 3/27/2024 |
1.1.12 | 123 | 3/26/2024 |
1.1.11 | 134 | 3/24/2024 |
1.1.10 | 131 | 3/10/2024 |
1.1.9 | 131 | 3/10/2024 |
1.1.8 | 131 | 3/8/2024 |
1.1.7 | 126 | 3/8/2024 |
1.1.6 | 130 | 3/8/2024 |
1.1.5 | 115 | 3/5/2024 |
1.1.4 | 131 | 3/4/2024 |
1.1.3 | 116 | 3/3/2024 |
1.1.2 | 115 | 3/3/2024 |
1.1.1 | 148 | 3/3/2024 |
1.1.0 | 121 | 3/2/2024 |
1.0.5 | 144 | 3/1/2024 |
1.0.4 | 165 | 3/1/2024 |
1.0.2 | 135 | 3/1/2024 |
1.0.1 | 136 | 3/1/2024 |