0

I am new to MVC and am working on error handling and exceptions. As you may or may not know, the implementation of handling HTTP errors through Views is outright clunky for the following reasons:

1.) The page status code is set to 200, which will result in the error page being indexed by a search engine and letting the user know that everything went OK, which is not true.

2.) The URL of the error page changes, which I do not want. Unfortunately, I cannot use ResponseRewrite with a View because it uses Server.Transfer under the hood, which means it looks for a file as opposed to a View.

I prefer to use a View for all application exception and HTTP error handling because the View maintains the site layout by calling _Layout.cshtml in the View startup. So, after working on this for the past week, I think I found an implementation that allows me to use a View while addressing the two issues that I mentioned above (see Solution 1 by Starain Chen in the weblink below).

My problem is this, for me the View is being displayed in all text. Any ideas why this is happening, and more importantly, how to force the site to be rendered as opposed to being dumped out as text?

https://forums.asp.net/t/1996026.aspx?How+to+keep+url+same+after+page+postback+with+error+in+MVC

My code:

web.config (truncated)

<system.web>
    <customErrors mode="On" >      
    </customErrors>
</system.web>

<system.webServer>
    <modules>
         <remove name="FormsAuthentication" />
         <remove name="UrlRoutingModule-4.0" />
         <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />     
    </modules>
</system.webServer> 

Global.asax

namespace WebApplication1
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
        protected void Application_Error()
        {

            if (Context.IsCustomErrorEnabled)
                ShowError(Server.GetLastError());
        }

        private void ShowError(Exception exception)
        {
            var httpException = exception as HttpException ?? new HttpException(500, "Internal Server Error", exception);

            Response.Clear();
            var routeData = new RouteData();
            routeData.Values.Add("Controller", "Error");
            routeData.Values.Add("fromAppErrorEvent", true);
            routeData.Values.Add("ErrorMessage", httpException.Message);
            routeData.Values.Add("httpStatusCode", httpException.GetHttpCode());
            switch (httpException.GetHttpCode())
            {
                case 403:
                    routeData.Values.Add("action", "HttpError403");
                    break;
                case 404:
                    routeData.Values.Add("action", "HttpError404");
                    break;
                case 500:
                    routeData.Values.Add("action", "HttpError500");
                    break;
                default:
                    routeData.Values.Add("action", "GeneralError");
                    break;
            }

            Server.ClearError();

            IController controller = new Controllers.ErrorController();
            controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));

        }
    }
}

ErrorController

namespace WebApplication1.Controllers
{
    public class ErrorController : Controller
    {
        // GET: Error
        public ActionResult HttpError404()
        {
            ViewBag.errormessage = this.RouteData.Values["ErrorMessage"];
            ViewBag.status = this.RouteData.Values["httpStatusCode"];
            Response.StatusCode = Convert.ToInt32(this.RouteData.Values["httpStatusCode"]);
            Response.TrySkipIisCustomErrors = true;
            return View();
        }
    }
}

HttpError404.cshtml View

@{
    ViewBag.Title = "HttpError404";
}

@*<h2>HttpError404</h2>
ErrorMessge: @ViewBag.errormessage
<br />
Status: @ViewBag.status*@
J Weezy
  • 3,507
  • 3
  • 32
  • 88
  • 1
    Sad to say, this isn't as easy in MVC as i should have been... – mortb Feb 16 '17 at 11:06
  • 1
    For example you can read about 404 handling: http://stackoverflow.com/questions/619895/how-can-i-properly-handle-404-in-asp-net-mvc – mortb Feb 16 '17 at 11:08
  • 1
    This is an answer where I explain how I got around that issue http://stackoverflow.com/a/38249656/5233410 – Nkosi Feb 16 '17 at 11:34
  • @Nkosi, thanks for posting the weblink. I am curious, how did you get all of the other controllers to inherit from the base controller? – J Weezy Feb 17 '17 at 02:00
  • 1
    @JWeezy `SomeController: BaseController { }` how else would you make a class inherit from a base class. – Nkosi Feb 17 '17 at 02:15
  • Durr. Sorry, that was a bad question. Thanks for the assistance. – J Weezy Feb 17 '17 at 10:28
  • @Nkosi. I am curious, if I set the issue of error handling aside and focus on the View itself, do you know why it is displaying as text for localhost/foo versus being rendered for localhost/foo.html? – J Weezy Feb 18 '17 at 06:30

1 Answers1

0

Problem is caused by the project being open in Visual Studio 2013, oddly enough. Close the project and the View renders correctly in Firefox and even Chrome. Open the project in VS2013 and Chrome and Firebox both go back to displaying text for the View. IE must have some code awareness to render the project while VS2013 has the project open. Bizarre.

J Weezy
  • 3,507
  • 3
  • 32
  • 88