I'm having trouble doing what I want to achieve when doing routing in ASP.NET MVC.
What I want to do is the following:
When typing http://localhost/MyWebsite/, I want to redirect to http://localhost/MyWebsite/Login/ (The redirection to the action Index is implied here)
When typing http://localhost/MyWebsite/MyAction, I want to redirect to http://localhost/MyWebsite/Login/MyAction
Point 1 was achieved using the following lines in the file RouteConfig.cs:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional });
But I cannot accomplish point 2. Note that the user does not come from another action in a controller, but actually types the address in his browser.
Thanks for your help.
since /MyWebsite/Login and /MyWebsite/MyAction both have two segments in the URL, they're both matching your defined Route.
You can use a Route Constraint to only match /MyWebsite/Login to your first point, followed by a modified second route mapping:
routes.MapRoute(
name: "Default",
url: "MyWebsite/Login/",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
name: "Actions",
url: "MyWebsite/{action}/",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional });
Related
Situation
I'll build my URL like follow:
The overview page on / (at HomeController).
The detail page on /details/123 instead of /home/details/123 knowing that 123 always is a number (at HomeController).
An info page on /info instead of /home/info (at HomeController).
The logon page on /account/signin (at AccountController).
I've don't have more pages on my application.
Try 1
I've created two routes like follow:
routes.MapRoute(
name: "Home",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The problem is that the account page gives a 404. The other pages works.
Try 2
I've created one route like below:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
On each method inside the HomeController added a the Route attribute with the correct URL.
The problem is now that the overview and logon pages works the others gives now a 404.
Question
How could I remove the home directory from the URL with ASP.NET MVC?
To use attribute routes you need to add
routes.MapMvcAttributeRoutes();
to your RouteConfig.cs file.
It should go before your default route.
In my MVC application's RouteConfig I am using this:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute (
name: "Dictionary", // Route name
url: "dictionary/{id}", // URL with parameters
defaults: new { controller = "Dictionary", action = "details" } // Defaults
);
At this time this URL succeeds in returning a page:
http://127.0.0.1:8080/dictionary/details/1
Whereas this fails:
http://127.0.0.1:8080/dictionary/1
With the exception
"HTTP 404.The resource you are looking for (or one of its dependencies) could have been removed, had its name changed..."
When I swap the routing around, like this:
routes.MapRoute (
name: "Dictionary", // Route name
url: "dictionary/{id}", // URL with parameters
defaults: new { controller = "Dictionary", action = "details" } // Defaults
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
It both URLs start returning a page.
Why is this?
Thanks in advance.
FYI This question is different to the possible duplicate because of the UrlParameter.Optional and the wild carded routing in the other question. This question is more about which specific ordering is correct and why.
The order of the routes that you add to the route table is important. If you reversed the order, then the Default route always will get called instead of the custom route.
Reference:
https://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/creating-custom-routes-cs
I am using MVC 4 and need to remove /Home/ folder from address bar...
Eg:
http://localhost:61700/Home/AboutUs
Need to be changed as...
http://localhost:61700/AboutUs
I did that by changing the default controller in "RouteConfig.cs"
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
//url: "{controller}/{action}/{id}",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
The above code is working as expected. I do have another folders as
brand, admin etc... here I want to show the url as
http://localhost:61700/brand/productInfo ... But I am getting server
error here as Server Error in '/' Application.
Can somebody suggest me, where am I doing wrong?
Screenshots here for more info:
This is your current RouteConfig.cs configuration:
routes.MapRoute(
name: "Default",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You're telling Asp.net, when a request arrives, assume the first parameter as the action and the second parameter as the id. Right now you're not telling Asp.net to parse any parameter as the controller. Because of this it uses the default value (given as the third parameter of the MapRoute method) which is in this case Home.
In that case when parsing the request http://localhost:61700/AboutUs the values end up being:
controller: Home (it uses the default controller)
action: AboutUs (from the first parameter)
id: null (this doesn't matter right now)
When parsing the request http://localhost:61700/brand/productInfo the values end up being:
controller: Home (it uses the default controller because you haven't specified where to get the controller name from)
action: Brand (from the first parameter)
id: "productInfo"
The error you're getting is because there isn't a Brand action method in HomeController.cs with a parameter of type string named id.
Asp.net processes incoming requests by trying to match with the routes configured and it uses the first route that matches.
There are several ways to achieve what you want, which include but are not limited to:
Manually mapping every action in your HomeController.cs (choosing this method will depend on the amount of actions in your HomeController). This would look like:
routes.MapRoute(
name: "AboutUs",
url: "AboutUs",
defaults: new { controller = "Home", action = "AboutUs" }
);
routes.MapRoute(
name: "ContactUs",
url: "ContactUs",
defaults: new {controller = "Home", action = "ContactUs" }
);
// etc...
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Note how the default route is the last one, this is important because it is less specific than the others and if put before would match the request and want to look for an AboutUsController.
You could use route constraints. This would look like:
route.MapRoute(
name: "HomeControllerRoutes",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { action = "AboutUs|ContactUs|etc..." } //Here you would put all your action methods from home controller that you want to accces as /{action}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
If you want to read more about route constraints, I found this article that explains that the constrains parameter can receive a regular expression (I suggest you modify the regular expression above to make it case insensitive) or an IRouteConstraint.
Update:
I just read your comment about having 160+ actions in your HomeController that would make your regular expression in my second suggestion quite long. In that case the other options you have could be:
Using a regular expression that rejects all other controller names, but that would violate the open/closed principle (OCP) and every time you add another controller you would have to add it to the regular expression.
Create the regular expression from the metadata of you HomeController class. This would look like
string.Join("|", typeof(HomeController).GetMethods().Select(info => info.Name))
Or you could take a look at IRouteConstraint to see if you could figure out a more elegant solution.
I have no experience with IRouteConstraint
Add this in your route.config / glibal.asax and don't change your default routes. Add following above it.
routes.MapRoute(
name: "About",
url: "AboutUs",
defaults: new { controller = "Home", action = "AboutUs" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I have 160+ views in the home controller
You don't mention how many views you have in the other controllers, nor how complicated they need to be.
Rather than keep the default controller/action and add routes for every view in home, you can add a route for each controller and then have your default route without a controller path.
While this means you do need a route for every controller, it's better than one for every view.
routes.MapRoute(
"AdminRoute",
"Admin/{action}/{id}",
new { controller = "Admin", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
"BrandRoute",
"Brand/{action}/{id}",
new { controller = "Brand", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
"HomeRoute",
"{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
"DefaultRoute",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
(afaicr you don't need the default route as all your views would be covered by the other 3 routes)
Note the path for 'HomeRoute' doesn't have a controller part.
As long as they are in this order any url with /Admin/ or /Brand/ will be picked up first.
I made a change to my routing map which is following now:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}/{title}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, title = UrlParameter.Optional }
);
And this is the actionlinks that are not working anymore:
#Html.ActionLink("Category", "CategoryList", "Category")
When I click on this actionlink nothing happens the url stays the same http://localhost:62394/ as the page reloads. its so weird
and when I check the html it looks like this:
Category
Any kind of help or tips is appreciate alot!
note: If I remove title from the routing it works...
It's because you've got 2 optional parameters so the routing engine doesn't know which one to map the third parameter to. It feels like title is going to be used for a specific route rather than a generic one. If that's the case, why not create a specific route for it and remove it from the generic fallback route?
Something like this:
routes.MapRoute(
name: "Title",
url: "Category-List/{title}",
defaults: new { controller = "Category", action = "CategoryList", title = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
My main starting page is ApplicantProfile, so my default route looks like this:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "ApplicantProfile", action = "Start", id = UrlParameter.Optional }
);
This controller has no index for public access, but all others do. What I would like is the wildcard equivalent, e.g.
routes.MapRoute(
name: "Others",
url: "{controller}/{action}/{id}",
defaults: new { controller = "*", action = "Start", id = UrlParameter.Optional }
);
How can I achieve this?
This should take care of it:
routes.MapRoute(
name: "Default",
url: "ApplicantProfile/{action}/{id}",
defaults: new { controller = "ApplicantProfile", action = "Start", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
Assuming you have ApplicantProfileController, HomeController and OtherController, this will result in:
/ApplicantProfile → ApplicantProfileController.Start
/Other → OtherController.Index
/SomeOtherPath → default 404 error page
/ → default 404 error page
See http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/asp-net-mvc-routing-overview-cs for an introduction to routing. It's a bit old, but it covers the basics well.
Routing happens top-down, meaning it stops at the first match in the routing table. In the first case, you will match your ApplicantProfile route first, so that controller is used. The second case gets Other from the path, finds a matching controller and uses that. The last 2 do not find a matching controller and there is no default specified so a default 404 error is returned. I'd suggest putting in a proper handler for errors. See the answers here and here.
This should work as per your requirement
routes.MapRoute(
name: "ApplicantProfile",
url: "ApplicantProfile/Start/{id}",
defaults: new { controller = "ApplicantProfile", action = "Start", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
First one is url which will route you to "Start' Action, other one is default replace "Home" controller with your default one
The default should goto profile controller with start action and all the other request should land to index action what ever the controller.
Use the IRouteConstraint to add the constraint to the URL for Other Routes and place that above the default controller with the constraint on the Route for the controller.
You can add a check if the controller is not ApplicationProfile use it.
I hope this helps.