OnRail 1.2.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package OnRail --version 1.2.0                
NuGet\Install-Package OnRail -Version 1.2.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="OnRail" Version="1.2.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add OnRail --version 1.2.0                
#r "nuget: OnRail, 1.2.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 OnRail as a Cake Addin
#addin nuget:?package=OnRail&version=1.2.0

// Install OnRail as a Cake Tool
#tool nuget:?package=OnRail&version=1.2.0                

OnRail library

Simple and powerful Railway Oriented library for C#.

Simple Sample

using FunctionalUtility.Extensions;

TryExtensions.Try(() => {
        Console.Write("Enter a number: ");
        var input = Console.ReadLine();
        return Convert.ToInt32(input);
    })
    .OnSuccess(number => Console.WriteLine($"Number is valid: {number}"))
    .OnFail(result => {
        Console.WriteLine("Result:");
        Console.WriteLine($"Is Success? {result.IsSuccess}"); //Is Success? False
        Console.WriteLine($"Error title: {result.Detail.Title}"); //Sample: Error title: ExceptionError
        Console.WriteLine($"Error message: {result.Detail.Message}"); //Sample: Error message: Input string was not in a correct format.
    });

Document

The output of each method is a MethodResult class. The MethodResult class has two important fields.

  1. IsSuccess: Determines whether the operation was successful or not.
  2. Detail: It keeps more details of the result. Like title, message, etc.

There are two types of MethodResult:

  1. MethodResult: Simple MethodResult that have no data.
  2. MethodResult<T>: MethodResult that holds data of type T.

The MethodResult class has two important methods.

  1. Ok: Indicates that the operation was successful and can include data and detail.

    • MethodResult.Ok()

    • MethodResult<string>.Ok("Hello")

    • MethodResult.Ok(new ResultDetail(statusCode: 200, "Title", "Message"))

    • MethodResult<string>.Ok("Hello", new ResultDetail(statusCode: 200, "Title", "Message"))

  2. Fail: Indicates that the operation failed and contains detail.

    MethodResult.Fail(new BadRequestError("title", "message"))

Sample

using FunctionalUtility.ResultUtility;

// This method returns "Hello" string.
private static MethodResult<string> GetHello() {
    return MethodResult<string>.Ok("Hello");
}

public static MethodResult PrintHello() =>
    GetHello()
        .OnSuccess(message => Console.WriteLine(message))
        .OnFail(result => Console.WriteLine($"Operation failed. {result.Detail.Title}-{result.Detail.Message}"));


public static MethodResult PrintHelloVerbose() {
    var messageResult = GetHello();

    if (!messageResult.IsSuccess) {
        //Operation was not successful. Print detail.
        var detail = messageResult.Detail;
        Console.WriteLine($"Operation failed. {detail.Title}-{detail.Message}");
        return MethodResult.Fail(detail);
    }

    //Operation was successful.
    Console.WriteLine(messageResult.Value); //Hello
    return MethodResult.Ok();
}

Custom ResultDetail

For simplicity, you can customize the ResultDetail:

public class CustomDetail : ResultDetail {
    public CustomDetail(int statusCode = 1000, string title = "Custom Title",
        string? message = "Custom Message") : base(statusCode, title, message) { }
}

static void PrintCustomDetail() =>
    MethodResult.Fail(new CustomDetail())
        .OnFail(result => {
            var detail = result.Detail;
            Console.WriteLine(detail.StatusCode); //1000
            Console.WriteLine(detail.Title); //Custom Title
            Console.WriteLine(detail.Message); //Custom Message
        });

You can also customize the fields:

public class CustomDetail : ResultDetail {
    public string CustomField { get; set; }

    public CustomDetail(string customField, int statusCode = 1000, string title = "Custom Title",
        string? message = "Custom Message") : base(statusCode, title, message) {
        CustomField = customField;
    }
}

static void PrintCustomDetail() =>
    MethodResult.Fail(new CustomDetail("Custom Field"))
        .OnFail(result => {
            if (result.Detail is CustomDetail customDetail) {
                Console.WriteLine(customDetail.CustomField); //Custom Field
            }

            var detail = result.Detail;
            Console.WriteLine(detail.StatusCode); //1000
            Console.WriteLine(detail.Title); //Custom Title
            Console.WriteLine(detail.Message); //Custom Message
        });

Customize Error Details

It is better to inherit from the ErrorDetail class to customize the error details. Because the ErrorDetail class includes fields like StackTrace and exception data.

ResultDetail is a base class for successful and unsuccessful operations. But the ErrorDetail class is designed for failed operations.

Usually, to increase the security of the program, the details of the errors (such as 500 errors in the server) are not displayed to users. With the ShowDefaultMessageToUser field in the ErrorDetail class you can specify whether the default message is displayed or not.

For example:

static MethodResult Print(bool showDefaultMessage) =>
    MethodResult.Fail(new InternalError(message: "This is an important bug",
            showDefaultMessageToUser: showDefaultMessage))
        .OnFail(result => Console.WriteLine(result.Detail.GetViewModel()));

Print(false);
/*
 * Output:
 * { StatusCode = 500, Title = InternalError, Message = This is an important bug }
 */

Print(true);
/*
 * Output:
 * { StatusCode = 500, Title = Error!, Message = something went wrong. }
 */

Add More Details

You can easily add the objects you need to the details.

static MethodResult Print(string input) =>
    MethodResult.Fail(new BadRequestError())
        .OnFail(result => result.Detail.AddDetail(new {input}))
        .OnFail(result => {
            if (result.Detail.MoreDetails is null)
                return;
            foreach (var detail in result.Detail.MoreDetails) {
                Console.WriteLine(detail);
            }
        });

/*
 * Sample Output:
 * { input = Test }
 */

Default ResultDetail

Types of Result Details that exist:

  • BadRequestError.cs
  • ConflictError.cs
  • ErrorDetail.cs
  • ExceptionData.cs
  • ExceptionError.cs
  • ForbiddenError.cs
  • InternalError.cs
  • NotFoundError.cs
  • NotImplementedError.cs
  • UnauthorizedError.cs
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 netcoreapp3.1 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
2.0.0 705 10/18/2022
1.4.1 382 10/17/2022
1.4.0 378 10/12/2022
1.3.0 495 8/18/2022
1.2.0 380 8/17/2022
1.1.0 400 8/15/2022
1.0.0 404 5/29/2022