ASP.NET Core – How to return a 500 response

The simplest way to return a 500 response is to use the Problem() helper method, like this:

[Route("[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
	[HttpPost]
	public IActionResult Save(Movie movie)
	{
		return Problem();
	}
}
Code language: C# (cs)

This method returns an ObjectResult with status code 500 and a generic error message, which gets serialized to JSON and returned in the response body. The response looks like this:

500 - Internal Server Error

Content-Type: application/problem+json

Body:
{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.6.1",
    "title": "An error occured while processing your request.",
    "status": 500,
    "traceId": "0HMDLK1UAAP5O:00000002"
}Code language: plaintext (plaintext)

The ControllerBase class has many helper methods like Problem() that simplify returning responses. These have several optional parameters that you can use to customize the response. Internally, these helper methods return result objects. You can build and return these result objects yourself if you want. Sometimes that might even be necessary, such as if there’s not a helper method for what you’re trying to return.

In this article, I’ll show how to customize the 500 response, and then I’ll show examples of returning other response status codes (such as 400 – Bad Request).

Customizing the 500 response

The Problem() method has the following signature:

public ObjectResult Problem(string detail = null, 
	string instance = null, 
	int? statusCode = null, 
	string title = null, 
	string type = null);
Code language: C# (cs)

There are several optional parameters. You can customize the response by using these parameters, as I’ll show below.

Note: When you don’t pass in values for these parameters, it’ll use default values. This can lead to surprising response values. I recommend double-checking the responses during development. You can completely control what it returns if you need to.

Change the status code

The client can get the status code indicating that it’s an error response and deal with it appropriately. To change the status code, pass in a value for the statusCode parameter. For example, let’s say you want to return 501 – Not Implemented:

using Microsoft.AspNetCore.Http;

[Route("[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
	[HttpPost]
	public IActionResult Save(Movie movie)
	{
		return Problem(statusCode: StatusCodes.Status501NotImplemented);
	}
}
Code language: C# (cs)

This generates the following response:

501 - Not Implemented

Content-Type: application/problem+json

Body:
{
    "status": 501,
    "traceId": "0HMDLKL0AFS4D:00000001"
}Code language: plaintext (plaintext)

Note: You can hardcode the status code value (501), use integer constants from Microsoft.AspNetCore.Http.StatusCodes, or use the System.Net.HttpStatusCode enum (which you have to cast to an int).

Change the response body

The response body has several properties in it that you can control through parameters. For example, let’s say you want to add details about the problem:

[Route("[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
	[HttpPost]
	public IActionResult Save(Movie movie)
	{
		return Problem(detail: "Movie doesn't exist");
	}
}
Code language: C# (cs)

This produces the following response. Notice that it added the detail property:

500 - Internal Server Error

Content-Type: application/problem+json

Body:
{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.6.1",
    "title": "An error occured while processing your request.",
    "status": 500,
    "detail": "Movie doesn't exist",
    "traceId": "0HMDLKRP86VKE:00000001"
}
Code language: plaintext (plaintext)

Completely customize the response

The Problem() method sets the content to a ProblemDetails object. The client can read this ProblemDetails JSON to get more information about the error. Let’s say you don’t want any of the ProblemDetails properties. One way to completely customize the response is to use the StatusCode() helper method:

using Microsoft.AspNetCore.Http;

[Route("[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
	[HttpPost]
	public IActionResult Save(Movie movie)
	{
		return StatusCode(StatusCodes.Status500InternalServerError, "Movie doesn't exist");
	}
}
Code language: C# (cs)

This generates the following response:

500 - Internal Server Error

Content-Type: text/plain

Body:
Movie doesn't existCode language: plaintext (plaintext)

Building a response object

The helper methods provided by the ControllerBase class are convenient and simplify building the response. Internally, these mostly just build and return result objects (such as StatusCodeResult). You can build the result objects yourself if you want.

Here’s an example. Let’s say you want to return a 500 response with no content. In this case, you can return a ContentResult and only set the StatusCode.

using Microsoft.AspNetCore.Http;

[Route("[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
	[HttpPost]
	public IActionResult Save(Movie movie)
	{
		return new ContentResult()
		{
			StatusCode = StatusCodes.Status500InternalServerError
		};
	}
}
Code language: C# (cs)

This generates the response:

500 - Internal Server Error

Content-Length: 0Code language: plaintext (plaintext)

There are several result types you can choose from (such as StatusCodeResult, ContentResult, ObjectResult, etc…). I usually pick ContentResult.

Examples of returning other response codes

ControllerBase has many helper methods that simplify returning responses. In this section, I’ll show examples of returning a few different response codes by using the helper methods.

200 – OK

If your method is returning an IActionResult, then you can return a 200 – OK response by using the Ok() helper method:

[Route("[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
	[HttpPost]
	public IActionResult Get(int id)
	{
		var movie = repository.GetMovie(id);
		return Ok(movie);
	}
}
Code language: C# (cs)

This generates the response:

200 - OK

Content-Type: application/json

Body:
{
    "title": "Dune",
    "yearReleased": 2021,
    "score": 9
}Code language: plaintext (plaintext)

400 – Bad Request

To return a 400 – Bad Request response, you can use the BadRequest() helper method:

[Route("[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
	[HttpPost]
	public IActionResult Save(Movie movie)
	{
		return BadRequest();
	}
}
Code language: C# (cs)

This generates the response:

400 - Bad Request

Content-Type: application/problem+json

Body:
{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "Bad Request",
    "status": 400,
    "traceId": "0HMDLM4FOTSV3:00000001"
}Code language: plaintext (plaintext)

With custom content:

return BadRequest(error: new { errorCode=12345 });
Code language: C# (cs)

This generates the response:

400 - Bad Request

Content-Type: application/json

Body:
{
    "errorCode": 12345
}Code language: plaintext (plaintext)

Returning any response code

Not all response codes have their own helper methods (like Problem() for 500) or result objects (like BadRequestResult for 400). When that’s the case, the simplest way to return any response code is to use the StatusCode() helper method, like this:

using Microsoft.AspNetCore.Http;

[Route("[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
	[HttpPost]
	public IActionResult Save(Movie movie)
	{
		return StatusCode(StatusCodes.Status429TooManyRequests);
	}
}
Code language: C# (cs)

This generates the response:

429 - Too Many Requests

Content-Type: application/problem+json

Body:
{
    "status": 429,
    "traceId": "0HMDLMAQ7DNES:00000001"
}Code language: plaintext (plaintext)

You can change the content via the value parameter:

return StatusCode(StatusCodes.Status429TooManyRequests, 
                value: "You've reached your limit for the day");
Code language: C# (cs)

This generates the response:

429 - Too Many Requests

Content-Type: text/plain

Body:
You've reached your limit for the dayCode language: plaintext (plaintext)

Leave a Comment