Learn the three ways you can return data from your ASP.NET Core Web API action methods. Credit: Thinkstock We have three ways to return data and HTTP status codes from an action method in ASP.NET Core. You can return a specific type, return an instance of type IActionResult, or return an instance of type ActionResult. Although returning a specific type is the simplest way, IActionResult lets you return both data and HTTP codes, and ActionResult lets you return a type that extends IActionResult. An ActionResult can be used to send an HTTP status code, data, or both from an action method. This article presents a discussion of how we can return data in ASP.NET Core Web API using each of those types, with relevant code examples in C#. To work with the code examples illustrated in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here. Create an ASP.Net Core API project First off, let’s create an ASP.NET Core project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new ASP.NET Core project in Visual Studio. Launch the Visual Studio IDE. Click on “Create new project.” In the “Create new project” window, select “ASP.Net Core Web Application” from the list of templates displayed. Click Next. In the “Configure your new project” window, specify the name and location for the new project. Click Create. In the “Create New ASP.Net Core Web Application” window shown next, select .NET Core as the runtime and ASP.NET Core 2.2 (or later) from the drop-down list at the top. I’ll be using ASP.NET Core 3.0 here. Select “API” as the project template to create a new ASP.NET Core API application. Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here. Ensure that Authentication is set as “No Authentication” as we won’t be using authentication either. Click Create. This will create a new ASP.NET Core API project in Visual Studio. Now select the Controllers solution folder in the Solution Explorer Window and click “Add -> Controller…” to create a new controller named DefaultController. We’ll use this project to explore returning data from action methods in the subsequent sections of this article. If you’d like an easy way to test the action methods we use below, I recommend taking advantage of Postman. You can download a copy of Postman from here. Create Controller and Model classes in ASP.NET Core Create a new solution folder and name it Models. It’s here that you will place your model classes. The following code listing illustrates how you can create a simple model class named Author. public class Author { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } } So far so good. Now, replace the generated code of the DefaultController class with the code listing given below. using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; namespace IDGCoreWebAPI.Controllers { [Route("api/[controller]")] [ApiController] public class DefaultController : ControllerBase { private readonly List<Author> authors = new List<Author>(); public DefaultController() { authors.Add(new Author() { Id = 1, FirstName = "Joydip", LastName = "Kanjilal" }); authors.Add(new Author() { Id = 2, FirstName = "Steve", LastName = "Smith" }); } [HttpGet] public IEnumerable<Author> Get() { return authors; } [HttpGet("{id}", Name = "Get")] public Author Get(int id) { return authors.Find(x => x.Id == id); } } } Return a specific type from an action method in ASP.NET Core The simplest way you can return data from an action method is to return a specific type. In the code listing shown above, the Get action method returns a list of Author instances. These instances are created and initialized in the constructor of the DefaultController class. Below is the action method again for your reference. Note that it returns IEnumerable. [HttpGet] public IEnumerable<Author> Get() { return authors; } Beginning with ASP.NET Core 3.0, you also have the option of returning IAsyncEnumerable from an action method. While IEnumerable performs a synchronous collection iteration, IAsyncEnumerable does an asynchronous iteration. Thus IAsyncEnumerable is more efficient because there are no blocking calls. (I’ll discuss IAsyncEnumerable further in a future post here.) Here is how you can re-write the preceding action method using IAsyncEnumerable. [HttpGet] public async IAsyncEnumerable<Author> Get() { var authors = await GetAuthors(); await foreach (var author in authors) { yield return author; } } Return an instance of type IActionResult from an action method in ASP.NET Core You can take advantage of the IActionResult interface when you would like to return both data and HTTP codes from your action method. The following code snippet illustrates how this can be achieved. [HttpGet] public IActionResult Get() { if (authors == null) return NotFound("No records"); return Ok(authors); } The IActionResult interface is implemented by the OkResult, NotFoundResult, CreatedResult, NoContentResult, BadRequestResult, UnauthorizedResult, and UnsupportedMediaTypeResult classes. In the preceding code snippet, the methods NotFound() and Ok() return instances of type IActionResult. Return an instance of type ActionResult from an action method in ASP.NET Core ActionResult was introduced in ASP.NET Core 2.1. An ActionResult is a type that implements the IActionResult interface. You can take advantage of the ActionResult return type to return a type that extends ActionResult or any other specific type (such as Author in our example). The following code snippet illustrates how we can return ActionResult from an action method. [HttpGet] public ActionResult<IEnumerable<Author>> Get() { if (authors == null) return NotFound("No records"); return authors; } As you can see in the preceding code snippet, you no longer need to wrap the object to be returned in the Ok() method — you can just return it as is. Let’s now make this asynchronous. Consider the following async method, which returns the list of authors. private async Task<List<Author>> GetAuthors() { await Task.Delay(100).ConfigureAwait(false); return authors; } An asynchronous method should have a minimum of one await statement. If it doesn’t have any await statements, the compiler will generate a warning stating that the method will run synchronously. To avoid this compiler warning, I’ve awaited a call to the Task.Delay method in the preceding code snippet. The updated action method is listed below. Note how the await keyword has been used to invoke the async method we just created. [HttpGet] public async Task<ActionResult<IEnumerable<Author>>> Get() { var data = await GetAuthors(); if (data == null) return NotFound("No record"); return data; } You can also return an instance of a custom ActionResult from your action method. All you need to need to do is create a class that implements the IActionResult interface and implements the ExecuteResultAsync method. We’ll discuss IActionResult and ActionResult as well as custom ActionResult classes in a future post here. Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos