CleanResult.AspNet 1.3.4

dotnet add package CleanResult.AspNet --version 1.3.4
                    
NuGet\Install-Package CleanResult.AspNet -Version 1.3.4
                    
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="CleanResult.AspNet" Version="1.3.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CleanResult.AspNet" Version="1.3.4" />
                    
Directory.Packages.props
<PackageReference Include="CleanResult.AspNet" />
                    
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 CleanResult.AspNet --version 1.3.4
                    
#r "nuget: CleanResult.AspNet, 1.3.4"
                    
#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 CleanResult.AspNet@1.3.4
                    
#: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=CleanResult.AspNet&version=1.3.4
                    
Install as a Cake Addin
#tool nuget:?package=CleanResult.AspNet&version=1.3.4
                    
Install as a Cake Tool

CleanResult.AspNet

CleanResult

<div align="center">

NuGet License: MIT .NET

Build Testing

IActionResult adapter for CleanResult

Explicit IActionResult conversion for traditional ASP.NET Core controllers

Main DocumentationFeaturesUsageWhen to Use

</div>


📦 Installation

dotnet add package CleanResult.AspNet

Requirements:

  • .NET 8.0, 9.0, or 10.0
  • ASP.NET Core 8.0+

✨ Features

  • 🔄 IActionResult Adapter - Explicit conversion from Result to IActionResult
  • 🎯 Controller Compatibility - Works with traditional controller patterns
  • Zero Overhead - Thin wrapper around existing IResult implementation
  • 📄 Clean Integration - Maintains all CleanResult features and behaviors

🚀 Usage

Basic Conversion

using CleanResult.AspNet;

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    // ✅ Convert Result to IActionResult
    [HttpGet("{id}")]
    public IActionResult GetUser(int id)
    {
        var result = _userService.GetById(id);
        return result.ToIActionResult();
    }

    // ✅ Convert Result<T> to IActionResult
    [HttpPost]
    public IActionResult CreateUser([FromBody] CreateUserDto dto)
    {
        var result = _userService.Create(dto);
        return result.ToIActionResult();
    }
}

Direct Return Pattern

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;

    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
        => _productService.GetById(id).ToIActionResult();

    [HttpPut("{id}")]
    public IActionResult UpdateProduct(int id, [FromBody] UpdateProductDto dto)
        => _productService.Update(id, dto).ToIActionResult();

    [HttpDelete("{id}")]
    public IActionResult DeleteProduct(int id)
        => _productService.Delete(id).ToIActionResult();
}

🤔 When to Use This Package

✅ Use CleanResult.AspNet When

  • You're working with existing controllers that return IActionResult
  • You need explicit conversion for compatibility
  • Your team prefers traditional controller patterns
  • You're gradually migrating to CleanResult
// ✅ Good use case: existing IActionResult pattern
public IActionResult GetUser(int id)
{
    var result = _service.GetUser(id);
    return result.ToIActionResult();
}

❌ Don't Use When

  • You're using minimal APIs → Use core CleanResult directly (implements IResult)
  • You can return Result types directly → Core CleanResult already implements IResult
// ❌ Unnecessary - CleanResult already implements IResult
[HttpGet("{id}")]
public Result<User> GetUser(int id)  // Direct return works!
    => _service.GetUser(id);

// ❌ Unnecessary conversion
public Result<User> GetUser(int id)
{
    var result = _service.GetUser(id);
    return result.ToIActionResult();  // Don't do this!
}

💡 Examples

Service Layer Integration

public interface IUserService
{
    Result<User> GetById(int id);
    Result<User> Create(CreateUserDto dto);
    Result Update(int id, UpdateUserDto dto);
    Result Delete(int id);
}

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IUserService _userService;

    public UsersController(IUserService userService)
    {
        _userService = userService;
    }

    [HttpGet("{id}")]
    public IActionResult GetUser(int id){
        return _userService.GetById(id).ToIActionResult();
    }

    [HttpPost]
    public IActionResult CreateUser([FromBody] CreateUserDto dto){
        return _userService.Create(dto).ToIActionResult();
    }

    [HttpPut("{id}")]
    public IActionResult UpdateUser(int id, [FromBody] UpdateUserDto dto){
        return _userService.Update(id, dto).ToIActionResult();
    }

    [HttpDelete("{id}")]
    public IActionResult DeleteUser(int id){ 
        return _userService.Delete(id).ToIActionResult();
    }
}

