dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.35k stars 9.99k forks source link

ExceptionHandlerMiddleware returns error page when exception occurs in the RazorPageMiddleware only #31717

Closed yvztzn closed 3 years ago

yvztzn commented 3 years ago

Describe the bug

ExceptionHandlerMiddleware responds with an error page if an exception occurs in a Razor page but does not if the exception occurs in some non-Razor middleware. Am I missing something?

To Reproduce

mkdir exceptionhandler
cd .\exceptionhandler\
dotnet new webapp
code .\Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        // because of simplicity
        app.UseExceptionHandler("/Error");
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    // could be any middleware. for example authentication middleware with OIDC authentication handler which
    // has wrong/expired client secret in appsettings.json.
    app.Use((context, next) =>
    {
        if ((DateTime.Now.Second / 3) % 2 == 0)
        {
            throw new Exception("Bad timing!");
        }

        return next();
    });

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
code .\Pages\Index.cshtml.cs
public void OnGet()
{
    if ((DateTime.Now.Second / 3) % 4 == 1)
    {
        throw new Exception("Bad timing in page!");
    }
}

Further technical details

Tratcher commented 3 years ago

UseExceptionHandler changes the request path and re-executes the middleware pipeline. Your exception throwing middleware will be hit again on the re-execution run and potentially throw a new exception.

If middleware exceptions are a common problem for you then you can use a different overload that creates an isolated pipeline for error handling. https://github.com/dotnet/aspnetcore/blob/c925f99cddac0df90ed0bc4a07ecda6b054a0b02/src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerExtensions.cs#L59

yvztzn commented 3 years ago

UseExceptionHandler changes the request path and re-executes the middleware pipeline.

I knew that. But I was not clever enough to see that the /Error requests passes the same middleware which throws the exception. Thank you