1

I have multiple services that return IResult and don´t want to use minimal API structure, but I want to use the same return type IResult, but when I use that in the controller it always returns Ok:

Minimal API example that returns 400 Bad request:

app.MapPut("test", async () =>
{
    return Results.BadRequest("hello");
});

The classic controller that returns 200 Ok:

[ApiController]
public class TestController : ControllerBase

    [HttpPut("test")]
    public async Task<IResult> Test()
    {
        return Results.BadRequest();
    }

Is there an easy way to fix this or do I need a mapping function?

I am using .NET 6.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
Moddaman
  • 2,538
  • 3
  • 23
  • 41
  • It would be handy to know which version of .NET you're using here. The answer you need varies from version to version. – Ethan Dec 08 '22 at 13:07
  • 1
    Why do you want to use `IResult` in classic controllers though? – DavidG Dec 08 '22 at 13:07
  • Thanks for adding the version of .NET you're using. In .NET 6, I think my answer should be accurate. – Ethan Dec 08 '22 at 13:10
  • 1
    @Ethan except your post doesn't really answer the question. – DavidG Dec 08 '22 at 13:11
  • @DavidG how so? The easy way to fix that is to use the BadRequest() instead of Results.BadRequest(). I can clarify that if you want – Ethan Dec 08 '22 at 13:12
  • Because then I can do this in my controller: return await TestService.DoStuff(); And the DoStuff method can return BadRequest if something is wrong But when I think about it I might just throw an exception in DoStuff and make the ErrorController handle the return value – Moddaman Dec 08 '22 at 13:12
  • 1
    @Ethan It doesn't say how OP can use `IResult`, it uses a different type. – DavidG Dec 08 '22 at 13:13
  • 3
    @Moddaman You shouldn't have your services know anything about HTTP stuff. Let them return a true/false/null/whatever of some sort and the controller is always responsible for the mapping to the correct response. – DavidG Dec 08 '22 at 13:15

2 Answers2

2

Technically you can call IResult.ExecuteAsync on the ControllerBase's context:

public class SomeController : ControllerBase
{
    public async Task SomeAction()
    {
        IResult result = Results.BadRequest(); // dummy result, use one from the service
        await result.ExecuteAsync(HttpContext);
    }
}

But in general it is better to follow standard patterns and in this case make your service return some custom app-specific response which is "platform-agnostic" i.e. it should not depend on web framework used and represent some business/domain related entity/data. Potentially you can look into some library which can represent "result" abstraction. For example FluentResults or go a bit more functional with some kind of Either (many options here CSharpFunctionalExtensions, language-ext, Optional, etc.).

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
2

This is supported in .NET 7 now.

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();

app.Run();

public class Home : ControllerBase
{
    [HttpGet("/")]
    public IResult Get() => Results.Ok("Okies");
}

davidfowl
  • 37,120
  • 7
  • 93
  • 103
  • And here is the documentation for it: https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0#httpresults-type – cremor Jun 19 '23 at 07:58