ASP.NET Core 2.1: ActionResult

This post is going to take the Contacts API from my ASP.NET Basics set of posts and move it from usingĀ IActionResulttoĀ ActionResult<T>Ā which was introduced with the 2.1 release. The changes are really simple, but if you are using OpenAPI/Swagger I have a call out later in the post about something I noticed. The code before any changes can be found here.

IActionResult vs ActionResult<T>

The official docsĀ explain the three different ways to return data in an API which are a specific type, IActionResultĀ type, or ActionResult<T>Ā type.

A specific type is great if you don’t have to do any sort of validation or the like, but as soon as you need to return a different HTTP status than OK is no longer sufficient. This is where you would have to move to IActionResult.

IActionResultĀ allows different HTTP statuses to be returned. In the following example,Ā NotFoundĀ is returned if a contact with the supplied ID isn’t found orĀ OK(contact)Ā if a contact is found.

public async Task<IActionResult> GetContact([FromRoute] int id)
{
     var contact = await _context.Contact
                                 .SingleOrDefaultAsync(m => m.Id == id);

     if (contact == null)
     {
        return NotFound();
     }
    
     return Ok(contact);
}

The advantage ofĀ ActionResult<T>Ā it is the return type of the function is clear. You can see in the following example whereĀ GetContactĀ has been changed to useĀ ActionResult<T>Ā that if all goes well you will be dealing with aĀ ContactĀ object in the end without the need to wrap the result in anĀ OK.

public async Task<ActionResult<Contact>> GetContact([FromRoute] int id)
{
     var contact = await _context.Contact
                             .SingleOrDefaultAsync(m => m.Id == id);

     if (contact == null)
     {
        return NotFound();
    }

    return contact;
}

OpenAPI/Swagger

If you are using OpenAPI/Swagger in your project with a function with the following definitionĀ it will automatically pick up the return type if you switch to usingĀ ActionResult<T>.

public async Task<ActionResult<Contact>> GetContact([FromRoute] int id)

The above function results in the following in OpenAPI/Swagger UI.

This is awesome and saves you from having toĀ ProducesResponseTypeĀ attributes to your API functions. Just note that as soon as you do add aĀ ProducesResponseTypeĀ for say aĀ NotFoundĀ response you will still need include a response forĀ OKĀ with the proper type or you will lose the return type in the OpenAPI/Swagger UI.

I’m calling that last bit out because I spent time trying to figure out why all the samples I saw the return type was automatically picked up, but in my sample application it wasn’t.

Wrapping Up

I’m a huge fan ofĀ ActionResult<T>Ā mostly because of the clarityĀ it adds to API function definitions. The fact that OpenAPI/Swagger can pick up on it in the simple cases is an added bonus.

If you are looking for more info check out theĀ Exploring ActionResult<T> in ASP.NET Core 2.1 post byĀ Joonas WestlinĀ in which there is more info on how the functionality is actually implemented. If you didn’t already make sure and check out theĀ Controller action return types in ASP.NET Core Web APIĀ page in the official docs for a detailed comparison of the return type options for APIs.

The completed code can be found here.


Also published on Medium.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.