Hart.ErrorHandlers 3.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Hart.ErrorHandlers --version 3.1.0
NuGet\Install-Package Hart.ErrorHandlers -Version 3.1.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Hart.ErrorHandlers" Version="3.1.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Hart.ErrorHandlers --version 3.1.0
#r "nuget: Hart.ErrorHandlers, 3.1.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Hart.ErrorHandlers as a Cake Addin
#addin nuget:?package=Hart.ErrorHandlers&version=3.1.0

// Install Hart.ErrorHandlers as a Cake Tool
#tool nuget:?package=Hart.ErrorHandlers&version=3.1.0

Hart.ErrorHandlers

Purpose

This project purpose is to provide helpers for error handling in .NET Standard. Basically anything involving wrapping exceptions, method calls, retrying, etc.

Language

This is a C# .Net Standard 2.0 library.

Where to get it

You can download the latest version from nuget.org or also from the nuget package manager in VS by searching for Hart.ErrorHandlers.

Safe Result returns

IResult is the interface that any type built to wrap function call results should implement. It's main purpose is to allow the needed covariance to return multiple types from the same function but "packed" under the same umbrella. IT also provides some methods to check if the call is Ok or if it returned any value.

Usage example:

var calculator = new Calculator();
// Divide by zero exception.
IResult<double> result = calculator.DoDivision(10, 0);

// The user has to check the type before accessing to the value.
if (result is Error) {
    var exception = (result as Error).ExceptionValue;
    Console.WriteLine(exception);
} 

// Or...
if (result is Success && result is Success<double>) {
    double divResult = (result as Success<double>).Value;
    Console.WriteLine(divResult);
}

Implementation in method:

// Doing division could throw a divide by zero exception.
public IResult<double> DoDivision(int x, int y)
{
    IResult<double> result;
    try
    {
        result = new Success<double>(x / y);
    }
    catch(DivideByZeroException ex)
    {
        result = new Error<double>(ex);
    }
    catch (Exception ex)
    {
        result = new Error<double>(ex);
    }
    return result;
}

There are examples of how to use the library on the Hart.ErrorHandlersTests project.


Retrying

In the namespace Hart.ErrorHandlers.Retry you will find and static class Retrier used to configure and retry functions or actions in a safe way. There are options to configure the number of retries, the ms wait between retries or even if the retrier will keep retrying until successful.

In it's simplest way it looks like this:

var res = Retrier.Init() // Create the default retry config
                 .Invoke(() => 2 + 2); // Pass the function to execute

int four = res.Result;

More Examples:


/// Call a function that will fail 5 times and return a default value.
var res = Retrier.Init()
    .WithMsWaitOf(100)
    .WithNumberOfRetries(5)
    .Invoke(() => 2 / zero)
    .WithFallBackValue(33);

// Calling and action.
var res = Retrier.Init()
    .Invoke(() => Trace.WriteLine("action"))
    .WithFallBack(() => Trace.WriteLine("fallback"));;

The default configuration is 3 retries with 0 ms wait between retries.

Of course it also supports async methods. But it's important to remember that you should use the .InvokeAsync method instead of the regular Invoke. It works for Funcs and Actions.


// You can use the .WaitForValue to keep chaining methods.
// (this way the method that contains this Retry doesn't need to be marked async)
public int GetValue() {
    var result = Retrier.Init()
        .WithNumberOfRetries(1)
        .InvokeAsync(async () => await yourAsyncFunction())
        .WaitForValue();
}

// Or if it's the last call, just use the regular await syntax.
public async int GetValueAsync() {
    // In this case needs the async and await keywords.
    var result = await Retrier.Init()
        .WithNumberOfRetries(1)
        .InvokeAsync(async () => await yourAsyncFunction());
}

// You also can use fallback async calls.
var result = Retrier.Init()
    .WithNumberOfRetries(5)
    .InvokeAsync(async () => await yourAsyncFunction())
    .WaitForValue()
    .WithFallbackAsync(async () => await yourAsyncFallbackFunction())
    .WaitForValue();

This class will try to handle any kind of errors that happen inside and return the result if successful, a collection with the possible exceptions thrown and also information about the fallback execution. Also contains the number of executions.

You can find more about what it returns on the class RetryResult<T> or RetryResult.

IMPORTANT: Since it doesn't throw exceptions you should check that the operation was successful before using the returned value. For example, a function that returns int that fails will return 0 as a Result, but also a list of exceptions.

Example:

var res = Retrier.Init()
                 .Invoke(() => 2 + 2);

// Check if the function was successful.
if (res.Successful)
{
    Console.WriteLine(res.Result); // 4  
} else {
    Console.WriteLine(res.RetryInfo
                        .Exceptions
                        .FirstOrDefault()
                        .Message);
}

// Number of executions of the function. (1)
Console.WriteLine(res.RetryInfo.Executions);

If too many failed retries are done the Exceptions collection could grow so much as to throw an OutOfMemoryException. Please, use it with caution. In future versions it will be possible to opt-out from doing exception logging and only store the last one or none.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.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
3.5.0 512 2/18/2020
3.4.0 816 8/6/2018
3.2.1 792 8/4/2018
3.1.0 760 8/4/2018
3.0.0 793 8/2/2018
2.0.0 826 7/7/2018
1.2.0 1,010 5/17/2018
1.1.0 949 4/28/2018
1.0.0 969 4/28/2018