Pitasoft.Result 7.1.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package Pitasoft.Result --version 7.1.2
                    
NuGet\Install-Package Pitasoft.Result -Version 7.1.2
                    
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="Pitasoft.Result" Version="7.1.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pitasoft.Result" Version="7.1.2" />
                    
Directory.Packages.props
<PackageReference Include="Pitasoft.Result" />
                    
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 Pitasoft.Result --version 7.1.2
                    
#r "nuget: Pitasoft.Result, 7.1.2"
                    
#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 Pitasoft.Result@7.1.2
                    
#: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=Pitasoft.Result&version=7.1.2
                    
Install as a Cake Addin
#tool nuget:?package=Pitasoft.Result&version=7.1.2
                    
Install as a Cake Tool

Pitasoft.Result

Build Status NuGet NuGet Downloads License Target Framework

English | Castellano


English

Pitasoft.Result is a .NET library designed to standardize responses from REST services and internal application layers. It provides a robust set of classes to wrap data, status codes, and error collections, facilitating a unified communication contract between APIs, services, and clients.

Features

  • Standardized Responses: Unify your API outputs using Result, ResultEntity<T>, ResultEntities<T>, and ResultBatch<T>.
  • Fluent Error Handling: Easily add validation errors, exceptions, or business rule violations using a fluent interface.
  • Rich Status Management: Built-in StatusResult enum covering common API scenarios (Success, Not Found, Validation Errors, Database Errors, etc.).
  • Batch Operations: Specialized support for processing multiple items with ResultBatch<T>.
  • Pagination Support: ResultEntities<T> includes metadata like total count, and the library provides PagingParameters for request handling.
  • Async Support: MatchAsync and MapAsync for chaining async operations cleanly.
  • Implicit Conversions: Convert StatusResult or entities directly to result types with zero boilerplate.
  • Deconstruction: Use C# deconstruction to extract values and status easily: var (status, user) = result;.
  • Extensions: Useful helper methods to check for success, specific errors, or state.
  • Functional API: Match, Map, Tap, Bind, and Ensure for fluent result processing.
  • Combine Results: Aggregate multiple results into one with Result.Combine().
  • Performance: High-performance implementation with minimal allocations and AggressiveInlining.

Installation

dotnet add package Pitasoft.Result

Quick start

// 1) Simple result
Result r1 = Result.Ok();
Result r2 = Result.ValidationError().AddError("Email", "Invalid");

// 2) Entity
ResultEntity<User> u = Result.Ok(new User { Id = 1, Name = "John" });
var (status, user) = u; // deconstruction

// 3) Entities with count (paged)
var users = new List<User> { new() { Id = 1, Name = "John" } };
ResultEntities<User> list = Result.OkEntities(users, users.Count);
foreach (var it in list) { /* iterate directly */ }

// 4) Functional extensions
var dto = u.Map(x => new UserDto(x!.Id, x.Name));
var okOrThrow = u.Match(
    onSuccess: () => dto,
    onFailure: res => throw new InvalidOperationException(res.Status.ToString()));

// 5) Combine results
var combined = Result.Combine(Result.Ok(), Result.Error().AddError("E", "err"));

Core Components

1. Simple Result (Result)

Used for operations that don't return data, only a completion status and optional errors.

public Result DeleteUser(int id)
{
    if (id <= 0)
        return Result.ValidationError().AddError("id", "Invalid ID");

    var deleted = _repository.Delete(id);
    if (!deleted) return Result.NotExists();

    return Result.Deleted();
}

// Deconstruction
var (status, errors) = DeleteUser(1);
if (status == StatusResult.Deleted) { /* ... */ }
2. Result with Entity (ResultEntity<T>)

Used for operations returning a single object.

public ResultEntity<User> GetUser(int id)
{
    var user = _repository.Find(id);
    if (user == null) return ResultEntity<User>.NotExists();

    return ResultEntity<User>.Ok(user);
}

Implicit conversions and fluent API:

public ResultEntity<User> GetUser(int id)
{
    var user = _repository.Find(id);
    // T implicitly converts to ResultEntity<T>.Ok(entity)
    return user ?? (ResultEntity<User>)StatusResult.NoExist;
}

// Deconstruction
var (status, user) = GetUser(1);
if (status == StatusResult.Ok) { /* ... */ }

// Fluent API
var result = ResultEntity<User>.Ok(user)
    .WithCode(200)
    .AddError("System", "Service throttled");
