0

I have some simple views like "About Us" and "Contact Us" that live in the Home controller.

I would prefer the url not have the home part in it like www.xyz.com/ContactUs instead of www.xyz.com/Home/ContactUs

I added a new route that takes care of this but breaks other controllers when not specifying an action in the url

// Home Routes
RouteTable.Routes.MapRoute("HomeRoute", "{action}", new { controller = "Home", action = "Index" });

// Default
RouteTable.Routes.MapRoute("Default", "{controller}/{action}", new { controller = "Home", action = "Index" });

This is obviously because the route engine can't tell which route to use for a url like www.xyz.com/ContactUs and uses the 1st one to match.

I also know I can make controllers for each but this seems like a less efficient way. I'd hate to end up with 30 controllers just to wrap one empty view action per view.

I'll probably end up making controllers for each anyway but wanted to know if there is a way to make a route that says something like "If only one parameter is passed, first check to see if it matches a controller, if not assume it's for the home controller."

user3953989
  • 1,844
  • 3
  • 25
  • 56
  • See [Why map special routes first before common routes in asp.net mvc?](https://stackoverflow.com/a/35674633/). You need *something* to tell MVC when to skip the first route and move to the second route. The simplest option is to use static URLs in your route config, like `ContactUs` rather than using `{action}` (which can literally match anything). Attribute routing is another option, but it comes with its own set of issues (namely, that you always have to be aware when you create them that attributes have *undefined order* by default, so you may have to explicitly set the Order property). – NightOwl888 Nov 18 '17 at 18:27

1 Answers1

3

You can use MVC Attribute routing to create these SEO friendly routes.

[Route("About")]
public ActionResult About()
{
    return View();
}
[Route("Contact")]
public ActionResult Contact()
{
    return View();
}

Assuming you have attribute routing enabled.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapMvcAttributeRoutes();

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", 
                                                          id = UrlParameter.Optional }

    );
}

Another option is to have 2 route registrations similar to what you have tried. It will work for handing the request like yourSite/About/ (it will render executes the About action in your HomeController). But when you request something like yourSite/Books, it will not be handled by Index action of Books controller as that url is matching to the first pattern we defined for SEO friendly routes and you will get a 404 if there is no Books action method in HomeController! (If you did not have this route registration, it would have worked)

routes.MapRoute(
    name: "JustActions",
    url: "{action}",
    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 }
);

Another option, if you do not prefer the attribute routing approach, you can register routes in your RegisterRoutes method for this specific routes one by one. (This is similar to defining the route via attribute routing, but we do it in a single place. Make sure to have the specific routes registered before the generic default one). I personally prefer attribute routing over that as i feel that is more readable.

Shyju
  • 214,206
  • 104
  • 411
  • 497
  • I guess I didn't think about just making a specific route per view instead of trying to make one generic one. Is there any downside to using attribute routing in terms of performance, testing, etc? – user3953989 Nov 18 '17 at 03:55
  • 1
    There is no performance overhead i am aware of. I personally prefer the attribute routing approach than separate specific route definition as i feel it is more readable. – Shyju Nov 18 '17 at 04:05
  • Of course there is performance overhead for using attribute routing. It relies on Reflection to read the values you put into the attributes. That overhead is usually limited to application startup, though. – NightOwl888 Nov 18 '17 at 18:20