2

Building an ASP.Net Core (V2) MVC Site.

We are using API Versions for this.

The site has controllers delivering MVC Razor Views as well as API-style Json responses.

I am trying to use the UseExceptionHandler() method, as shown below.

When i hit an exception in one of my actions, the action gets executed again and then a blank page shown. The browser console is free from any errors too. Finally, my error action is never hit.

I have a custom exception filter in place for the API controllers, also shown below. I have commented this out, figuring it was interfering. This didn't resolve any issue.

Where am I going wrong? And how can i have my custom error page hit when there is an exception.

Exception Handler Method - This results in "/v1.0/home/error"

app.UseExceptionHandler($"/v{appSettings.Value.APIVersion}/home/error");

I have also tried, after reading that this is supposed to be the path to a view

app.UseExceptionHandler("/error");

and

app.UseExceptionHandler("/views/home/error");

The Error Action

 [HttpGet("error")]
 public IActionResult Error()
 {
      var exception = HttpContext.Features.Get<IExceptionHandlerFeature>();
      ViewData["statusCode"] = HttpContext.Response.StatusCode;
      ViewData["message"] = exception.Error.Message;
      return View();
 }

The Exception Filter (currently commented out in the startup.cs)

public override void OnException(ExceptionContext context)
 {
       if (context.HttpContext.Request.Path.Value.Contains("/api"))
       {
             // Set the response
             context.ModelState.GroupErrorsIntoKey("ErrorArray");
             context.ModelState.AddModelError("ErrorArray", context.Exception.Message);
             context.Result = new BadRequestObjectResult(context.ModelState);
         }
 }
4
  • Seems like a routing issue. Try to access the URL you put in UseExceptionHandler() directly. Does Error() action hit? Commented Mar 7, 2018 at 14:20
  • I can hit the route just fine, when entered into the browser. I have since changed it to use UseStatusCodePagesWithReExecute() - this works with 404 but gives a blank page on an exception; so very frustrating! Commented Mar 7, 2018 at 16:22
  • I can't reproduce your problem. Probably you have some issues with startup configuration. Is it possible to put test project for which the problem reproduces on github? Commented Mar 7, 2018 at 18:34
  • @CodeFuller thanks for looking. I'm going to delete this question and re-ask with different detail. I'm finding results to be very inconsistent. I've since implemented a custom exception handler. Commented Mar 7, 2018 at 18:40

1 Answer 1

4

I have a similar mixed Razor/API design and ran into the same issue. Apparently, it is happening due to a change in the action resolution process in 2.0. This issue "Problems using UseExceptionHandler()" describes it in great detail and offers workarounds.

To quote the explanation offered by Microsoft/aspnet-api-versioning developer (from the link above):

"This issue is happening due to a change in the action resolution process in 2.0, which fixed a bug that affected some, but not all, in 1.0. The ASP.NET Core design expects that the pipeline stops on the first action match. If there are no actions, the error path is taken, which is usually 404. This is combined by the fact that the platform might call the action selector multiple times. The consequence of this behavior is that API versioning cannot make its decision until all possible routes have been considered. The only way to know that is to have a catch all route that is executed at the end. Unfortunately, this causes some other end of route behaviors to behave unexpectedly as you are seeing. As you can imagine, it would be highly inefficient to re-evaluate the entire route tree on every request. To optimize things, API versioning tracks whether the versioning policy has been evaluated at least once for a given route. Once it has, it can make the final decision much earlier in the pipeline. This is what is resulting the behavior where you first see things not do what you expected and then subsequent calls are ok."

The workaround is to configure UseExceptionHandler() a bit differently. Here is what worked for me:

app.UseExceptionHandler(new ExceptionHandlerOptions
{
  ExceptionHandler = async context =>
  {
     var exception = context.Features.Get<IExceptionHandlerFeature>().Error;

     if (!context.Request.Path.StartsWithSegments(new PathString("/api"), StringComparison.OrdinalIgnoreCase))
     {
        context.Response.Redirect("Error");
     }
     else
     {
        context.Response.ContentType = "application/json";
        var response = new
        {
            Error = exception.Message
        };
        await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
     }
   }
});
Sign up to request clarification or add additional context in comments.

2 Comments

Fixed the answer. It was a really hard to find information for a very specific use case. Downvoting will not serve anyone looking for it any good.

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.