MVC 3: Как визуализировать представление без его страницы макета при загрузке через ajax?

Я узнал о Progressive Enhancement, и у меня есть вопрос об AJAXifying представлениях. В моем проекте MVC 3 у меня есть страница макета, страница просмотра и два простых вида.

Страница просмотра находится в корне папки "Представления" и, таким образом, применяется ко всем представлениям. Он указывает, что все представления должны использовать _Layout.cshtml для своей страницы макета. Страница макета содержит две навигационные ссылки, по одному для каждого вида. В ссылках используется @Html.ActionLink() для отображения страницы.

Теперь я добавил jQuery и хочу захватить эти ссылки и использовать Ajax для динамического загрузки их содержимого на странице.

<script type="text/javascript">
    $(function () {
        $('#theLink').click(function () {
            $.ajax({
                url: $(this).attr('href'),
                type: "GET",
                success: function (response) {
                    $('#mainContent').html(response);
                }
            });
            return false;
        });
    });
</script>

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

1) Я могу взять все содержимое View и поместить их в частичное представление, а затем вызвать основной просмотр частичного представления при его рендеринге. Таким образом, используя Request.IsAjaxRequest() в контроллере, я могу вернуть View() или вернуть PartialView() на основании того, является ли запрос Ajax-запросом. Я не могу вернуть регулярное представление к запросу Ajax, потому что тогда он будет использовать страницу макета, и я бы получил вторую копию страницы макета, которую вы вводили. Однако мне это не нравится, потому что он заставляет меня создавать пустые представления только с @{Html.RenderPartial();} в них для стандартных запросов GET.

    public ActionResult Index()
    {
        if (Request.IsAjaxRequest())
            return PartialView("partialView");
        else
            return View();
    }

Затем в Index.cshtml сделайте следующее:

@{Html.RenderPartial("partialView");}

2) Я могу удалить обозначение макета из _viewstart и указать его вручную, когда запрос НЕ Ajax:

    public ActionResult Index()
    {
        if (Request.IsAjaxRequest())
            return View(); // Return view with no master.
        else
            return View("Index", "_Layout"); // Return view with master.
    }

Есть ли у кого-нибудь лучшее предложение? Есть ли способ вернуть представление без его страницы макета? Было бы гораздо проще явно сказать "не включать ваш макет", если это запрос ajax, чем было бы явно включать макет, если он не является ajax.

Ответ 1

В ~/Views/ViewStart.cshtml:

@{
    Layout = Request.IsAjaxRequest() ? null : "~/Views/Shared/_Layout.cshtml";
}

и в контроллере:

public ActionResult Index()
{
    return View();
}

Ответ 2

Просто разместите следующий код в верхней части страницы

@{
    Layout = "";
}

Ответ 3

Я предпочитаю и использую ваш вариант # 1. Мне не нравится # 2, потому что для меня View() подразумевается, что вы возвращаете целую страницу. Он должен быть полностью фальшивым и действительным HTML-страницей, когда с ним будет работать механизм просмотра. PartialView() был создан для возврата произвольных фрагментов HTML.

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

Многие люди не любят фрагментировать свои пути действий с помощью Request.IsAjaxRequest(), и я могу это оценить. Но IMO, если все, что вы делаете, решает, следует ли звонить View() или PartialView(), тогда ветка не имеет большого значения и ее легко поддерживать (и тестировать). Если вы обнаружите, что используете IsAjaxRequest(), чтобы определить большие части того, как ваше действие разыгрывается, возможно, сделать отдельное действие AJAX лучше.

Ответ 4

Создайте два макета: 1. пустой макет, 2. основной макет, а затем напишите в файле _viewStart этот код:

@{
if (Request.IsAjaxRequest())
{
    Layout = "~/Areas/Dashboard/Views/Shared/_emptyLayout.cshtml";
}
else
{
    Layout = "~/Areas/Dashboard/Views/Shared/_Layout.cshtml";
}}

конечно, возможно, это не лучшее решение

Ответ 5

Вам не нужно создавать пустые представления для этого.

В контроллере:

if (Request.IsAjaxRequest())
  return PartialView();
else
  return View();

возврат PartialViewResult переопределит определение макета при рендеринге ответа.

Ответ 6

В ASP.NET 5 больше нет переменной Request. Вы можете получить к нему доступ сейчас с помощью Context.Request

Также больше нет метода IsAjaxRequest(), вы должны написать его самостоятельно, например, в Extensions\HttpRequestExtensions.cs

using System;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.Mvc
{
    public static class HttpRequestExtensions
    {
        public static bool IsAjaxRequest(this HttpRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            return (request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest");
        }
    }
}

Я долго искал это и надеюсь, что это поможет и другим;)

Ресурс: https://github.com/aspnet/AspNetCore/issues/2729

Ответ 7

Для приложения Ruby on Rails мне удалось предотвратить загрузку макета, указав render layout: false в действии контроллера, на который я хотел ответить ajax html.