1

Is there a simple catch-all way to ensure only rewritten URLs can invoke a controller?

For example, if we have a URL www.somesite.com/about pointing to action "About" in controller "Shared", can it be ensured that any requests to www.somesite.com/shared/about end up at the rewritten URL, in this case www.somesite.com/about?

In other words, the user should not be able to just type /controller/action without being redirected to the rewritten URL.

However, we don't want to actively check and redirect but were hoping for some built-in function of MVC. The only suggestions I found along those lines were ChildActionOnly and HttpPost attributes, but they don't seem to be the answer (normal links don't work).

As mentioned, we're looking for something simple, more or less built-in - if it doesn't exist then so be it...

devlock
  • 959
  • 1
  • 9
  • 14

1 Answers1

1

The built-in way of blocking routes is to use IgnoreRoute. It short-circuits routing and always makes the path throw a 404 not found.

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

        // Ignore /Home/About
        routes.IgnoreRoute("Home/About");

        // Register /About
        routes.MapRoute(
            name: "About",
            url: "About",
            defaults: new { controller = "Home", action = "About" }
        );

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

Note that under the covers, it uses the StopRoutingHandler, which can be used (as a replacement for MvcRouteHandler) in any custom Route or RouteBase implementation to make more dynamic ignore rules than this.

NOTE: It is extremely important that IgnoreRoute is registered before the route you want to ignore in the route table.

Community
  • 1
  • 1
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • Good answer. However, if you're going to be doing this type of thing a lot, you may be better served by utilizing attribute routing instead. That way you customize the route for each action exactly how you want it to be. – Chris Pratt Jun 02 '16 at 16:12
  • @Chris Pratt: wouldn't it be a problem if multiple rewritten urls invoke the same controller action (e.g. localised urls)? – devlock Jun 02 '16 at 16:16
  • Not at all. You can add multiple route attributes to an action or even paramaterize portions. For example: `[Route("about"), Route("{lang}/about")]`. Now, either `/about/` or `/es/about/` would match. Technically, that would allow something like `/home/about/`, but "home" would be passed as the value for the `lang` parameter, not as the controller name. You could limit the the `lang` parameter, though, to stop this, i.e. `Route("{lang:regex(es|en)}/about")` – Chris Pratt Jun 02 '16 at 16:30
  • @devlock - See [this question](http://stackoverflow.com/questions/37492195/how-do-you-route-a-page-to-an-attribute-route-in-mvc-5). Attribute routes automatically block the usage of convention-based alternate URLs to an action. Even those who *want* it can't seem to find a way to do it. – NightOwl888 Jun 02 '16 at 16:31