1

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

网址示例:

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

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

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

有了这个,我可以将 pc、p、c 映射到必要的控制器,但如果可能的话,我宁愿避免。

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

4

1 回答 1

1

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 _urlsvariable. (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)

于 2012-12-16T11:04:50.223 回答