【问题标题】:How to route very similar URLs to different controller actions?如何将非常相似的 URL 路由到不同的控制器操作?
【发布时间】:2012-12-03 13:55:38
【问题描述】:

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

网址示例:

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

有什么方法可以在不包含 URL 中的标识符来映射控制器操作的情况下完成此操作。例如:

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

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

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

【问题讨论】:

  • 那么,您希望将相同的路由映射到两个控制器,而对于什么映射到什么没有任何规则?这听起来像是要求奇怪的命名空间冲突。
  • 当你这样说的时候还不错:-)
  • 我相信您只需将无法区分的 URL 模式映射到单个控制器操作,并根据您想要的任何规则消除歧义。 ASP.NET 路由似乎与 URL 模式完美结合。

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


【解决方案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 函数采用路由参数字典(例如控制器、操作、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 加载和缓存数据)

【讨论】:

  • 感谢您提供此信息,这是最有帮助的。我明白了,但我不能 100% 确定您概述的方法的实施。也许我问了很多,但是您可以通过电子邮件将您必须增强我理解的自定义解决方案发送给我吗?
  • 我已在答案中添加了方法的示例实现。它仍然不是复制粘贴解决方案,但现在应该更清楚了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多