Background:
I'm setting up error handling in an ASP.NET Core 2.2 MVC app. When in development environment, I use the app.UseDeveloperExceptionPage();
, and in production - app.UseExceptionHandler("/Error/Index");
. I am navigated to the correct error page during non-AJAX (regular form submission) requests based on the environment.
If an exception occurs in the server during an AJAX request, I want the app to display the correct error page depending on the environment.
I have already set up all of what I described above, as you can see in my code examples below.
Problem/Concern:
While this works (though still have to complete the TODO in InitializeGlobalAjaxEventHandlers
function), I have some concerns.
With non-AJAX calls in MVC, it feels like there is a "official/correct" way to do it with app.UseDeveloperExceptionPage();
and app.UseExceptionHandler("/Error/Index");
, which automatically redirects the program to the error page. With the AJAX end of error handling, however, I don't feel as confident because I pieced it together with parts from different solutions I've researched. I'm worried I'm not aware of what could go wrong.
Question:
Is this the proper way to handle errors during AJAX requests in MVC? Could something possibly go wrong with this set up? Is this in any way improper or too far from common standards?
Code:
Startup.cs > Configure method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//using build config to use the correct error page: https://stackoverflow.com/a/62177235/12300287
//Reason why we don't use environmental variables is because we can't guarantee access to clients'
//machines to create them.
#if (DEVELOPMENT || STAGING)
app.UseDeveloperExceptionPage();
#else
app.UseExceptionHandler("/Error/Index");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
#endif
app.UseHttpsRedirection();
app.UseStaticFiles();
//app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=UserAccess}/{action=Index}/{id?}");
});
}
ErrorController.cs:
public class ErrorController : Controller
{
[AllowAnonymous]
public IActionResult Index()
{
IExceptionHandlerPathFeature exceptionDetails = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
Exception exception = exceptionDetails?.Error; // Here will be the exception details.
Error model = new Error();
model.ID = exception.HResult;
model.Message = exception.Message;
model.Path = exceptionDetails.Path;
return View(model);
}
}
Global AJAX error event handler (the if
statement is to handle authentication):
function InitializeGlobalAjaxEventHandlers() {
$(document).ajaxError(function (event, xhr, ajaxSettings, thrownError) {
//status is set in the [AuthorizeAjax] action filter if user isn't authenticated
if (xhr.status == 403) {
var response = $.parseJSON(xhr.responseText);
window.location = response.redirectUrl;
}
//the document HTML is replaces by responseText value, which contains the HTML of error page
document.write(xhr.responseText);
//TODO: will need to display an error page if responseText is empty, which
//can happen if an AJAX request doesn't reach the server (for example: if URL is incorrect).
});
}