Changing URL with Routing, ASP.NET MVC - asp.net-mvc

I am still very new to routing with asp.net mvc, so perhaps this is obvious and I am just missing the answer...
I have a controller named 'pages', and it has several action results, 'Information', 'History' etc. Each action result takes a string, and from that, it returns a View based on the name of the string. So...
Pages/Information/About
Pages/Information/Products
Pages/History/Employees
etc. The Controller is named 'Pages', of course. I'm wondering if I can use Routing to remove the 'Pages' part of the URL on the user side, just for a more user-friendly approach?

Yep you can do that:
context.MapRoute(
"Pages_History_Employees",
"History/Employees", // URL with parameters
new { controller = "Pages", action = "History" }
);
Just specify the controller as Pages and specify whatever url you want as the second parameter. What this is saying is I want to route the History/Employees URI to the Pages controller and use the History action to handle this route.
Just be careful that if you have the default MVC route in there that it appears at the end of your routes or it will match this route first. Then you will get an error since it will be looking for the History controller with the Employees action.

Related

How do I tell what is part of a route is the controller and what is just a sub folder?

When looking at an MVC page and looking at the form action I can see it is set to:
/admin/WikiAdmin/edit/
So I spent my time looking for a controller called admin. I looked in the routes in the global and nothing was there.
Eventually I found that this url actually maps to the WikiAdmin controller which is confusing. Do does this mean you can have controllers in sub-folders? How does the app know not to forward the request to the admin controller and to actually send it to the WikiAdmin controller?
The admin part of the url is called area. You could read more about areas in this article. And a video here. Basically areas allow you to group multiple controllers sharing some common functionality on the site.
Yes, you can have controllers in sub-folders. With routing it could be a lot of possible URLs.
For example, if you have a route registered as below:
routes.MapRoute(
"admin1",
"admin/{controller}/{action}/",
new { controller = "WikiAdmin", action = "Index"}
);
The url can be /admin/WikiAdmin/Index/ or /admin/WikiAdmin/Edit/ or something else that matches the route. (Assume that there is an Edit action in WikiAdmin controller)
More example, if you have a route registered as below:
routes.MapRoute(
"admin2",
"account/{action}/", //no controller specified in url
new { controller = "WikiAdmin", action = "Index"}
);
Then the url can be /account/Index/ or /account/Edit/ or even /account/. (Because default controller is WikiAdmin and default action is Index)

What do the curly braces mean in a route in MVC?

