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

153

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

Страница Viewstart находится в корне папки Views и поэтому применяется ко всем представлениям. Он указывает, что все представления должны использовать _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) Я могу взять все содержимое представления и поместить его в частичное представление, а затем сделать так, чтобы основной вид вызывал частичное представление при его визуализации. Таким образом, используя 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.

Чев
источник

Ответы:

259

В ~/Views/ViewStart.cshtml:

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

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

public ActionResult Index()
{
    return View();
}
Дарин димитров
источник
3
Можно ли это указать в viewstart?
Chev
10
@Matt Greer, вы называете это противным, я называю это СУХОЙ, в любом случае субъективные вещи :-)
Дарин Димитров
2
Должен признать, сначала мне это не нравилось, но объем кода, который он сохраняет, может показаться слишком большим, что является недостатком. Это простое логическое значение, если оно не слишком навязывает IMO. Мне это нравится больше, чем когда я делаю свои методы действий пополам каждый раз. Плюс это мешает мне делать то, что вы сказали, Мэтт, и потенциально идти по двум гигантским логическим путям в методе действия. Я либо пишу действие, чтобы оно работало одинаково в обоих случаях, либо пишу новое действие.
Chev
1
Вы не могли бы сделать это в базовом контроллере, установить свойство в ViewData и использовать это? Тогда линия будет Layout = ViewBag.LayoutFile.
RPM1984
2
Я полагаю, что мог, но на самом деле зачем создавать baseController для одной маленькой строки?
Chev
92

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

@{
    Layout = "";
}
roncansan
источник
4
Это не работает, потому что я хочу иметь возможность включать или выключать макет в зависимости от того, запрашивается ли он через AJAX. Это только позволяет отключить макет, но не переключать его.
Chev
4
Почему это имеет подъемы голосов ?? Пожалуйста, объясните, так что я тоже буду голосовать.
Усман Юнас
1
@UsmanY. Вам не нужно голосовать за это. Но я делаю. Мой аргумент перейти к google.com.pk/#q=mvc3%20view%20without%20layout . И это идеальный ответ на этот запрос.
Сами
3
Тема о переключении макета в двух разных сценариях. Этот ответ просто устанавливает пустой макет независимо от сценария.
Раджшекар Редди
Чувак, это работает, и это действительно приятно. Сценарий, который я использую: неавторизованный пользователь пытается войти в систему, никто не хочет, чтобы на странице ошибок отображались ссылки и т. Д. Неавторизованному пользователю! Конечно, это работает и для всего остального!
JosephDoggie
13

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

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

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

Мэтт Грир
источник
13

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

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

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

Араш Карами
источник
8

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

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

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

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

Сухайб Бесбес
источник
2

В 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

Drotak
источник
-5

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

user4381244
источник
6
теги: c # asp.net, а не ruby
MrKekson