Back to: ASP.NET Core Web API Tutorials
503 HTTP Status Code in ASP.NET Core Web API
In this article, I will discuss How to Return a 503 Service Unavailable HTTP Status Code in an ASP.NET Core Web API Application with Examples. Please read our previous article discussing How to Return 501 Not Implemented HTTP Status Code in ASP.NET Core Web API with Examples.
What is 503 HTTP Status Code?
The 503 HTTP Status Code stands for “Service Unavailable,” which indicates that the web server is currently unable to handle the request. This could be due to the server being overloaded or down for maintenance. This status code indicates that the server is currently unable to handle the request but may be available in the future. So, it is commonly used to inform the client to retry the request after some time. Servers can optionally include a Retry-After header in the 503 Response to indicate how long the service is expected to be unavailable. Clients can use this information to decide when to retry the request.
503 HTTP Status Code in ASP.NET Core Web API
In an ASP.NET Core Web API application, a 503 status code indicates that the API service is either down or unable to process requests at the moment. This can be caused by various factors, including:
- Service Overload: If the server is receiving more requests than it can handle, it might start rejecting some with a 503 status. That means the web server (like IIS, Kestrel, etc.) hosting the API is overloaded. The web server could be running out of critical resources such as memory or CPU, affecting its ability to handle requests.
- Maintenance Mode: The server could be in a maintenance mode where it is intentionally unavailable for updates or changes.
- Dependency Issues: Unreachable dependencies, such as databases, external services, or other resources that the API relies on, could result in a 503 error.
- Application Pool Issues: In environments like IIS, issues with the application pool, such as crashes, down, or disabled, can lead to 503 errors.
How to Return 503 HTTP Status Code in ASP.NET Core Web API
In ASP.NET Core Web API, returning a 503 HTTP status code (Service Unavailable) can be done explicitly within your controllers using the StatusCode method of the ControllerBase class or by configuring middleware to handle specific scenarios. Let us proceed and understand both scenarios.
We will create a simple example to demonstrate how to return a 503 Status Code in an ASP.NET Core Web API. This involves configuring middleware that checks for a specific condition (e.g., a flag indicating maintenance mode) and, based on that, either allows the request to proceed or returns a 503 Service Unavailable response.
Configure appsettings.json
We need to add a key in the appsettings.json file, which will tell whether the service is under maintenance. So, add the following key in the appsettings.json file and set its value to true:
"IsApplicationUnderMaintenance": "true"
Returning 503 from a Controller Action using StatusCode Method
You can return a 503 status code directly from any action within your controllers by using the StatusCode method of the ControllerBase Class. For a better understanding, please modify the Sample Controller as follows:
using Microsoft.AspNetCore.Mvc; namespace ReturnTypeAndStatusCodes.Controllers { [Route("api/[controller]")] [ApiController] public class SampleController : ControllerBase { // Field to hold the configuration settings. public IConfiguration _configuration; // Constructor to initialize the configuration field. public SampleController(IConfiguration configuration) { _configuration = configuration; } // HTTP GET method to handle GET requests to the controller's route. [HttpGet] public IActionResult GetResource() { // Read a configuration value which indicates whether the server is under maintenance. bool IsUnderMaintenance = Convert.ToBoolean(_configuration["IsApplicationUnderMaintenance"]); // Check if the application is under maintenance. if (IsUnderMaintenance) { // Create a custom response object. var customResponse = new { Code = 503, Message = "Service is under maintenance. Please try again later." }; // Return a 503 status code with the custom response object. return StatusCode(503, customResponse); } // If the application is not under maintenance, return a 200 OK status with a message. return Ok("Service is Available"); } } }
Now, run the application and make a request to the above endpoint. You should receive a 503 Service Unavailable response with the message “Service is under maintenance. Please try again later.” as shown in the below image:
Implement a Custom Middleware Component to Return 503 Status Code:
If you need to return a 503 status code based on application-wide conditions, such as maintenance mode or high load, it’s efficient to use middleware. This approach centralizes the logic instead of checking the same across multiple controllers. Create a new class file named MaintenanceMiddleware.cs, then copy and paste the following code. The following MaintenanceMiddleware class checks if the application is under maintenance and, if so, returns a 503 Service Unavailable response. The following code is self-explained, so please read the comment lines for a better understanding:
// Using directive for JSON serialization. using System.Text.Json; namespace ReturnTypeAndStatusCodes.Models { // Custom middleware class for handling maintenance mode. public class MaintenanceMiddleware { // Field to hold the next middleware in the pipeline. private readonly RequestDelegate _next; // Constructor to initialize the next middleware delegate. public MaintenanceMiddleware(RequestDelegate next) { // Assigns the next delegate to the _next field _next = next; } // Method invoked by the middleware to handle HTTP requests. public async Task Invoke(HttpContext httpContext, IConfiguration configuration) { // Implement your logic here // Read a configuration value which indicates whether the server is under maintenance. bool IsUnderMaintenance = Convert.ToBoolean(configuration["IsApplicationUnderMaintenance"]); // Check if the application is under maintenance. if (IsUnderMaintenance) { // Set the HTTP status code to 503 (Service Unavailable). httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable; // Set the content type of the response to JSON. httpContext.Response.ContentType = "application/json"; // Set the Retry-After header to indicate when the client should retry (in seconds). httpContext.Response.Headers["Retry-After"] = "120"; // Create a custom response object. var customResponse = new { Code = 503, Message = "Service is under maintenance. Please try again later." }; // Serialize the custom response object to a JSON string. var responseJson = JsonSerializer.Serialize(customResponse); // Write the JSON response to the HTTP response body. await httpContext.Response.WriteAsync(responseJson); } else { // If not under maintenance, invoke the next middleware in the pipeline. await _next(httpContext); } } } }
Register the Middleware
In the Program.cs file, we need to register the middleware component as follows: This ensures it’s part of the request processing pipeline.
app.UseMiddleware<MaintenanceMiddleware>();
Modifying the Sample Controller:
Next, modify the Sample Controller as follows:
using Microsoft.AspNetCore.Mvc; namespace ReturnTypeAndStatusCodes.Controllers { [Route("api/[controller]")] [ApiController] public class SampleController : ControllerBase { [HttpGet] public IActionResult GetResource() { return Ok("Service is Available"); } } }
Now, run the application and make a request to the above endpoint. You should receive a 503 Service Unavailable response with the message “Service is under maintenance. Please try again later.” as shown in the below image:
Implementing Retry Logic to Handle the 503 Service Unavailable:
Let us understand this with an example. Handling a 503 Service Unavailable status code involves implementing retry logic in our application. This can be done using various libraries and techniques. One popular library for handling retries in .NET is Polly.
Polly is a resilience and transient-fault-handling library that allows us to define policies such as retries, fallbacks, etc. Let us proceed and understand how we can use Polly to handle 503 status codes when calling an external service in an ASP.NET Core Web API application.
Step 1: Install Polly
First, we need to install Polly via NuGet. You can do this using the Package Manager Console by executing the following command:
Install-Package Polly
Install-Package Microsoft.Extensions.Http.Polly
Step 2: Define the Retry Policy
Define a retry policy using Polly. You can configure it to retry the request a certain number of times with an exponential backoff or fixed delay. So, create a class file named PollyPolicies.cs within the Models folder and then copy and paste the following code. The following code is self-explained, so please read the comment lines for a better understanding:
// Using directive for Polly, a library for handling transient faults. using Polly; // Using directive for Polly's HTTP extensions. using Polly.Extensions.Http; namespace ReturnTypeAndStatusCodes.Models { // Static class to hold Polly policies. public static class PollyPolicies { // Method to define and return a retry policy for HTTP requests. // Defines a static method named GetRetryPolicy that returns an asynchronous policy for HTTP responses. // The policy type is IAsyncPolicy<HttpResponseMessage>, indicating it operates on HttpResponseMessage objects. public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() { // Define a retry policy for handling transient HTTP errors and specific status codes. return HttpPolicyExtensions //Starts defining a policy to handle transient HTTP errors. //This includes network failures and HTTP 5xx status codes, which are considered transient and retryable. // Specifically includes status codes 500(Internal Server Error), 502(Bad Gateway), 503(Service Unavailable), and 504(Gateway Timeout). .HandleTransientHttpError() //Adds an additional condition to the policy, specifying that the policy should also handle responses with a 503 Service Unavailable status code. //This allows the policy to retry the request if it receives a 503 status code. //.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable) //.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.InternalServerError) //A function that determines the delay between retries. //It uses exponential backoff, meaning the delay increases exponentially with each retry attempt //(1 second for the first retry, 2 seconds for the second retry, and 4 seconds for the third retry). .WaitAndRetryAsync( 3, // Retry the request up to 3 times. retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) ); } } }
Customizing Retry Logic
You can customize the retry logic to suit your needs, such as:
- Retry Count: Change the number of retries.
- Backoff Strategy: Use a fixed delay instead of exponential backoff.
- Retry on Specific Status Codes: Add more status codes to the retry condition.
Step 3: Configure HttpClient with Polly
We need to configure HttpClient with Polly policies in the Program.cs file. So, modify the Program.cs class file as follows. Please focus on the comment lines for a better understanding. Here, you will see the error for IMyService and MyService. In the next step, we will implement the service.
using ReturnTypeAndStatusCodes.Models; namespace ReturnTypeAndStatusCodes { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // Register HttpClient with Polly retry policy //This registers an HttpClient for the service IMyService with its implementation MyService //in the dependency injection (DI) container. builder.Services.AddHttpClient<IMyService, MyService>() // This method adds a policy handler to the HttpClient. // It specifies that the HttpClient should use the retry policy defined in the PollyPolicies.GetRetryPolicy method. .AddPolicyHandler(PollyPolicies.GetRetryPolicy()); //PollyPolicies.GetRetryPolicy(): A static method in the PollyPolicies class that returns a retry policy. //This policy determines how the HttpClient should handle transient errors and specific HTTP status codes (such as 503 Service Unavailable). var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); } } }
Step 4: Implement the Service
Implement the service that calls the external API. Inject the configured HttpClient into your service. So, create a class file named MyService.cs within the Models folder and then copy and paste the following code. The following code is self-explained, so please read the comment lines for a better understanding:
namespace ReturnTypeAndStatusCodes.Models { // Define an interface to abstract the service. public interface IMyService { // Method to get external data asynchronously. Task<string> GetExternalDataAsync(); } // Implementation of the IMyService interface. public class MyService : IMyService { // Readonly field to hold the HttpClient instance. private readonly HttpClient _httpClient; // Constructor to inject the HttpClient instance. public MyService(HttpClient httpClient) { // Assign the injected HttpClient to the readonly field. _httpClient = httpClient; } // Implementation of the GetExternalDataAsync method. public async Task<string> GetExternalDataAsync() { // Send an HTTP GET request to the specified URL. // Here, we are using the Demo URL https://httpstat.us/503 to return 503 HTTP Response var response = await _httpClient.GetAsync("https://httpstat.us/503"); // Check if the response status code indicates success. if (response.IsSuccessStatusCode) { // Read the response content as a string and return it. return await response.Content.ReadAsStringAsync(); } else if (response.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable) { //Throw 503 Exception throw new HttpRequestException("Service is temporarily unavailable.", null, System.Net.HttpStatusCode.ServiceUnavailable); } else { // Throw an exception if the request failed, including the status code in the message. throw new HttpRequestException($"Request failed with status code: {response.StatusCode}"); } } } }
Step 5: Use the Service in Your Controller
Inject the service into your controller and use it to call the external API. So, modify the Sample Controller as follows:
using Microsoft.AspNetCore.Mvc; using ReturnTypeAndStatusCodes.Models; namespace ReturnTypeAndStatusCodes.Controllers { [Route("api/[controller]")] [ApiController] public class SampleController : ControllerBase { // Readonly field to hold the IMyService instance. private readonly IMyService _myService; // Constructor to inject the IMyService instance. public SampleController(IMyService myService) { // Assign the injected service to the readonly field. _myService = myService; } // HTTP GET method to handle GET requests to the controller's route. [HttpGet] public async Task<IActionResult> GetExternalData() { try { // Uses the service to call the external API and handles exceptions. var data = await _myService.GetExternalDataAsync(); return Ok(data); // Return the data with a 200 OK status code. } catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable) { // Catch block to handle 503 Service Unavailable exceptions. var customResponse = new { Code = 503, Message = "Service is temporarily unavailable. Please try again later.", }; return StatusCode(503, customResponse); } catch (Exception) { // Catch block to handle any other exceptions. var customResponse = new { Code = 500, Message = "An internal server error occurred. Please try again later.", }; return StatusCode(500, customResponse); } } } }
Now, access the above endpoint, and you should get 503 Service Unavailable HTTP Response.
How to Troubleshoot 503 HTTP Status Code in ASP.NET Core Web API
To Troubleshoot 503 HTTP Status Code in ASP.NET Core Web API, you need to check the following:
- Check Server Load: Monitor server performance metrics (CPU, memory, and network usage) to identify if the server is under heavy load. Implement rate limiting and load balancing to manage incoming requests better. Use tools like Performance Monitor, Azure Monitor, or AWS CloudWatch to track server performance. Scale up or out your server resources if needed.
- Maintenance Mode: Use a maintenance page or message to inform clients about planned maintenance. Use a status page to keep users informed about the current status of your services.
- Dependency Issues: Check the status of all dependent services, such as databases, third-party APIs, and other microservices. Ensure all services are operational and not undergoing maintenance.
- Review Application Logs: Check the application logs for any errors or warnings that might indicate issues. Use logging frameworks like Serilog, NLog, or the built-in ASP.NET Core logging to capture detailed information.
- Retry Mechanism: Implement retry logic in your application to handle transient errors.
- Load Balancing: Use load balancers to distribute traffic across multiple servers. Ensure the load balancer is configured correctly.
In the next article, I will discuss How to Return 504 Gateway Timeout HTTP Status Code in ASP.NET Core Web API with Examples. In this article, I try to explain How to Return 503 Service Unavailable HTTP Status Code in ASP.NET Core Web API with Examples, and I hope you enjoy this article “503 Service Unavailable HTTP Status Code in ASP.NET Core Web API”.
Implementing Retry Logic to Handle the 503 Service Unavailable.
is heavy.need more explanation.