My default routes are very simple, but the page doesn't properly load without fully qualifying the entire route.
Here are the routes I'm using:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
Here's the only action in the application in a HomeController:
public ActionResult Index()
{
return Content("New stuff");
}
With these URLs:
http://localhost:8081/NewMvc1/
I get The incoming request does not match any route.
With:
http://localhost:8081/NewMvc1/Home
http://localhost:8081/NewMvc1/Home/Index
I get a 404 Mvc page that says it tried to handle the request with a static file.
Yet, finally with a 'fully qualified url'
http://localhost:8081/NewMvc1/Home/Index/1
I get the expected result output from the one and only one action.
New Stuff
This doesn't seem right at all. I've also been getting Failed to Execute Action from this same application (not sure if that's related).
I've used Phil Haack's RouteDebugger to get this far, which pointed out that it wasn't matching the URL when the Optional parameters were missing, but did when those parameters were provided.
You're missing the id from your defaults:
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
Related
I need to provide language specific routes for my Asp.Net MVC application. The language should be part of the Url Path (http://myapp/en/Blog) and when it is ommitted the default language have to be used.
http://myapp/en/Blog -> Blog in the English version
http://myapp/Blog -> Blog in the Default (portuguese) Language version
To address this issue I created two Routes bellow:
routes.MapRoute(
name: "Default.lang",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { lang = #"^[a-zA-Z]{2}$" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The routes are working as expected but I'm getting weird results when I try to use the Url.RouteUrl method to get alternative language urls.
Example 1 - Path: /
url.Action("Index", "Blog") // returns "/Blog" that is OK
url.Action("Index", "Blog", new { lang = "en" }); // returns "/en/Blog" that is also OK
Example 2 - Path: /en
url.Action("Index", "Home") // returns "/en/Blog" (??????????) Not OK
url.Action("Index", "Home", new { lang = "en" }); // returns "/en/Blog" that is OK
As you can see I get a wrong result when I access the url http://myappurl/en and try to use the Url.Action method without pass any route value (same result with Url.RouteUrl)
Does anyone knows what is wrong with my routes?
[EDIT] I'm not sure if the issue is related to the route because I've tested the routes using "en" as first route's constraint and I got the same result.
After some digging inside System.Web.Mvc and System.Web.Routing source code I found that this behavior is expected. I presume that it is designed to correctly work in applications running inside Virtual Directories.
This can be confirmed in this answer that I found when was researching if someone else had the same problem with virtual path and route resolution.
Workaround
Use named route resolution with Url.RouteUrl method that has and different implementation and works as expected.
Example:
var blogDefaultUrl = url.RouteUrl("Default", new {action = "Index", controller = "Blog"});
var blogLangageSpecifictUrl = url.RouteUrl("Default.lang", new { action = "Index", controller = "Blog", lang = language });
I was avoiding to use named routes because my application design is a little bit more complicated than I demonstrated above. By this reason I have to discover at run time the route that matches the Request.Url and from that point I call the RouteUrl to get the alternative languages url to the content.
I'm brand new to MVC so please bear with me as I'm only on the second page of the MS Tutorial (see last code example). For the HelloWorldController the following MapRoute is added:
routes.MapRoute(
name: "Hello",
url: "{controller}/{action}/{name}/{id}");
I'm just wondering, is it purely the pattern matching that does the work and the name "Hello" is just for my own reference? If so, are there not naming conventions that should be followed saying the MapRoute should be called HelloWorldWelcome, where welcome is a method inside the HelloWorldController.cs (see above link). Or am i being pedantic?
The route name is also used by the UrlHelper class. For example:
var url = Url.Route("Hello", new
{
controller = "SomeController",
action = "SomeAction",
name = "charlie",
id = 123
});
This will generate a matching URL.
This feature is much more useful when you use Attribute Routing. For example, if on some controller you have an action:
[RoutePrefix("api/phonebook")]
public class PhonebookController
{
[HttpGet("contact/{id}", Name = "GetContact")]
public Contact GetContact(int id)
{
...
}
}
In other code you could use Url.Route("GetContact", new { id = 7 }) to generate the URL /api/phonebook/contact/7.
Please refer to details on ASP.NET MVC Routing Overview
Name attribute is for callign a route from your views or controller with route name.
From ActionLink your can use a routename:
Html.RouteLink("link_text", "route_name", route_parameters)
The question seems to be not so clearly answered (how the "Hello" route is choosen by the "HelloWorld" controller?), but as an Asp.Net MV5 begginer, I can see that the route is selected by default according to the match between the router url property and the URL parameters.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "ImageScan", action = "ScanImage", id = UrlParameter.Optional },
namespaces: new[] { "WebApplication3.Controllers" }
);
I am finding error :
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: /Views/ImageScan/ScanImage.cshtml
In my asp.net MVC application, the Home controller works without any problems. But remaining controller class or action method couldn't call instead of i got the HTTP status 404 error - File not found.
MY web-server - IIS 5.1
Note: I added wild character in the configuration (.*)
the following code snippet contains Global.asx file
routes.MapRoute("Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
I am running into the following error with my ASP.NET MVC 3 project:
Multiple types were found that match
the controller named 'Home'. This can
happen if the route that services this
request ('Home/{action}/{id}') does
not specify namespaces to search for a
controller that matches the request.
If this is the case, register this
route by calling an overload of the
'MapRoute' method that takes a
'namespaces' parameter.
The request for 'Home' has found the
following matching controllers:
MyCompany.MyProject.WebMvc.Controllers.HomeController
MyCompany.MyProject.WebMvc.Areas.Company.Controllers.HomeController
I have a HomeController in my default controller folder, with a class name of MyCompany.MyProject.WebMvc.Controllers.HomeController.
My RegisterRoutes method, in my global.asax, looks like:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
I then have an area called Company, with a HomeController in the default controller folder for the area, with a class name of MyCompany.MyProject.WebMvc.Areas.Company.Controllers.HomeController.
The RegisterArea method in the CompanyAreaRegistration file looks like:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Company_default",
"Company/{controller}/{action}/{id}",
new { area = "Company", action = "Index", id = UrlParameter.Optional }
);
}
This is all leading the error I highlighted at the beginning of this post. I am struggling trying to piece together a solution from various other posts, with NO LUCK.
Is it possible to have a HomeController in the default controllers folder and then one in EACH area? If so, do I need to make (assuming I do) changes to my configuration file to make this work?
Any help would be much appreciated!
The error message contains the recommended solution: "If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter."
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new string[] { "MyCompany.MyProject.WebMvc.Controllers"}
);
This will make http://server/ go to your HomeController's Index action which is, I think, what you want. http://server/company/home will go to the Company area's HomeController's Index action, as defined in the area registration.
This is the asp.net mvc4 approach:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "RegisterNow", id = UrlParameter.Optional },
namespaces: new[] { "YourCompany.Controllers" }
);
I had renamed the namespaces, so, i only delete de folders bin and obj and rebuild, work again.
If you're using RazorGenerator, just informing the namespaces parameter could be not enough.
I got to solve adding the statement marked below at Global.asax.cs:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ControllerBuilder.Current.DefaultNamespaces.Add("MyProject.Controllers"); // This one
}
Another plausible cause of this issue could be found below:
Multiple types were found that match the controller named 'Home'
use this
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "ProjectName.Controllers" }
);
Use only the name of the project:
Public Class RouteConfig
Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
routes.MapRoute( _
name:="Default", _
url:="{controller}/{action}/{id}", _
defaults:=New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional} _
, namespaces:={"MvcAreas"})
End Sub
I had the same issue and found that the older version had created compiled files in the "bin" folder.
Once I deleted these the error disappeared.
As Chris Moschini mention the namespaces parameter may not be enough if you have two areas with same controller name with different namespaces and the default none area route will return 500 server error.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new string[] { "MyCompany.MyProject.WebMvc.Controllers"}
);
It "best" to override the default route handler and add this line:
RequestContext.RouteData.DataTokens["UseNamespaceFallback"] = false;
I had this issue after I added a reference to another project that had the same routes and the problem continued after I removed the reference.
Resolved by deleting the .dll file of that added reference from the bin folder and rebuilding.
Like many others, I had this problem after creating a new MVC template project from VS2017 menu, on building the project I would get the op's error message. I then used the answer https://stackoverflow.com/a/15651619/2417292 posted earlier in this thread by cooloverride
for mvc4 projects.
This still didn't fix my issue so I renamed my Home view folder and HomeController file to be the view folder Company/ and controller file CompanyController. This then worked for me, not a fix per say but a workaround if your not stuck on having the route Home/Index my other issue was I couldn't find the reference causing the error and due to my dev platform being Azure WebApplication vs a full VM with a complete file system and IIS settings to mess with.
For MVC5 below code works for issue same controller name for different areas. You have to specify which area controller have to hit first.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "ApplicationName.Areas.AreaName.Controllers" }
).DataTokens.Add("area", "AreaName");
This issue occurred when I accidentally added
[Route("api/[controllers]s")]
instead of
[RoutePrefix("api/[controllers]s")]
to the top of my ApiController.
In trying to get my application to produce 404 errors correctly, I have implemented a catch all route at the end of my route table, as shown below:
routes.MapRoute(
"NotFound", _
"{*url}", _
New With {.controller = "Error", .action = "PageNotFound"} _
)
However, to get this working, I had to remove the default route:
{controller}/action/{id}
But now that the default has been removed, most of my action links no longer work, and the only way I have found to get them working again is to add individual routes for each controller/action.
Is there a simpler way of doing this, rather than adding a route for each controller/action?
Is it possible to create a default route that still allows the catch all route to work if the user tries to navigate to an unknown route?
Use route constraints
In your case you should define your default route {controller}/{action}/{id} and put a constraint on it. Probably related to controller names or maybe even actions. Then put the catch all one after it and it should work just fine.
So when someone would request a resource that fails a constraint the catch-all route would match the request.
So. Define your default route with route constraints first and then the catch all route after it:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { controller = "Home|Settings|General|..." } // this is basically a regular expression
);
routes.MapRoute(
"NotFound",
"{*url}",
new { controller = "Error", action = "PageNotFound" }
);
//this catches all requests
routes.MapRoute(
"Error",
"{*.}",
new { controller = "PublicDisplay", action = "Error404" }
);
add this route at the end the routes table
Ah, the problem is your default route catches all 3 segment URLs. The issue here is that Routing runs way before we determine who is going to handle the request. Thus any three segment URL will match the default route, even if it ends up later that there's no controller to handle it.
One thing you can do is on your controller override the HandleMissingAction method. You should also use the tag to catch all 404 issues.
Well, what I have found is that there is no good way to do this. I have set the redirectMode property of the customErrors to ResponseRewrite.
<customErrors mode="On" defaultRedirect="~/Shared/Error" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="~/Shared/PageNotFound"/>
</customErrors>
This gives me the sought after behavior, but does not display the formatted page.
To me this is poorly done, as far as SEO goes. However, I feel there is a solution that I am missing as SO does exactly what I want to happen. The URL remains on the failed page and throws a 404. Inspect stackoverflow.com/fail in Firebug.
My Solution is 2 steps.
I originally solved this problem by adding this function to my Global.asax.cs file:
protected void Application_Error(Object sender, EventArgs e)
Where I tried casting Server.GetLastError() to a HttpException, and then checked GetHttpCode.
This solution is detailed here:
ASP.NET MVC Custom Error Handling Application_Error Global.asax?
This isn't the original source where I got the code. However, this only catches 404 errors which have already been routed. In my case, that ment any 2 level URL.
for instance, these URLs would display the 404 page:
www.site.com/blah
www.site.com/blah/blah
however, www.site.com/blah/blah/blah would simply say page could not be found.
Adding your catch all route AFTER all of my other routes solved this:
routes.MapRoute(
"NotFound",
"{*url}",
new { controller = "Errors", action = "Http404" }
);
However, the NotFound route does not seem to route requests which have file extensions. This does work when they are captured by different routes.
I would recommend this as the most readable version. You need this in your RouteConfig.cs, and a controller called ErrorController.cs, containing an action 'PageNotFound'. This can return a view. Create a PageNotFound.cshtml, and it'll be returned in response to the 404:
routes.MapRoute(
name: "PageNotFound",
url: "{*url}",
defaults: new { controller = "Error", action = "PageNotFound" }
);
How to read this:
name: "PageNotFound"
= create a new route template, with the arbitrary name 'PageNotFound'
url:"{*url}"
= use this template to map all otherwise unhandled routes
defaults: new { controller = "Error", action = "PageNotFound" }
= define the action that an incorrect path will map to (the 'PageNotFound' Action Method in the Error controller). This is needed since an incorrectly entered path will not obviously not map to any action method
I tried all of the above pattern without luck, but finally found out that ASP.NET considered the url I used as a static file, so none of my request was hidding the single controller endpoint. I ended up adding this snipper to the web.config
<modules runAllManagedModulesForAllRequests="true"/>
And then use the below route match pattern, and it solved the issue:
routes.MapRoute(
name: "RouteForAnyRequest",
url: "{*url}",
defaults: new { controller = "RouteForAnyRequest", action = "PageNotFound" }
);