How to configure a route to dynamically map url to a compiled named controller in ASP.NET MVC3

I need to map the urls like this:

/ stocks / risk → StockRiskController.Index()

/ stock / risk / attr → StockRiskController.Attr()

/ srock / risk / chart → StockRiskController.Chart()

...

/ communication / performance - BondPerformanceController.Index()

/ bond / performance / attr → BondPerformanceController.Attr()

/ communication / performance / schedule → BondPerformanceController.Chart() ...

The first part is dynamic, but enumerable, the second part has only two options (risk | performance).

Now I know only two ways:

  • configured ControllerFactory (seems too overpriced or complicated)
  • hard code of all combinations because they are listed (ugly).

Can I use routes.MapRoute to achieve this? Or any other convenient way?

+3
source share
1 answer

There is a good solution based on IRouteConstraint . First of all, we need to create a new route mapping:

 routes.MapRoute( name: "PrefixedMap", url: "{prefix}/{body}/{action}/{id}", defaults: new { prefix = string.Empty, body = string.Empty , action = "Index", id = string.Empty }, constraints: new { lang = new MyRouteConstraint() } ); 

The next step is to create our constraint. Before I talk about how to check relevance, as mentioned above, there are two lists with possible values, but the logic can be adjusted.

 public class MyRouteConstraint : IRouteConstraint { public readonly IList<string> ControllerPrefixes = new List<string> { "stock", "bond" }; public readonly IList<string> ControllerBodies = new List<string> { "risk", "performance" }; ... 

And now the Match method, which will adjust the routing as needed

 public bool Match(System.Web.HttpContextBase httpContext , Route route, string parameterName, RouteValueDictionary values , RouteDirection routeDirection) { // for now skip the Url generation if (routeDirection.Equals(RouteDirection.UrlGeneration)) { return false; } // try to find out our parameters string prefix = values["prefix"].ToString(); string body = values["body"].ToString(); var arePartsKnown = ControllerPrefixes.Contains(prefix, StringComparer.InvariantCultureIgnoreCase) && ControllerBodies.Contains(body, StringComparer.InvariantCultureIgnoreCase); // not our case if (!arePartsKnown) { return false; } // change controller value values["controller"] = prefix + body; values.Remove("prefix"); values.Remove("body"); return true; } 

You can play with this method more, but the concept should be clear now.

NOTE. I like your approach. Sometimes it’s much more important to extend / configure routing, then go to the code and “correct the names”. A similar solution works here: Dynamically change RouteValueDictionary

+2
source

All Articles