3. Result with Multiple Entities (ResultEntities<T>)

Used for lists or paged results. It includes an optional Count property for total records. Direct iteration is supported via foreach as it implements IEnumerable<T>.

public ResultEntities<User> GetUsers(PagingParameters paging)
{
    var (users, total) = _repository.GetAll(paging);
    var result = ResultEntities<User>.Ok(users, total);

    // Direct iteration is supported
    foreach (var user in result)
    {
        // ...
    }

    return result;
}
4. Batch Result (ResultBatch<T>)

Used for processing multiple items in a single request, providing a global status and individual results for each item.

public ResultBatch<User> ImportUsers(List<User> users)
{
    var results = users.Select(u => (ResultEntity<User>)Process(u)).ToList();
    return ResultBatch<User>.Ok(results);
}

Error Handling

The library supports a fluent API for adding errors, which are stored in an ErrorCollection:

return Result.ValidationError()
    .AddError("Email", "Invalid format")
    .AddError("Password", "Too short")
    .AddError(new Exception("Inner system error"));

Associate a numeric code with any result using WithCode():

return Result.Error().WithCode(4001);

Status Codes (StatusResult)

Status Category Description
Ok, Added, Updated, Deleted Success Successful operations.
NoExist Informational Requested resource was not found.
Warning Informational Completed with non-critical issues.
CancelOperation Control Operation was cancelled.
ValidationError Error Client-side input validation failed.
DataError, DatabaseError Error Issues with data processing or persistence.
ConcurrencyError Error Data was modified by another process.
ConnectionError Error Connection to an external service failed.
HttpError Error An external HTTP call returned an error.
Unauthorized Security Authentication or authorization failed.
ChangePassword Security User must change their password.
Exception Error An unhandled exception occurred.

Extensions

Import Pitasoft.Result.Extensions to use these helper methods on any IResult:

  • result.IsSuccess(): Returns true if status is Ok, Added, Updated, or Deleted.
  • result.IsError(): Returns true for most error-related statuses.
  • result.IsFailure(): Returns true for any non-successful state, excluding None, NoExist, and Warning. Covers Unauthorized, Exception, CancelOperation, and more.
  • result.IsNotExist(): Returns true if the resource was not found.
  • result.HasErrors(): Returns true if there are any errors in the Errors collection.
  • result.IsSuccessOrNotExist(): Useful for "Delete" operations where both cases are often handled similarly.

Functional API (Match and Map)

Import Pitasoft.Result.Extensions to use functional-style transformations:

Match — branch on success or failure
var dto = result.Match(
    onSuccess: () => mapper.ToDto(result.Entity),
    onFailure: r => throw new InvalidOperationException(r.Status.ToString())
);
Map — transform the entity if successful
ResultEntity<UserDto> dto = userResult.Map(user => mapper.ToDto(user));
Tap — execute an action without changing the result
result.Tap(() => _logger.LogInformation("Operation successful"))
      .Tap(user => _cache.Set(user));
Bind — chain operations that return results (FlatMap)
ResultEntity<Order> result = GetUser(id)
    .Bind(user => CreateOrder(user));
Ensure — validate a condition on the entity
ResultEntity<User> result = GetUser(id)
    .Ensure(u => u.Age >= 18, "User must be an adult", "Age");
MapAsync — chain async operations
var result = await GetUserAsync(id)
    .MapAsync(user => EnrichWithRolesAsync(user));

Pagination Parameters

Use PagingParameters to receive pagination input in your API endpoints:

public ResultEntities<User> GetUsers(PagingParameters paging)
{
    // Index must be >= 0; Size must be > 0 (validated automatically)
    var (users, total) = _repository.GetAll(paging);
    return ResultEntities<User>.Ok(users, total);
}

Batch Helper (Batch<T>)

Use Batch<T> to describe a set of entities and the action to perform on them:

var batch = Batch<User>.Append(newUsers);
var batch = Batch<User>.Update(modifiedUsers);
var batch = Batch<User>.Delete(removedUsers);

Performance

Performance tips
  • Prefer using the provided static factories (e.g., Result.Ok(), Result.Added()). They are very small and are annotated with AggressiveInlining to minimize overhead.
  • ResultEntities<T> supports direct iteration via foreach. Internally, its enumerator delegates to the underlying Entities collection without using yield, avoiding extra state-machine allocations.
  • When creating error results from exceptions, pass deep: false unless you explicitly need inner exception details. This reduces allocations in the ErrorCollection.
  • For JSON payload size, consider ignoring nulls at the application level (e.g., JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull). This reduces I/O without affecting CPU hot paths.

