371

Back in RC1, I would do this:

[HttpPost]
public IActionResult Post([FromBody]string something)
{    
    try{
        // ...
    }
    catch(Exception e)
    {
         return new HttpStatusCodeResult((int)HttpStatusCode.InternalServerError);
    }
}

In RC2, there no longer is HttpStatusCodeResult, and there is nothing I can find that lets me return a 500 type of IActionResult.

Is the approach now entirely different for what I'm asking? Do we no longer try-catch in Controller code? Do we just let the framework throw a generic 500 exception back to the API caller? For development, how can I see the exact exception stack?

13 Answers 13

425

From what I can see there are helper methods inside the ControllerBase class. Just use the StatusCode method:

[HttpPost]
public IActionResult Post([FromBody] string something)
{    
    //...
    try
    {
        DoSomething();
    }
    catch(Exception e)
    {
         LogException(e);
         return StatusCode(500);
    }
}

You may also use the StatusCode(int statusCode, object value) overload which also negotiates the content.

Sign up to request clarification or add additional context in comments.

4 Comments

doing this, we lose the CORS headers, so errors are hidden from browser clients. V frustrating.
@bbsimonbb Internal errors should be hidden from clients. They should be logged for developers.
Developers should have, have traditionally enjoyed, the prerogative to choose what level of error information is returned.
better: return StatusCode(StatusCodes.Status500InternalServerError);
284

You could use Microsoft.AspNetCore.Mvc.ControllerBase.StatusCode and Microsoft.AspNetCore.Http.StatusCodes to form your response, if you don't wish to hardcode specific numbers.

return  StatusCode(StatusCodes.Status500InternalServerError);

UPDATE: Aug 2019

Perhaps not directly related to the original question but when trying to achieve the same result with Microsoft Azure Functions I found that I had to construct a new StatusCodeResult object found in the Microsoft.AspNetCore.Mvc.Core assembly. My code now looks like this;

return new StatusCodeResult(StatusCodes.Status500InternalServerError);

4 Comments

Great one, avoids any hardcoded parts/"magic numbers". I've used StatusCode((int)HttpStatusCode.InternalServerError) before but I like yours better.
One thing I didn't consider at the time is that it makes the code more readable, coming back to it you know what error number 500 relates to, it's right there in the code. Self documenting :-)
I can't imagine internal server error (500) changing anytime soon.
awesome. this also really cleans up my swagger attributes. ex: [ProducesResponseType(StatusCodes.Status500InternalServerError)]
127

If you need a body in your response, you can call

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

This will return a 500 with the response object.

6 Comments

If you don't want to create a specific response object type: return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" }); And of course, you can add as descriptive a message as you like, and other elements as well.
Lol, you can't return a reponse body with a 500. It doesn't work.
No, you can. Ive just tested it. @JSON
@DavidMcEleney No you can't. Not in a .net http response.
You 100% can. Perhaps you are on .NET Framework instead of .NET Core or .NET?
@JSON try it yourself using the above example. i'm not arguing with you anymore. it works. end of.
49

For aspnetcore-3.1, you can also use Problem() like below;

https://learn.microsoft.com/en-us/aspnet/core/web-api/handle-errors?view=aspnetcore-3.1

 [Route("/error-local-development")]
public IActionResult ErrorLocalDevelopment(
    [FromServices] IWebHostEnvironment webHostEnvironment)
{
    if (webHostEnvironment.EnvironmentName != "Development")
    {
        throw new InvalidOperationException(
            "This shouldn't be invoked in non-development environments.");
    }

    var context = HttpContext.Features.Get<IExceptionHandlerFeature>();

    return Problem(
        detail: context.Error.StackTrace,
        title: context.Error.Message);
}

2 Comments

the same is true for NET5
I did return Results.Problem(...)
28

A better way to handle this as of now (1.1) is to do this in Startup.cs's Configure():

app.UseExceptionHandler("/Error");

This will execute the route for /Error. This will save you from adding try-catch blocks to every action you write.

Of course, you'll need to add an ErrorController similar to this:

[Route("[controller]")]
public class ErrorController : Controller
{
    [Route("")]
    [AllowAnonymous]
    public IActionResult Get()
    {
        return StatusCode(StatusCodes.Status500InternalServerError);
    }
}

More information here.


In case you want to get the actual exception data, you may add this to the above Get() right before the return statement.

// Get the details of the exception that occurred
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();

if (exceptionFeature != null)
{
    // Get which route the exception occurred at
    string routeWhereExceptionOccurred = exceptionFeature.Path;

    // Get the exception that occurred
    Exception exceptionThatOccurred = exceptionFeature.Error;

    // TODO: Do something with the exception
    // Log it with Serilog?
    // Send an e-mail, text, fax, or carrier pidgeon?  Maybe all of the above?
    // Whatever you do, be careful to catch any exceptions, otherwise you'll end up with a blank page and throwing a 500
}

Above snippet taken from Scott Sauber's blog.

4 Comments

