MVC 3: Wie rendere ich eine Ansicht ohne Layoutseite, wenn sie über Ajax geladen wird?

153

Ich lerne etwas über progressive Verbesserung und habe eine Frage zu AJAXifying-Ansichten. In meinem MVC 3-Projekt habe ich eine Layoutseite, eine Ansichtsstartseite und zwei einfache Ansichten.

Die Viewstart-Seite befindet sich im Stammverzeichnis des Views-Ordners und gilt daher für alle Views. Es gibt an, dass alle Ansichten _Layout.cshtmlfür ihre Layoutseite verwendet werden sollen. Die Layoutseite enthält zwei Navigationslinks, einen für jede Ansicht. Die Links werden verwendet @Html.ActionLink(), um sich selbst auf die Seite zu rendern.

Jetzt habe ich jQuery hinzugefügt und möchte diese Links entführen und Ajax verwenden, um ihren Inhalt dynamisch auf die Seite zu laden.

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

Es gibt zwei Möglichkeiten, wie ich mir das vorstellen kann, aber ich mag keine besonders:

1) Ich kann den gesamten Inhalt der Ansicht in eine Teilansicht einfügen und dann die Hauptansicht beim Rendern die Teilansicht aufrufen lassen. Auf diese Weise Request.IsAjaxRequest()kann ich mithilfe des Controllers zurückgeben View()oder zurückgeben PartialView(), je nachdem, ob es sich bei der Anforderung um eine Ajax-Anforderung handelt oder nicht. Ich kann die reguläre Ansicht nicht an die Ajax-Anforderung zurückgeben, da dann die Layoutseite verwendet wird und eine zweite Kopie der Layoutseite eingefügt wird. Dies gefällt mir jedoch nicht, da ich gezwungen bin, leere Ansichten mit nur einem @{Html.RenderPartial();}in ihnen für die Standard-GET-Anforderungen zu erstellen .

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

Dann machen Sie in Index.cshtml Folgendes:

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

2) Ich kann die Layoutbezeichnung aus _viewstart entfernen und manuell angeben, wenn die Anforderung NICHT Ajax lautet:

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

Hat jemand einen besseren Vorschlag? Gibt es eine Möglichkeit, eine Ansicht ohne Layoutseite zurückzugeben? Es wäre viel einfacher, explizit zu sagen, dass Sie Ihr Layout nicht einschließen sollen, wenn es sich um eine Ajax-Anforderung handelt, als das Layout explizit einzuschließen, wenn es kein Ajax ist.

Chev
quelle

Antworten:

259

In ~/Views/ViewStart.cshtml:

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

und in der Steuerung:

public ActionResult Index()
{
    return View();
}
Darin Dimitrov
quelle
3
Kann dies im viewstart angegeben werden?
Chev
10
@ Matt Greer, du nennst es böse, ich nenne es trocken, subjektives Zeug sowieso :-)
Darin Dimitrov
2
Ich muss zugeben, es hat mir anfangs nicht gefallen, aber die Menge an Code, die es speichert, scheint den Nachteil weit zu übertreffen. Es ist ein einfacher Boolescher Wert, wenn und nicht wirklich viel IMO auferlegt. Ich mag es besser, als meine Aktionsmethoden jedes Mal in zwei Hälften zu teilen. Außerdem hindert es mich daran, das zu tun, was Sie gesagt haben, Matt, und möglicherweise zwei riesige Logikpfade in der Aktionsmethode einzuschlagen. Ich schreibe entweder die Aktion so, dass sie in beiden Fällen gleich funktioniert, oder ich schreibe eine neue Aktion.
Chev
1
Können Sie dies nicht in einem Basis-Controller tun, eine Eigenschaft in den ViewData festlegen und diese verwenden? Dann wäre die Linie Layout = ViewBag.LayoutFile.
RPM1984
2
Ich denke, ich könnte, aber warum wirklich einen baseController für eine kleine Zeile erstellen?
Chev
92

