202 HTTP Status Code in ASP.NET Core Web API

202 HTTP Status Code in ASP.NET Core Web API

In this article, I will discuss How to Return 202 Accepted HTTP Status Code in ASP.NET Core Web API with Examples. Please read our previous article discussing How to Return 201 HTTP Status Code from the ASP.NET Core Web API Controller Action method with Examples.

202 HTTP Status Code

The 202 Accepted HTTP status code is a response status code indicating that the request has been accepted for processing, but the processing has not been completed. The 202 Status Code is primarily intended for situations where a request is being processed asynchronously, meaning the server has received the request, but the outcome has not yet been determined. The following are the Key characteristics of the 202 Status Code:

  • Asynchronous Processing: It is used when a server accepts a request to be processed, but the processing occurs asynchronously. This implies that the server does not provide an immediate response or outcome of the request processing in the HTTP response.
  • Temporary Status: The 202 Status Code does not necessarily indicate the final outcome of the request processing. It only signifies that the request was valid and has been accepted to be processed, which could eventually succeed or fail based on further internal processing.
  • Response Body: While not strictly required, the response body of a 202 Status Code typically includes a message indicating the request’s current status or a link to where the status of the request can be monitored.
  • Location Header: The response might include a Location header pointing to a URL where the status of the request can be checked. This allows clients to monitor the progress or outcome of the request.
  • Use Cases: Common scenarios for using the 202 Status Code include batch processing, long-running processes, or other operations where immediate completion is not possible or expected. For example, submitting a request for generating a report that requires significant computation time might return a 202 Status Code, with details on how to check for the report’s completion status later.
How to Return 202 HTTP Status Code in ASP.NET Core Web API?

To return a 202 Accepted HTTP status code in an ASP.NET Core Web API, you can use the Accepted, AcceptedAtAction or AcceptedAtRoute methods from your controller. These methods are useful for creating responses that indicate a request has been accepted for processing, but the processing is not yet complete, which is often the case in asynchronous operations or operations that require some processing time before completion.

Using Accepted in ASP.NET Core Web API:

The Accepted method is used to return a 202 Accepted status code. This status code indicates that the request has been accepted for processing, but the processing has not been completed. The Accepted method can be used in scenarios where the action has been queued or started but not finished. The following three overloaded versions of the Accepted method are available in ASP.NET Core.

  • Accepted(): Returns a 202 Accepted response without additional URI or content.
  • Accepted(object value): Returns a 202 Accepted response with a serializable object that can be included in the response body.
  • Accepted(Uri uri): Returns a 202 Accepted response with a URI indicating where the status of the request can be monitored.
  • Accepted(string uri): Returns a 202 Accepted response with a string URI indicating where the status of the request can be monitored.
  • Accepted(Uri uri, object value): Returns a 202 Accepted response with a URI indicating where the status of the request can be monitored and an optional object that can be included in the response body.
  • Accepted(string uri, object value): Returns a 202 Accepted response with a string URI indicating where the status of the request can be monitored and an optional object that can be included in the response body.

So, let us understand the above four overloaded Accepted methods with an example. So, let us add an Empty API Controller with the name JobController and then copy and paste the following code. The following code is self-explained, so please go through the comment lines for a better understanding.

