Рекурсивный ViewComponent вызывает бесконечный цикл

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

Мое мышление было так:

  1. В главном представлении компонент вызывается с пустым List<ViewModelProductCategory> в качестве параметра, чтобы указать, что я хочу получить корневые категории в первую очередь.

  2. ViewComponent запрашивает базу данных для категорий с ParentId == null и возвращает его Default.cshtml,

  3. В Default.cshtml, компонент вызывается снова, но на этот раз со списком дочерних категорий в качестве параметра.

Я вызываю ViewComponent следующим образом:

@await Component.InvokeAsync("SelectCategories", 
        new List<MyStore.Models.ViewModels.ViewModelProductCategory> { })

Класс ViewComponent выглядит следующим образом:

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MyStore.Models;
using MyStore.Models.ViewModels;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyStore.Areas.Admin.ViewComponents
{
    public class SelectCategoriesViewComponent : ViewComponent
    {
        private readonly MyStoreContext _context;
        private readonly IMapper _mapper;

        public SelectCategoriesViewComponent(MyStoreContext context, IMapper mapper)
        {
            _context = context;
            _mapper = mapper;
        }

        public async Task<IViewComponentResult> InvokeAsync(List<ViewModelProductCategory> catList)
        {
            List<ViewModelProductCategory> VM = await GetCategoriesAsync(catList);
            return View(VM);
        }

        private async Task<List<ViewModelProductCategory>> GetCategoriesAsync(List<ViewModelProductCategory> catList)
        {
            List<ViewModelProductCategory> VM = new List<ViewModelProductCategory>();
            if (catList.Count() == 0)
            {
                VM = _mapper.Map<List<ViewModelProductCategory>>
                    (await _context.ProductCategories
                    .Where(x => x.ParentId == null)
                    .ToListAsync());
            }
            else
            {
                VM = catList;
            }
            return VM;
        }
    }
}

ViewComponent's Default.cshtml выглядит так:

@model IEnumerable<MyStore.Models.ViewModels.ViewModelProductCategory>
<ul style="list-style:none;padding-left:0px;">
    @if (Model != null)
    {
        foreach (var item in Model)
        {
            <li style="margin-top:4px;padding:0px;">
                @Html.HiddenFor(m => item.Id)
                @Html.CheckBoxFor(m => item.Checked)
                @Html.LabelFor(m => item.Id, item.Title)
                <ul>
                    @await Component.InvokeAsync("SelectCategories", item.Children)
                </ul>
            </li>
        }
    }
</ul>

Где / находятся ошибки / с?

редактировать

Комментарий от Тарека. Легко заставил меня понять, что у меня был плохой логический недостаток в GetCategoriesAsync-метод. Я внес эти изменения в свой код, и теперь он работает:

Вызов ViewComponent в первый раз:

@await Component.InvokeAsync("SelectCategories",
new
{
    root = true,
    catList = new List<MyStore.Models.ViewModels.ViewModelProductCategory>()
})

ViewComponent-методы:

public async Task<IViewComponentResult> InvokeAsync(bool root, List<ViewModelProductCategory> catList)
{
    List<ViewModelProductCategory> VM = await GetCategoriesAsync(root, catList);
    return View(VM);
}

private async Task<List<ViewModelProductCategory>> GetCategoriesAsync(bool root, List<ViewModelProductCategory> catList)
{
    List<ViewModelProductCategory> VM = new List<ViewModelProductCategory>();
    if (root)
    {
        VM = _mapper.Map<List<ViewModelProductCategory>>
            (await _context.ProductCategories
            .Where(x => x.ParentId == null)
            .ToListAsync());
    }
    else
    {
        VM = catList;
    }
    return VM;
}

Вызов ViewComponent в Default.cshtml:

@await Component.InvokeAsync("SelectCategories",
new
{
    root = false,
    catList = item.Children
})

:)

1 ответ

Решение

Если я прав, просто посмотрите на (.Where(x => x.ParentId == null)) в GetCategoriesAsync Вы всегда получаете корневую категорию и больше ничего не проверяете.

Другие вопросы по тегам