I'm trying to follow the answer to this question:
How to make custom error pages work in ASP.NET MVC 4
I have the following in my Web.Release.config:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error">
<error redirect="~/Error/NotFound" statusCode="404" />
</customErrors>
</system.web>
I'm running in Release mode. I've added the following controller:
public class ErrorController : Controller
{
public ViewResult Index()
{
return View("Error");
}
public ViewResult NotFound()
{
Response.StatusCode = 404; //you may want to set this to 200
return View("NotFound");
}
}
And views for the controller actions:
#model System.Web.Mvc.HandleErrorInfo
#{
Layout = "../Shared/_Layout.cshtml";
ViewBag.Title = "Error";
}
<div class="list-header clearfix">
<span>Error</span>
</div>
<div class="list-sfs-holder">
<div class="alert alert-error">
An unexpected error has occurred.
</div>
</div>
I can access these pages via manual navigation. If I navigate to some bogus URL though, I get the standard yellow error page with ugly diagnostics info.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make
sure that it is spelled correctly.
Requested URL: /ss
What am I doing wrong?
If custom errors are enabled, as in your example, and you are using the HandleErrorAttribute, the ASP.NET MVC runtime looks for the Error.chtml file in the current requests folder or in the shared
views folder. In this setup, the defaultRedirect (to GenericErrorPage.htm) and status
code redirect URI ("~/Error/NotFound") are ignored.
Related
I have the following route in RouteConfig.cs:
routes.MapRoute(
"MyLegacyRoute",
"Content/bootstrap.css",
new { controller = "Legacy", action = "GetLegacyUrl", legacyUrl = "someUrl" });
~/Content/bootstrap.css exists and rather than display its content when I navigate to http://localhost:27541/Content/bootstrap.css, I want to hit the GetLegacyUrl action in the Legacy controller.
I have added this to Web.config:
<system.webServer>
<handlers>
<add name="UrlRoutingHandler" path="/Content/*" verb="GET" type="System.Web.Routing.UrlRoutingHandler" />
...
and
<system.web>
<httpRuntime targetFramework="4.5" relaxedUrlToFileSystemMapping="true"/>
...
However when I access http://localhost:27541/Content/bootstrap.css I get this error:
Server Error in '/' Application.
Cannot create an abstract class.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: Cannot create an abstract class.
My controller looks like this:
public class LegacyController : Controller
{
public ActionResult GetLegacyUrl(string legacyUrl)
{
return View((object)legacyUrl);
}
}
My view (GetLegacyUrl.cshtml) looks like this:
#model string
#{
ViewBag.Title = "GetLegacyUrl";
Layout = null;
}
<h2>GetLegacyUrl</h2>
The URL requested was #Model
I am trying to do this just so I can learn more about routing.
What can I do to successfully use this route?
I got it to work by putting this in RouteConfig.cs:
routes.RouteExistingFiles = true;
And by making the preCondition value an empty string:
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
in this file: C:\Users\user.name\Documents\IISExpress\config\applicationhost.config
I found the answer on pg 99/115 chapter 16 in Adam Freeman's Pro ASP.NET MVC5 book.
I also removed the handler I added in the Web.config and removed the relaxedUrlToFileSystemMapping="true" since that doesn't work in MVC5.
I can't get ANY custom error pages to appear in IIS8.5!
When I run my MVC 5 app locally in Visual Studio, custom error pages are displayed. But when I deploy to IIS on my webserver, and navigate to the site sub-page with a 'bad URL' my custom 404 page should be displayed, but the default generic 404 page is shown instead.
Here is what I've done:
web.config
customError section has been deleted.
Added the following section
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<remove statusCode="500" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error/ServerError" />
</httpErrors>
</system.webServer>
Controller
namespace MyApp.Controllers
{
[Authorize(Roles = "MyRole")]
public class ErrorController : Controller
{
[AllowAnonymous]
public ActionResult NotFound()
{
Response.StatusCode = 404;
return View();
}
[AllowAnonymous]
public ActionResult ServerError()
{
Response.StatusCode = 500;
return View();
}
}
}
Views
Very simple and straight forwards (not included here).
IIS
Verified the IIS Error Page feature is identical to what's in my config. A page for each error status code. Feature and Pages are set to 'custom'.
Checked Windows Features\Web Server (IIS)\Web Server\Common HTTP Features\HTTP Errors is installed.
Developer Tools
Navigating to a sub-page spelt incorrectly shows I'm getting a 404 Client Error.
Help
I've tries many things! Am I missing something? IIS environmental issue, i.e. a setting somewhere?
Custom errors work in my IDE but not on IIS. I've spent over a day on this! Read many pages, articles, and similar questions on SO.
After several days of investigating, finally found the issue.
In IIS, my website was residing as an Application under the Default Web Site, e.g. Default Web Site\MyDevSite. (All my dev sites are under the default web site).
When I moved the website to it's own IIS site, custom error pages are now being displayed!
If anyone knowns the reason why having an Application in IIS prevents custom error pages from being displayed, please add a comment here. It would be good to understand why this occurs.
I hope this helps somebody out. Had me going for quite a while.
How are you browsing IIS? If you're doing it from the same machine, then you aren't going to see your custom error pages, because the customErrors section will default to using RemoteOnly if not specified.
the problem is with the path in web.config(path="/Error/NotFound"). the url path of NotFound page will be changed when you move your website under the Default Web Site. So, give the correct url of the page at path then it will work(this is worked for me).
I'm currently developing custom error pages in my error handling code for my MVC application. But I'm unclear as to which HTTP status codes I'm meant to cover.
Question: is there a typical list of HTTP status codes that should be catered for?
Alot articles which explain how to do MVC error handling and custom error pages but appear to only show several of the HTTP Status Codes: 403, 404, and 500 in their error handling code. What about HTTP Status Code: 408 as an example? Should this be covered? What about the tonne of other status codes - HTTP status codes on wiki
This may sound like a dumb question, but I really don't know the answer and can't find an information on this. Am I missing something here, i.e. should only a subset of status codes be covered?
If it helps, below is what I've done for my MVC error handling. This code (so far with the little testing that I've done) covers 404, and all 50x type exceptions:
1 In web.config, and entry for each HTTP status code I want to cover
<httpErrors errorMode="Custom" existingResponse="Replace" >
<remove statusCode="403" />
<remove statusCode="404" />
<remove statusCode="500" />
<error statusCode="403" responseMode="ExecuteURL" path="/Error/Forbidden" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error" />
</httpErrors>
2 An error controller
namespace MyApp.Controllers
{
public class ErrorController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Forbidden()
{
return View();
}
public ActionResult NotFound()
{
return View();
}
3 User friendly error pages:
/Views/Shared/Index.cshtml
/Views/Shared/Forbidden.cshtml
/Views/Shared/NotFound.cshtml
4 ELMAH for logging
Further findings at 2 Nov 2015
Something I've just discovered that has been staring me in the face which I've missed... In IIS, the default Error pages covered are:
401 – Unauthorized
403 – Forbidden
404 – Not Found
405 – Method Not Allowed
406 – Not Acceptable
412 – Precondition Failed
500 – Internal Server Error
501 – Not Implemented
502 – Bad Gateway
If this is good range Microsoft have set, then I will go by this as a guide going forwards!
There may be another way: this solution uses 1 custom-error page to handle all types (I think?)
[1]: Remove all 'customErrors' & 'httpErrors' from Web.config
[2]: Check 'App_Start/FilterConfig.cs' looks like this:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
[3]: in 'Global.asax' add this method:
public void Application_Error(Object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Server.ClearError();
var routeData = new RouteData();
routeData.Values.Add("controller", "ErrorPage");
routeData.Values.Add("action", "Error");
routeData.Values.Add("exception", exception);
if (exception.GetType() == typeof(HttpException))
{
routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
}
else
{
routeData.Values.Add("statusCode", 500);
}
Response.TrySkipIisCustomErrors = true;
IController controller = new ErrorPageController();
controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
Response.End();
}
[4]: Add 'Controllers/ErrorPageController.cs'
public class ErrorPageController : Controller
{
public ActionResult Error(int statusCode, Exception exception)
{
Response.StatusCode = statusCode;
ViewBag.StatusCode = statusCode + " Error";
return View();
}
}
[5]: in 'Views/Shared/Error.cshtml'
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = (!String.IsNullOrEmpty(ViewBag.StatusCode)) ? ViewBag.StatusCode : "500 Error";
}
<h1 class="error">#(!String.IsNullOrEmpty(ViewBag.StatusCode) ? ViewBag.StatusCode : "500 Error"):</h1>
//#Model.ActionName
//#Model.ContollerName
//#Model.Exception.Message
//#Model.Exception.StackTrace
An interesting question, IMHO.
These three errors (403, 404 and 500) are the most common errors that can happen to the real user accessing your site with a standard browser.
On other hand, the HTTP standard was written for both server and agent developers in order to define how both sides should operate. Naturally, the standard browsers like IE, Chrome, Firefox, etc. as well as the standard robots like Google or Bing bots correctly fulfill the requirements, but some proprietary written agent may send a malformed request, and the standard provides the set of codes the server should send in this situation. For example, if the Content-Length field is missed the server returns the error code 411. However, you shouldn't provide user-friendly pages for such a situation.
The code 408 (Request timeout) is explained in the standard as following:
"The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time."
and it also not a case you should make user-friendly page for.
To make a long story short, don't worry :)
I'm trying to find out the answer also. My code looks scarily like yours. This is a great question with so few views, I've set a bounty on this question. I myself have handled the following codes so far:
<system.webServer>
<!-- Custom error pages -->
<httpErrors errorMode="Custom" existingResponse="Replace">
<!-- Redirect IIS 400 Bad Request responses to the error controllers bad request action. -->
<remove statusCode="400" />
<error statusCode="400" responseMode="ExecuteURL" path="/error/badrequest" />
<!-- Redirect IIS 401 Unauthorized responses to the error controllers unauthorized action. -->
<remove statusCode="401" />
<error statusCode="401" responseMode="ExecuteURL" path="/error/unauthorized" />
<!-- Redirect IIS 403.14 Forbidden responses to the error controllers not found action.
A 403.14 happens when navigating to an empty folder like /Content and directory browsing is turned off
See http://rehansaeed.co.uk/securing-the-aspnet-mvc-web-config/ and http://www.troyhunt.com/2014/09/solving-tyranny-of-http-403-responses.html -->
<error statusCode="403" subStatusCode="14" responseMode="ExecuteURL" path="/error/notfound" />
<!-- Redirect IIS 404 Not Found responses to the error controllers not found action. -->
<remove statusCode="404" />
<error statusCode="404" responseMode="ExecuteURL" path="/error/notfound" />
<!-- Redirect IIS 500 Internal Server Error responses to the error controllers internal server error action. -->
<remove statusCode="500" />
<error statusCode="500" responseMode="ExecuteURL" path="/error" />
</httpErrors>
</system.webServer>
My reasoning is as follows:
400 - Controllers have the BadRequest() method built in and you may want to return this when a parameter passed to the action is invalid.
401 - Applying the Authorize attribute to a controller or action causes a 401 Unauthorized response. Controllers also have the Unauthorized() method built in.
403.14 - Redirect these to 404 Not Found responses as a Forbidden is just plain wrong (See Securing your web.config and Troy Hunt's blog for more information).
404 - Thrown when the user browses to a page not found.
500 - Thrown when something goes catastrophically wrong.
Overall I feel you should handle those codes that you yourself are going to use. The problem is that IIS does all kinds of strange things and we need to handle some of it's incorrect or invalid responses such as the 403.14 I listed above.
Here is a complete list of IIS HTTP Status Codes and Sub-Status Codes which might be useful to our cause. I have a feeling the 403 Forbidden response should also be supported as it seems to be a fairly prominent response thrown by IIS.
One interesting thing I discovered while Googling is that navigating to:
yoursite/<script></script>
Returns a 500 Internal Server from IIS. I feel this should return a 404. The IIS error page does not tell us what the Sub-Status Code is and I would be interested to know how we can find out, so that we can redirect the 500.Something to a 404 Not Found page.
Here is a link to the GitHub page for the ASP.NET MVC Boilerplate project, for which I am doing this research and where you can look at my code.
Don't rely too much on http status codes.
I have worked with a few bad web developers over the last couple of years that have incorrectly used them in their responses.
I may look for codes within 200-299 for an indication of success.
I may look for codes >500 to indicate a server failure.
Beyond that, I use a selfish approach i.e. if you are making a request that your are expecting to have a package of data returned to you, then inspect the data. If there is no data or if the data is bad then I know for certain that there was a problem, because I didn't get what I needed to continue running my application in a nominal way.
How can I pass exceptions to my custom error page and present them the same way you can on the standard error page you get when you first create a new application? The code below works on the standard error page but not on my custom. Any ideas?
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Error";
}
<h1 class="error">Error.</h1>
<h2 class="error">An error occurred while processing your request.</h2>
#if (Model != null)
{
#Model.Exception.Message
#Model.Exception.InnerException
}
you can define customError configuration in web.config here you can give path for error page.
<customErrors mode="On">
<error code="404" path="404.html" />
</customErrors>
for more info see these links
http://ben.onfabrik.com/posts/aspnet-mvc-custom-error-pages
How to make custom error pages work in ASP.NET MVC 4
custom error page in mvc
As I have already mentioned in topic, I have a MVC site and I need to disable loading it into IFrame.
I have created simple page for testing purpose and I try to load into two IFrames my site and Google.com. I can see that my site is loaded but Google isn't. It means that it's necessary to change something in my MVC site.
<!DOCTYPE html>
<html>
<body>
<iframe src="http://localhost:61831/" width="1200" height="800">
<p>Your browser does not support iframes.</p>
</iframe>
<iframe src="http://google.com" width="1200" height="800">
<p>Your browser does not support iframes.</p>
</iframe>
</body>
</html>
So what and where in MVC site I have to write to achieve that?
It is possible to use X-Frame-Options HTTP header attribute to avoid ASP.NET MVC application be opened in IFrame.
There are several different way to insert this attribute to HTTP header:
1.Configure IIS to add this attribute to all HTTP responses
2.Set this attribute in every necessary action method of every controller
public class HomeController : Controller
{
public ActionResult Index()
{
Response.AppendHeader("X-Frame-Options", "SAMEORIGIN");
return View();
}
}
3.Create C# attribute in a way described here and apply it to action methods and controllers
[HttpHeader("X-Frame-Options", "SAMEORIGIN")]
public class HomeController : Controller
{
public ActionResult Index()
{
}
}
4.Set this attribute in Global.asax file
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
...
}
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
Response.AppendHeader("X-Frame-Options", "SAMEORIGIN");
}
}
Simple and quick Solution is to add following in Global.asax -
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
Response.AddHeader("X-Frame-Options", "SAMEORIGIN");
}
Then give a try with iframe. Pages will not open in iframes. HTH.
You can also add an entry in web.config:
<system.webServer>
...
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
...
</system.webServer>
You can configure IIS to always append the X-Frame-Options SAMEORIGIN header in it's responses.
From IIS Management Console, select your application.
In the main panel, double click Http Response Headers.
Click Add from the upper right pane.
Set the name to X-Frame-Options and the value to SAMEORIGIN then
click OK.
This should prevent your site from being loaded into an iframe on a different host, without using any javascript or any extra code.
See developper.mozilla.org for the header documentation and technet.microsoft.com for IIS' configuration.
As DrewMan suggested, you want to use X-Frame-Options header.
I would suggest you to download Nuget Package NWebsec and there's MVC specific package. Also check out the configuration part.