Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add route parameter before MVC choses a route

I am trying to add support for different languages to existing MVC 3 application. So far my links were

oldUrl -> myapp.com/Item/Details/5/some-title

And there are links to the website from different places on the web. But now I want to change the URL so the language is included:

newUrl -> kmyapp.com/en/Item/Details/5/some-title

However I want the oldUrl links to be valid. And the question is how do I do this... The easiest way would be to add another route, but I already have too many of them and it is getting kind of ugly, and when I create urls from a page that doesn't have the language the links also don't have the language so I have to do something else then.

Another way would be to override something that stands just before MVC tries to map the request to a specific route, but has already parsed the request url and filled the routeValues dictionary. So I can just check for the language and if it is not included in the route parameters I can add it on my own and call the implementation of the parent class to continue. Is that possible? What should I look at - UrlRoutingModule, MvcHttpHandler or something else? What can I override and how to tell MVC to use my version?

Any other ideas would be also appreciated!

like image 641
Draganov Avatar asked Feb 07 '12 21:02

Draganov


1 Answers

There are of course many solutions. I'm going to show you two:

  • one that you control in your application
  • one that you control outside of your application (on IIS)

Solution one - Asp.net MVC routing

Provide routing that covers old and new routing:

routes.MapRoute(
    "New",
    "{lang}/{controller}/{action}/{id}",
    new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { lang = "en|de|it|es|fr" }
);
routes.MapRoute(
    "NewEx",
    "{lang}/{controller}/{action}/{id}/{title}",
    new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional, title = UrlParameter.Optional },
    new { lang = "en|de|it|es|fr" }
);

routes.MapRoute(
    "Old",
    "{controller}/{action}/{id}",
    new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
    "OldEx",
    "{controller}/{action}/{id}/{title}",
    new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional, title = UrlParameter.Optional }
);

As you can see I've provided language default for the old routes as well since it's not present in the URL. Whether you want that or not is your own decision but this kind of routing makes it possible to not duplicate your controller actions. In any case you'd have to define a default language which can be provided this way.

There's a bigger question whether you still want to support old URLs or you'd rather redirect them (HTTP Redirect Permanent Status 301).

Permanent redirection

Change old routes to:

routes.MapRoute(
    "Old",
    "{controllerOld}/{actionOld}/{idOld}",
    new { controller = "Redirect", action = "Permanent", id = UrlParameter.Optional }
);
routes.MapRoute(
    "OldEx",
    "{controllerOld}/{actionOld}/{idOld}/{titleOld}",
    new { controller = "Redirect", action = "Permanent", id = UrlParameter.Optional, title = UrlParameter.Optional }
);

Then write a controller class that does redirection:

public class RedirectController : Controller
{
    public ActionResult Permanent(string controllerOld, string actionOld, string idOld, string titleOld)
    {
        return RedirectToRoutePermanent(new {
            lang = "en",
            controller = controllerOld,
            action = actionOld,
            id = idOld,
            title = titleOld
        });
    }
}

Solution two - IIS URL rewriting module

This solution relies on IIS URL Rewriting module, where you could rewrite any requests without language selection to your preferred default.

I'm not going to wrote how URL Rewriting works here, because there're plenty of web resources with detailed info about that.

like image 78
Robert Koritnik Avatar answered Sep 22 '22 05:09

Robert Koritnik