It isn't possible with the built-in routes, but you can extend the RouteBase class to support it.
public class ProductRoute : RouteBase {
private readonly IRouteHandler _routeHandler;
public ProductRoute(IRouteHandler handler) {
_routeHandler = handler;
}
public override RouteData GetRouteData(HttpContextBase httpContext) {
string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath + httpContext.Request.PathInfo;
IDictionary<string, string> routeValues;
if (TryGetRouteValuesForAlias(virtualPath, out routeValues)) {
var data = new RouteData(this, _routeHandler);
foreach (var routeValue in routeValues) {
data.Values.Add(routeValue.Key, routeValue.Value);
}
return data;
}
//No route data for alias found, return null, which means that this route doesn't match the path
return null;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) {
string virtualPath = null;
if (GetVirtualPathForRouteData(values, out virtualPath);) {
VirtualPathData result = new VirtualPathData(this, match);
return result;
}
//No virtual path found for the route data
return null;
}
}
We are using something similar in our CMS. The implementation of the functions GetVirtualPathForRouteData
and TryGetRouteValuesForAlias
is tied with our solution, so I won't post it here, but I think you get an idea, how it is working.
Essentially the GetVirtualPathForRouteData
function takes dictionary of route parameters (e.g. controller, action, id) and tries to find an URL for them. The TryGetRouteValuesForAlias
do the reverse process it takes URL and tries to find a route parameters for it.
Edit (sample implementation of the GetVirtualPathForRouteData and TryGetRouteValuesForAlias)
//key - url, value - route values
IDictionary<string, IDictionary<string, string>> _urls;
public bool TryGetRouteValuesForAlias(string path, out IDictionary<string, string> routeValues) {
return _urls.TryGetValue(path, out routeValues);
}
public bool GetVirtualPathForRouteData(RouteValueDictionary routeValues, out string virtualPath) {
foreach (var url in _urls) {
if (this.CompareValuesLists(url.Value, routeValues)) {
virtualPath = url.Key;
return true;
}
}
return false;
}
private bool CompareValuesLists(IDictionary<string, string> urlValues, IDictionary<string, object> routeValues) {
if (urlValues.Count != routeValues.Count) {
return false;
}
foreach (var key in urlValues.Keys) {
if (!routeValues.ContainsKey(key)) {
return false;
}
if (!string.Equals(urlValues[key], Convert.ToString(routeValues[key]), StringComparison.OrdinalIgnoreCase)) {
return false;
}
}
return true;
}
}
Routing data is held in the _urls
variable. (In our solution we have a little more complicated solution - instead of the simple variable we are using a DI container to get an instance of a class, that is responsible for loading and caching data from DB)