ASP.Net MVC 4 w/ AttributeRouting and multiple RoutePrefix attributes

Andrew Murphy picture Andrew Murphy · Oct 23, 2014 · Viewed 12.1k times · Source

TL;DR

I need a way to programtically choose which RoutePrefix is chosen when generating URLs based on the properties of a user in my MVC app

Not TL;DR

I have an MVC 4 app (with the AttributeRouting NuGet package)

Due to the requirements of the hosting environment I have to have two routes for a lot of my actions so that the hosting environment can have different permissions for access.

I am solving this by decorating my controller with with [RoutePrefix("full")] [RoutePrefix("lite)]. which allows each action method to be accessed via /full/{action} and /lite/{action}.

This works perfectly.

[RoutePrefix("full")]
[RoutePrefix("lite")]
public class ResultsController : BaseController
{
    // Can be accessed via /full/results/your-results and /lite/results/your-results and 
    [Route("results/your-results")]              
    public async Task<ActionResult> All()
    {
    }

}

However, each user should only use either full or lite in their urls, which is determined by some properties of that user.

Obviously when I use RedirectToAction() or @Html.ActionLink() it will just choose the first available route and won't keep the "correct" prefix.

I figured I can override the RedirectToAction() method as well as add my own version of @Html.ActionLink() methods.

This will work, but it will involve some nasty code for me to generate the URLs because all I get is a string representing the action and controllers, but not the reflected types. Also there might be route attributes such as in my example, so I am going to have to replicated a lot of MVCs built in code.

Is there a better solution to the problem I am trying to solve?

Answer

Chris Pratt picture Chris Pratt · Oct 23, 2014

How about something like:

[RoutePrefix("{version:regex(^full|lite$)}")]

Then, when you create your links:

@Url.RouteUrl("SomeRoute", new { version = "full" })

Or

@Url.RouteUrl("SomeRoute", new { version = "lite" })

You could even do the following to just keep whatever was already set:

@Url.RouteUrl("SomeRoute", new { version = Request["version"] })