4

I have ASP .NET Core 3.1 web site that uses razor pages, but also has single controller that inherits from ASP .NET Core Controller class. The controller handles payload and then redirects to one of the razor pages when successful. I'm noticing that when there is unhandled exception in the controller, browser displays HTTP 400 - Bad Request error, but I want the controller to simply use the exception handler I already defined, which looks like this:

if (env.IsDevelopment())
   app.UseDeveloperExceptionPage();
else
   app.UseExceptionHandler("/Error");

In the above, the "/Error" path is razor page. In non-development mode, controller doesn't use my exception handler and just displays HTTP 400 - Bad Request browser error.

I managed to get it to work with exception filter class where inside OnException() method, I log the error and manually redirect to "/Error" page. The exception filter looks like this:

private class CustomExceptionFilter : IExceptionFilter
{
    private readonly IWebHostEnvironment hostingEnvironment;

    private readonly ILogger<CustomExceptionFilter> logger;

    public CustomExceptionFilter(IWebHostEnvironment hostingEnvironment, ILogger<CustomExceptionFilter> logger)
    {
        this.hostingEnvironment = hostingEnvironment;
        this.logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        if (this.hostingEnvironment.IsDevelopment())
        {
            return;
        }

        this.logger.LogError(context.Exception, string.Empty);
        context.Result = new RedirectToPageResult("/Error");
    }

Then, I defined [TypeFilter(typeof(CustomExceptionFilter))] on the controller itself. Everything appears to be working, but it seems like a lot of moving parts. Is this the only way to do it or maybe I'm missing something?

Here is Startup code:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseForwardedHeaders();

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

        app.UseHsts(options => options.MaxAge(365).IncludeSubdomains());
    }

    app.UseStaticFiles();

    app.UseCookiePolicy();

    app.UseXRobotsTag(options => options.NoIndex().NoFollow());

    app.UseXfo(options => options.SameOrigin());

    app.UseXXssProtection(options => options.EnabledWithBlockMode());

    app.UseXContentTypeOptions();

    app.UseNoCacheHttpHeaders();

    app.UseRedirectValidation();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapRazorPages();
    });
}

Thanks in advance!

3
  • Is there anything in your web.config or Startup.cs (or similar) files that might be interfering with your code? Commented Apr 26, 2020 at 1:52
  • I couldn't find anything out of the ordinary. See the startup code in my post. Commented Apr 26, 2020 at 14:53
  • Sounds like you are trying to use this method? learnrazorpages.com/configuration/global-error-handling Commented Jun 28, 2023 at 15:41

3 Answers 3

0

If you want to go with app.UseExceptionHandler("/Error"); then your Razor Page might look something like following.

Error.cshtml

@page "/Error"
@model Pages.Error

@{
  Layout = null;
}

<h1>An unexpected error occured. Status Code: @HttpContext.Response.StatusCode</h1>

Error.cshtml.cs

public class Error : PageModel
  {
    private readonly ILogger<Error> _logger;

    public Error(ILogger<Error> logger)
    {
      _logger = logger;
    }

    public void OnGet()
    {
      var exceptionHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>();
      if(exceptionHandlerFeature?.Error != null)
        _logger.LogError($"This is a message from logger: {exceptionHandlerFeature.Error.Message}");
    }
  }
Sign up to request clarification or add additional context in comments.

2 Comments

I already have public async Task OnGetAsync() method in my error page, but the redirect to the error page doesn't happen when unhandled exception occurs my controller.
Here it is: public async Task OnGetAsync() { await this.HttpContext.SignOutAsync(); } But actually that method wasn't getting fired in unhandled exceptions. It was the OnPostAsync() that was getting fired. Also, I finally figured it out why I was getting HTTP 400 error. See my answer -- it was due to anti forgery token.
0

I finally figured out what happened. My controller was handling POST method. When any unhandled exceptions occurred, the code would attempt to run my exception handler. Because of the POST, it would post to my exception handler page, but that would fail because of AntiForgery request validation token missing, so it issue HTTP 400 - Bad Request, which I have seen before in my pages that use jQuery with AJAX if token was missing. So basically, to solve this issue, I'm going to add [IgnoreAntiforgeryToken] attribute to my razor error page handler.

Comments

-2

Try this app.UseExceptionHandler("/Home/Error"); Reason for working please check your HomeController there should be default below action method

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
  return View(new ErrorViewModel { RequestId = Activity.Current?.Id ??   HttpContext.TraceIdentifier });
}

If it is not there you can create this method in any of your controller and provide path of that controller e.g. app.UseExceptionHandler("/YourController/Error");

1 Comment

I already have Error razor page and already use app.UseExceptionHandler("/Error")

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.