WebApi.ServiceResult
1.0.1
dotnet add package WebApi.ServiceResult --version 1.0.1
NuGet\Install-Package WebApi.ServiceResult -Version 1.0.1
<PackageReference Include="WebApi.ServiceResult" Version="1.0.1" />
<PackageVersion Include="WebApi.ServiceResult" Version="1.0.1" />
<PackageReference Include="WebApi.ServiceResult" />
paket add WebApi.ServiceResult --version 1.0.1
#r "nuget: WebApi.ServiceResult, 1.0.1"
#:package WebApi.ServiceResult@1.0.1
#addin nuget:?package=WebApi.ServiceResult&version=1.0.1
#tool nuget:?package=WebApi.ServiceResult&version=1.0.1
WebApi.ServiceResult
A lightweight and flexible library for standardizing API responses between the Service and Controller layers in ASP.NET Core applications using the Result pattern. It enables consistent, type-safe HTTP responses with built-in support for common status codes and customizable response contexts.
Features
- 🎯 Type-safe generic Result pattern
- 📦 Built-in HTTP status codes for common scenarios
- 🔄 Easy conversion to ASP.NET Core IActionResult
- 🎨 Flexible response formatting with Context and Data properties
- ✨ Clean API with static factory methods
- 🚀 Targets .NET 10 with C# 14.0
Installation
dotnet add package WebApi.ServiceResult
Quick Start
Success Responses
// 200 OK - Return data with optional message
Result<User>.Ok(user);
Result<User>.Ok(user, "User retrieved successfully");
// 201 Created - For resource creation
Result<Product>.Created(newProduct, "Product created");
// 202 Accepted - For async operations
Result<string>.Accepted("Request accepted for processing");
// 204 No Content - For successful operations with no data
Result<object>.NoContent();
Client Error Responses
// 400 Bad Request
Result<User>.BadRequest("Invalid user data provided");
// 401 Unauthorized
Result<User>.Unauthorized("Authentication required");
// 403 Forbidden
Result<User>.Forbidden("You don't have permission to access this resource");
// 404 Not Found
Result<Product>.NotFound("Product not found");
// 409 Conflict
Result<User>.Conflict("A user with this email already exists");
// 422 Unprocessable Entity
Result<Order>.UnprocessableEntity("Order validation failed");
// 429 Too Many Requests
Result<object>.TooManyRequests("Rate limit exceeded. Please try again later");
Server Error Responses
// 500 Internal Server Error
Result<object>.InternalError("An unexpected error occurred");
// 503 Service Unavailable
Result<object>.ServiceUnavailable("Service is temporarily unavailable");
Custom Responses
// Custom status code with context
var context = new { Code = "CUSTOM_ERROR", Details = "Custom error details" };
Result<object>.Custom(context, 418, isSuccess: false);
Advanced Usage
Service Layer Integration
public interface IProductService
{
Result<Product> GetById(int id);
Result<Product> Create(CreateProductDto dto);
Result<IEnumerable<Product>> GetAll();
}
public class ProductService : IProductService
{
public Result<Product> GetById(int id)
{
var product = _repository.FindById(id);
return product == null
? Result<Product>.NotFound($"Product with ID {id} not found")
: Result<Product>.Ok(product);
}
public Result<Product> Create(CreateProductDto dto)
{
try
{
var product = _repository.Add(dto);
return Result<Product>.Created(product, "Product created successfully");
}
catch (DuplicateException)
{
return Result<Product>.Conflict("Product already exists");
}
catch (Exception ex)
{
return Result<Product>.InternalError($"Failed to create product: {ex.Message}");
}
}
public Result<IEnumerable<Product>> GetAll()
{
var products = _repository.GetAll();
return Result<IEnumerable<Product>>.Ok(products);
}
}
Controller with Service Integration
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
var result = _productService.GetById(id);
return result.ToResult();
}
[HttpGet]
public IActionResult GetAllProducts()
{
return _productService.GetAll().ToResult();
}
[HttpPost]
public IActionResult CreateProduct([FromBody] CreateProductDto dto)
{
return _productService.Create(dto).ToResult();
}
}
Using ToResultAll() for Full Response
The ToResultAll() extension returns all properties of the Result object:
[HttpGet("{id}")]
public IActionResult GetProductWithMetadata(int id)
{
var result = _productService.GetById(id);
return result.ToResultAll();
}
// Response body will include:
// {
// "success": true,
// "statusCode": 200,
// "message": null,
// "context": null,
// "data": { "id": 1, "name": "Product", "price": 29.99 }
// }
Error Handling Pattern
public Result<Product> Update(int id, UpdateProductDto dto)
{
try
{
var existingProduct = _repository.FindById(id);
if (existingProduct == null)
return Result<Product>.NotFound($"Product with ID {id} not found");
var updatedProduct = _repository.Update(id, dto);
return Result<Product>.Ok(updatedProduct, "Product updated successfully");
}
catch (UnauthorizedAccessException)
{
return Result<Product>.Forbidden("You don't have permission to update this product");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating product {ProductId}", id);
return Result<Product>.InternalError("An error occurred while updating the product");
}
}
Using Custom Context for Additional Data
public Result<Order> PlaceOrder(PlaceOrderDto dto)
{
var order = _orderService.Place(dto);
if (order != null)
{
var context = new
{
Details = "Order placed successfully",
OrderId = order.Id,
};
return Result<Order>.Custom(context, 200, isSuccess: true);
}
return Result<Order>.InternalError("Failed to place order");
}
Using Context for Rich Error Information
[HttpPost]
public IActionResult CreateUser([FromBody] CreateUserDto dto)
{
var validationErrors = ValidateUser(dto);
if (validationErrors.Any())
{
var errorContext = new
{
Errors = validationErrors,
Timestamp = DateTime.UtcNow
};
return Result<User>.Custom(errorContext, 400, isSuccess: false).ToResult();
}
var user = _userService.Create(dto);
return Result<User>.Created(user, "User created successfully").ToResult();
}
API Reference
Result<T> Properties
| Property | Type | Description |
|---|---|---|
Success |
bool |
Indicates whether the operation was successful |
StatusCode |
int |
HTTP status code (e.g., 200, 404, 500) |
Message |
string? |
Optional message providing additional information |
Context |
object? |
Optional context object for additional data |
Data |
T? |
The actual data returned from the operation |
Extension Methods
| Method | Description |
|---|---|
ToResult() |
Converts Result to IActionResult (returns Context, Data, or Message) |
ToResultAll() |
Converts Result to IActionResult (returns all Result properties) |
Response Priority in ToResult()
The ToResult() extension method determines the response body in this order:
- Context - if not null, returns Context
- Data - if Context is null, returns Data
- Message - if both Context and Data are null (or on error), returns
{ Message: "..." } - StatusCode only - if all are null, returns just the status code
License
MIT License
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For issues, questions, or suggestions, please open an issue on the GitHub repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Microsoft.AspNetCore.Mvc.Abstractions (>= 2.3.9)
- Microsoft.AspNetCore.Mvc.Core (>= 2.3.9)
- Newtonsoft.Json (>= 13.0.4)
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.1 | 167 | 4/7/2026 |