Returning error string from MVC6/WepApi controller

10,326

Solution 1

You will need to add some piece of code yourself that will handle errors and return a message.

One option is to use an exception filter and add it either globally or on selected controllers, although this approach would only cover exceptions coming from the controller action methods. For example the following filter will return a json object only when the request accept was application/json (Otherwise it would let the exception pass through which for example could be handled by the global error page):

public class CustomJSONExceptionFilter : ExceptionFilterAttribute
{    
    public override void OnException(ExceptionContext context)
    {
        if (context.HttpContext.Request.GetTypedHeaders().Accept.Any(header => header.MediaType == "application/json"))
        {
            var jsonResult = new JsonResult(new { error = context.Exception.Message });
            jsonResult.StatusCode = Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError;
            context.Result = jsonResult;
        }
    }
}

services.AddMvc(opts => 
{
    //Here it is being added globally. 
    //Could be used as attribute on selected controllers instead
    opts.Filters.Add(new CustomJSONExceptionFilter());
});

Another option is You can change the signature to make providing a response more flexible. Then you can handle the error like one normally would and then return a user friendly error message.

public IActionResult Get() {
    try {
        IEnumerable<MyEntity> result;
        //...result populated
       return new HttpOkObjectResult(result);
    } catch (Exception ex) {
        //You should handle the error
        HandleError(ex);//the is not an actual method. Create your own.
        //You could then create your own error so as not to leak
        //internal information.
        var error = new 
            { 
                 message = "Enter you user friendly error message",
                 status = Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError
            };
        Context.Response.StatusCode = error.status;            
        return new ObjectResult(error);
    }
}

Solution 2

Change your method to look like

[HttpGet]
[ResponseType(typeof(IEnumerable<MyEntity>))]
public IHttpActionResult Get()
{
    //when ok
    return Ok(response); // response is your IEnumerable<MyEntity>

    //when error
    throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.WhateverStatusCodeSuitable)
            {
                ReasonPhrase = "your message"
            });

}

Solution 3

Migth be little bit late to anserw but now the best way to get a custom error with a custom code seems to be using StatusCode method.

` [HttpGet("{id}")]
[ProducesResponseType(typeof(IEnumerable<string>), 200)]
[ProducesResponseType(typeof(void), 404)]
public IActionResult Get(int id)
{
    Product product = null;
    if (!this.productRepository.TryGet(id, out product))
    {
        return StatsusCode(500, "NotFound");
    }

    return Ok(product);
}`

Solution 4

Just like you would to keep any program running.

try {
    ...
} catch (Exception e) {
    return errorMessageView;
}

Alternatively you can use the HandleErrorAttribute.

Share:
10,326
NicolasR
Author by

NicolasR

Updated on June 09, 2022

Comments

  • NicolasR
    NicolasR almost 2 years

    The template WebApi controller in MVC6/WebApi implements an action that returns a collection for the Get method like this:

    [HttpGet]
    public IEnumerable<MyEntity> Get()
    {
        //my code to return entities
    }
    

    Assuming that my code to return the result throws an exception, how would I return an error message to the consumer?

    As far as I noticed an exception would result in HTTP 500. This is fine but I would like to give the caller a message telling him what went wrong. Because of the signature of the template action I can not catch the exception and return some Http*** or ObjectResult instance.

  • NicolasR
    NicolasR about 8 years
    Thanks, but I think I wasn't clear enough. I am writing an API so I don't want to return a view. The client should check for Http OK (200) or 500 (internal error). In case the client got 500 he should be able to display an error message. How do I get this error message from the exception handler to the client? Searching for HandleErrorAttribute I found HttpResponseException but this seems not to be supported in MVC 6.
  • will
    will about 8 years
    can you return JSON {'result': 'error', 'status', 500}?
  • NicolasR
    NicolasR about 8 years
    Looks nice but as explained in this post stackoverflow.com/questions/31054012/… HttpResponseException is not available anymore.
  • NicolasR
    NicolasR about 8 years
    Only when I change the return statement but that feels unnatural because the controller template always creates Get actions with returning collections. From what others suggested it looks like the best way is to let the exception fall through and implement a filter or error middleware.
  • NicolasR
    NicolasR about 8 years
    Together with the link that you provided that makes three possible ways to do it. I will see what fits best. I will accept your answer!
  • NicolasR
    NicolasR almost 7 years
    If it were only about found or not found, then ok. But what about all the actual exceptions that happen in realistic scenarios like broken database, unavailable nested services and, not to forget, bugs introduced by programmers. I agree that IActionResult would give me the freedom to return whatever is needed but that would mean that I had to catch exceptions in every controller method just to convert it to something like "An error occurred, please consult..." (as the minimum).
  • Quarkly
    Quarkly almost 7 years
    Whether you like it or not, all those exceptions are turned into HTTP results of one form or another. This, IMO, is just capturing that paradigm rather than giving the illusion that some exception is actually passed back to the client.
  • NicolasR
    NicolasR almost 7 years
    I agree with you about the paradigm and I use code like you posted in most of my methods. On the other side, have a look at the second code snippet in the answer of Nkosi. I really don't want to have that kind of code in each of my controllers. My problem is that the default exception handler only returns code 500 to the client without any error text. That is why I like the CustomExceptionFilter solution.