locked
How to create custom 500 error page RRS feed

  • Question

  • User-501297529 posted

    I need to create a custom 500 error code page in my solution and I'm not sure how to do it. I asked this for 403, 404 error pages and was successful in getting that to work. Should that be used as statuscodes in the startup like 404. 

     /// <summary>
            /// Error handling code
            /// </summary>
            /// <param name="app">Instance of application builder</param>
            /// <param name="env">Instance of hosting environment</param>
            [ExcludeFromCodeCoverage]
            private static void SetErrorHandling(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {                
                    app.UseStatusCodePagesWithReExecute("/StatusCode", "?code={0}");                
                }
                else
                {
                    app.UseStatusCodePagesWithReExecute("/StatusCode", "?code={0}");
                    app.UseHsts();
                }
            }

    Monday, February 3, 2020 7:29 PM

All replies

  • User711641945 posted

    Hi bootzilla,

    You could custom middleware to deal with it:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {   
        app.UseStatusCodePagesWithReExecute("/error/{0}");
        app.UseExceptionHandler("/error/500");     
        app.Use(async (context, next) =>
        {
            await next();
            var code = context.Response.StatusCode; 
            var newPath = new PathString("/error/"+code);
            var originalPath = context.Request.Path;
            var originalQueryString = context.Request.QueryString;
            context.Features.Set<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
            {
                OriginalPathBase = context.Request.PathBase.Value,
                OriginalPath = originalPath.Value,
                OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
            });
    
            // An endpoint may have already been set. Since we're going to re-invoke the middleware pipeline we need to reset
            // the endpoint and route values to ensure things are re-calculated.
            context.SetEndpoint(endpoint: null);
            var routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
            routeValuesFeature?.RouteValues?.Clear();
    
            context.Request.Path = newPath;
            try
            {
                await next();
            }
            finally
            {
                context.Request.QueryString = originalQueryString;
                context.Request.Path = originalPath;
                context.Features.Set<IStatusCodeReExecuteFeature>(null);
            }              
        });
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        //...
    }

    ErrorController:

    public class ErrorController : Controller
    {
        // GET: /<controller>/
        public IActionResult InternalServerError()
        {
            return View();
        }
        [Route("error/404")]
        public IActionResult StatusCode404()
        {
           //redirect to the StatusCode404.cshtml
            return View();
        }
        [Route("error/400")]
        public IActionResult StatusCode400()
        {
            return View();
        }
    }

    Reference:

    https://stackoverflow.com/a/58760360/11398810

    Best Regards,

    Rena

    Tuesday, February 4, 2020 5:02 AM
  • User-501297529 posted

    Rena Ni

    Hi bootzilla,

    You could custom middleware to deal with it:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {   
        app.UseStatusCodePagesWithReExecute("/error/{0}");
        app.UseExceptionHandler("/error/500");     
        app.Use(async (context, next) =>
        {
            await next();
            var code = context.Response.StatusCode; 
            var newPath = new PathString("/error/"+code);
            var originalPath = context.Request.Path;
            var originalQueryString = context.Request.QueryString;
            context.Features.Set<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
            {
                OriginalPathBase = context.Request.PathBase.Value,
                OriginalPath = originalPath.Value,
                OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
            });
    
            // An endpoint may have already been set. Since we're going to re-invoke the middleware pipeline we need to reset
            // the endpoint and route values to ensure things are re-calculated.
            context.SetEndpoint(endpoint: null);
            var routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
            routeValuesFeature?.RouteValues?.Clear();
    
            context.Request.Path = newPath;
            try
            {
                await next();
            }
            finally
            {
                context.Request.QueryString = originalQueryString;
                context.Request.Path = originalPath;
                context.Features.Set<IStatusCodeReExecuteFeature>(null);
            }              
        });
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        //...
    }

    ErrorController:

    public class ErrorController : Controller
    {
        // GET: /<controller>/
        public IActionResult InternalServerError()
        {
            return View();
        }
        [Route("error/404")]
        public IActionResult StatusCode404()
        {
           //redirect to the StatusCode404.cshtml
            return View();
        }
        [Route("error/400")]
        public IActionResult StatusCode400()
        {
            return View();
        }
    }

    Reference:

    https://stackoverflow.com/a/58760360/11398810

    Best Regards,

    Rena

    I get an error on this line:

    context.SetEndpoint(endpoint: null);

    'HttpContext' does not contain a definition for 'SetEndpoint' and no accessible extension method 'SetEndpoint' accepting a first argument of type 'HttpContext' could be found (are you missing a using directive or an assembly reference?) 

    I also had a previous StatusCodeController for the 404 error codes:

     public class StatusCodeController : Controller
        {
            // GET: /<controller>/
            public IActionResult InternalServerError()
            {
                return View();
            }
            public IActionResult Index(string code)
            {
                if (string.IsNullOrEmpty(code))
                {
                    code = "Unknown.cshtml";
                }
                return View($"/Views/Shared/{code}.cshtml");
            }
        }

    I added the InternalServerError action to it. Is that correct?

    Tuesday, February 4, 2020 2:47 PM
  • User711641945 posted

    Hi bootzilla,

    I get an error on this line:

    context.SetEndpoint(endpoint: null);

    Maybe you did not use asp.net core 3.0?If so, I suggest that you could comment on this line:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseStatusCodePagesWithReExecute("/error/{0}");
        app.UseExceptionHandler("/error/500");
        app.Use(async (context, next) =>
        {
            await next();
            var code = context.Response.StatusCode;
            var newPath = new PathString("/error/" + code);
            var originalPath = context.Request.Path;
            var originalQueryString = context.Request.QueryString;
            context.Features.Set<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
            {
                OriginalPathBase = context.Request.PathBase.Value,
                OriginalPath = originalPath.Value,
                OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
            });
    
            // An endpoint may have already been set. Since we're going to re-invoke the middleware pipeline we need to reset
            // the endpoint and route values to ensure things are re-calculated.
            //context.SetEndpoint(endpoint: null);
            var routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
            routeValuesFeature?.RouteValues?.Clear();
    
            context.Request.Path = newPath;
            try
            {
                await next();
            }
            finally
            {
                context.Request.QueryString = originalQueryString;
                context.Request.Path = originalPath;
                context.Features.Set<IStatusCodeReExecuteFeature>(null);
            }
        });
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();
    
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

    and add the Route attribute to your action like below:

    public class StatusCodeController : Controller
    {
        [Route("error/{code}")]
        public IActionResult Index(string code)
        {
            if (string.IsNullOrEmpty(code))
            {
                code = "Unknown.cshtml";
            }
            return View($"/Views/Shared/{code}.cshtml");
        }
    }

    I added the InternalServerError action to it. Is that correct?

    No need to add this action,only use Index action is enough.

    Best Regards,

    Rena

    Wednesday, February 5, 2020 6:37 AM