Using recursive partial view in MVC raises Stack empty InvalidOperationException

时间秒杀一切 提交于 2019-12-11 03:20:10

问题


I want to create a recursive menu with recursive elements. My first approach was to use Partial Views in order to re-use code.. Alas, when I run the code, it throws a "System.InvalidOperationException" "Stack empty" error.

I am mapping data from a web service with AutoMapper, which results in the following entity:

public interface INavigationItemContract
{
    int Id { get; set; }
    string Title { get; set; }
    int ParentId { get; set; }
    string Url { get; set; }
    bool DisplayInMenu { get; set; }
    decimal SortOrder { get; set; }
    IEnumerable<IPageBaseContract> Pages { get; set; }
    IEnumerable<INavigationItemContract> Sites { get; set; }
}

The partial view to initialize the menu (_Menu.cshtml):

@model IEnumerable<INavigationItemContract>

<div class="navbar navbar-default" role="navigation">
    <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
    </div>
    <div class="navbar-collapse collapse">
        <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
            @foreach (var navigationItem in Model)
            {
                @Html.Partial("_MenuItem", navigationItem);
            }
        </ul>
    </div>
</div>

The partial to display the menu item (_MenuItem.cshtml):

@model INavigationItemContract

@if (Model.Pages != null && Model.Pages.Any())
{
    if (Model.Pages.Count() == 1 || !Model.DisplayInMenu)
    {
        // Only one page, so this will be the default.
        // Other option is that the pages should not be displayed, so then we'll only display the link to the site.
        <li><a href="@Model.Url">@Model.Title</a></li>
    }
    else
    {
        <li>
            <a href="#">@Model.Title</a>
            <ul class="dropdown-menu">
                @foreach (var page in Model.Pages)
                {
                    <li><a href="@page.RelativeUrl">@page.Title</a></li>
                }
                @foreach (var site in Model.Sites)
                {
                    @Html.Partial("_MenuItem", site)
                }
            </ul>
        </li>
    }
}

When replacing the

@Html.Partial("_MenuItem", site)

with

<li>@site.Title</li>

everything works like a charm (except for the fact that it is not the desired result).

I have tried the following approaches as well:

  • Create a DisplayTemplate
  • Use Html.RenderPartial instead of Html.Partial

The exception occurs in the _MenuItem.cshtml:

@Html.Partial("_MenuItem", site)

It does not occur the first time the partial is called (in the _Menu.cshtml), only in the _MenuItem.cshtml itself, when it is calling itself.

Why am I getting this exception? And what might be the solution?


回答1:


I have found a workaround. The exception still puzzles me, but I can continue to render the menu (even though I do not have the ability to set a breakpoint on the helper code)..

@model IEnumerable

@helper RecursiveMenuItem(INavigationItemContract menuItem)
{
    if (menuItem.Pages != null && menuItem.Pages.Any())
    {
        if (menuItem.Pages.Count() == 1 || !menuItem.DisplayInMenu)
        {
            // Only one page, so this will be the default.
            // Other option is that the pages should not be displayed, so then we'll only display the link to the site.
            <li><a href="@menuItem.Url">@menuItem.Title</a></li>
        }
        else
        {
            <li>
                <a href="#">@menuItem.Title</a>
                <ul class="dropdown-menu">
                    @foreach (var page in menuItem.Pages)
                    {
                        <li><a href="@page.Url">@page.Title</a></li>
                    }
                    @foreach (var site in menuItem.Sites)
                    {
                        @RecursiveMenuItem(site)
                    }
                </ul>
            </li>
        }
    }
}
<div role="navigation">
    <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
    </div>
    <div class="navbar-collapse collapse">
        <ul class="nav navbar-nav">
            <li><a href="">Home</a></li>
            @foreach (var menuItem in Model)
            {
                @RecursiveMenuItem(menuItem)
            }
        </ul>
    </div>
</div>



回答2:


Not sure, but shouldn't you explicit the enumeration to use in the model by replacing :

@foreach (var navigationItem in Model)

by

@foreach (var navigationItem in Model.Sites)

for instance ?



来源:https://stackoverflow.com/questions/24280534/using-recursive-partial-view-in-mvc-raises-stack-empty-invalidoperationexception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!