Benchmark results for core operations (Mean time / Allocated memory):

The library is optimized to minimize allocations and maximize throughput. Benchmark results for core operations (Mean time / Allocated memory):

Operation .NET 8 .NET 9 .NET 10
Result.Ok 17.0 ns / 64 B 17.1 ns / 64 B 17.5 ns / 64 B
ResultEntity.Ok 17.7 ns / 72 B 17.1 ns / 72 B 18.3 ns / 72 B
ResultEntities.Ok 17.2 ns / 80 B 17.3 ns / 80 B 17.7 ns / 80 B
Error (with Exception) 43.2 ns / 408 B 48.3 ns / 408 B 37.9 ns / 408 B

Note: Benchmarks performed on Apple M-series (Arm64).


Castellano

Pitasoft.Result es una librería .NET diseñada para estandarizar las respuestas de los servicios REST y las capas internas de la aplicación. Proporciona un conjunto robusto de clases para envolver datos, códigos de estado y colecciones de errores, facilitando un contrato de comunicación unificado entre APIs, servicios y clientes.

Características

  • Respuestas Estandarizadas: Unifica las salidas de tu API usando Result, ResultEntity<T>, ResultEntities<T> y ResultBatch<T>.
  • Gestión de Errores Fluida: Añade fácilmente errores de validación, excepciones o violaciones de reglas de negocio mediante una interfaz fluida.
  • Gestión de Estados Enriquecida: Enumerado StatusResult integrado que cubre escenarios comunes (Éxito, No Encontrado, Errores de Validación, Errores de Base de Datos, etc.).
  • Operaciones por Lote: Soporte especializado para procesar múltiples elementos con ResultBatch<T>.
  • Soporte para Paginación: ResultEntities<T> incluye metadatos como el conteo total, y la librería proporciona PagingParameters para el manejo de peticiones.
  • API Funcional: Métodos de extensión Match y Map para transformar resultados sin bloques if/switch.
  • Soporte Async: MatchAsync y MapAsync para encadenar operaciones asíncronas de forma limpia.
  • Conversiones Implícitas: Convierte StatusResult o entidades directamente a tipos de resultado sin código repetitivo.
  • Deconstrucción: Usa la deconstrucción de C# para extraer valores y estado fácilmente: var (status, user) = result;.
  • Extensiones: Métodos de ayuda útiles para comprobar éxito, errores específicos o estado.
  • API Funcional: Match, Map, Tap, Bind y Ensure para el procesamiento fluido de resultados.
  • Combinar Resultados: Agrega múltiples resultados en uno solo con Result.Combine().
  • Rendimiento: Implementación de alto rendimiento con mínimas asignaciones y AggressiveInlining.

Instalación

dotnet add package Pitasoft.Result

Inicio rápido

// 1) Resultado simple
Result r1 = Result.Ok();
Result r2 = Result.ValidationError().AddError("Email", "No válido");

// 2) Entidad
ResultEntity<User> u = Result.Ok(new User { Id = 1, Name = "John" });
var (status, user) = u; // deconstrucción

// 3) Colección con total (paginado)
var users = new List<User> { new() { Id = 1, Name = "John" } };
ResultEntities<User> list = Result.OkEntities(users, users.Count);
foreach (var it in list) { /* iteración directa */ }

// 4) Extensiones funcionales
var dto = u.Map(x => new UserDto(x!.Id, x.Name));
var okOTira = u.Match(
    onSuccess: () => dto,
    onFailure: res => throw new InvalidOperationException(res.Status.ToString()));

// 5) Combinar resultados
var combinado = Result.Combine(Result.Ok(), Result.Error().AddError("E", "err"));

Componentes Principales

1. Resultado Simple (Result)

Utilizado para operaciones que no devuelven datos, solo un estado de finalización y errores opcionales.

public Result DeleteUser(int id)
{
    if (id <= 0)
        return Result.ValidationError().AddError("id", "ID no válido");

    var deleted = _repository.Delete(id);
    if (!deleted) return Result.NotExists();

    return Result.Deleted();
}

// Deconstrucción
var (status, errors) = DeleteUser(1);
if (status == StatusResult.Deleted) { /* ... */ }
2. Resultado con Entidad (ResultEntity<T>)

