Error Handling¶
Overview¶
TinyResult provides a clean and type-safe way to handle errors in your applications. The error handling features offer a comprehensive solution for catching, processing, and reporting errors.
Key Concepts¶
1. Error Types¶
// Simple error
var error = Error.Create("Something went wrong");
// Error with code
var error = Error.Create(ErrorCode.NotFound, "User not found");
// Error with metadata
var error = Error.Create(
ErrorCode.ValidationError,
"Invalid input",
new Dictionary<string, object>
{
{ "Field", "Name" },
{ "Value", "" }
}
);
2. Error Codes¶
Predefined error codes:
public enum ErrorCode
{
Unknown, // Unknown error
NotFound, // Resource not found
ValidationError, // Validation error
Unauthorized, // Unauthorized access
InvalidOperation, // Invalid operation
NetworkError, // Network error
Timeout, // Timeout
ConfigurationError,// Configuration error
DatabaseError // Database error
}
Error Handling Strategies¶
1. Basic Error Handling¶
var result = GetUser(1);
// Error handling with Match
result.Match(
user => Console.WriteLine($"User found: {user.Name}"),
error => Console.WriteLine($"Error: {error.Message}")
);
// Error handling with OnFailure
result.OnFailure(error => Console.WriteLine($"Error: {error.Message}"));
2. Error Code Based Handling¶
var result = GetUser(1);
if (result.IsFailure)
{
switch (result.Error.Code)
{
case ErrorCode.NotFound:
Console.WriteLine("User not found");
break;
case ErrorCode.ValidationError:
Console.WriteLine("Validation error");
break;
default:
Console.WriteLine("Unknown error");
break;
}
}
3. Error Transformation¶
var result = GetUser(1)
.TransformError(error => new Error(
ErrorCode.Unknown,
$"Unexpected error: {error.Message}"
));
Advanced Features¶
1. Error Aggregation¶
var results = new[]
{
GetUser(1),
GetUser(2),
GetUser(3)
};
var combinedResult = Result.Combine(results);
if (combinedResult.IsFailure)
{
foreach (var error in combinedResult.Error.Metadata["Errors"] as IEnumerable<Error>)
{
Console.WriteLine($"Error: {error.Message}");
}
}
2. Error Logging¶
// Error logging configuration
Result.OnError = error =>
{
Console.WriteLine($"Error Code: {error.Code}");
Console.WriteLine($"Error Message: {error.Message}");
foreach (var metadata in error.Metadata)
{
Console.WriteLine($"{metadata.Key}: {metadata.Value}");
}
};
3. Custom Error Handlers¶
public class CustomErrorHandler
{
public static Result<T> HandleError<T>(Error error)
{
switch (error.Code)
{
case ErrorCode.NotFound:
return Result<T>.Failure("Resource not found. Please try again.");
case ErrorCode.ValidationError:
return Result<T>.Failure("Invalid data.");
default:
return Result<T>.Failure("An unexpected error occurred.");
}
}
}
var result = GetUser(1)
.Catch(CustomErrorHandler.HandleError);
Best Practices¶
1. Descriptive Error Messages¶
// Avoid
return Result<User>.Failure("Error");
// Prefer
return Result<User>.Failure(
ErrorCode.ValidationError,
"User name must be between 3 and 50 characters",
new Dictionary<string, object>
{
{ "Field", "Name" },
{ "MinLength", 3 },
{ "MaxLength", 50 }
}
);
2. Error Chaining¶
var result = GetUser(1)
.Catch(error => CustomErrorHandler.HandleError(error))
.Catch(error => FallbackErrorHandler.HandleError(error));
3. Error Tracking¶
public static Result<T> WithErrorTracking<T>(Func<Result<T>> operation)
{
try
{
return operation();
}
catch (Exception ex)
{
return Result<T>.Failure(
ErrorCode.Unknown,
"An unexpected error occurred",
new Dictionary<string, object>
{
{ "Exception", ex },
{ "StackTrace", ex.StackTrace }
}
);
}
}
Common Use Cases¶
1. API Responses¶
public async Task<IActionResult> GetUser(int id)
{
var result = await _userService.GetUser(id);
return result.Match(
user => Ok(user),
error => StatusCode(GetStatusCode(error.Code), error.Message)
);
}
2. Database Operations¶
public async Task<Result<User>> CreateUser(User user)
{
try
{
var createdUser = await _repository.CreateAsync(user);
return Result<User>.Success(createdUser);
}
catch (Exception ex)
{
return Result<User>.Failure(
ErrorCode.DatabaseError,
"Failed to create user",
new Dictionary<string, object> { { "Exception", ex } }
);
}
}
3. Validation¶
public Result<User> ValidateUser(User user)
{
var validationResult = ValidationResult.Create();
if (string.IsNullOrEmpty(user.Name))
{
validationResult.AddError("Name", "Name is required");
}
if (user.Age < 18)
{
validationResult.AddError("Age", "User must be at least 18 years old");
}
return validationResult.IsValid
? Result<User>.Success(user)
: Result<User>.Failure(validationResult);
}