Search code examples
asp.net-corerazor-pagesasp.net-core-identityasp.net-core-7.0

Separate status code pages in ASP.NET Core Razor Pages


I'm using ASP.NET Core Razor Pages with Identity. I use the StatusCodePages middleware in the standard way:

app.UseStatusCodePagesWithReExecute("/Error", "?statusCode={0}");

In that razor page, I can switch on the status code to render different content for 401, 403, 404 and "other" (all other codes in range 400..599). However that gets messy; I prefer separate pages.

So instead of this:

  • /Pages/Error.cshtml

I want this:

  • /Pages/401.cshtml
  • /Pages/403.cshtml
  • /Pages/404.cshtml
  • /Pages/400_599.cshtml

Is that possible?

Ugly workarounds which I already know about:

  • I could use the URL template "/Error/{0}", but that's impractical: I'd have to define a separate page for every code in the range 400..599. I definitely cannot do this.
  • In the "/Pages/Error.cshtml.cs" page model class I could redirect to different pages based on the status code. I prefer not to do this, I suspect it's bad for SEO.
  • For the "/Error" endpoint I could use an MVC controller with views (instead of Razor Pages); the action method could return the appropriate view. Not a bad solution, but adds unnecessary complexity; I prefer a Razor Pages approach.

Solution

  • I want this:

    /Pages/401.cshtml /Pages/403.cshtml /Pages/404.cshtml /Pages/400_599.cshtml Is that possible?

    Of course you can, just create the page in Pages folder like below: enter image description here

    Then use app.UseStatusCodePagesWithReExecute("/{0}") in Program.cs:

    app.UseStatusCodePagesWithReExecute("/{0}");
    app.UseExceptionHandler("/500");
    
    //app.UseDeveloperExceptionPage();
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapRazorPages();
    
    app.Run();
    

    For the catch-all page, you can maitain the Error Pages like below:

    @page "/Error/{statusCode}"
    @model ErrorModel
    @{
        var statusCode = HttpContext.Request.RouteValues["statusCode"];
    
    }
    @switch (statusCode)
    {
        case "400":
            <h1>BadRequest</h1>
            <p>You send wrong model to this resource.</p>
            break;
        case "401":
            <h1>Unauthorized</h1>
            <p>You are not authorized to this resource.</p>
            break;
        case "403":
            <h1>Forbidden</h1>
            <p>You don't have permission to this resource.</p>
            break;
        case "404":
            <h1>Not Found</h1>
            <p>The resource you are looking for could not be found.</p>
            break;
        default:
            <h1>Error @(statusCode)</h1>
            <p>An error occurred while processing your request.</p>
            break;
    }
    

    Program.cs:

     app.UseStatusCodePagesWithReExecute("/Error/{0}");
     app.UseExceptionHandler("/Error/500");