Utilizado para operaciones que devuelven un único objeto.

public ResultEntity<User> GetUser(int id)
{
    var user = _repository.Find(id);
    if (user == null) return ResultEntity<User>.NotExists();

    return ResultEntity<User>.Ok(user);
}

Conversiones implícitas y API fluida:

public ResultEntity<User> GetUser(int id)
{
    var user = _repository.Find(id);
    // T se convierte implícitamente a ResultEntity<T>.Ok(entity)
    return user ?? (ResultEntity<User>)StatusResult.NoExist;
}

// Deconstrucción
var (status, user) = GetUser(1);
if (status == StatusResult.Ok) { /* ... */ }

// API Fluida
var result = ResultEntity<User>.Ok(user)
    .WithCode(200)
    .AddError("System", "Servicio saturado");
3. Resultado con Múltiples Entidades (ResultEntities<T>)

Utilizado para listas o resultados paginados. Incluye una propiedad opcional Count para el total de registros. Se puede iterar directamente sobre el objeto mediante foreach, ya que implementa IEnumerable<T>.

public ResultEntities<User> GetUsers(PagingParameters paging)
{
    var (users, total) = _repository.GetAll(paging);
    var result = ResultEntities<User>.Ok(users, total);

    // Se puede iterar directamente
    foreach (var user in result)
    {
        // ...
    }

    return result;
}
4. Resultado por Lote (ResultBatch<T>)

Utilizado para procesar múltiples elementos en una sola petición, proporcionando un estado global y resultados individuales para cada elemento.

public ResultBatch<User> ImportUsers(List<User> users)
{
    var results = users.Select(u => (ResultEntity<User>)Process(u)).ToList();
    return ResultBatch<User>.Ok(results);
}

Gestión de Errores

La librería soporta una API fluida para añadir errores, que se almacenan en una ErrorCollection:

return Result.ValidationError()
    .AddError("Email", "Formato no válido")
    .AddError("Password", "Demasiado corta")
    .AddError(new Exception("Error interno del sistema"));

Asocia un código numérico a cualquier resultado con WithCode():

return Result.Error().WithCode(4001);

Códigos de Estado (StatusResult)

Estado Categoría Descripción
Ok, Added, Updated, Deleted Éxito Operaciones exitosas.
NoExist Informativo El recurso solicitado no fue encontrado.
Warning Informativo Completado con problemas no críticos.
CancelOperation Control La operación fue cancelada.
ValidationError Error Falló la validación de entrada del cliente.
DataError, DatabaseError Error Problemas en el procesamiento o persistencia de datos.
ConcurrencyError Error Los datos fueron modificados por otro proceso.
ConnectionError Error Falló la conexión a un servicio externo.
HttpError Error Una llamada HTTP externa devolvió un error.
Unauthorized Seguridad Falló la autenticación o autorización.
ChangePassword Seguridad El usuario debe cambiar su contraseña.
Exception Error Ocurrió una excepción no controlada.

Extensiones

Importa Pitasoft.Result.Extensions para usar estos métodos de ayuda en cualquier IResult:

  • result.IsSuccess(): Devuelve true si el estado es Ok, Added, Updated o Deleted.
  • result.IsError(): Devuelve true para la mayoría de los estados relacionados con errores.
  • result.IsFailure(): Devuelve true para cualquier estado no exitoso, excluyendo None, NoExist y Warning. Cubre Unauthorized, Exception, CancelOperation y más.
  • result.IsNotExist(): Devuelve true si el recurso no fue encontrado.
  • result.HasErrors(): Devuelve true si hay algún error en la colección Errors.
  • result.IsSuccessOrNotExist(): Útil para operaciones "Delete" donde ambos casos suelen manejarse de forma similar.

API Funcional (Match y Map)

Importa Pitasoft.Result.Extensions para usar transformaciones de estilo funcional:

Match — bifurcar según éxito o error
var dto = result.Match(
    onSuccess: () => mapper.ToDto(result.Entity),
    onFailure: r => throw new InvalidOperationException(r.Status.ToString())
);
Map — transformar la entidad si el resultado es exitoso
ResultEntity<UserDto> dto = userResult.Map(user => mapper.ToDto(user));
Tap — ejecutar una acción sin cambiar el resultado
result.Tap(() => _logger.LogInformation("Operación exitosa"))
      .Tap(user => _cache.Set(user));
