Search code examples
asp.net-mvcasp.net-coreerror-handlingasp.net-core-7.0

ASP.Net Core 7.0 Web App (Model-View-Controller) ErrorViewModel OnGet OnPost do not get called or executed


I've been struggling with setting up global error handling for my ASP.Net Core MVC Web App. I've been trying to apply the following article and I've had no luck.

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-7.0

Running the app with IIS Express in debug.

The setup is, at this point, I'm simply creating a new Web App project. Specifically, ASP.Net Core 7.0 Web App (Model-View-Controller). The only code I've changed from what you get by default when creating a new project is the following.

Program.cs

// Configure the HTTP request pipeline.
//if (!app.Environment.IsDevelopment())
//{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
//}

Controllers/HomeController.cs

//added HttpGet attribute to main index action.
[HttpGet]
public IActionResult Index()
{
    //throw an application exception to test error handling
    throw new ApplicationException("This is an error");
    return View();
}

Models/ErrorViewModel.cs

    //Added class attributes and PageModel inheritance
    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    [IgnoreAntiforgeryToken]
    public class ErrorViewModel : PageModel

        public string? RequestId { get; set; }

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


        //added OnGet method
        public void OnGet()
        {
            string thisIsDumb = "dumb";
        }

Shared/Error.cshtml - No change. If I add @page to the top, it breaks the ViewData["Title"] usage, i.e. ViewData["Title"] = "Error" doesn't work any more. ViewData becomes null.

I feel like this should be more straight forward but I'm clearly missing something. What I'm trying to do is get whatever unhandled exception occurs in my Web App to populate to an Error Detail Web Page. I'd really like some global error handling, but I just can't seem to get the basic OnGet OnPost to work in the model and I don't know how to trickle any form of exception to the ErrorViewModel for usage by a view.


Solution

  • In case anyone else trips on this, the sample code in the linked article Handle errors in ASP.NET Core seems to be for Blazor, not MVC. The following point from the referenced article is a pointer to this.

    For MVC, apply HTTP verb attributes to multiple actions. For example, use [HttpGet] to handle GET exceptions and use [HttpPost] to handle POST exceptions.

    For MVC Apps, when you add the following code, you're routing all unhandled errors in the logic of your MVC app to your Default Controller's Error Action.

    Program.cs

    var app = builder.Build();
    
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Default/Error");
        app.UseHsts();
    }
    

    While the referenced article has the code of

    app.UseExceptionHandler("/Error");
    

    It seems the omission of the "default" controller in the route of that code is more Blazor related. The absent "default" controller in the routes path needs to be added for MVC. At least so that I could get it to work.

    From that point, your Default Controller will have an action something like the following...

    Controllers/DefaultController.cs

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            string exceptionMessage = string.Empty;
            string typeOfException = string.Empty;
            var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
    
            if (exceptionHandlerPathFeature != null)
            {
                if (exceptionHandlerPathFeature.Error != null)
                {
                    typeOfException = exceptionHandlerPathFeature.Error.GetType().Name;
                    exceptionMessage = exceptionHandlerPathFeature.Error.Message;   
                }
            }
    
            // ... Other Code used to update your ErrorViewModel ...
    
            ErrorViewModel model = new ErrorViewModel();            
            model.RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
            model.SessionID = HttpContext.Session.Id ?? "No Session ID Found"; //Extended ErrorViewModel
            model.ExceptionType = typeOfException; //Extended ErrorViewModel
    
            //Resolves to the /Views/Shared/Error.cshtml view.
            return View(model);
        }
    

    MVC is just different as opposed to what is shown in the referenced article even though it's supposed to be teaching for both MVC and Blazor.

    Hope this helps some one else's confusion.