2010-03-31 3 views
1

У меня есть база данных приводится в меню Помощника, который вызывается из моей главной странице:ASP.Net MVC базы данных Driven меню Странный HTML выход

<div class="topBar"> 
     <%= Html.MenuTree(39, false, "first", "last") %>  
     <div class="clear"></div> 
    </div> 

Ниже приведен код, который выводит мой HTML неупорядоченный список. Проблема в том, что иногда вывод меню полностью неправильный и повсюду, т.е. элементы подменю выглядят одинаково как элементы верхнего меню.

Я не могу найти ни одного шаблона, почему он так думает, я бы опубликовал код, чтобы узнать, может ли кто-нибудь обнаружить проблему. Моя единственная мысль состоит в том, что каким-то образом ее половина кэшируется наполовину и смешивает выход.

Это то, что он должен выглядеть Correct http://img718.imageshack.us/img718/9317/screenshot20100328at120.png

Иногда выходит так: alt text http://img413.imageshack.us/img413/9317/screenshot20100328at120.png

Вот код (булево IsAdmin ложна в этом сценарии):

public static string MenuTree(this HtmlHelper helper, int MenuCategoryID, bool Admin, string firstCssClass, string lastCssClass) 
    { 

     //TODO: Check for Subsonic fix for UNION bug 
     IOrderedQueryable<Menu> menuItems; 
     if (Admin) 
     { 
      menuItems = (from menu2 in Menu.All() 
         join pages in WebPage.All() on menu2.PageID equals pages.ID 
         join pagesRoles in PageRole.All() on pages.ID equals pagesRoles.PageID 
         join roles in aspnet_Role.All() on pagesRoles.RoleId equals roles.RoleId 
         where Roles.GetRolesForUser().Contains(roles.RoleName) && menu2.CategoryID == MenuCategoryID && menu2.Visible 
         select menu2).Distinct().OrderBy(f => f.OrderID); 
     } 
     else 
     { 
      menuItems = (from menu2 in Menu.All() 
         join pages in WebPage.All() on menu2.PageID equals pages.ID 
         where menu2.CategoryID == MenuCategoryID && menu2.Visible 
         select menu2).Distinct().OrderBy(f => f.OrderID); 
     } 

     var nonlinkedmenuItems = (from menu in Menu.All().Where(x => x.PageID == null && x.CategoryID == MenuCategoryID && x.Visible).OrderBy(f => f.OrderID) select menu); 

     var allCategories = menuItems.ToList().Concat<Menu>(nonlinkedmenuItems.ToList()).OrderBy(p => p.OrderID).ToList(); 

     allCategories.ForEach(x => x.Children = allCategories.Where(y => y.ParentID == x.ID).OrderBy(f => f.OrderID)); 

     Menu home = null; 

     if (Admin) 
     { 
      home = (from menu in Menu.All() 
        join pages in WebPage.All() on menu.PageID equals pages.ID 
        where pages.MenuName == "Home" && pages.IsAdmin 
        select menu).SingleOrDefault(); 
     } 

     IEnumerable<Menu> topLevelItems; 
     if (Admin) 
      topLevelItems = allCategories.Where(f => f.ParentID == 0 && (f.Children.Count() > 0 || f.ID == home.ID)); 
     else 
      topLevelItems = allCategories.Where(f => f.ParentID == 0); 

     var topLevelItemList = topLevelItems.ToList(); 

     sbMenu.Length = 0; 
     sbMenu.AppendLine("<ul>"); 

     LoopChildren(helper, Admin, topLevelItemList, 0, firstCssClass, lastCssClass); 
     sbMenu.AppendLine("</ul>"); 



     string menuString = sbMenu.ToString(); 

     //if ((menuString.IndexOf("<li>")) > 0) 
     // menuString = menuString.Insert((menuString.IndexOf("<li>") + 3), " class='first'"); 

     //if (menuString.LastIndexOf("<li>\r\n") > 0) 
     // menuString = menuString.Insert((menuString.LastIndexOf("<li>\r\n") + 3), " class='last'"); 

     return sbMenu.ToString(); 
    } 

    private static void LoopChildren(this HtmlHelper helper, bool Admin, List<Menu> CurrentNode, int TabIndents, string firstCssClass, string lastCssClass) 
    { 
     for (int i = 0; i < CurrentNode.Count; i++) 
     { 
      sbMenu.Append(Tabs(TabIndents + 1)); 
      string linkUrl = ""; 
      string urlTitle = ""; 
      if (CurrentNode[i].PageID != null) 
      { 
       WebPage item = WebPage.SingleOrDefault(x => x.ID == CurrentNode[i].PageID); 
       linkUrl = item.URL; 
       urlTitle = item.MenuName; 
      } 
      else 
      { 
       linkUrl = CurrentNode[i].URL; 
       urlTitle = CurrentNode[i].Title; 
      } 

      //Specify a RouteLink so that when in Error 404 page for example the links don't become /error/homepage 
      //If in admin we can manually write the <a> tag as it has the controller and action in it 
      bool selected = false; 
      if (helper.ViewContext.RouteData.Values["pageName"] != null && helper.ViewContext.RouteData.Values["pageName"].ToString() == linkUrl) 
       selected = true; 

      string anchorTag = Admin ? "<a href='" + linkUrl + "'>" + urlTitle + "</a>" : helper.RouteLink(urlTitle, new { controller = "WebPage", action = "Details", pageName = linkUrl }); 

      if (TabIndents == 0 && i == 0 && firstCssClass != null) 
       sbMenu.AppendLine("<li class='" + firstCssClass + "'>" + anchorTag); 
      else if (TabIndents == 0 && i == (CurrentNode.Count - 1) && lastCssClass != null) 
       sbMenu.AppendLine("<li class='" + lastCssClass + "'>" + anchorTag); 
      else if (selected) 
       sbMenu.AppendLine("<li class='selected'>" + anchorTag); 
      else 
       sbMenu.AppendLine("<li>" + anchorTag); 



      if (CurrentNode[i].Children != null && CurrentNode[i].Children.Count() > 0) 
      { 
       sbMenu.Append(Tabs(TabIndents + 2)); 
       sbMenu.AppendLine("<ul>"); 
       LoopChildren(helper, Admin, CurrentNode[i].Children.ToList(), TabIndents + 2, "", ""); 
       sbMenu.Append(Tabs(TabIndents + 2)); 
       sbMenu.AppendLine("</ul>"); 
      } 
      sbMenu.Append(Tabs(TabIndents + 1)); 
      sbMenu.AppendLine("</li>"); 
     } 

    } 

    private static string Tabs(int n) 
    { 
     return new String('\t', n); 
    } 
