I have problems accessing a route, if it contains a dot. For reproducing, create a default MVC4 WebApi application. Take the default route...
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
write the controller as follows...
public class HomeController : Controller
{
public ActionResult Index(string id)
{
if (id == null)
{
return View();
}
else
{
return PartialView(id);
}
}
}
and create two files "test.cshtml" and "test.menu.cshtml" next to the existing "index.cshtml".
Opening /home/index/test works as expected. It brings back the contents of "test.cshtml".
However, opening /home/index/test.menu brings back a 404 error.
Why does this happen? And how can it be avoided?
The 404 error that you are seeing is from IIS. The module for MVC routing is never getting control.
Adding the following option to the modules section of the <system.webServer> section in web.config will make sure that the MVC routing gets attempted and should fix your problem:
runAllManagedModulesForAllRequests="true"
in my web.config there was no existing modules section so I added the following line to the <system.webServer> section:
<modules runAllManagedModulesForAllRequests="true" />
And now it works for me.
Related
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 have created the following MapRoute function. And it's being called right from Application_Start() in Global.asax.
public static class RouteConfig
{
public static void RegisterRoutes( RouteCollection routes )
{
routes.MapRoute(
name: "TestMe",
url: "TestMe.axd",
defaults: new { controller = "Access", action = "SignOn" }
);
}
}
While I can access the specific controller if I use
http://localhost/TestSite/Access/SignOn,
I can't access it with this URL.
http://localhost/TestSite/TestMe.axd.
Can someone please point out what I am missing here?
Many thanks!!
Found some information from this link
I added
<modules runAllManagedModulesForAllRequests="true" />
into my Web.config and it's working now.
I have only 1 controller and have 1 action only in my example like this:
//
// GET: /Home/
public ActionResult Index(string source,string id)
{
return View();
}
I have 2 routes registered for this action like -:
routes.MapRoute(
name: "Default2",
url: "{source}/{id}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "",
defaults: new { controller = "Home", action = "Index", source="source1", id = UrlParameter.Optional }
);
When I call default, it calls Index action, which is OK
when I call like this, /source1/12 - it works.
But when I call like this /source1/12.0 - it does not work and shows up 404 ..
Can anyone suggest why is this happening ?
It's probably interpreting the .0 as a file extension, and thus looking for a file on disk. Can you replace "." with "_" for the purposes of redirection, and replace back in your action method? Otherwise, you have to look at ways you can get the routing not to interpret ".0" as a file extension. Not sure exactly how off of the top of my head...
MVC routes errors like this to special methods. One is in the controller: HandleUnknownAction, which is called when the action can't be matched. You can override it and handle the action (logging it, etc.) there.
Check this article, it has a solution for you:
From the link:
<configuration>
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true"/>
<!-- ... your other settings ... -->
</system.web>
</configuration>
change the ROuteCOnfig to:
routes.MapRoute(
name: "Default2",
url: "{source}/{id}/",
defaults: new { controller = "Home", action = "Index" }
);
Should solve your issue.
You can also check this SO Thread
I have an MVC application and am using the standard routeconfig that routes /Controller/Action/Id
I want it to additionally capture /Controller/Action.html as the url and as well and point to /controller/action also.
I am using a jquery library that I have no control over, and a function requires a url that points to a webpage or an image. However, it doesn't appear to understand that ends without an extension(.html, .php etc) is a link to html and throws an error.
Edit: I tried as the commenter below suggested, and still can't seem to get it to work. Here is my route config.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("routeWithHtmlExtension",
"{controller}/{action}.html",
new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
This Url works:
http://localhost:14418/Album/Test
This one does not:
http://localhost:14418/Album/Test.html
In web.config
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
...
</system.webServer>
If you set up the following route, it will work:
routes.MapRoute("routeWithHtmlExtension",
"{controller}/{action}.html",
new {controller = "Home", action = "Index" }
);
I just created an empty application, added a view, a controller and ran it.
I am getting the following error:
"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.
My code:
TestController.cs
namespace WOSubmittal.Controllers
{
public class TestController : Controller
{
public ActionResult Index()
{
return View();
}
}
}
View located under Views/Test
Index.cshtml
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
I put a breakpoint to the Index() routine and it doesn't even get hit. Any ideas?
Change this in public static void RegisterRoutes(RouteCollection routes)
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
for this:
new { controller = "Test", action = "Index", id = UrlParameter.Optional }
in your Global.asax.cs
Change TestlController to TestController.
When looking for a view for your controller, MVC will use the name of your controller, without the word Controller, when attempting to resolve it.
From the code you've given, MVC would look in Views/Testl, not Views/Test.
Change this line in the Web.config file:
<httpRuntime enable="false" targetFramework="4.5"/>
to
<httpRuntime enable="true" targetFramework="4.5"/>