ASP.net MVC — Razor HTML Helper захватывает память и не отпускает

У меня есть совершенно новый проект ASP.Net MVC, который потребляет память и отказывается его выпускать по причинам, которые я не могу понять.

Приложение

На сайте всего 2 страницы, обе обслуживаются HomeController.

public class HomeController: Controller
{
    public ActionResult Index()
    {
        GC.Collect();

        return View();
    }

    public ActionResult List()
    {
        GC.Collect();

        var homeViewModel = new HomeViewModel();

        for (int i = 0; i < 300; i++)
        {
            homeViewModel.MyList.Add(new MyClass
            {
                Field1 = "AAAAAAAAAAAAAAAAAAAAAAAAAAA",
                Field2 = "BBBBBBBBBBBBBBBBBBBBBBBBBBB",
                Field3 = "CCCCCCCCCCCCCCCCCCCCCCCCCCC",
                Field4 = "DDDDDDDDDDDDDDDDDDDDDDDDDDD",
                Field5 = "EEEEEEEEEEEEEEEEEEEEEEEEEEE",
                Field6 = "FFFFFFFFFFFFFFFFFFFFFFFFFFF"
            });
        }

        return View(homeViewModel);
    }
}

public class HomeViewModel
{
    public List<MyClass> MyList { get; set; }

    public HomeViewModel()
    {
        MyList = new List<MyClass>();
    }
}

public class MyClass
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
    public string Field3 { get; set; }
    public string Field4 { get; set; }
    public string Field5 { get; set; }
    public string Field6 { get; set; }
}

Вы заметите, что и действия Index, и List вызывают сборку мусора в начале каждого вызова.

Страница индекса просто содержит общий файл _Layout.cshtml и никакого другого содержимого.

@model WebApplication1.Controllers.HomeViewModel

@{
    ViewBag.Title = "Home Page";
}

Страница списка содержит таблицу из 300 строк, каждая из которых показывает 6 строковых свойств класса, предназначенных для демонстрации моей проблемы.

@model WebApplication1.Controllers.HomeViewModel

@{
    ViewBag.Title = "List Page";
}

<table class="table table-condensed">
    @foreach (var item in Model.MyList)
    {
        <tr>
            <td style="@MyHelpers.DetermineStrikethruStyle(true)">@item.Field1</td>
            <td style="@MyHelpers.DetermineStrikethruStyle(true)">@item.Field2</td>
            <td style="@MyHelpers.DetermineStrikethruStyle(true)">@item.Field3</td>
            <td style="@MyHelpers.DetermineStrikethruStyle(true)">@item.Field4</td>
            <td style="@MyHelpers.DetermineStrikethruStyle(true)">@item.Field5</td>
            <td style="@MyHelpers.DetermineStrikethruStyle(true)">@item.Field6</td>
        </tr>
    }
</table>

Как видите, стиль ячеек в таблице основан на результатах Razor HTML Helper, как показано ниже:

@helper DetermineStrikethruStyle(bool isStrikeThru)
{
    @(isStrikeThru ? "text-decoration: line-through;" : "")
}

Проблема

Ниже вы можете увидеть, как съедается память при каждом обновлении страницы списка.

При запуске — показывать домашнюю страницу

введите здесь описание изображения

После обновления индексной страницы x 10

введите здесь описание изображения

После отображения страницы со списком в первый раз

введите здесь описание изображения

После отображения страницы списка во второй раз

введите здесь описание изображения

После отображения страницы списка в третий раз

введите здесь описание изображения

После четвертого отображения страницы со списком

введите здесь описание изображения

После отображения страницы списка в пятый раз

введите здесь описание изображения

Как избежать проблемы

Просто удалив вызовы Razor HTML Helper на странице списка, вы полностью избегаете этой проблемы.

@model WebApplication1.Controllers.HomeViewModel

@{
    ViewBag.Title = "List Page";
}

<table class="table table-condensed">
    @foreach (var item in Model.MyList)
    {
        <tr>
            <td>@item.Field1</td>
            <td>@item.Field2</td>
            <td>@item.Field3</td>
            <td>@item.Field4</td>
            <td>@item.Field5</td>
            <td>@item.Field6</td>
        </tr>
    }
</table>

При запуске — показывать домашнюю страницу

введите здесь описание изображения

После обновления индексной страницы x 10

введите здесь описание изображения

После отображения страницы со списком в первый раз

введите здесь описание изображения

… после пятого раза

введите здесь описание изображения

… после 25-го раза

введите здесь описание изображения

… после 50-го раза

введите здесь описание изображения

Есть идеи? Сейчас я в тупике, и в результате у меня непригодное для использования приложение.

Может ли кто-нибудь предложить какое-либо руководство?


person user2209634    schedule 26.04.2017    source источник
comment
Предполагая, что вы разместили код как есть, не пытаясь его упростить, здесь нет ничего, что могло бы вызвать утечку памяти. Возможно, в том, как вы определяете помощника Razor, есть что-то, что приводит к потреблению большего количества памяти, чем должно быть. Что, если вы попробуете добавить этот помощник как расширение HtmlHelper, а не использовать синтаксис @helper?   -  person Chris Pratt    schedule 26.04.2017
comment
Мне бы хотелось узнать, почему помощник, объявленный директивой использования, вызвал проблему в любом из новых ответов.   -  person vendettamit    schedule 26.04.2017


Ответы (2)


Переехать

@helper DetermineStrikethruStyle(bool isStrikeThru)
{
    @(isStrikeThru ? "text-decoration: line-through;" : "")
}

в методе расширений HtmlHelper на стороне сервера.

public static string DetermineStrikethruStyle(this HtmlHelper helper, bool isStrikeThru)
{
    return isStrikeThru ? "text-decoration: line-through;" : String.Empty;
}
person User.Anonymous    schedule 26.04.2017
comment
Это помогло. Больше никакой утечки памяти! Спасибо! Но есть идеи, почему это может вызвать использование Razor, а не метода расширения HtmlHelper? - person user2209634; 26.04.2017
comment
Я не знаю, но, вероятно, HtmlHelper компилируется внутри сборки, а razer helper на View компилируется на лету. - person User.Anonymous; 26.04.2017

Я думаю, что это рекурсивно, когда вы делаете return View(homeViewModel);

Попробуйте вернуть View() для просмотра по умолчанию и посмотрите, останется ли проблема.

person Sam    schedule 26.04.2017