OperationResultTools 1.0.39
dotnet add package OperationResultTools --version 1.0.39
NuGet\Install-Package OperationResultTools -Version 1.0.39
<PackageReference Include="OperationResultTools" Version="1.0.39" />
<PackageVersion Include="OperationResultTools" Version="1.0.39" />
<PackageReference Include="OperationResultTools" />
paket add OperationResultTools --version 1.0.39
#r "nuget: OperationResultTools, 1.0.39"
#:package OperationResultTools@1.0.39
#addin nuget:?package=OperationResultTools&version=1.0.39
#tool nuget:?package=OperationResultTools&version=1.0.39
OperationResults
A set of lightweight libraries to totally decouple operation results and actual application responses.
Core library
Installation
The library is available on NuGet. Just search for OperationResultTools in the Package Manager GUI or run the following command in the .NET CLI:
dotnet add package OperationResultTools
Usage example
The core library can be used in your business layer to return successful or failed results without referencing ASP.NET Core types.
public class PeopleService(ApplicationDbContext dbContext, IImageService imageService) : IPeopleService
{
public async Task<Result<Person>> GetAsync(Guid id)
{
var dbPerson = await dbContext.People.AsNoTracking().FirstOrDefaultAsync(p => p.Id == id);
if (dbPerson is null)
{
return Result.Fail(FailureReasons.ItemNotFound);
}
var person = new Person
{
Id = dbPerson.Id,
FirstName = dbPerson.FirstName,
LastName = dbPerson.LastName,
Email = dbPerson.Email,
City = dbPerson.City
};
return person;
}
public async Task<Result<Person>> SaveAsync(Person person)
{
var samePersonExists = await dbContext.People
.AnyAsync(p => p.FirstName == person.FirstName && p.LastName == person.LastName
&& p.CreateDate.AddMinutes(1) > DateTime.UtcNow);
if (samePersonExists)
{
var validationErrors = new List<ValidationError>
{
new("FirstName", "First name already in use"),
new("LastName", "Last name already in use")
};
return Result.Fail(
FailureReasons.ClientError,
"Unable to create a person with same first name and last name within 1 minute",
validationErrors);
}
return person;
}
}
The same pattern also works for file results or other payloads:
public class ImageService : IImageService
{
public async Task<Result<ByteArrayFileContent>> GetImageAsync()
{
if (!File.Exists(@"D:\Taggia.jpg"))
{
return Result.Fail(FailureReasons.ItemNotFound);
}
var content = await File.ReadAllBytesAsync(@"D:\Taggia.jpg");
return new ByteArrayFileContent(content, "image/jpg");
}
}
ASP.NET Core integration library (Controller-based projects)
Note: This is the library to use if you're working with Controller.
This library provides HttpContext extension methods to automatically map Operation Results (that may come, for sample, from a business layer) to HTTP responses, along with the appropriate status codes.
A full sample is available in the Sample folder. Search for the registration in the Program.cs file and the usage in Controllers folder.
Installation
The library is available on NuGet. Just search for OperationResultTools.AspNetCore in the Package Manager GUI or run the following command in the .NET CLI:
dotnet add package OperationResultTools.AspNetCore
Usage example
Once the package is registered, your controllers can delegate the HTTP response generation to HttpContext.CreateResponse.
[ApiController]
[Route("api/[controller]")]
[Produces(MediaTypeNames.Application.Json)]
public class PeopleController(IPeopleService peopleService) : ControllerBase
{
[HttpGet("{id:guid}", Name = nameof(GetPerson))]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Person))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetPerson(Guid id)
{
var result = await peopleService.GetAsync(id);
return HttpContext.CreateResponse(result);
}
[HttpPost]
[ProducesResponseType<Person>(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Save(Person person)
{
var result = await peopleService.SaveAsync(person);
return HttpContext.CreateResponse(result, nameof(GetPerson), new { id = result.Content?.Id });
}
[HttpDelete("{id:guid}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(Guid id)
{
var result = await peopleService.DeleteAsync(id);
return HttpContext.CreateResponse(result);
}
}
This approach also works for binary responses:
[ApiController]
[Route("api/[controller]")]
public class ImageController(IImageService imageService) : ControllerBase
{
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetImage()
=> HttpContext.CreateResponse(await imageService.GetImageAsync());
}
ASP.NET Core integration library (Minimal API projects)
Note: This is the library to use if you're working with Minimal APIs.
This library provides HttpContext extension methods to automatically map Operation Results (that may come, for sample, from a business layer) to HTTP responses, along with the appropriate status codes.
A full sample is available in the Samples folder. Search for the registration and the usage in Program.cs file.
Installation
The library is available on NuGet. Just search for OperationResultTools.AspNetCore.Http in the Package Manager GUI or run the following command in the .NET CLI:
dotnet add package OperationResultTools.AspNetCore.Http
Usage example
Register the library in your Minimal API application and customize the mapping between operation failures and HTTP status codes:
builder.Services.AddOperationResult(options =>
{
options.ErrorResponseFormat = ErrorResponseFormat.Default;
options.StatusCodesMapping.Add(CustomFailureReasons.NotAvailable, StatusCodes.Status501NotImplemented);
// If you want to use failure reasons directly as HTTP status codes:
// options.MapStatusCodes = false;
});
Then convert results returned by your services into HTTP responses inside your endpoints:
var peopleApi = app.MapGroup("api/people");
peopleApi.MapGet("/", async (IPeopleService peopleService, HttpContext httpContext) =>
{
var result = await peopleService.GetAsync();
return httpContext.CreateResponse(result);
})
.Produces<IEnumerable<Person>>();
peopleApi.MapGet("{id:guid}", async (Guid id, IPeopleService peopleService, HttpContext httpContext) =>
{
var result = await peopleService.GetAsync(id);
return httpContext.CreateResponse(result);
})
.Produces<Person>()
.Produces(StatusCodes.Status404NotFound)
.WithName("GetPerson");
peopleApi.MapPost("/", async (Person person, IPeopleService peopleService, HttpContext httpContext) =>
{
var result = await peopleService.SaveAsync(person);
return httpContext.CreateResponse(result, "GetPerson", new { id = result.Content?.Id });
})
.Produces<Person>(StatusCodes.Status201Created)
.ProducesProblem(StatusCodes.Status400BadRequest, MediaTypeNames.Application.Json);
The same mechanism can also return files:
app.MapGet("api/image", async (IImageService imageService, HttpContext httpContext)
=> httpContext.CreateResponse(await imageService.GetImageAsync())
)
.Produces<FileContentResult>(StatusCodes.Status200OK, contentType: MediaTypeNames.Application.Octet)
.Produces(StatusCodes.Status404NotFound);
In this way, the business layer remains completely decoupled from ASP.NET Core, while the web layer consistently translates Result and Result<T> instances into HTTP responses.
Contribute
The project is constantly evolving. Contributions are welcome. Feel free to file issues and pull requests on the repo and we'll address them as we can.
| Product | Versions 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. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on OperationResultTools:
| Package | Downloads |
|---|---|
|
OperationResultTools.AspNetCore
A lightweight library to totally decouple operation results and responses in ASP.NET Controller-based projects. |
|
|
OperationResultTools.AspNetCore.Http
A lightweight library to totally decouple operation results and responses in Minimal API projects. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.39 | 41 | 6/18/2026 |
| 1.0.37 | 634 | 3/11/2026 |
| 1.0.33 | 624 | 11/12/2025 |
| 1.0.32 | 645 | 9/18/2025 |
| 1.0.30 | 1,812 | 1/15/2025 |
| 1.0.29 | 714 | 10/21/2024 |
| 1.0.26 | 996 | 6/17/2024 |
| 1.0.25 | 1,646 | 2/23/2024 |
| 1.0.15 | 1,012 | 12/13/2023 |
| 1.0.12 | 5,016 | 12/2/2022 |
| 1.0.9 | 1,104 | 11/9/2022 |
| 1.0.8 | 862 | 10/4/2022 |
| 1.0.3 | 991 | 9/17/2022 |