Home Ask Login Register

Developers Planet

Your answer is one click away!

John February 2016

MVC 6 WebAPI returning html error page instead of json version of exception object

I am calling an api endpoint in an MVC 6 WebAPI:

POST http://localhost:57287/mytestapi/testentity/ HTTP/1.1
Accept: application/json
X-APIKey: 00000000-0000-0000-0000-000000000000
Content-Type: application/json; charset=utf-8
Host: localhost:57287
Content-Length: 1837
Expect: 100-continue
Connection: Keep-Alive

In the body I have json serialized test entity.

I have a bug in my entity controller code and the api is returning a 500 response 'Server Error' I know what the bug is an will fix it, however the issue I need some help with is that the API is returning HTML instead of the json serialized exception object - Json is what I expect: it's what the old webapi would return. I have ported the coded from an old test project that I know works.

So why is MVC 6 WebAPI returning html rather than json? Is there some configuration I need to do?

EDIT: I added Accept: application/json to headers as suggested by @danludwig, however this did not resolve the issue, I still got an html error page back.

I looked at my StartUp.cs and found:

if (env.IsDevelopment())
{
    //app.UseBrowserLink();
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Home/Error");
}

in the ConfigureApp method. I tested with app.UseDeveloperExceptionPage(); commented out. This prevented the return of the html error page in the api response body, however I am still not getting the json serialised exception object.

Answers


Daniel J.G. February 2016

The ExceptionHandlerMiddleware configured when using UseExceptionHandler("Home/Error") does not include any support for JSON. It will just return the error html page. The same can be said when using UseDeveloperExceptionPage.

As far as I know you will need to add yourself some piece of code that will handle errors and return a json.

  • 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 = (int)System.Net.HttpStatusCode.InternalServerError;
                context.Result = jsonResult;
            }
        }
    }
    
    services.AddMvc(opts => 
    {
        //Here it is being added globally. 
        //Could be used as attr 


John February 2016

I found a cheap hack to get what I want by adding this to the Startup Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        // Simple error page to avoid a repo dependency.
        app.Use(async (context, next) =>
        {
            try
            {
                await next();
            }
            catch (Exception ex)
            {
                if (context.Response.HasStarted)
                {
                    throw;
                }
                context.Response.StatusCode = 500;
                context.Response.ContentType = "application/json";
                var json = JToken.FromObject(ex);
                await context.Response.WriteAsync(json.ToString());
            }
        });
 //Rest of configure method omitted for brevity.
}

Post Status

Asked in February 2016
Viewed 2,578 times
Voted 10
Answered 2 times

Search




Leave an answer


Quote of the day: live life