简体   繁体   中英

How to properly handle AJAX errors in ASP.NET Core MVC?

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).
    });
}

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?

As far as I know, there are no unified/official way of handling Ajax errors in ASP.NET Core MVC project.

Normally we show specific confirm message/content through Ajax error callback function if the Ajax request fails rather than directly displaying detailed exception information to client user, which would help achieve a better customer experience.

If you have specific requirement that requires displaying the Developer Exception Page/custom error page while Ajax request fails, as you did, you can dynamically write the returned responseText to the HTML document using document.write(xhr.responseText); in global error handler.

As you explain, there are two threads of code to consider. One is at the client and the other at the server.

Whilst the server can return codes and messages for non-expected results, the client must still be robust and stand-alone. For example, if the server cannot be reached, a time-out error can occur at the client which it must handle. As mentioned above, you can catch errors at the local and global Ajax level.

The server may also generate an error response that never reaches the client.

In some projects I have performed the following:- If a non-expected result is generated on the server, it is logged in a database and returns an JSON message as an error.

If a non-expected result is generated on the client, a server service is called to log the error on the database.

In both cases, a message is displayed in the current page. A user can also navigate to an error page where recent errors (stored in the database) are displayed.

Working on many project of varying sizes, I've come to the conclusion that there isn't really a solution that fits everything

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM