ASP.Net MVC Управление базами данных меню Странный вывод HTML - PullRequest
1 голос
/ 31 марта 2010

У меня есть вспомогательное меню, управляемое базой данных, которое вызывается из моей главной страницы:

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

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

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

Вот как это должно выглядеть Правильно http://img718.imageshack.us/img718/9317/screenshot20100328at120.png

Иногда это выглядит так: альтернативный текст http://img413.imageshack.us/img413/9317/screenshot20100328at120.png

Вот код (логическое значение IsAdmin в этом сценарии равно false):

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

1 Ответ

0 голосов
/ 25 мая 2011

Я согласен с комментариями, что объединение строк для этого является болезненным. TagBuilder намного менее болезнен для вас.

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

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

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

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

...