Avoiding the Controller with Routing Rules in ASP.NET MVC - asp.net-mvc

I've created a website with ASP.NET MVC. I have a number of static pages that I am currently serving through a single controller called Home. This creates some rather ugly URLs.
example.com/Home/About
example.com/Home/ContactUs
example.com/Home/Features
You get the idea. I'd rather not have to create a controller for each one of these as the actions simply call the View with no model being passed in.
Is there a way to write a routing rule that will remove the controller from the URL? I'd like it to look like:
example.com/About
example.com/ContactUs
example.com/Features
If not, how is this situation normally handled? I imagine I'm not the first person to run in to this.

Here's what I've done previously, using a constraint to make sure the shortcuts don't conflict with other routing rules:
routes.MapRoute(
"HomeShortcuts",
"{action}",
new { controller = "Home", action = "Index" },
new { action = "Index|About|ContactUs|Features" }
);

Add defaults for the controller names in the new statement. You don't have to have {controller} in the url.

Related

Conditional routing in ASP.NET MVC

I'll try to describe my problem as simple as I can. I have several controllers which are loaded dynamically at runtime. Those controllers hosts several web apis for different partners. What I want to achieve is to have a prefix in URL before accessing the controller. In other words, I have Partner1 and Partner2. Both of them has some controllers, for example
Partner1: Service1Controller, Service2Controller2.
Partner2: Api1Controller, Api2Controller etc.
Now I want to achieve the following. I want partner1's controllers to be accessible only with Partner1 prefix in the url, for example http://somehost.com/Partner1/Service1, but I don't want Api1Controller to be accessible from http://somehost.com/Partner1/Api1, but instead it should be accessible from http://somehost.com/Partner2/Api1.
Is there any way to achieve my goal?
Thanks
An inelegant solution could be to use 2 separate route mappings:
routes.MapRoute(
"partner1",
"partner1/{controller}/{action}",
new { contoller = Service1Controller, action = "Index" },
new { contoller = #"(Service1Controller)|(Service2Controller)"}
);
routes.MapRoute(
"partner2",
"partner2/{controller}/{action}",
new { controller = Api1Controller, action = "Index" },
new { contoller = #"(Api1Controller)|(Api2Controller)"}
);
Teh 4th parameter of MapRoute defines constraints as regular expressions
You could create a custom ActionFilter that looks at the Request and User and determines if the route is valid. If it's not, then you can return some ActionResult that either redirects or returns an error to the user.

ASP.NET MVC: Many routes -> always only one controller

I have very simple question. My site, based on ASP.NET MVC, can have many urls, but all of them should bring to the one controller. How to do that?
I suppose I need some magic in Global.asax but I don't know how to create route that will redirect any url to the specific controller.
For example I have url /about, /product/id etc. but all of them should be really bring to the content/show where the parts of url will be recognized and the decision what information to show will be make. It's some like CMS when you cannot define routes in advance. Is this information enough?
Thanks
This sounds like a horrible idea, but, well, if you must;
routes.MapRoute(
"ReallyBadIdea",
"{*url}",
new { controller = "MyFatController", action = "MySingleAction" }
);
This routes everything to a single action in a single controller. There's also {*path} and other URL patterns should you want slightly more flexibility.
Ideally you should try and specific with your routes, for example if you have a URL that is /products/42 and you want it to go to a generic controller you should specify it explicitly like
routes.MapRoute(
"Poducts",
"products/{id}",
new { controller = "Content", action = "Show", id = UrlParameter.Optional }
);
then you would specify another route for something else like /customers/42
routes.MapRoute(
"Customers",
"customers/{id}",
new { controller = "Content", action = "Show", id = UrlParameter.Optional }
);
this may seem a little verbose, and creating a single route might seem cleaner, but the issue a single route is you will never get a 404 and will have to handle such things in code.

How can i create a route that returns a URL without controller reference in ASP.NET MVC

I have a controller call DefaultController. Inside this controller i have views for what would be the equivalent of static pages.
The URLs look like www.site.com/Default/PageName
Is it possible to create a route that would format these URL like:
www.site.com/PageName
I want to avoid creating controllers for each of these. An alternative would be to create .aspx pages in the root but can i create routes for these pages ie:
www.site.com/PageName.aspx becomes www.site.com/PageName ?
Thanks!
You can create explicit route for the PageName action on the DefaultController like this:
routes.MapRoute(
"PageName",
"pagename",
new { controller = "DefaultController", action = "PageName" }
);
You have to put this route before the default MVC route. The biggest drawback for this approach is that you have to create one route per static page.
An alternative approach would be to add an additional route after the default MVC route:
routes.MapRoute(
"DefaultController",
"{page}/{*path}",
new { controller = "DefaultController", action = "{page}" }
);
The drawback for this approach is that this rule would be handling all the URLs, even those that would normally return 404.
First approach
Create a route that catches actions:
routes.MapRoute(
"Catcher1",
"{action}",
new { controller = "Default", action = string.Empty });
But this means you'd have to create just as many controller actions on your default controller.
Second approach
If you'd like to avoid that as well and have just one controller+action instead, write a route this way:
routes.MapRoute(
"Catcher2",
"{path}",
new { controller = "Default", action = "PageName", path = string.Emtpy },
new { path = #"[a-zA-Z0-9]+" });
This route also defines a route constraint so it will catch only those routes, that actually have something in first route segment. You can define this constraint to only catch those requests that you need (ie. path = "Result|Search|Whatever")
then your DefaultController would have something like this:
public ActionResult PageName(string path)
{
// code goes here
}
Second approach seems very feasible, but I wouldn't recommend it because all logic would have to go through this controller action (for these kind of requests). It would be better to separate these actions into logical ones. Those that actually do the same thing (so they wouldn't have a bunch of switch statements or similar) would be defined with separate routes (if they couldn't be done using a single one).

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 do you change the controller text in an ASP.NET MVC URL?

I was recently asked to modify a small asp.net mvc application such that the controler name in the urls contained dashes. For example, where I created a controller named ContactUs with a View named Index and Sent the urls would be http://example.com/ContactUs and http://example.com/ContactUs/Sent. The person who asked me to make the change wants the urls to be http://example/contact-us and http://example.com/contact-us/sent.
I don't believe that I can change the name of the controller because a '-' would be an illegal character in a class name.
I was looking for an attribute that I could apply to the controller class that would let me specify the string the controller would use int the url, but I haven't found one yet.
How can I accomplish this?
Simply change the URL used in the route itself to point to the existing controller. In your Global.asax:
routes.MapRoute(
"Contact Us",
"contact-us/{action}/",
new { controller = "ContactUs", action = "Default" }
);
I don't believe you can change the display name of a controller. In the beta, the controller was created using route data "controller" with a "Controller" suffix. This may have changed in RC/RTM, but I'm not sure.
If you create a custom route of "contact-us/{action}" and specify a default value: new { controller = "ContactUs" } you should get the result you are after.
You need to configure routing. In your Global.asax, do the following:
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapRoute(
"route-name", "contact-us/{action}", // specify a propriate route name...
new { controller = "ContactUs", action = "Index" }
);
...
As noted by Richard Szalay, the sent action does not need to be specified. If the url misses the .../sent part, it will default to the Index action.
Note that the order of the routes matter when you add routes to the RouteCollection. The first matched route will be selected, and the rest will be ignored.
One of the ASP.NET MVC developers covers what Iconic is talking about. This was something I was looking at today in fact over at haacked. It's worth checking out for custom routes in your MVC architecture.
EDIT: Ah I see, you could use custom routes but that's probably not the best solution in this case. Unless there's a way of dealing with the {controller} before mapping it? If that were possible then you could replace all "-" characters.

Resources