using Microsoft.AspNetCore.Mvc;
namespace ReturnTypeAndStatusCodes.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class JobController : ControllerBase
    {
        //POST: api/Job/CreateJobAsyncWithoutData
        [HttpPost]
        public async Task<IActionResult> CreateJobAsyncWithoutData()
        {
            // Logic to start asynchronous processing and we are not blocking the thread
            // The LongRunningTask will take 60 seconds to complete
            // The main thread will not block till the LongRunningTask is completed
            LongRunningTask();

            // Return 202 Accepted without any data
            return Accepted();
        }

        //POST: api/Job/CreateJobAsyncWithData
        [HttpPost]
        public async Task<IActionResult> CreateJobAsyncWithData()
        {
            // Logic to start asynchronous processing and we are not blocking the thread
            LongRunningTask();

            var resourceStatus = new 
            { 
                Status = "Processing", 
                EstimatedCompletionTime = "2 hours" 
            };

            // Return 202 Accepted with data
            return Accepted(resourceStatus);
        }

        //POST: api/Job/CreateJobWithLocation
        [HttpPost]
        public async Task<IActionResult> CreateJobWithLocation()
        {
            // Logic to start asynchronous processing and we are not blocking the thread
            LongRunningTask();

            //Let is asume the Processing JobId is 123
            var processingJobId = 123;

            // The following Location URI we will return along with 202 Status Code
            // Location URI to check status
            //var locationUri = new Uri($"https://localhost:7248/api/Job/GetStatus/{processingJobId}");
            var locationUri = $"https://localhost:7248/api/Job/GetStatus/{processingJobId}";

            // Return a 202 Accepted status code with a location URI
            return Accepted(locationUri);
        }

        //POST: api/Job/CreateJobWithLocationAndData
        [HttpPost]
        public async Task<IActionResult> CreateJobWithLocationAndData()
        {
            // Logic to start asynchronous processing and we are not blocking the thread
            LongRunningTask();

            //Let is asume the Processing JobId is 123
            var processingJobId = 123;

            //The following data we will return along with 202 Status Code
            var resourceStatus = new 
            { 
                Status = "Processing", 
                EstimatedCompletionTime = "2 hours",
                Jobid = processingJobId
            };

            // The following Location URI we will return along with the Data and 202 Status Code
            // Location URI to check status
            // var locationUri = $"https://localhost:7248/api/Job/GetStatus/{processingJobId}";
            var locationUri = new Uri($"https://localhost:7248/api/Job/GetStatus/{processingJobId}");

            // Return a 202 Accepted status code with a location URI and a response body
            return Accepted(locationUri, resourceStatus);
        }

        //GET:  api/Job/GetStatus/123
        [HttpGet("{JobId}")]
        public IActionResult GetStatus(int JobId)
        {
            //Return the Current Status of the Jon
            var resourceStatus = new { Status = "Processing", EstimatedCompletionTime = "2 hours" };
            return Ok(resourceStatus);
        }

        //This is the method which is going to perform the time-consuming asynchronous operation
        private async Task LongRunningTask()
        {
            // Simulate a long-running task
            await Task.Delay(TimeSpan.FromSeconds(120)); // 60 Seconds delay
            // Task logic here
        }
    }
}
Testing the APIs:

Now, run the application and test the APIs using Postman, Fiddler, Swagger, or .http files. You can test the APIs using Postman as follows: Please change the port number where your application is running:

API1: Returning 202 Status Code without Data

URL: https://localhost:7128/api/Job/CreateJobAsyncWithoutData

Method: POST

Response Body: The Response body will be empty

How to Return 202 HTTP Status Code from the ASP.NET Core Web API Controller Action method with Examples

API2: Returning 202 Status Code with Data

URL: https://localhost:7128/api/Job/CreateJobAsyncWithData

Method: POST

Response Body: The Response body will contain the data

How to Return 202 HTTP Status Code from the ASP.NET Core Web API Controller Action method with Examples

API3: Returning 202 Status Code with Location URL

URL: https://localhost:7128/api/Job/CreateJobWithLocation

Method: Post

Response Body: The response body will be empty

Response Header: The response header will contain the Location URI, which you can use to get the current status.

How to Return 202 HTTP Status Code from the ASP.NET Core Web API Controller Action method

API4: Returning 202 Status Code with Location URL and Data

URL: https://localhost:7128/api/Job/CreateJobWithLocationAndData

Method: POST

Response Body: The Response body will contain the data

How to Return 202 HTTP Status Code in ASP.NET Core Web API

Response Header: The response header will contain the Location URI, which you can use to get the current status.

How to Return 202 HTTP Status Code in ASP.NET Core

API5: Checking the Job Status with Location URL

URL: https://localhost:7128/api/Job/GetStatus/123

Method: POST

Response Body: The Response body will contain the data

202 HTTP Status Code in ASP.NET Core

Using AcceptedAtAction in ASP.NET Core Web API:

