ASP.Net MVC 4 w/ AttributeRouting and multiple RoutePrefix attributes
Solution 1
I ended up finding a solution to this
I just overrided the default routes to include this. ASP.Net automatically keeps the usertype value and puts it back in when it regenerates the routes
const string userTypeRegex = "^(full|lite)$";
routes.Add("Default", new Route("{usertype}/{controller}/{action}/{id}",
new { controller = "Sessions", action = "Login", id = UrlParameter.Optional }, new { usertype = userTypeRegex }));
I found that this didn't work with the Route
or RoutePrefix
attributes, and so I had to remove all of them. Forcing me to add specific routes in these cases
routes.Add("Profile-Simple", new Route("{usertype}/profile/simple",
new { controller = "ProfileSimple", action = "Index" }, new { usertype = userTypeRegex }));
I thought that a half-dozen hard coded routes in my RouteConfig
file was a better solution than having to manually add values to each place I generated a URL (as in Chris's solution).
Solution 2
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"] })
Andrew Murphy
Updated on June 19, 2022Comments
-
Andrew Murphy almost 2 years
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?
-
John over 9 yearsI'm confused, is there any difference in what those routes are actually providing or just so the url looks different but the same data is returned to the user? Are you using the url to check for authentication?
-
Andrew Murphy over 9 yearsThe URL needs to look different but the same data is returned to the user. There's an external authentication system for the two different types of user that requires "lite" users to have all their URLs prefixed with /lite/ and "full" users to have all their URLs prefixed with "full"
-
Samuele over 9 yearsI'm not sure if it would work (typing from my tablet atm), but you could try subclassing your
ResultsController
toFullResultsController
andLiteResultsController
, and apply the relativeRoutePrefix
attributes to both. No need to duplicate any code. -
John over 9 yearsI'm hoping thats not the only authentication that is happening or it would be very easy (though it does seem pointless) for the user to change from
lite
tofull
. You might want to see about using re-write rules or something or like you mentioned wrap the route change methods with your own that does the replacement after creating the route. -
Andrew Murphy over 9 years@John No, there is external authentication. It's just for that to work it requires my URLs to be structured as I mentioned
-
Andrew Murphy over 9 years@Samuele I'm not duplicating code. The solution I have allows the correct URLs to access the correct methods. It's more about the generation of Url.Action and RedirectToAction values
-