I need to map URLs like this:
/stock/risk -->StockRiskController.Index()
/stock/risk/attr -->StockRiskController.Attr()
/srock/risk/chart -->StockRiskController.Chart()
...
/bond/performance -->BondPerformanceController.Index()
/bond/performance/attr -->BondPerformanceController.Attr()
/bond/performance/chart -->BondPerformanceController.Chart()
...
The first part is dynamic but enumerable, the second part has only two options(risk|performance).
For now I know only two ways:
Can I use routes.MapRoute to achieve this? Or any other handy way?
There is a nice solution based on IRouteConstraint. First of all we have to create 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() }
);
Next step is to create our Constraint. Before I will introduce some way how to check relevance as mentioned above - two list with possible values, but logic could 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 we need
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 is simply much more important to extend/adjust routing then go to code and "fix names". Similar solution was working here: Dynamically modify RouteValueDictionary
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With