Fügen Sie einfach den folgenden Code oben auf der Seite ein

@{
    Layout = "";
}
Roncansan
quelle
4
Dies funktioniert nicht, da ich das Layout ein- oder ausschalten möchte, je nachdem, ob es über AJAX angefordert wird oder nicht. Auf diese Weise können Sie das Layout nur deaktivieren und nicht umschalten.
Chev
4
Warum hat dies Abstimmungen? Bitte erklären Sie, damit ich auch darüber abstimmen kann.
Usman Younas
1
@ UsmanY. Sie müssen nicht abstimmen. Aber ich tue. Mein Argument gehe zu google.com.pk/#q=mvc3%20view%20without%20layout . Und es ist die perfekte Antwort auf diese Frage.
Sami
3
In diesem Thema wird das Layout in zwei verschiedenen Szenarien umgeschaltet. Diese Antwort setzt das Layout einfach so, dass es leer ist, egal in welchem ​​Szenario.
Rajshekar Reddy
Alter, das funktioniert und es ist wirklich schön. Das Szenario, das ich benutze: Der nicht autorisierte Benutzer versucht sich anzumelden, man möchte nicht, dass auf der Fehlerseite Links usw. zu einem nicht autorisierten Benutzer angezeigt werden! Natürlich funktioniert es auch für alles andere!
Joseph
13

Ich bevorzuge und verwende Ihre Option Nr. 1. Ich mag # 2 nicht, weil für mich View()bedeutet, dass Sie eine ganze Seite zurückgeben. Sobald die View Engine damit fertig ist, sollte es sich um eine vollständig ausgearbeitete und gültige HTML-Seite handeln.PartialView()wurde erstellt, um beliebige HTML-Blöcke zurückzugeben.

Ich denke nicht, dass es eine große Sache ist, eine Ansicht zu haben, die nur einen Teil nennt. Es ist immer noch trocken und ermöglicht es Ihnen, die Logik des Teils in zwei Szenarien zu verwenden.

Viele Leute mögen es nicht, die Anrufpfade ihrer Aktion zu fragmentieren Request.IsAjaxRequest(), und das kann ich zu schätzen wissen. Aber IMO, wenn Sie nur entscheiden, ob Sie anrufen möchten View()oder nicht, PartialView()ist die Filiale keine große Sache und einfach zu warten (und zu testen). Wenn Sie IsAjaxRequest()große Teile des Ablaufs Ihrer Aktion bestimmen, ist es wahrscheinlich besser, eine separate AJAX-Aktion durchzuführen.

Matt Greer
quelle
13

Erstellen Sie zwei Layouts: 1. leeres Layout, 2. Hauptlayout und schreiben Sie dann in die _viewStart-Datei diesen Code:

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

Natürlich ist es vielleicht nicht die beste Lösung

Arash Karami
quelle
8

Sie müssen dafür keine leere Ansicht erstellen.

In der Steuerung:

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

Wenn Sie ein PartialViewResult zurückgeben, wird die Layoutdefinition beim Rendern der Antwort überschrieben.

Souhaieb Besbes
quelle
2

Mit ASP.NET 5 ist keine Anforderungsvariable mehr verfügbar. Sie können jetzt mit Context.Request darauf zugreifen

Außerdem gibt es keine IsAjaxRequest () -Methode mehr. Sie müssen sie selbst schreiben, beispielsweise in 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");
        }
    }
}

Ich habe jetzt eine Weile danach gesucht und hoffe, dass das auch einigen anderen hilft;)

Ressource: https://github.com/aspnet/AspNetCore/issues/2729

Drotak
quelle
-5

Bei einer Ruby on Rails-Anwendung konnte ich das Laden eines Layouts verhindern, indem render layout: falseich in der Controller-Aktion angab, dass ich mit ajax html antworten wollte.

user4381244
quelle
6
Tags: c # asp.net, nicht
rubin