A C# library for clean, functional error handling. This library provides a robust alternative to exception-based error handling, making your code more predictable and easier to reason about.
# Package manager
Install-Package OliveStudio.Results
# .NET CLI
dotnet add package OliveStudio.Results
Represents a successful operation with no return value.
var result = OkResult.Ok();
if (result.Success)
{
Console.WriteLine("Operation completed successfully!");
}
Represents a failed operation with error details.
var result = ErrorResult.Fail("User not found", 404);
if (result.IsFailure)
{
Console.WriteLine($"Error: {result.Error} (Code: {result.ErrorCode})");
}
Represents a successful operation that returns a value.
var result = OkObjectResult<string>.Ok("Hello, World!");
if (result.Success)
{
Console.WriteLine(result.Value); // Output: Hello, World!
}
Represents a failed operation for a specific type.
var result = ErrorObjectResult<User>.Fail("Invalid user data", 400);
if (result.IsFailure)
{
Console.WriteLine($"Failed to create user: {result.Error}");
// result.Value will be default(User)
}
public Result ValidateEmail(string email)
{
if (string.IsNullOrWhiteSpace(email))
return ErrorResult.Fail("Email is required");
if (!email.Contains("@"))
return ErrorResult.Fail("Invalid email format");
return OkResult.Ok();
}
// Usage
var validationResult = ValidateEmail("[email protected]");
if (validationResult.Success)
{
Console.WriteLine("Email is valid!");
}
public ObjectResult<User> CreateUser(string name, string email)
{
if (string.IsNullOrWhiteSpace(name))
return ErrorObjectResult<User>.Fail("Name is required");
if (string.IsNullOrWhiteSpace(email))
return ErrorObjectResult<User>.Fail("Email is required");
var user = new User { Name = name, Email = email };
return OkObjectResult<User>.Ok(user);
}
// Usage
var userResult = CreateUser("John Doe", "[email protected]");
if (userResult.Success)
{
Console.WriteLine($"Created user: {userResult.Value.Name}");
}
else
{
Console.WriteLine($"Failed to create user: {userResult.Error}");
}
The library supports combining multiple results using the &
operator:
public Result ValidateUserData(string name, string email, int age)
{
var nameValidation = ValidateName(name);
var emailValidation = ValidateEmail(email);
var ageValidation = ValidateAge(age);
// All validations must succeed for the combined result to succeed
return nameValidation & emailValidation & ageValidation;
}
Results can be used directly in conditional statements:
var result = ValidateEmail("[email protected]");
// Direct boolean usage
if (result)
{
Console.WriteLine("Validation passed");
}
public class UserService
{
public ObjectResult<User> RegisterUser(string name, string email, string password)
{
// Validate input
var validation = ValidateUserInput(name, email, password);
if (validation.IsFailure)
return ErrorObjectResult<User>.Fail(validation.Error, validation.ErrorCode);
// Check if user exists
var existingUser = FindUserByEmail(email);
if (existingUser.Success)
return ErrorObjectResult<User>.Fail("User already exists", 409);
// Create and save user
var user = new User { Name = name, Email = email };
var saveResult = SaveUser(user);
if (saveResult.IsFailure)
return ErrorObjectResult<User>.Fail("Failed to save user", 500);
return OkObjectResult<User>.Ok(user);
}
private Result ValidateUserInput(string name, string email, string password)
{
var nameValidation = ValidateName(name);
var emailValidation = ValidateEmail(email);
var passwordValidation = ValidatePassword(password);
return nameValidation & emailValidation & passwordValidation;
}
}
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly UserService _userService;
[HttpPost]
public IActionResult CreateUser([FromBody] CreateUserRequest request)
{
var result = _userService.RegisterUser(
request.Name,
request.Email,
request.Password);
if (result.Success)
{
return Ok(result.Value);
}
return result.ErrorCode switch
{
409 => Conflict(result.Error),
500 => StatusCode(500, result.Error),
_ => BadRequest(result.Error)
};
}
}
public static class ErrorCodes
{
public const int ValidationError = 400;
public const int NotFound = 404;
public const int Conflict = 409;
public const int InternalError = 500;
}
// Usage
return ErrorResult.Fail("User not found", ErrorCodes.NotFound);
public static class UserErrors
{
public static ErrorObjectResult<User> UserNotFound(int userId) =>
ErrorObjectResult<User>.Fail($"User with ID {userId} not found", 404);
public static ErrorObjectResult<User> EmailAlreadyExists(string email) =>
ErrorObjectResult<User>.Fail($"User with email {email} already exists", 409);
}