Dennis
Dennis

Reputation: 37780

Razor custom error page ignores it's OnGet handler

There is custom error page:

public sealed class ErrorModel : PageModel
{
    public ErrorModel()
    {
       // app stops at breakpoint inside ctor
    }

    public IActionResult OnGet()
    {
        // app doesn't stop here, why?

        // this is for debugging purposes only
        return BadRequest();
    }
}

and its view:

@page
@model ErrorModel

@if (Model != null)
{
    <p>
        The error page.
    </p>
}

Page is registered in usual way:

app.UseExceptionHandler("/Error");

When application redirects to error page, it stops on breakpoints inside page constructor and page view, but ignores code inside OnGet. Since app doesn't call my OnGet, page renders without any useful data I fill inside OnGet.

All breakpoints are enabled - I'm debugging actual code.

Any idea what's happening and how to solve this?

UPD

I've reduced the page model code and the view. When app stops at this line:

@if (Model != null)

the call stack is:

Portal.App.Views.dll!Portal.Pages.Pages_Error.ExecuteAsync() Line 4 C# Microsoft.AspNetCore.Mvc.RazorPages.dll!Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAdapter.ExecuteAsync() Unknown Microsoft.AspNetCore.Mvc.Razor.dll!Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(Microsoft.AspNetCore.Mvc.Razor.IRazorPage page, Microsoft.AspNetCore.Mvc.Rendering.ViewContext context) Unknown Microsoft.AspNetCore.Mvc.Razor.dll!Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(Microsoft.AspNetCore.Mvc.Razor.IRazorPage page, Microsoft.AspNetCore.Mvc.Rendering.ViewContext context, bool invokeViewStarts) Unknown Microsoft.AspNetCore.Mvc.Razor.dll!Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(Microsoft.AspNetCore.Mvc.Rendering.ViewContext context) Unknown Microsoft.AspNetCore.Mvc.ViewFeatures.dll!Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext, string contentType, int? statusCode) Unknown Microsoft.AspNetCore.Mvc.RazorPages.dll!Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageResultExecutor.ExecuteAsync(Microsoft.AspNetCore.Mvc.RazorPages.PageContext pageContext, Microsoft.AspNetCore.Mvc.RazorPages.PageResult result) Unknown Microsoft.AspNetCore.Mvc.RazorPages.dll!Microsoft.AspNetCore.Mvc.RazorPages.PageResult.ExecuteResultAsync(Microsoft.AspNetCore.Mvc.ActionContext context) Unknown

So, app executes PageResult. Where this result comes from?

UPD 2

This looks like authentication issue. When user is authenticated, everything works as expected. But for non-authenticated users my OnGet isn't called. ErrorModel hasn't Authorize attribute. How authentication affects this?

I've no any custom authentication config, so, I assume defaults are used:

    private void ConfigureMvcServices(IServiceCollection services)
    {
        services
            .AddMvc()
            // another services;
    }

Error page is in the Pages folder - Pages/Error.

Besides, if user is not authenticated, and page requires authentication, 401 must be returned, isn't it?

Upvotes: 1

Views: 1730

Answers (2)

Dennis
Dennis

Reputation: 37780

I've figured it out. The pitfall is here:

To configure a custom error handling page for the Production environment, use the Exception Handling Middleware. The middleware:

  • Catches and logs exceptions.
  • Re-executes the request in an alternate pipeline for the page or controller indicated. The request isn't re-executed if the response has started.

"Re-executes" means, literally, that if exception was raised in GET handler, middleware calls error page's OnGet. If it was raised in POST handler, middleware calls OnPost, etc:

public class ErrorModel : PageModel
{
    public ErrorModel()
    {
    }

    public void OnGet()
    {
        // This executes when exception was in OnGet
    }

    public void OnPost()
    {
        // This executes when exception was in OnPost
    }

    // ...
}

In my case there was a GET request on page with authentication, and POST one on non-authenticated page, so here's the difference in behavior.

Upvotes: 4

bzLoLIp0p
bzLoLIp0p

Reputation: 91

Have you enabled custom errors in the web config. Like this:

<httpErrors errorMode="Custom" existingResponse="Replace">
  <clear />
  <error statusCode="500" path="/Error" responseMode="ExecuteURL" />
</httpErrors>

Upvotes: 0

Related Questions