Bind — encadenar operaciones que devuelven resultados (FlatMap)
ResultEntity<Order> result = GetUser(id)
    .Bind(user => CreateOrder(user));
Ensure — validar una condición sobre la entidad
ResultEntity<User> result = GetUser(id)
    .Ensure(u => u.Age >= 18, "El usuario debe ser mayor de edad", "Edad");
MapAsync — encadenar operaciones asíncronas
var result = await GetUserAsync(id)
    .MapAsync(user => EnrichWithRolesAsync(user));

Parámetros de Paginación

Usa PagingParameters para recibir la entrada de paginación en tus endpoints:

public ResultEntities<User> GetUsers(PagingParameters paging)
{
    // Index debe ser >= 0; Size debe ser > 0 (validado automáticamente)
    var (users, total) = _repository.GetAll(paging);
    return ResultEntities<User>.Ok(users, total);
}

Helper de Lote (Batch<T>)

Usa Batch<T> para describir un conjunto de entidades y la acción a realizar sobre ellas:

var batch = Batch<User>.Append(newUsers);
var batch = Batch<User>.Update(modifiedUsers);
var batch = Batch<User>.Delete(removedUsers);

Rendimiento

Consejos de rendimiento
  • Prefiere las factorías estáticas provistas (por ejemplo, Result.Ok(), Result.Added()). Son muy pequeñas y están anotadas con AggressiveInlining para minimizar el overhead.
  • ResultEntities<T> permite la iteración directa con foreach. Internamente, su enumerador delega en la colección Entities sin usar yield, evitando asignaciones de la máquina de estados.
  • Al crear resultados de error desde excepciones, usa deep: false salvo que necesites explícitamente el detalle de inner exceptions. Esto reduce asignaciones en ErrorCollection.
  • Para reducir el tamaño de los JSON, valora ignorar nulos a nivel de aplicación (por ejemplo, JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull). Esto reduce E/S sin afectar a rutas críticas de CPU.

Resultados de benchmarks para operaciones principales (Tiempo medio / Memoria asignada):

La librería está optimizada para minimizar asignaciones y maximizar el rendimiento. Resultados de benchmarks para operaciones principales (Tiempo medio / Memoria asignada):

Operación .NET 8 .NET 9 .NET 10
Result.Ok 17.0 ns / 64 B 17.1 ns / 64 B 17.5 ns / 64 B
ResultEntity.Ok 17.7 ns / 72 B 17.1 ns / 72 B 18.3 ns / 72 B
ResultEntities.Ok 17.2 ns / 80 B 17.3 ns / 80 B 17.7 ns / 80 B
Error (con Excepción) 43.2 ns / 408 B 48.3 ns / 408 B 37.9 ns / 408 B

Nota: Benchmarks realizados en Apple M-series (Arm64).


Autor

Sebastián Martínez Pérez

License

Copyright © 2019-2026 Pitasoft, S.L. Licensed under the LICENSE.txt provided in this repository.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  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 is compatible.  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.

NuGet packages (9)

Showing the top 5 NuGet packages that depend on Pitasoft.Result:

Package Downloads
Pitasoft.Client

.NET library designed to simplify the consumption of RESTful services. It provides a robust base class and helpers to handle HTTP requests, JSON serialization, and common API patterns.

Pitasoft.Web

Librerias basicas de aplicaciones web

Pitasoft.Blazor.Result

Application of the functionalities of the Pitasoft.Blazor package, adding functionalities of Pitasoft.Result.

Pitasoft.Mail

E-Mail server service.

Pitasoft.Result.AspNetCore

ASP.NET Core integration for Pitasoft.Result. Provides HTTP result mapping, JSON helpers, DI-based configuration, and exception handling for MVC and Minimal APIs.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
7.4.1 159 4/19/2026
7.3.2 220 4/3/2026
7.3.1 359 3/26/2026
7.2.9 162 3/24/2026
7.2.8 140 3/23/2026
7.2.7 142 3/22/2026
7.2.6 172 3/20/2026
7.2.5 144 3/20/2026
7.2.4 208 3/13/2026
7.2.3 145 3/11/2026
7.2.2 166 3/10/2026
7.2.1 157 3/9/2026
7.1.4 196 3/2/2026
7.1.3 184 2/24/2026
7.1.2 150 2/24/2026
7.1.1 191 2/23/2026
7.0.2 176 2/12/2026
7.0.1 203 1/26/2026
6.5.7 393 5/27/2025
6.5.6 361 5/27/2025
Loading failed