The AcceptedAtAction method is a variation of the Accepted method used to generate a 202 Accepted response and include a Location header in the response. The Location header specifies the URI of the action to monitor the status of the request. This is particularly useful for REST APIs where the client might need to poll or check the status of the request at a later time. The following overloaded versions are available in ASP.NET Core:

  • AcceptedAtAction(string actionName): Returns a 202 Accepted response with a Location header pointing to the specified action.
  • AcceptedAtAction(string actionName): Returns a 202 Accepted response with a Location header pointing to the specified action and controller.
  • AcceptedAtAction(string actionName, object routeValues): Returns a 202 Accepted response with a Location header pointing to the specified action, using the provided route values to generate the URI.
  • AcceptedAtAction(string actionName, string controllerName, object routeValues, object value): Returns a 202 Accepted response with a Location header pointing to the specified action and controller, using the provided route values to generate the URI, and includes a serializable object in the response body.

So, let us understand the AcceptedAtAction methods with an example. So, let us add an Empty API Controller with the name JobController and then copy and paste the following code. The following code is self-explained, so please go through the comment lines for a better understanding.

using Microsoft.AspNetCore.Mvc;
namespace ReturnTypeAndStatusCodes.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class JobController : ControllerBase
    {
        //POST: api/Job/CreateJobWithLocation
        [HttpPost]
        public async Task<IActionResult> CreateJobWithLocation()
        {
            // Logic to start asynchronous processing and we are not blocking the thread
            LongRunningTask();

            //Let is asume the Processing JobId is 123
            var processingJobId = 123;

            // Assuming the job has an ID assigned after being added
            // Passing object value as null as we don't want to return any data
            // Here, GetStatus is the Action Method Name
            return AcceptedAtAction("GetStatus", new { JobId = processingJobId }, null);
        }

        //POST: api/Job/CreateJobWithLocationAndData
        [HttpPost]
        public async Task<IActionResult> CreateJobWithLocationAndData()
        {
            // Logic to start asynchronous processing and we are not blocking the thread
            LongRunningTask();

            //Let us asume the Processing JobId is 123
            var processingJobId = 123;

            //The following data we will return along with 202 Status Code
            var resourceStatus = new { Status = "Processing", EstimatedCompletionTime = "2 hours" };

            // Here, GetStatus is the Action Method Name and Job is the Controller Name
            // return AcceptedAtAction("GetStatus", new { JobId = processingJobId }, resourceStatus);
            return AcceptedAtAction("GetStatus", "Job", new { JobId = processingJobId }, resourceStatus);
        }

        //GET:  api/Job/GetStatus/123
        [HttpGet("{JobId}")]
        public IActionResult GetStatus(int JobId)
        {
            //Return the Current Status of the Job
            var resourceStatus = new { Status = "Processing", EstimatedCompletionTime = "2 hours" };
            return Ok(resourceStatus);
        }

        //This is the method which is going to perform the time consuming asynchronous operation
        private async Task LongRunningTask()
        {
            // Simulate a long-running task
            await Task.Delay(TimeSpan.FromSeconds(60)); // 60 Seconds Delay
            // Task logic here
        }
    }
}

Using AcceptedAtRoute in ASP.NET Core Web API

In ASP.NET Core Web API, the AcceptedAtRoute method is also to return a Status Code of 202 (Accepted) along with a Location header to the client. This method is similar to AcceptedAtAction, but instead of specifying an action name and optionally a controller name, you specify a route name. This is particularly useful when you have named routes or prefer to use route names instead of action names for generating the Location header’s URI.

The Location header indicates the URI where the client can send a GET request to obtain the status of the request’s processing or the result of the operation. This approach is often used in asynchronous processing scenarios or when the result of the request is not immediately available. For a better understanding, please modify the Job Controller as follows:

