OnRails is a railway-oriented programming library for C#. It simplifies handling complex workflows by utilizing the principles of success and failure paths, making code easier to read, maintain, and extend.
The Railway Oriented Programming (ROP) pattern separates the pure functional domain logic from the side effects, by
representing them as a sequence of functions that return an Either type, representing either a successful Result
or an error. This allows for better composition and testing of functions, as well as improving the code's **
maintainability** and readability.
It also facilitates the handling of errors, as the error handling logic is separated from the main logic, making it easier to reason about and handle errors in a consistent and predictable manner. Overall, ROP can lead to more robust and reliable software systems.
In functional programming, it is not always appropriate to use traditional try-except
blocks because they can lead to
code that is difficult to read, understand, and maintain.
OnRails
supports functional error handling. The goal of this library is to make error handling more explicit,
composable, and testable. By using this library, developers can write code that is more robust, maintainable, and
expressive.
Railway Oriented Programming (ROP) solves several common problems in software development, such as:
-
Handling errors: By using an Either (
Result
) type, ROP makes it easy to represent and handle errors in a consistent and predictable manner, avoiding errors being thrown and allowing for error handling logic to be separated from the main logic. -
Composition: ROP separates the pure functional domain logic from the side effects, such as I/O, by representing them as a sequence of functions. This makes it easy to compose and chain functions together, enabling better code reuse and maintainability.
-
Readability: The separation of pure functional domain logic from the side effects makes the code more readable and understandable, as it makes it clear what each function does and how they relate to each other.
-
Testing: The pure functional domain logic can be easily tested, as it does not depend on any external state or side effects. This simplifies testing and ensures that the code is correct.
Overall, ROP provides a structured approach to software development that makes it easier to handle errors, compose functions, and test code, leading to more robust and reliable software systems.
Developers can spend less time debugging and more time writing code that adds value to their organization. Additionally, by using functional programming concepts, developers can write code that is easier to reason about and understand, which can lead to faster development cycles and better quality code.
- Dotnet 8+
Use nuget to install the package.
dotnet add package OnRails
using OnRails.Extensions.OnFail;
using OnRails.Extensions.OnSuccess;
using OnRails.Extensions.Try;
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($"Is Success? {result.Success}"); // False
Console.WriteLine("Error Detail:");
Console.WriteLine(result.Detail?.ToString() ?? "No Data!");
return result;
});
using OnRails;
using OnRails.Extensions.OnFail;
using OnRails.Extensions.OnSuccess;
using OnRails.ResultDetails.Errors.BadRequest;
DivideNumber(5, 0)
.OnSuccess(value => Console.WriteLine($"Result: {value}"))
.OnFailOperateWhen(result => result.Detail is DivideByZeroError,
result => {
Console.WriteLine($"Oops! We can not divide by zero! \n{result.Detail}");
return result;
});
static Result<double> DivideNumber(int a, int b) =>
b == 0
? Result<double>.Fail(new DivideByZeroError(nameof(b)))
: Result<double>.Ok(a * 1.0 / b);
// Define Custom ErrorDetail
public class DivideByZeroError(
string fieldName,
string fieldMessage = "Cannot divide by zero",
bool view = true) : ValidationError(fieldName, fieldMessage, view);
-
ActionResult: Provides methods for working with ASP.NET Action Results, such as
ReturnAccepted
,ReturnCreated
, andResetContent
. -
Bind: Methods for binding data efficiently, e.g.,
BindExtensions
. -
Configuration: Extensions for configuration management, e.g.,
ConfigurationExtensions
. -
Fail: Handles failure conditions with methods like
FailWhen
. -
ForEach: Iteration helpers for both synchronous and asynchronous loops.
-
Must: Asserts conditions using
MustExtensions
. -
Object: General-purpose object manipulation methods.
-
OnFail / OnSuccess: Handles failure and success conditions, including adding or removing details, operations, and chaining methods.
-
OperateWhen: Facilitates conditional operations.
-
Tee / Using: Implements functional programming patterns like
Tee
and resource management withUsing
.
- Errors:
- Structured error types like
BadRequestError
,ConflictError
,ValidationError
, andUnauthorizedError
. - Specialized internal errors (
ExceptionError
,InternalError
, etc.).
- Structured error types like
- Success:
- Success result types such as
AcceptedDetail
,CreatedDetail
,NoContentDetail
, and more.
- Success result types such as
- Warnings:
- Supports warning details via
WarningDetail
.
- Supports warning details via
Please see the CHANGELOG file.
-
Rich Extensions: Offers a wide range of extension methods grouped by functionality for streamlined workflows.
-
Error Handling: Detailed error management with a structured hierarchy.
-
Customizable: Extensible design allowing users to add their own custom result details and extensions.
-
Integration Support: Built-in features for integrating with ASP.NET
First off, thanks for taking the time to contribute! Contributions are what make the free/open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody else and are greatly appreciated.
Please read our contribution guidelines, and thank you for being involved!
The original setup of this repository is by Payadel.
For a full list of all authors and contributors, see the contributors page.
OnRails follows good practices of security, but 100% security cannot be assured. OnRails is provided "as is" without any warranty.
For more information and to report security issues, please refer to our security documentation.
This project is licensed under the GPLv3.
See LICENSE for more information.
Here are some related projects