I'm setting up my routes with an MVC project but im a little confused about the curly braces...
If I have...
routes.MapRoute( "Music", "Music/{name}", new { } );
What is the purpose of the curly braces around name, does this get passed to something? Or does this map to something if I pass a default object in?
They are parameter names that are used in routing requests. For example the default route defines three of them:
{controller}/{action}/{id}
controller and action parameters are for finding your controller action. id parameter can be used as an input in those actions.
When you define a custom route you have to provide controller and action parameters. If they are not defined in your URL, you should provide default values so MVC knows what action to run when a request matches that route.
routes.MapRoute("Music",
"Music/{name}",
new { controller="Music", action="SomeAction" });
Other parameters like id or name like you defined can be used to provide input to actions. In your example, name parameter is passed to matching action like this:
public ActionResult SomeAction(string name)
{
//do something
}
The curlybraces indicate a kind of named wildcard.
The "Music/Index" route will only match the URL Music/Index and nothing else
The "Music/{Name}" route will match any URLs starting with Music, and having anything after the slash. It will match both the URLs Music/metallica and Music/madonna.
With the curly brace, you'll be able to pick up "metallica" or "madonna" from the above URLS as routevalues.
As a final example: With ASP.NET MVC, there's always a standard route. {controller}/{action}/{id}. This route will catch URLs like Music/genre/rock or Product/edit/5.
The resulting routevalues for these two will be:
controller=music, action=genre and id=rock for the first one
controller=product, action=edit and id=5 for the last one.
I'll try to provide a less contrived example.
Routes in ASP.NET MVC are placed into a dictionary, and when there's an incoming request, the MVC pipeline looks at the request and tries to determine what Controller and Action to route it to.
So let's say I have the following controllers: Home, Forum, and Article
And while we're at it, let's say I have the following actions: View, Edit, Create on both the Forum and Article controllers.
Those braces allow me to create one route for both:
routes.MapRoute("Viewing",
{controller}/{action}/{id},
new {controller = "Article", action="" }, //The article controller has precedence
new { controller = "Article|Forum" } //contrived for this example
);
Those braces mean that whatever controller they put in (as long as it's Article or Forum based on the Constraints), the same route works. This keeps me from having to have a route for each and every action in the Forum and Article controller.
I could have just as easily made two routes:
routes.MapRoute("Articles",
article/{action}/{id},
new {controller = "Article" } //The article controller has precedence
);
routes.MapRoute("Forums",
forum/{action}/{id},
new { controller = "forum" }
);
But there's duplication there that doesn't need to be there.
Routes are also pretty tricky things, in that order matters. The top route will be evaluated before the bottom route. If it matches the top route's structure, it will go to that action, even if that's not the right action.
Phil Haack has a Route Debugger that helps with this. And I've also taken his source code and modified it so that you can make it a control and put it on all your pages as a partial (and hopefully you will also put code on there that would only allow internal folks to see it).

MVC Routing: Trying to get dynamic root value working

I am trying to define dynamic sections of my site with the root url of the site. I am having some trouble defining the right MVC Route for it. Can someone please help.
My desired url will look like this: http://website.com/[dynamic-string]
But I have other standard pages like: http://website.com/about or http://website.com/faq or even just http://website.com.
My routes don't work correctly with that dynamic string. As shown below.
This is the route for the dynamic-string.
routes.MapRoute(
"CommunityName", // Route name
"{communityName}", // URL with parameters
new { controller = "Community", action = "Community", communityName = UrlParameter.Optional }
);
This is the route for all other STANDARD PAGES
routes.MapRoute(
"Default", // Route name
"{action}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
My routes just don't match up. Everything either gets diverted to one or the other route depending on which route is declared first.
There is no difference between the two routes you mention. How can MVC know which url should be mapped to communityName and which to action? Any url can match both.
You can define your standard pages as a route (before the CommunityName route) or you can catch them in your Community action, see if the name matches a function in your Home controller and then call the right action function.
I've never done this before but you might be able to create a more intelligent routehandler that looks at your controller actions, checks if the action really exists and if true selects that route.
this is beacuse the routes are effectively the same. When you declare the action route you do not state any constraints to the route, for this reason anything will be assumed to be a the action name.
If you want two routes to capture at the same level then you must constrain the action names to those that exist on your controller, this way if it does not match it will pass to the next route.
You can see an example of and advanced constraint here:
http://blogs.planetcloud.co.uk/mygreatdiscovery/post/Custom-route-constraint-to-validate-against-a-list.aspx

ASP.NET MVC Routing Questions

I just started using ASP.NET MVC and I have two routing questions.
How do I set up the following routes
in ASP.NET MVC?
domain.com/about-us/
domain.com/contact-us/
domain.com/staff-bios/
I don't want to have a controller specified in the actual url in order to keep the urls shorter. If the urls looked liked this:
domain.com/company/about-us/
domain.com/company/contact-us/
domain.com/company/staff-bios/
it would make more sense to me as I can add a CompanyController and have ActionResults setup for about-us, contact-us, staff-bios and return appropriate views. What am I missing?
What purpose does the name "Default" name have in the default routing rule in Global.asax? Is it used for anything?
Thank you!
I'll answer your second question first - the "Default" is just a name for the route. This can be used if you ever need to refer to a route by name, such as when you want to do URL generation from a route.
Now, for the URLs that you want to set up, you can bypass the controller parameter as long as you're ok with always specifying the same controller as a default. The route might simply look like this:
{action}/{page}
Make sure that it's declared after your other routes, because this will match a lot of URLs that you don't intend to, so you want the other routes to have a crack at it first. Set it up like so:
routes.MapRoute(null, "{action}/{page}",
new { controller = "CompanyController", action = "Company", page = "contact-us" } );
Of course your action method "Company" in your MyDefault controller would need to have a "string page" parameter, but this should do the trick for you. Your Company method would simply check to see if the View existed for whatever the page parameter was, return a 404 if it didn't, or return the View if it did.
Speaking of setting up routes and Phil Haack, I have found his Route Debugger to be invaluable. It's a great tool for when you don't understand why particular routes are being used in place of others or learning how to set up special routing scenarios (such as the one you've mentioned). It's helped clear up many of the intricacies of route creation for me more than any other resource.
To answer your second question about Global.asax, it an optional file used for responding to application level and session-level events raised by ASP.NET or HTTP modules. The Global.asax file resides in the root directory of the ASP.NET application.If you do not define it assumes you have not defined any application handler or session handler. MVC framework uses the routing engine to which the routing rules are defined in the engine, so as to map incoming URL to the correct controller.
From the controller, you can access the ActionName. If there is no specific controller, it will direct to the default page. The default controller is "Home" with its default action "Index". Refer to MSDN:
http://msdn.microsoft.com/en-us/library/2027ewzw%28v=vs.100%29.aspx
Refer to stackoverflow question
What is global.asax used for?
This is a sample of how a default route should look like
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id =
UrlParameter.Optional }
);

How can I implement Dynamic Routing with my choice of URL format?

My URL requirement is countryname/statename/cityname. For this I'm writing my own RouteHandler and adding one new route into the routecollection like this:
routes.Add(new Route("{*data}",
new RouteValueDictionary(new
{
controller = "Location",
action = "GetLocations"
}),
new MyRoutehandler()));
Now my question is: How do I generate this type of URL?
I tried Html.ActionLink() but it's asking for an action name and controller name. However, in my URL format I don't have any action name or controller name. How do I solve this?
Is there a reason you can't just use the following with the built-in route handler:
routes.MapRoute("LocationRoute",
"{countryname}/{statename}/{cityname}",
new { controller = "Location", action = "GetLocations" });
That may conflict with the default "{controller}/{action}/{id}" route, but that would happen with your current system anyway (unless you make a custom Route, inheriting from System.Web.Routing.RouteBase, rather than a custom Route Handler). The Route Handler is for handling what to do AFTER the route data has been extracted. Since you're still using Controller and Action, you should still be able to use the MvcRouteHandler. If you want to customize how the Route Data is extracted, you probably want a custom Route.
Btw, if you want to use a route which doesn't involve Controller and Action names, use Html.RouteLink. ActionLink is just a wrapper which puts the controller and action into the RouteValuesDictionary and calls the same internal helper as RouteLink.
Although in this case, the route still has a Controller and Action ("Location" and "GetLocations"), so you can still use ActionLink. I think ActionLink lets you specify a Route Name, so if you give your route a name you can specify that name in ActionLink and it will use that route to generate the URL (I may be wrong about that and if so you can still use RouteLink and manually add the controller and action route values)

Resources