If we use this standard route:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
and within Windows 2008 IIS7 with MVC 2 setup we go to here:
"http://www.mywebsite.com/SomePageThatDoesNotExist.aspx"
and then under the Application_Error method we have this:
protected void Application_Error(object sender, EventArgs e)
{
Response.Clear();
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "Index");
Server.ClearError();
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(
new HttpContextWrapper(Context), routeData));
}
Instead of getting a route and a page we expect, we get a nasty 404 Server error page. Any idea how to capture url errors and direct them to a page of our choice?
MVC has HandleErrorAttribute. You can customize it to handle only 404 or other types of error.
[HandleError(ExceptionType = typeof(ResourceNotFoundException),
View = "ResourceNotFound")]
You can associate different type of exception with different views. In the above example, when the action throw ResourceNotFoundException, it will render ResourceNotFound view.
Here is a link on how to handle 404 errors, the author provided a couple of ways to handle it.
You can do it in the web.config like this.
<customErrors mode="Off" defaultRedirect="~/Error/">
<error statusCode="403" redirect="~/Error/Forbidden" />
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
Related
I have asp.net mvc RouteConfig as below, it's default one
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Home", id = UrlParameter.Optional }
);
}
In the web.config I have enabled the customerrors as below
Web.config
<customErrors mode="On" defaultRedirect="/Error/Error">
<error statusCode="404" redirect="/Error/NotFound" />
<error statusCode="500" redirect="/Error/Error" />
</customErrors>
Error Controller
public class ErrorController : Controller
{
public ActionResult Error()
{
if (!string.IsNullOrEmpty(Request.QueryString["aspxerrorpath"]))
{
return RedirectToAction("Error");
}
return View();
}
public ActionResult NotFound()
{
if (!string.IsNullOrEmpty(Request.QueryString["aspxerrorpath"]))
{
return RedirectToAction("Home", "Home");
}
return View();
}
}
When I hit the URL https://localhost:44351/a/a/a getting 404 and it's coming to Error controller, NotFound action from there it's redirecting to "Home" controller and "Home" action.
But when I hit the URL with more slashes in deep like https://localhost:44351/a/a/a/a getting default HTTP Error 404.0 - Not Found It's not routing to Error Controller, NotFound Action.
How to handle any level deep path to handle the custom 404?
I have this code in global.asax
protected void Application_Error(object sender, EventArgs e)
{
// ...
var routeData = new RouteData();
routeData.Values.Add("controller", "Home");
routeData.Values.Add("action", "Error");
IController controller = new Controllers.HomeController();
controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
how can I add parameter to Action method / RouteData ? I would like to show exception message to the user.
I have figure it out,
routeData.Values.Add("message", exception.Message);
and in action just catch that parameter
public ActionResult Index(string message)
To show the custom error page you need to change the web.config.
<system.web>
<customErrors mode="On" defaultRedirect="~/Error">
<error redirect="~/Error/NotFound" statusCode="404" />
</customErrors>
</system.web>
You can create error pages for different status code.
Make sure you have controller and action method to return view.
After Application_error MVC it self will redirect to the same page as described in web.config.
Please refer this link for more information.
I have implemented exception handling as mentioned in below link
How to pass error message to error view in MVC 5?
It is working fine. But I have requirement to handle 404 Error.
How can I do that?
if I use below code,
<customErrors mode="On">
<error statusCode="404" redirect="/Home/Error"></error>
</customErrors>
it works well when any 404 error occurs. But in case any other exception occurs then my error.cshtml call twice and show same exception two times.
web.config
Turn off custom errors in system.web
<system.web>
<customErrors mode="Off" />
</system.web>
configure http errors in system.webServer
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Auto">
<clear />
<error statusCode="404" responseMode="ExecuteURL" path="/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error" />
</httpErrors>
</system.webServer>
Create simple error controller to handle those requests ErrorContoller.cs
[AllowAnonymous]
public class ErrorController : Controller {
// GET: Error
public ActionResult NotFound() {
var statusCode = (int)System.Net.HttpStatusCode.NotFound;
Response.StatusCode = statusCode;
Response.TrySkipIisCustomErrors = true;
HttpContext.Response.StatusCode = statusCode;
HttpContext.Response.TrySkipIisCustomErrors = true;
return View();
}
public ActionResult Error() {
Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
Response.TrySkipIisCustomErrors = true;
return View();
}
}
configure routes RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes) {
//...other routes
routes.MapRoute(
name: "404-NotFound",
url: "NotFound",
defaults: new { controller = "Error", action = "NotFound" }
);
routes.MapRoute(
name: "500-Error",
url: "Error",
defaults: new { controller = "Error", action = "Error" }
);
//..other routes
//I also put a catch all mapping as last route
//Catch All InValid (NotFound) Routes
routes.MapRoute(
name: "NotFound",
url: "{*url}",
defaults: new { controller = "Error", action = "NotFound" }
);
}
And finally make sure you have views for the controller actions
Views/Shared/NotFound.cshtml
Views/Shared/Error.cshtml
If there are any additional error you want to handle you can follow that pattern and add as needed. This will avoid redirects and maintain the original http error status that was raised.
If you will define defaultRedirect attribute for customErrors then error.cshtml will be rendered only once in your case:
<customErrors mode="On" defaultRedirect="/Home/Error">
<error statusCode="404" redirect="/Home/Error"/>
</customErrors>
We have a multilingual website that has content in four languages.Every language is understood by the language name that we add at the first of our url.
This is our routeConfig.cs:
routes.MapRoute(
name: "Default",
url: "{lang}/{controller}/{action}/{id}/{title}",
defaults: new { lang = "fa", controller = "Home", action = "Index", id = UrlParameter.Optional,title = UrlParameter.Optional }
and this is generated the url: /en/ContactUs/Index
Also, in our controllers we get the language name from url and change the currentCulture and currentUiCulture based on it.
Now, we want to have a not found page in all of the languages. Normally, to make it happen we add an error contoller and a NotFound action and view, then we add this section in our web.config:
<customErrors mode="On" defaultRedirect="error">
<error statusCode="404" redirect="error/notfound" />
<error statusCode="403" redirect="error/forbidden" />
</customErrors>
We have added a NotFound page that we use .resx files in it to make rtl/ltr and to show the messages in four languages.
But the problem here is that in a multilingual website we are not allowed to use this address "error/notfound" because there is no languagename in it and we don't know how to add the language name in redirect="error/notfound" in the web.config file to create something like "en/error/notfound" or "fa/error/notfound".
every help would be highly appreciated
First of all, have a look at this answer for info about localizing your site via URL.
Next, <customErrors> is a catch-all for ASP.NET error messages. But in general, you have control over a 404 (routing miss) within ASP.NET MVC by using a catch-all route. In this case, you can simply localize the catch-all route and get rid of this configuration in web.config.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Localized-Default",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { lang = new CultureConstraint(defaultCulture: "fa", pattern: "[a-z]{2}") }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { lang = "fa", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
// Catch-all route (for routing misses)
routes.MapRoute(
name: "Localized-404",
url: "{lang}/{*url}",
defaults: new { controller = "Error", action = "PageNotFound" },
constraints: new { lang = new CultureConstraint(defaultCulture: "fa", pattern: "[a-z]{2}") }
);
routes.MapRoute(
name: "Default-404",
url: "{*url}",
defaults: new { lang = "fa", controller = "Error", action = "PageNotFound" }
);
}
}
ErrorController
public class ErrorController : Controller
{
public ActionResult PageNotFound()
{
Response.CacheControl = "no-cache";
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
}
That takes care of the route misses within ASP.NET. For those that don't hit ASP.NET (assuming you are hosting using IIS), you should use the <httpErrors> section of web.config rather than <customErrors>. <httpErrors> is localizable via the prefixLanguageFilePath setting.
Optional string attribute.
Specifies the initial path segment when generating the path for a custom error. This segment appears before the language-specific portion of the custom error path. For example, in the path C:\Inetpub\Custerr\en-us\404.htm, C:\Inetpub\Custerr is the prefixLanguageFilePath.
<configuration>
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File" >
<remove statusCode="404" />
<error statusCode="404"
prefixLanguageFilePath="C:\Contoso\Content\errors"
path="404.htm" />
</httpErrors>
</system.webServer>
</configuration>
Which means you would need to set up a file structure with language prefix, and use static files as targets.
C:\Contoso\Content\errors\fa\404.htm
C:\Contoso\Content\errors\en\404.htm
AFAIK, this unfortunately means you need to have physical files at these locations. However, you could have the content of these pages setup to do both a meta-refresh redirect and a JavaScript redirect to the correct controller action.
<html>
<head>
<title>404 Not Found</title>
<meta http-equiv="refresh" content="1;http://www.example.com/fa/Error/PageNotFound" />
</head>
<body>
<!-- Add localized message (for those browsers that don't redirect). -->
<script>
//<!--
setTimeout(function () {
window.location = "http://www.example.com/fa/Error/PageNotFound";
}, 1000);
//-->
</script>
</body>
</html>
The customErrors section in web.config is the static data about some status-code and how they will be handled. The responsibility of this section can be generated dynamically by the Application_EndRequest method in Global.asax.
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();
var routeData = new RouteData();
HttpContextBase currentContext = new HttpContextWrapper(HttpContext.Current);
var lang = RouteTable.Routes.GetRouteData(currentContext).Values["lang"];
routeData.Values["lang"] = lang;
routeData.Values["controller"] = "CustomError";
routeData.Values["action"] = "NotFound";
IController customErrorController = new CustomErrorController();
customErrorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
}
I believe you can use a session variable to hold current user's ui-culture data.
I don't see a point but, if you don't want to do that, you can follow this tutorial to generate your own routes for MVC custom error page handling.
http://setiabud.blogspot.com.tr/2013/04/handling-404-error-in-aspnet-mvc.html
I can't seem to figure this out. I'm experimenting with MVC Beta and am trying to implement a catchall route such that if the user enters mysite.com/blah instead of mysite.com/home/index it will hit the "Error" route.
Unfortunately it seems that the "Default" route always catches "blah" first. In fact the only route I've been able to get to the "Error" route with is blah/blah/blah/blah.
Is this the way it's supposed to work, because I've seen other examples that have the "Default" and "Error" route set up just like this and it seems that if they were to type in a controller that doesn't exist it would hit the "Error" route.
Is there something I'm missing (very possible) or will I just have to create a specific route for each controller?
Code I'm using:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
routes.MapRoute(
"Error",
"{*catchall}",
new { controller = "Base", action = "Error", id = "404" }
);
Thank you,
Jeff
Your first route will catch the most urls since you have defaults for the elements, you can visualize this using the route debugger from Phil Haack, see the link:
Route Debugger
In order to handle errors I used the Application_Error event in one of my projects:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
HttpException httpException = exception as HttpException;
if (httpException != null)
{
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "HttpError500");
if (httpException.GetHttpCode() == 404)
{
routeData.Values["action"] = "HttpError404";
}
Server.ClearError();
Response.Clear();
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
}
MVC routes are checked in the order that they are entered.
Mysite/blah will be found by the default route. The controller will be blah, and the action is index.
When you entered the mysite/blah/blah/blah/blah route you gave it a route it could not map the default route to and then your catchall route was called.
For those other examples, did you notice if they had some error filters setup? I'm pretty sure the default asp.net mvc site has some error handling attributes on the pages already.
This can also help when dealing with MVC catchall problems:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{*id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
That is, where it says {id}, change it to {*id}. This allows the final id parameter to consume as much additional path as might be passed in. The default rule accepts this:
/person/name/joe
But not this:
/products/list/sortby/name
The second URL will throw a 404 without this modification to the route.