this is awesome, but how can i log the exception that was thrown?
@redwards510 Here's how you do it: scottsauber.com/2017/04/03/… I'll update my answer to reflect it, since it's a very common use case 😊
@gldraphael We are currently using Core 2.1. Scott's blog is great, but I'm curious if using IExceptionHandlerPathFeature is currently the recommended best practices. Perhaps creating custom middleware is better?
@Pavel we are using the ExceptionHandler middleware here. You may, of course, roll your own or extend it as you see fit. Here's the link to the sources. EDIT: See this line for IExceptionHandlerPathFeature .
27

How about creating a custom ObjectResult class that represents an Internal Server Error like the one for OkObjectResult? You can put a simple method in your own base class so that you can easily generate the InternalServerError and return it just like you do Ok() or BadRequest().

[Route("api/[controller]")]
[ApiController]
public class MyController : MyControllerBase
{
    [HttpGet]
    [Route("{key}")]
    public IActionResult Get(int key)
    {
        try
        {
            //do something that fails
        }
        catch (Exception e)
        {
            LogException(e);
            return InternalServerError();
        }
    }
}

public class MyControllerBase : ControllerBase
{
    public InternalServerErrorObjectResult InternalServerError()
    {
        return new InternalServerErrorObjectResult();
    }

    public InternalServerErrorObjectResult InternalServerError(object value)
    {
        return new InternalServerErrorObjectResult(value);
    }
}

public class InternalServerErrorObjectResult : ObjectResult
{
    public InternalServerErrorObjectResult(object value) : base(value)
    {
        StatusCode = StatusCodes.Status500InternalServerError;
    }

    public InternalServerErrorObjectResult() : this(null)
    {
        StatusCode = StatusCodes.Status500InternalServerError;
    }
}

2 Comments

Thank you we have a class library and it has a method that returns ActionResult so regular solutions to return StatusCode(500) don't work in this case and having a custom ObjectResult is what we needed.
Amazing this wasn't included in the options but oh well. simple enough. thanks!
22
return StatusCode((int)HttpStatusCode.InternalServerError, e);

Should be used in non-ASP.NET contexts (see other answers for ASP.NET Core).

HttpStatusCode is an enumeration in System.Net.

Comments

12

You can use the following code:

return StatusCode(500,"message");

Here is a sample code:

public Task<IActionResult> GetById(int courseId)
{
  try
  {
     var result = await _mediator.Send(new GetCourse(courseId));
     return Ok(result);
  }
  catch(Exception ex) 
  {
     return StatusCode(500,ex.Message);
  }
}

Comments

11

The built-in Problem()-method of Microsoft.AspNetCore.Mvc will return a "problem detail"-response based on RFC 7807 (in ASP.NET Core 3.0 and later). It will always return status-code 500 as long as no other status is explicitly set.

[HttpPost]
public IActionResult Post([FromBody] string value)
{
    try
    {
        // ...
    }
    catch (Exception ex)
    {
        return Problem(
            //all parameters are optional:
            //detail: "Error while processing posted data."; //an explanation, ex.Stacktrace, ...
            //instance: "/city/London"  //A reference that identifies the specific occurrence of the problem
            //title: "An error occured." //a short title, maybe ex.Message
            //statusCode: StatusCodes.Status504GatewayTimeout, //will always return code 500 if not explicitly set
            //type: "http://example.com/errors/error-123-details"  //a reference to more information
            );
    }           
}

Without setting any parameters it will return this:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.6.1",
    "title": "An error occured while processing your request.",
    "status": 500,
    "traceId": "|fadaed95-4d06eb16160e4996."
}

More infos about "problem details" parameters: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.problemdetails?view=aspnetcore-5.0

Comments

9

When you want to return a JSON response in MVC .Net Core You can also use:

Response.StatusCode = (int)HttpStatusCode.InternalServerError;//Equals to HTTPResponse 500
return Json(new { responseText = "my error" });

This will return both JSON result and HTTPStatus. I use it for returning results to jQuery.ajax().

1 Comment

I had to use return new JsonResult ... but otherwise worked great.
4

In Microsoft.AspNetCore.Mvc ControllerBase there is a method named Problem that specifically can handle 500 Errors. It returns Object result with Problem details; such as StatusCode, type, instance, detail.

All you have to do is just call it.

return Problem();

1 Comment

To anyone who wonders how to unit test it see stackoverflow.com/q/60740134/9547346
2

when using an error filter, this would be handy to return a 500 from an ASP.NET API,

return new ObjectResult(new { /* any object */ })
{
    StatusCode = StatusCodes.Status500InternalServerError
};

Comments

1

For API Responses (using net core), I have tried this and seems that it is working fine:

var err = Content(JsonConvert.SerializeObject(response, SerializerSettings), "application/x-javascript", contentEncoding: System.Text.Encoding.UTF8);
err.StatusCode = StatusCodes.Status500InternalServerError;
return err;

You just need to create a response object first, then respond this. Doing this, we can retain the content type, encoding, and add a status code as well.

Just adding this for future reference to anybody who is stuck as well and wants a quick and easy way to do this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.