using Microsoft.AspNetCore.Mvc;
namespace ReturnTypeAndStatusCodes.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class JobController : ControllerBase
    {
        //POST: api/Job/CreateJobWithLocation
        [HttpPost]
        public async Task<IActionResult> CreateJobWithLocation()
        {
            // Logic to start asynchronous processing and we are not blocking the thread
            LongRunningTask();

            //Let is asume the Processing JobId is 123
            var processingJobId = 123;

            // Assuming the job has an ID assigned after being added
            // GetJobStatus is the Route Name
            // Passing object value as null as we don't want to return any data
            return AcceptedAtRoute("GetJobStatus", new { JobId = processingJobId }, null);
        }

        //POST: api/Job/CreateJobWithLocationAndData
        [HttpPost]
        public async Task<IActionResult> CreateJobWithLocationAndData()
        {
            // Logic to start asynchronous processing and we are not blocking the thread
            LongRunningTask();

            //Let is asume the Processing JobId is 123
            var processingJobId = 123; 

            //The following data we will return along with 202 Status Code
            var resourceStatus = new { Status = "Processing", EstimatedCompletionTime = "2 hours" };

            // GetJobStatus is the Route Name
            return AcceptedAtRoute("GetJobStatus", new { JobId = processingJobId }, resourceStatus);
        }

        //GET:  api/Job/GetStatus/123
        //We have assigned the Route Name as GetJobStatus
        [HttpGet("{JobId}",Name ="GetJobStatus")]
        public IActionResult GetStatus(int JobId)
        {
            //Return the Current Status of the Job
            var resourceStatus = new { Status = "Processing", EstimatedCompletionTime = "2 hours" };
            return Ok(resourceStatus);
        }

        //This is the method which is going to perform the time consuming asynchronous operation
        private async Task LongRunningTask()
        {
            // Simulate a long-running task
            await Task.Delay(TimeSpan.FromSeconds(60)); // 60 Seconds Delay
            // Task logic here
        }
    }
}
When should you use the 202 Accepted Status Code in ASP.NET Core Web API?

The 202 HTTP Status Code is useful in scenarios where the operations required to fulfil the request are expected to take a long time. Here are several scenarios where returning a 202 Status Code is appropriate:

  • Asynchronous Processing: When the API initiates a process that runs in the background, the completion of that process is not immediate. For instance, if the API starts a batch job for processing a large number of records, it can immediately return a 202 status to indicate that the request has been accepted and processing has started but is not yet complete.
  • Delayed Resource Creation: In situations where a resource creation request has been accepted but the resource is not immediately available, or its creation is deferred for processing at a later time. The 202 Status Code informs the client that the request is valid and under process, but the resource is not yet ready.
  • Long-Running Operations: For operations that require a significant amount of time to complete, such as generating a report, processing a video, or executing a complex database operation. By returning a 202 Status Code, the server indicates that it has received the request, but it might take some time to complete.
  • Queueing Requests: When requests are put into a queue for later processing due to high load or throttling. The 202 Status Code signifies that the request has been queued successfully.
When should we use Accepted vs AcceptedAtAction vs AcceptedAtRoute?

These methods are part of the ControllerBase class and are used to return 202 Accepted status codes, indicating that a request has been received and will be processed, but the processing is not yet complete. Each method has specific use cases based on how much information you want to provide the client about where and how to get updates on the request’s status or results.

Accepted
  • When you want to acknowledge that a request has been accepted for processing but either doesn’t need to or cannot specify where the client can follow up on the status of the request.
  • When the client does not need to be directed to a specific resource or action for follow-up.
  • Example Scenario: Processing a background task where the client does not need immediate results or status updates.
AcceptedAtAction
  • When you want to direct the client to a specific action method within a controller to get the status of the request or the result.
  • Ideal for situations where the follow-up endpoint (action) is within the same controller or a specified controller, and you want to use action names rather than route names.
  • Example Scenario: After submitting a job for background processing, you direct the client to a Status action within the same controller where they can check the job’s status or result using the job ID.
AcceptedAtRoute
  • When you want to direct the client to a specific route to get the status of the request or the result, this is useful when the follow-up endpoint can be identified by a route name.
  • Preferred in scenarios where routes are named, and you wish to decouple the follow-up URI from specific action methods, offering more flexibility in how routes are structured and named.
  • Example Scenario: After initiating a data import process, you direct the client to a named route designed to provide the status of the import process. This route could be handled by any controller or action that matches the route definition, allowing for a more flexible API design.

In the next article, I will discuss How to Return 204 HTTP Status Code in ASP.NET Core Web API with Examples. In this article, I try to explain How to Return the 202 Accepted HTTP Status Code from ASP.NET Core Web API Application with Examples, and I hope you enjoy this article on “202 HTTP Status Code in the ASP.NET Core Web API”.

Leave a Reply

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