Asp.net mvc 3.0树形结构页面自定义路由

时间:2011-06-30 06:08:25

标签: asp.net-mvc seo asp.net-mvc-routing url-routing

我想将所有CMS页面网址映射到单个控制器(PageController)和操作(详细信息)。

如何创建自定义路由以映射所有这些网址?

/teacher
/teacher/kindergarten
/teacher/kindergarten/1
/teacher/primary
/teacher/primary/english
/teacher/primary/language
/teacher/primary/language/chinese
/teacher/primary/math
/teacher/primary/science
/parent
/parent/kindergarten
/parent/primary1-3
/parent/primary4-6
/leader
/leader/kindergarten
/leader/kindergarten/1

2 个答案:

答案 0 :(得分:1)

如果您在数据库中有这些URL,则可以在应用程序启动时映射路由:

  var pages = siteDB.Pages.ToList();
  string pagePath = "";
  foreach (var page in pages)
  {
    routeVals = new RouteValueDictionary();
    constraints = new RouteValueDictionary();

    routeVals.Add("controller", "page");
    routeVals.Add("action", "details");

    constraints.Add("path", "[a-zA-Z0-9\\-]*");

    // any child pages? must add these routes before their parent pages.
    var childPages = siteDB.Pages.Where(p => p.ParentPageId == page.PageId).ToList();
    foreach (var childPage in childPages)
    {
      pagePath = BuildPath(childPage);
      RouteTable.Routes.Add(new Route(pagePath, new MvcRouteHandler())
      {
        Defaults = routeVals,
        Constraints = constraints,
        DataTokens =
            new RouteValueDictionary {
            { "pageid", childPage.PageId },
            { "path", pagePath }
          }
      });

      // Any further child pages? (Only 3 levels supported)
        var childSubPages = siteDB.Pages.Where(p => p.ParentPageId == childPage.PageId).ToList();
        foreach (var childSubPage in childSubPages)
        {
            pagePath = BuildPath(childSubPage);
            RouteTable.Routes.Add(new Route(pagePath, new MvcRouteHandler())
            {
                Defaults = routeVals,
                Constraints = constraints,
                DataTokens =
                    new RouteValueDictionary {
                { "pageid", childSubPage.PageId },
                { "path", pagePath }
              }
            });
        }
    }

此代码从数据库中获取页面,这些页面由父ID链接。

这是BuildPath函数,它生成每个页面的完整路径:

public static string BuildPath(Page page)
{
  if (page.ParentPageId == 1)
  {
    return page.PageKey;
  }
  else
  {
    SiteDataEntities siteDB = new SiteDataEntities();
    string path = page.PageKey;
    Page parent = siteDB.Pages.Find(page.ParentPageId);
    while (parent != null)
    {
      path = parent.PageKey + "/" + path;
      parent = siteDB.Pages.Find(parent.ParentPageId);
      if (parent.PageKey == "home") break;
    }
    return path;
  }
}

答案 1 :(得分:1)

以前提出的解决方案仅适用于少量页面。 因为根据代码:

应用程序为每个站点页面生成并注册Route。结果,我们的网站数量至少与网站中的网页数量相同。您可能知道RouteModule必须通过路由检查每个路由以找到第一个并执行正确的处理程序,控制器,操作,视图......

还有另外两种方法可以解决这个问题:

  • 您可以创建一个派生自RouteBase的类,并实现您需要的属性和方法:将url拆分为segment,使用pageid,path,parents等确定当前页面填充RouteValueDictionary

  • 您可以使用custom rewrite provider自定义UrlRewriteModule。想要将所有请求URL从树基础结构转换为mvc默认路由:

    {控制器} / {行动} / {ID}?路径= parentlevel1 / parent2 / parent3 /....

可以准备两种变体的90%相同的代码。 当你有不同的控制器时,该解决方案也很有用,正确的当前页面可以确定(通过页面数据:类型)