Zentient.Results 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Zentient.Results --version 0.1.0
                    
NuGet\Install-Package Zentient.Results -Version 0.1.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="Zentient.Results" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zentient.Results" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Zentient.Results" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Zentient.Results --version 0.1.0
                    
#r "nuget: Zentient.Results, 0.1.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.
#:package Zentient.Results@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Zentient.Results&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Zentient.Results&version=0.1.0
                    
Install as a Cake Tool

Zentient.Results

NuGet Badge

A robust and flexible result object for .NET 9, providing a standardized way to represent the outcome of operations, whether successful or not. This library encourages explicit error handling and clear communication of operation status.

Overview

Zentient.Results introduces the IResult and IResult<T> interfaces, along with concrete Result and Result<T> structs. These structures allow you to encapsulate the outcome of a function or operation, including:

  • Success or Failure: Clearly indicates whether the operation succeeded.
  • Value (Generic Result): Holds the result of a successful operation.
  • Errors: A collection of detailed ErrorInfo objects for failures, including category, code, message, and optional data/inner errors.
  • Messages: A collection of informational messages for successful operations.
  • Status: An IResultStatus object providing a numerical code and description of the outcome (e.g., Success, BadRequest, NotFound).
  • Monadic Operations: Includes Map, Bind, and Tap for composable operations.
  • Implicit Conversions: Simplifies the creation of successful generic results.
  • JSON Serialization: Built-in System.Text.Json converters for seamless API integration.

Installation

You can install the Zentient.Results NuGet package using the .NET CLI:

dotnet add package Zentient.Results

Or using the NuGet Package Manager in Visual Studio.

Key Features

Clear Result Representation

The Result and Result<T> structs provide a clear and consistent way to represent operation outcomes, making your code more readable and maintainable.

public IResult<User> GetUserById(int id)
{
    var user = _dbContext.Users.Find(id);
    if (user is null)
    {
        return Result<User>.NotFound(new ErrorInfo(ErrorCategory.NotFound, "UserNotFound", $"User with ID '{id}' not found."));
    }
    return Result<User>.Success(user);
}

public IResult UpdateUserProfile(User user)
{
    if (string.IsNullOrWhiteSpace(user.Email))
    {
        return Result.Validation(new[] { new ErrorInfo(ErrorCategory.Validation, "InvalidEmail", "Email cannot be empty.") });
    }
    _dbContext.Users.Update(user);
    _dbContext.SaveChanges();
    return Result.Success("User profile updated successfully.");
}

Detailed Error Information

The ErrorInfo struct provides structured information about errors, making it easier to understand and handle failures.

if (result.IsFailure)
{
    foreach (var error in result.Errors)
    {
        Console.WriteLine($"Error Category: {error.Category}, Code: {error.Code}, Message: {error.Message}");
        if (error.Data != null)
        {
            Console.WriteLine($"  Data: {error.Data}");
        }
        if (error.InnerErrors.Any())
        {
            Console.WriteLine("  Inner Errors:");
            foreach (var innerError in error.InnerErrors)
            {
                Console.WriteLine($"    Code: {innerError.Code}, Message: {innerError.Message}");
            }
        }
    }
}

Predefined Result Statuses

The ResultStatuses static class offers a set of commonly used result statuses, promoting consistency across your application.

return Result.Failure(new ErrorInfo(ErrorCategory.Authorization, "InsufficientPermissions", "User does not have required permissions."), ResultStatuses.Forbidden);

Monadic Operations for Composition

Zentient.Results includes Map and Bind methods for Result<T>, enabling you to chain operations in a functional style while handling potential failures gracefully.

public IResult<string> GetUserName(int userId) =>
    GetUserById(userId)
        .Map(user => user.Name);

public IResult<OrderDetails> GetOrderDetails(int orderId) =>
    GetOrder(orderId)
        .Bind(order => _orderService.FetchDetails(order));

Seamless JSON Serialization

The library provides custom System.Text.Json converters (ResultJsonConverter) to ensure that Result and Result<T> objects are serialized correctly when used in ASP.NET Core APIs or other scenarios involving JSON serialization.

[HttpGet("{id}")]
public ActionResult<Result<User>> Get(int id)
{
    var result = _userService.GetUserById(id);
    return result.IsSuccess ? Ok(result) : NotFound(result);
}

Implicit Conversion

Creating successful generic results is simplified with implicit conversion from the value type T.

public IResult<int> GetCount()
{
    int count = _dataService.CountItems();
    return count; // Implicitly converted to Result<int>.Success(count)
}

Usage Examples

Returning a Successful Result with a Value

public IResult<Customer> GetCustomer(int id)
{
    var customer = _customerRepository.GetById(id);
    if (customer != null)
    {
        return Result<Customer>.Success(customer, "Customer retrieved successfully.");
    }
    return Result<Customer>.NotFound(new ErrorInfo(ErrorCategory.NotFound, "CustomerNotFound", $"Customer with ID '{id}' not found."));
}

Returning a Failure Result with Multiple Validation Errors

public IResult CreateOrder(OrderDto orderDto)
{
    var errors = new List<ErrorInfo>();
    if (orderDto.TotalAmount <= 0)
    {
        errors.Add(new ErrorInfo(ErrorCategory.Validation, "InvalidAmount", "Total amount must be greater than zero."));
    }
    if (string.IsNullOrWhiteSpace(orderDto.ShippingAddress))
    {
        errors.Add(new ErrorInfo(ErrorCategory.Validation, "MissingAddress", "Shipping address is required."));
    }

    if (errors.Any())
    {
        return Result.Validation(errors);
    }

    // Proceed with order creation
    var order = MapToOrder(orderDto);
    _orderRepository.Add(order);
    _orderRepository.SaveChanges();
    return Result.Success("Order created successfully.");
}

Using Monadic Operations

public IResult<string> GetCustomerEmail(int customerId) =>
    GetCustomer(customerId)
        .Bind(customer => _emailService.GetEmailForCustomer(customer.Id));

// Assume _emailService.GetEmailForCustomer returns IResult<string>

Contribution Guidelines

Contributions to Zentient.Results are welcome! Please ensure that your contributions:

  • Are compatible with .NET 9.
  • Include appropriate unit tests.
  • Follow the existing code style.
  • Clearly explain the purpose and benefits of your changes.

Feel free to submit pull requests or open issues for bug reports and feature requests.

License

Zentient.Results is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net9.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Zentient.Results:

Package Downloads
Zentient.Endpoints

Core abstractions and utilities for unifying result handling across transport protocols (HTTP, gRPC, Messaging) using Zentient.Results.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.4.4 233 7/1/2025
0.4.4-beta0001 93 6/29/2025
0.4.2 136 6/27/2025
0.4.1 158 6/23/2025
0.4.0 118 6/21/2025
0.3.0 153 6/7/2025
0.2.0 152 5/28/2025
0.1.0 155 5/22/2025