How to create root routes without displaying controller name in link - asp.net-mvc

I was just wondering if anybody can point me to right direction. Here's my problem:
I have a controller in Controllers folder called Events, and there I have some ActonResult methods Index, Search, Details, which returns Views from the
View/Events/Index,Search,Details
and some partial views from shared folder.
Now what will be the best way to display those Views without controllers name. My index view is now displayed as
localhosts|domain.com.../Events/Index or localhosts|domain.com.../Events/Details/1
and I wan't to be displayed as
localhosts|domain.com... or localhosts|domain.com.../Details/1
Now, I am curious if those changes will have any effects for my AJAX calls which are:
just part of a js code
#Url.Action("index", "Events"),
and
url: "#Url.Content("~/Events/MyAjaxSearch")",
data: "searchString=test&Location=test",
I also have some params in my Index method for pageNum(this is for infinite pagination).
Bellow is my RouteConfig code:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Events", "", new { controller = "Events", action = "Index" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Events", action = "Index", id = UrlParameter.Optional });
Regards!

Try this:
routes.MapRoute(
name: "EventDetails",
url: "Details/{id}",
defaults: new { controller = "Events", action = "Details", id = UrlParameter.Optional }
);

Related

MVC 4 - Remove /Home/ from address bar and retain folder name for others

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.

Need to simplify URLs via ASP.NET MVC routing pattern in RouteConfig.cs

I'm trying to simplify the URLs in an application, and am struggling with the route registration. This is an administrative tool. In many cases we have a List view (List.cshtml) and a Details view (Index.cshtml). The pattern that I would like to implement for these URLs are as follows:
http://mysite/person/list (This view shows a list of people)
http://mysite/person/123 (View will show details for a person with an ID of 123)
Formatting the URls that way is more of a nice-to-have feature for polishing the site. I tried several routes, and in RouteConfig here are some of the more recent routes that I've tried.
routes.MapRoute(
name: "Person",
url: "Person/{action}/{id}",
defaults: new { controller = "Person", action = "Index" }
);
routes.MapRoute(
name: "PersonID",
url: "Person/{id}",
defaults: new { controller = "Person", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Dashboard", action = "Index", id = UrlParameter.Optional }
);
Now if I remove those custom routes, and just run with the default route, the "mysite/person/list" view works just fine. But when I select a person, the URL ends up being "mysite/person/index/[id]" instead of "mysite/person/[id]". And if I manually remove "index" from that URL and make the path "mysite/person/[id]", a "resource cannot be found" message appears.
In that second route shown, I figured that giving the route a default action would route to the Index page and treat the ID in the URL as an ID, rather than as an action. With the current configuration shown above, if I navigate to the Person/List view I'm routed to the Person/Index view.
There are a few other actions associated with that controller (like JsonResults), which I'll need to handle as well.
What is the correct way to write the routes to support the URLs that I've indicated above? Also, can you recommend a resource that shows multiple examples of route-to-URL comparisons? Thanks for your help!
=== Edit 4/9/2015 at 10:21 AM ===
Based on the answer provided by #stephen-reindl, this is the solution that I implemented. Since we have multiple interfaces with a "Detail" view, I chose a default action of "Detail". This route recognizes a GUID.
// Support URL format of http://mysite/{controller}/{guid}
// Example: http://mysite/person/474f4357-39b2-45a2-b02b-6be04b2302fe
routes.MapRoute(
name: "DetailViewWithGuid",
url: "{controller}/{id}",
constraints: new { id = #"\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b" },
defaults: new { action = "Detail", id = UrlParameter.Optional }
);
You can add a constraint that a specific route is only taken into consideration if the constraint is fulfilled:
routes.MapRoute(
name: "PersonID",
url: "Person/{id}",
constraints: new { id = #"\d+" },
defaults: new { controller = "Person", action = "Index", id = UrlParameter.Optional }
);
In this case this route is only taken if id is a number.

ASP.NET MVC4 - Different routing for 2 controllers with actionLinks

Okay, I've got this case where I have two controllers:
HomeController
MathController
I want the routing for my HomeController to stay as default:{controller}/{action}/{id}. But I want to access the actions in the MathController with http://myurl/Task/Math/{action}.
So what I've done is to write my RouteConfig like this:
routes.MapRoute(
name: "Math",
url: "Task/{controller}/{action}",
defaults: new { controller = "Math", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Hem", id = UrlParameter.Optional }
);
When using the above configuration and manually entering the URLs in the browser both routing methods are working. Though when trying to add a "actionLink" it always uses the Task/{Controller}/{Action} route. Even if I'm creating a link for the Home controller like this: #Html.ActionLink("Hem", "Hem", "Home", null, new { #class = "navbar-brand" })
How do I configure either my routing or my action links so that I'll get the preferred functionality?
Routes match from top down in RouteConfig.cs. Your problem is that both route configs are "catch all" routes, which means both work for any controller/action. When you use #Html.ActionLink, MVC will render the url based on the 1st route it finds, which matches your "Task" path. There are few ways to change this to get what you want.
If you want to only use the "Task" path for the Math controller, then I'd change your route to this:
routes.MapRoute(
name: "Math",
url: "Task/Math/{action}",
defaults: new { controller = "Math", action = "Index" }
);
If you want to use several controllers for the "Task" path, then you can add a route constraint. You can use it like below and specify a list of controllers (regex), or you can create your own custom Route Constraint class and implement whatever functionality you want.
routes.MapRoute(
name: "Math",
url: "Task/{controller}/{action}",
defaults: new { controller = "Math", action = "Index" },
constraints: new { controller = "Math|OtherController" }
);
Or if you want to keep all controllers/actions matching both urls, then you have to flip your routes to get the default route to display first, or you can use #Html.RouteLink like so:
#Html.RouteLink("Hem", "Default", new { controller = "Home", action = "Hem" }, new { #class = "navbar-brand" })

Change Index of Directory

I'm working on an ASP.NET MVC web application. By default, browsing to the root of a directory seems to call the controller's Index() method. Is there way to change which method is called by default here? I know I could probably name the method I want to call "Index" and it would likely work, but I'd like to know if there's a way to point the directory root to a method that I choose.
For example: mysite.com/MyDirectory/ will call Index(), which is effectively browsing to mysite.com/MyDirectory/Index. I'd like to change it so that mysite.com/MyDirectory/ calls Details, (or "browses" to mysite.com/MyDirectory/Details).
Just change the action in the default route. Something like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Details", id = UrlParameter.Optional } // Parameter defaults
);
You could specify the behavior in your routes. If you are using the latest version of MVC, that would be in your \App_Start\RouteConfig.cs
You would have something like:
routes.MapRoute(
name: "MyDirectory",
url: "MyDirectory",
defaults: new { controller = "MyDirectory", action = "Details" });
You would place this before your default route, as your route table acts kind of like a switch statement matching on the first route that it finds.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "MyDirectory",
url: "MyDirectory",
defaults: new { controller = "MyDirectory", action = "Details" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}

ASP.NET MVC routing to action

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 });

Resources