Async Patterns

[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;

    // ✅ Async with IActionResult
    [HttpGet("{id}")]
    public async Task<IActionResult> GetOrder(int id)
    {
        var result = await _orderService.GetByIdAsync(id);
        return result.ToIActionResult();
    }

    // ✅ Direct async pattern
    [HttpPost]
    public async Task<IActionResult> CreateOrder([FromBody] CreateOrderDto dto)
        => (await _orderService.CreateAsync(dto)).ToIActionResult();
}

Error Handling

[ApiController]
[Route("api/[controller]")]
public class PaymentsController : ControllerBase
{
    [HttpPost("process")]
    public IActionResult ProcessPayment([FromBody] PaymentDto dto)
    {
        // Service returns Result<PaymentConfirmation>
        var result = _paymentService.Process(dto);

        // Automatically handles:
        // - Success: HTTP 200 with PaymentConfirmation
        // - Error: HTTP status from error with Problem Details
        return result.ToIActionResult();
    }
}

🔧 How It Works

Implementation

The package provides thin wrapper classes that delegate to the underlying IResult implementation:

// For non-generic Result
public static IActionResult ToIActionResult(this Result result)
    => new AspActionResult(result);

// For generic Result<T>
public static IActionResult ToIActionResult<T>(this Result<T> result)
    => new AspActionResult<T>(result);

The wrapper classes implement IActionResult by calling the Result's ExecuteAsync method:

internal class AspActionResult<T> : IActionResult
{
    private readonly Result<T> _result;

    public Task ExecuteResultAsync(ActionContext context)
        => _result.ExecuteAsync(context.HttpContext);
}

Response Behavior

Result Type HTTP Status Content-Type Body
Result.Ok() 204 No Content application/json Empty
Result<string>.Ok("text") 200 OK text/plain Raw string
Result<User>.Ok(user) 200 OK application/json JSON object
Result<byte[]>.Ok(data) 200 OK application/octet-stream Binary data
Result.Error("msg", 404) 404 Not Found application/json Problem Details (RFC 9457)

🎯 Best Practices

✅ Do's

// ✅ Use for existing IActionResult controllers
[HttpGet("{id}")]
public IActionResult GetUser(int id)
    => _service.GetUser(id).ToIActionResult();

// ✅ Use when you need IActionResult explicitly
public IActionResult PerformAction()
{
    var result = _service.DoSomething();
    if (someCondition)
    {
        return Redirect("/somewhere");
    }
    return result.ToIActionResult();
}

// ✅ Consistent with service layer returning Results
public IActionResult ProcessRequest([FromBody] RequestDto dto)
{
    var validationResult = _validator.Validate(dto);
    if (validationResult.IsError())
        return validationResult.ToIActionResult();

    return _service.Process(dto).ToIActionResult();
}

❌ Don'ts

// ❌ Don't use when you can return Result directly
[HttpGet("{id}")]
public Result<User> GetUser(int id)  // Better: return Result directly
    => _service.GetUser(id).ToIActionResult();

// ❌ Don't double-wrap in IActionResult
[HttpGet("{id}")]
public IActionResult GetUser(int id)
{
    var result = _service.GetUser(id).ToIActionResult();
    return Ok(result);  // Bad: unnecessary nesting
}

// ❌ Don't use for minimal APIs
app.MapGet("/users/{id}", (int id) =>
{
    var result = _service.GetUser(id);
    return result.ToIActionResult();  // Unnecessary - use Result directly
});


📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


<div align="center">

⬆ Back to TopMain Documentation

</div>

<div align="center"> Gwynbleid85 © 2025 </div>

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

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.3.4 102 1/5/2026
1.3.3 203 11/25/2025
1.3.2 198 11/25/2025
1.3.1 198 11/25/2025
1.3.0 212 11/4/2025
1.2.9 189 10/9/2025
1.2.8 198 10/8/2025
1.2.7 313 8/25/2025
1.2.6 203 8/11/2025
1.2.5 737 8/11/2025