YellowCucumber.ErrorHandling.CodeFixes
1.0.0
dotnet add package YellowCucumber.ErrorHandling.CodeFixes --version 1.0.0
NuGet\Install-Package YellowCucumber.ErrorHandling.CodeFixes -Version 1.0.0
<PackageReference Include="YellowCucumber.ErrorHandling.CodeFixes" Version="1.0.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="YellowCucumber.ErrorHandling.CodeFixes" Version="1.0.0" />
<PackageReference Include="YellowCucumber.ErrorHandling.CodeFixes"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add YellowCucumber.ErrorHandling.CodeFixes --version 1.0.0
#r "nuget: YellowCucumber.ErrorHandling.CodeFixes, 1.0.0"
#:package YellowCucumber.ErrorHandling.CodeFixes@1.0.0
#addin nuget:?package=YellowCucumber.ErrorHandling.CodeFixes&version=1.0.0
#tool nuget:?package=YellowCucumber.ErrorHandling.CodeFixes&version=1.0.0
YellowCucumber.ErrorHandling
A modern .NET library for handling operation results and execution statuses in a type-safe manner. This library provides a comprehensive result pattern implementation that eliminates exceptions in business logic and promotes clear error handling patterns.
Features
- Type-safe Result Pattern: Strongly-typed result handling with clear success/failure semantics
- Execution Status System: Extensible status types using modern C# features (records, CRTP pattern)
- Message Propagation: Detailed error messages and context information
- Pattern Matching: Fluent API for handling different result states
- Async Support: Full async/await integration
- Roslyn Analyzers: Compile-time safety checks for proper usage patterns
- .NET 9 Ready: Built with the latest .NET features and performance optimizations
Quick Start
Installation
dotnet add package YellowCucumber.ErrorHandling
Basic Usage
using Results.Core;
// Simple result without a value
Result result = Result.Success();
Result failedResult = Result.Failure();
// Result with a value
Result<string> dataResult = Result<string>.Success("Hello, World!");
Result<int> errorResult = Result<int>.Failure();
// Check the status
if (result.Status is Success)
{
Console.WriteLine("Operation succeeded!");
}
// Get value safely
string value = dataResult.TryGetValue("default");
Detailed Results with Messages
using Results.Core;
// Create detailed results with contextual messages
DetailedResult<User> userResult = await ValidateUserAsync(userData);
if (userResult.Status is Failure)
{
Console.WriteLine($"Validation failed: {userResult.Message.Message}");
if (userResult.Message.Exception != null)
{
// Handle the underlying exception
logger.LogError(userResult.Message.Exception, "User validation error");
}
}
else
{
User user = userResult.TryGetValue(null);
// Process the valid user
}
Pattern Matching
string result = userResult.Match<string>(builder => builder
.When<Success>(value => $"User created: {value.Name}")
.When<Warning>(value => $"User created with warnings: {value.Name}")
.When<Failure>(() => "User creation failed")
.Otherwise(() => "Unknown status"));
// Async pattern matching
await userResult.MatchAsync(builder => builder
.When<Success>(async user => await SendWelcomeEmailAsync(user))
.When<Failure>(async () => await LogFailureAsync())
.Otherwise(async () => await HandleUnknownStatusAsync()));
Custom Status Types
// Define custom execution statuses
public record PendingStatus : ExecutionStatus<PendingStatus>
{
public PendingStatus() : base("Pending") { }
}
public record ProcessingStatus : ExecutionStatus<ProcessingStatus>
{
public ProcessingStatus() : base("Processing") { }
}
// Use them in results
Result<string> pendingResult = Result<string>.Create<PendingStatus>("Queued for processing");
Custom Messages
public record ValidationMessage : ExecutionMessage<ValidationMessage>
{
public ValidationMessage(string field, string issue)
: base($"Validation error in {field}: {issue}") { }
public ValidationMessage(string field, string issue, Exception exception)
: base($"Validation error in {field}: {issue}", exception) { }
}
// Use with DetailedResult
DetailedResult<User> result = DetailedResult<User>.Failure<ValidationMessage>();
Chaining Operations
public class UserService
{
public DetailedResult<User> CreateUser(CreateUserRequest request)
{
var validationResult = ValidateRequest(request);
if (validationResult.Status is Failure)
{
return DetailedResult<User>.Failure(validationResult.Message);
}
var user = new User { Name = request.Name, Email = request.Email };
var saveResult = SaveUser(user);
return saveResult.Status switch
{
Success => DetailedResult<User>.Create<Success>(user, saveResult.Message),
_ => DetailedResult<User>.Failure(saveResult.Message)
};
}
private DetailedResult ValidateRequest(CreateUserRequest request)
{
if (string.IsNullOrEmpty(request.Name))
{
var message = new ValidationMessage("Name", "Name is required");
return DetailedResult.Failure(message);
}
return DetailedResult.Create<Success, SuccessMessage>();
}
}
API Reference
Core Types
Result<T>: Result with a value and execution statusResult: Result without a value (payload-less operations)DetailedResult<T>: Result with value, status, and detailed messageDetailedResult: Payload-less result with detailed message
Status Types
Success: Operation completed successfullyWarning: Operation completed with warningsFailure: Operation failedExecutionStatus<TSelf>: Base class for custom statuses
Message Types
IExecutionMessage: Interface for execution messagesExecutionMessage<TSelf>: Base class for custom messages
Pattern Matching
MatchBuilder<TResult>: Synchronous pattern matching with return valueMatchBuilder: Synchronous pattern matching without return valueAsyncMatchBuilder<TResult>: Asynchronous pattern matching with return valueAsyncMatchBuilder: Asynchronous pattern matching without return value
Best Practices
1. Use Appropriate Result Types
// For operations that return data
Result<User> GetUser(int id);
// For operations that don't return data
Result DeleteUser(int id);
// When you need detailed error information
DetailedResult<User> ValidateAndCreateUser(CreateUserRequest request);
2. Handle All Status Cases
// Use pattern matching to handle all cases
var message = result.Match<string>(builder => builder
.When<Success>(user => $"Welcome, {user.Name}!")
.When<Warning>(user => $"Welcome, {user.Name}! Please verify your email.")
.When<Failure>(() => "Registration failed. Please try again.")
.Otherwise(() => "Unknown status"));
3. Create Domain-Specific Statuses
public record ValidationFailure : ExecutionStatus<ValidationFailure>
{
public ValidationFailure() : base("ValidationFailure") { }
}
public record NetworkTimeout : ExecutionStatus<NetworkTimeout>
{
public NetworkTimeout() : base("NetworkTimeout") { }
}
4. Use Custom Messages for Context
public record DatabaseErrorMessage : ExecutionMessage<DatabaseErrorMessage>
{
public DatabaseErrorMessage(string operation, Exception exception)
: base($"Database operation '{operation}' failed", exception) { }
}
Error Handling Without Exceptions
This library promotes handling errors as data rather than exceptional control flow:
// Instead of this:
public User GetUser(int id)
{
if (id <= 0)
throw new ArgumentException("Invalid user ID");
var user = database.GetUser(id);
if (user == null)
throw new UserNotFoundException($"User {id} not found");
return user;
}
// Use this:
public DetailedResult<User> GetUser(int id)
{
if (id <= 0)
{
var message = new ValidationMessage("id", "User ID must be positive");
return DetailedResult<User>.Failure(message);
}
var user = database.GetUser(id);
if (user == null)
{
var message = new NotFoundMessage($"User {id} not found");
return DetailedResult<User>.Failure(message);
}
var successMessage = new SuccessMessage($"User {id} retrieved successfully");
return DetailedResult<User>.Create<Success>(user, successMessage);
}
Async Support
Full support for async operations:
public async Task<DetailedResult<User>> CreateUserAsync(CreateUserRequest request)
{
var validationResult = await ValidateUserAsync(request);
if (validationResult.Status is Failure)
{
return DetailedResult<User>.Failure(validationResult.Message);
}
var user = new User(request.Name, request.Email);
var saveResult = await SaveUserAsync(user);
return saveResult.Match(builder => builder
.When<Success>(() => DetailedResult<User>.Create<Success>(user, saveResult.Message))
.Otherwise(() => DetailedResult<User>.Failure(saveResult.Message)));
}
Roslyn Analyzers
The library includes Roslyn analyzers to enforce proper usage patterns at compile time:
- RequireOtherwiseAnalyzer: Ensures that pattern matching operations include an
Otherwiseclause for completeness
Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
Version 1.0.0
- Initial release
- Core Result and DetailedResult types
- Pattern matching support
- Async/await integration
- Roslyn analyzers
- .NET 9 support
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp.Workspaces (>= 3.3.1)
- YellowCucumber.ErrorHandling.Analyzers (>= 1.0.0)
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 |
|---|---|---|
| 1.0.0 | 429 | 11/6/2025 |
Initial release with code fixes for pattern matching operations.