'ASP.NET Core MVC app can't find error page?

I have an ASP.NET Core 3.1 MVC applications (not a Razor Pages project) and I'm trying to use the exception handling middleware via app.UseExceptionHandle("/error") to handle exceptions.

It seems like I could create my own MVC error controller to do this, but I saw some advice that you can actually utilize Razor Pages from within an MVC app. This may be simpler for something like an error handling page since it will probably be a simple display to the user (maybe include request ID), do some logging, and not really needing an entire controller. It also looks like in the Microsoft example they are using Razor Pages, but that's because their example is a Razor Pages project. In my MVC project, I tried adding a Pages directory to my MVC app and adding an error page with some really simple content, but the middleware can't find it.

~/Pages/Error.cshtml

@page

<h2>Sorry...</h2>

I'm not sure if I should include the Error.cshtml.cs file here, since it's not a Razor Pages project...I tried changing the middleware path to one of my MVC controllers and it worked:

app.UseExceptionHandler("/app/about");

...so I think I'm screwing up something with routing to the Razor Page since it's redirecting appropriately for an MVC controller action route.

  1. Should I be able to add Razor Pages into a standard MVC project?
  2. Is this common practice or even a good idea, should I just create an Error controller?
  3. Is there any way I can shield my users from navigating directly to an MVC Error controller route (i.e. /Error)?


Solution 1:[1]

Firstly, you don't need to create a separate Error controller. You can create a Error action method in your existing controller with corresponding View to display custom error message.

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

And configure error handler path like below.

app.UseExceptionHandler("/Controller_Name_Here/Error");

Besides, if you'd like to integrate Razor Pages into your existing MVC app, then configure and use Error.cshtml (a razor page) to show custom exception message, you can try following steps:

Configure Razor Pages service

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    //...
    //configure other services
    //...
}

Add endpoints for Razor Pages

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //configure custom error handling page

    app.UseExceptionHandler("/Error");

    //....

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

        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Error page

enter image description here

@page
@{
    ViewData["Title"] = "Error";
}

<h1>Error</h1>


<h3>SomeThing Wrong With This Operation...</h3>

Solution 2:[2]

I know this old thread, but to respond to @Herman Schoenfeld question: you need to add IExceptionhandlePathFeature to the Error IActionResults.

HomeController

using System.Diagnostics;
[AllowAnonymous]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
       var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
       return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier, ErrorMessage = exceptionHandlerPathFeature.Error.Source });
}

ErrorViewModel

 public class ErrorViewModel
    {
        public string RequestId { get; set; }

        public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

        public string ErrorMessage { get; set; }
    }

Error View

@page
@{
    ViewData["Title"] = "Error";
}

<h1>Error</h1>

@if (Model.ShowRequestId)
{
 <p>
    <strong>Request ID:</strong> <code>@Model.RequestId</code>
  </p>
}

@if (!string.IsNullOrEmpty(Model.ErrorMessage))
{
    <p>
     <strong>Error Message:</strong> <code>@Model.ErrorMessage</code>
    </p>
}

You will be able to use the default Error page to throw Exceptions from try-catch or from if-else statements.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Fei Han
Solution 2