Как использовать RenderBody() в частичном представлении, когда частичное представление используется на всех страницах макета?

Ниже приведен точный сценарий в моем приложении ASP.NET MVC:

Есть две страницы макета, которые совершенно идентичны друг другу. Но у одного есть атрибуты, связанные с angular, в теге "", тогда как другой - неугловой макет. Чтобы избежать дублирования разметки в обоих файлах макета бритвы, я решил создать частичное представление и поделиться им на всех страницах макета.

Ниже приведен частичный вид (бритва), я назвал его «_LayoutPartial»:

_LayoutPartial.cshtml

<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            @Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li>@Html.ActionLink("Home", "Index", "Home")</li>
                <li>@Html.ActionLink("About", "About", "Home")</li>
                <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
            </ul>
            @Html.Partial("_LoginPartial")
        </div>
    </div>
</div>
<div class="container body-content">
    @RenderBody()
    <hr />
    <footer>
        <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
    </footer>
</div>

Приведенное выше частичное представление используется в файлах «_Layout.cshtml» и «_AngularLayout.cshtml», как показано ниже:

_Layout.cshtml

<body>
    @Html.Partial("_LayoutPartial")

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>

_AngularLayout.cshtml

<body ng-app="myAngularLab">
    @Html.Partial("_LayoutPartial")

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>

Когда я пытаюсь запустить приложение MVC, я получаю следующую ошибку:

Файл "~/Views/Shared/_LayoutPartial.cshtml" нельзя запросить напрямую, так как он вызывает метод "RenderBody".

Сообщение об ошибке очень очевидно, и кажется, что мы можем использовать метод RenderBody только на мастер-странице и больше нигде. Но мне интересно знать, как мы можем иметь две идентичные страницы макета (с небольшими различиями, как показано в примере), написав общий код вместо того, чтобы хранить дублирующийся код на обеих страницах макета?


person Nirman    schedule 26.07.2017    source источник
comment
Можете ли вы вынуть этот код <div class="container body-content"> @RenderBody() <hr /> <footer> <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p> </footer> </div> ИЗ общего файла и поместить его отдельно в файл Angular и _Layout?   -  person Unbreakable    schedule 26.07.2017
comment
Я новичок, просто интересно, будет ли это иметь какое-то значение   -  person Unbreakable    schedule 26.07.2017
comment
Да, это работает. По сути, если мы поместим RenderBody на страницу _Layout, он должен работать по дизайну. Но причина, по которой я не предпочитаю делать это на данном этапе, заключается в том, что в настоящее время на странице макета не так много содержимого, но по мере расширения нашего веб-сайта страница макета неизбежно станет более сложной, и тогда на ней будет много дублированного содержимого. в обоих файлах, если мы скопируем все, начиная с RenderBody, в оба файла макета, и это не поможет.   -  person Nirman    schedule 26.07.2017
comment
Другой вариант — создать несколько частичных представлений и вынести большую часть вещей, кроме RenderBody, в соответствующие частичные представления, а также поместить RenderBody на страницы макета. Но это будет связано с количеством частичных просмотров, так что просто подумайте, есть ли более эффективный способ, чем этот?   -  person Nirman    schedule 26.07.2017
comment
@Nirman Как насчет использования вложенного макета? Я часто использую несколько основных макетов в качестве общих макетов с другими дочерними макетами, ссылающимися на него, нет необходимости повторять объявление @Scripts и @Styles в дочерних макетах. В этом случае ng-app="myAngularLab" помещается на div вместо body.   -  person Tetsuya Yamamoto    schedule 26.07.2017
comment
Спасибо @TetsuyaYamamoto, да, кажется, вложенный макет — идеальное решение в таких сценариях. Я расскажу об этом немного больше и обновлю свой код в соответствии с этим. Спасибо за помощь.   -  person Nirman    schedule 26.07.2017
comment
@TetsuyaYamamoto - не могли бы вы опубликовать свои комментарии в качестве ответа, чтобы я мог их отметить.   -  person Nirman    schedule 04.08.2017


Ответы (2)


Я думаю, вам нужно использовать «вложенный макет», поместив одну страницу макета в качестве «главной страницы» для других макетов, аналогично аналогу веб-форм:

_BaseLayout.cshtml

<html>
<head>
    <!-- other header tags (link, meta, title etc.) -->

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")

    <!-- JS & CSS includes if available -->
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <!-- other elements -->
    </div>
    <div class="container body-content">
        @RenderBody()
        <!-- other elements -->
    </div>

    @RenderSection("scripts", required: false)
</body>
</html>

_Layout.cshtml

@{ Layout = "~/Views/Shared/_BaseLayout.cshtml"; } // put reference to base layout here

<div>
    <!-- Non-Angular layout -->
    @RenderBody()
</div>

_AngularLayout.cshtml

@{ Layout = "~/Views/Shared/_BaseLayout.cshtml"; } // put reference to base layout here

<div ng-app="myAngularLab">
    <!-- Angular layout -->
    @RenderBody()
</div>

Преимущества использования «вложенного макета»:

  1. Устраняет необходимость повторения @Styles.Render и @Scripts.Render, а также для @RenderSection (они вставляются автоматически для каждой страницы, ссылающейся на базовый макет).

  2. Устраняет необходимость использования более одного тега body, просто замените его тегом div, чтобы сохранить содержимое страницы просмотра.

Файл "X" не может быть запрошен напрямую, потому что он вызывает метод "RenderBody", безусловно, созданный из Html.Partial, который вызывается непосредственно из дочерних макетов, где страница макета с методом RenderBody не может быть запрошена напрямую как шаблон.

Если вы хотите установить макет по умолчанию для вложенного макета, поместите ссылку на один из дочерних макетов в _ViewStart.cshtml:

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Еще одно примечание: частичные представления предназначены для использования на страницах просмотра, а не на страницах макета. Страницы макета специально используются в качестве заполнителя для страниц просмотра, а не для прямого доступа с помощью методов действий.

person Tetsuya Yamamoto    schedule 04.08.2017

Попробуйте это в _Layout.cshtml:

<body>
    @Html.Partial("_LayoutPartial")

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
   <div class="container body-content">
    @RenderBody()
    <hr />
    <footer>
        <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
    </footer>
</div>
</body>

и удалите @RenderBody() из _LayoutPartial.cshtml.

@RenderBody() обычно используется на страницах макета, он отображает часть страницы с содержанием, которая не находится в именованном разделе.

Надеюсь, это будет полезно :)

person Ahmad    schedule 26.07.2017
comment
Спасибо и ценю ваш ответ. Но, как я предположил, это потребует большого количества дублированного кода на страницах макета, если предполагается, что они будут отображать один и тот же контент, иначе мне может потребоваться создать несколько частичных представлений и подключить их в разных местах на странице макета. Вложенный макет — это то, что я хотел бы изучить подробнее. - person Nirman; 26.07.2017
comment
о, хорошо, нп, проверьте это для вложенного макета , надеюсь, это поможет @Nirman - person Ahmad; 26.07.2017