+3

Почему вы не используете PartialView для этого? Все, что встроенная конкатенация строк болезненно читать, не удивительно, почему ее трудно найти проблемы. ;) – jfar

+1

yaiks, пожалуйста, не 'StringBuilder' для генерации HTML! Для этой цели существует «TagBuilder». –

ответ

0

I согласитесь с комментариями, что конкатенация строк для этого болезненно. TagBuilder гораздо менее болезнен для вас.

Я не проверял ваш код на наличие проблем, но я полагаю, что то, что я хотел бы сделать, это в основном вывести текст из вашего помощника в хорошем случае и в плохом случае и запустить их через инструмент diff. Оставьте некоторые маркеры до и после точки, где вы вызываете Html.MenuTree() для целей отладки - таким образом вы точно узнаете, где начинается и останавливается вывод.

Инструмент diff подскажет вам, каковы различия в двух выходах. Затем вы можете искать причину этих различий.

Еще один способ, который я бы всерьез рассматривал, заключается в его модульном тестировании. Начните с простого модульного теста, дающего метод MenuTree() очень простую структуру для работы. Убедитесь, что выход является нормальным. Затем проверьте более сложные сценарии. Если вы во время тестирования, отладки или в производстве обнаружите определенную комбинацию ввода, которая вызывает проблему, напишите единичный тест, который проверяет правильность вывода . Затем исправьте его. Когда тест пройдет, вы узнаете, что закончите. Кроме того, если вы проводите тесты каждый раз, когда вы что-то меняете, вы узнаете, что эта конкретная ошибка никогда не вернется.

Новая ошибка? Новый единичный тест. И так далее. Единичные тесты никогда не решают проблему для вас, но они дают вам уверенность в том, что то, что раньше работало, даже когда вы реорганизуете и придумываете интересные новые вещи.

Смежные вопросы