Search code examples
asp.net-coreasp.net-core-mvcasp.net-core-webapirazor-pages

Asp.net core exception handling in applications that combines Razor Pages and ApiControllers


when using asp.net applications that combines Razor Pages and Api Controllers. how to globally check if the exception is thrown from an Api Controller ?

the idea is to use UseExceptionHandler midlleware but conditionally return an html response if the unhanded exception is thrown from a Razor Page and a json ProblemDetails response if the excpetion is thrown from an ApiController


Solution

  • For web Api, add attribute route with Api, and then check the request path in the middleware or exception handler like this:

    app.UseExceptionHandler("/Error"); //handle the exception from the razor page
    
    //handle the exception from the API.
    app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), subApp =>
    {
        subApp.UseExceptionHandler(builder =>
        {
            builder.Run(async context =>
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; 
                context.Response.ContentType = "application/json"; 
                await context.Response.WriteAsync("{\"error\":\"Exception from API!\"}");
                //await context.Response.WriteAsync("ERROR From API!<br><br>\r\n"); 
                //await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
                //await context.Response.WriteAsync("</body></html>\r\n");
            });
        });
    });
    

    The result as below:

    enter image description here

    Besides, you can also use a custom exception handler page is to provide a lambda to UseExceptionHandler. Using a lambda allows access to the path of the request that made the error before returning the response.

    For example:

    //app.UseExceptionHandler("/Home/Error");
    app.UseExceptionHandler(errorApp =>
    {
        errorApp.Run(async context =>
        { 
            var exceptionHandlerPathFeature =
                context.Features.Get<IExceptionHandlerPathFeature>();
            //check if the handler path contains api or not.
            if (exceptionHandlerPathFeature.Path.Contains("api"))
            { 
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; ;
                context.Response.ContentType = "text/html";
    
                await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
                await context.Response.WriteAsync("ERROR From API!<br><br>\r\n");
    
                await context.Response.WriteAsync(
                                                "<a href=\"/\">Home</a><br>\r\n");
                await context.Response.WriteAsync("</body></html>\r\n"); 
            }
            else
            {
                context.Response.Redirect("/Home/Error");
            }
        });
    });
    

    More detail information, see asp.net core app.UseExceptionHandler() to handle exceptions for certain endpoints?