如何将非常相似的URL路由到不同的控制器操作?

时间:2012-12-16 01:20:23

标签: asp.net-mvc url-rewriting routing asp.net-mvc-4

我目前正在使用MVC4 Web应用程序并遇到了一些我不确定如何处理的路由问题。我希望能够将我的URL映射到控制器操作,但URL没有区别因素来帮助我理解哪些URL需要哪些控制器操作。

网址示例:

  • / [产品类别]
  • / [产品类别] / [产品名称]
  • / [产品类别] / [产品子类别] / [产品名称]
  • / [随机内容名称]

有没有办法在不在URL中包含标识符来映射控制器操作的情况下工作。例如:

  • / pc / [产品类别]
  • / p / [产品类别] / [产品名称]
  • / p / [产品类别] / [产品子类别] / [产品名称]
  • / c / [随机内容名称]

有了这个,我可以将pc,p,c映射到必要的控制器,但我希望尽可能避免。

有没有办法实现我的概述?

1 个答案:

答案 0 :(得分:1)

内置路由无法实现,但您可以扩展RouteBase类以支持它。

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;
    }
}

我们在CMS中使用类似的东西。函数GetVirtualPathForRouteDataTryGetRouteValuesForAlias的实现与我们的解决方案相关联,因此我不会在此发布,但我认为您会了解它是如何工作的。

基本上GetVirtualPathForRouteData函数接受路由参数字典(例如controller,action,id)并尝试查找它们的URL。 TryGetRouteValuesForAlias执行与URL相关的反向过程并尝试为其查找路由参数。

编辑(GetVirtualPathForRouteData和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;
    }
}

路由数据保存在_urls变量中。 (在我们的解决方案中,我们有一个更复杂的解决方案 - 而不是简单的变量,我们使用DI容器来获取类的实例,负责从DB加载和缓存数据)