MVC 3: Come eseguire il rendering di una vista senza la sua pagina di layout se caricato tramite Ajax?


153

Sto imparando su Progressive Enhancement e ho una domanda sulle opinioni AJAXifying. Nel mio progetto MVC 3 ho una pagina di layout, una pagina viewstart e due viste semplici.

La pagina viewstart si trova nella radice della cartella Viste e quindi si applica a tutte le viste. Specifica che tutte le viste devono essere utilizzate _Layout.cshtmlper la loro pagina di layout. La pagina di layout contiene due collegamenti di navigazione, uno per ogni vista. I collegamenti utilizzano @Html.ActionLink()per renderizzare se stessi alla pagina.

Ora ho aggiunto jQuery e voglio dirottare questi collegamenti e usare Ajax per caricare dinamicamente i loro contenuti sulla pagina.

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

Ci sono due modi in cui posso pensare di farlo, ma non mi piace particolarmente uno dei due:

1) Posso prendere l'intero contenuto della Vista e posizionarli in una vista parziale, quindi la vista principale può chiamare la vista parziale quando viene visualizzata. In questo modo, utilizzando Request.IsAjaxRequest()nel controller, posso tornare View()o tornare in PartialView()base alla richiesta o meno di una richiesta Ajax. Non riesco a restituire la visualizzazione normale alla richiesta Ajax perché in tal caso utilizzerebbe la pagina di layout e verrebbe iniettata una seconda copia della pagina di layout. Tuttavia, non mi piace perché mi costringe a creare viste vuote con solo un @{Html.RenderPartial();}in esse per le richieste GET standard.

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

Quindi in Index.cshtml fai questo:

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

2) Posso rimuovere la designazione del layout da _viewstart e specificarla manualmente quando la richiesta NON è Ajax:

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

Qualcuno ha un suggerimento migliore? C'è un modo per restituire una vista senza la sua pagina di layout? Sarebbe molto più facile dire esplicitamente "non includere il layout" se si tratta di una richiesta Ajax, piuttosto che includere esplicitamente il layout se non è un Ajax.

Risposte:


259

In ~/Views/ViewStart.cshtml:

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

e nel controller:

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

3
Questo può essere specificato nel viewstart?
Chev,

10
@Matt Greer, lo chiami cattivo, io lo chiamo DRY, roba soggettiva comunque :-)
Darin Dimitrov

2
Devo ammetterlo, all'inizio non mi piaceva, ma la quantità di codice che salva sembrerebbe di gran lunga superiore al suo lato negativo. È un semplice booleano se e non impone molto IMO. Mi piace di più che tagliare a metà i miei metodi di azione ogni volta. Inoltre mi impedisce di fare ciò che hai detto Matt e potenzialmente di percorrere due giganteschi percorsi logici nel metodo di azione. Scrivo l'azione per lavorare allo stesso modo in entrambi i casi o scrivo una nuova azione.
Chev,

1
non potresti farlo in un controller di base, impostare una proprietà in ViewData e utilizzarla? Quindi la linea sarebbe Layout = ViewBag.LayoutFile.
RPM1984,

2
Suppongo di poterlo fare, ma davvero perché creare un baseController per una piccola linea?
Chev,

92

Basta inserire il seguente codice nella parte superiore della pagina

@{
    Layout = "";
}

4
Questo non funziona perché voglio essere in grado di attivare o disattivare il layout in base alla richiesta o meno tramite AJAX. Ciò consente solo di disattivare il layout, non di attivarlo.
Chev,

4
Perché questo ha voti alti ?? per favore, spiego anche io.
Usman Younas

1
@UsmanY. Non è necessario votarlo. Ma io faccio. Il mio argomento va su google.com.pk/#q=mvc3%20view%20without%20layout . Ed è la risposta perfetta a quella domanda.
Sami,

3
L'argomento riguarda l'attivazione / disattivazione del layout in due diversi scenari. Questa risposta ha appena impostato il layout su vuoto, indipendentemente dallo scenario.
Rajshekar Reddy,

Amico, questo funziona ed è davvero bello. Lo scenario che uso: l'utente non autorizzato tenta di accedere, non si desidera che la pagina di errore mostri i collegamenti e così via a un utente non autorizzato! Certo, funziona anche per tutto il resto!
JosephDoggie,

13

Preferisco e utilizzo la tua opzione n. 1. Non mi piace # 2 perché per me View()implica che stai restituendo un'intera pagina. Dovrebbe essere una pagina HTML completa e valida una volta che il motore di visualizzazione è stato completato. PartialView()è stato creato per restituire blocchi arbitrari di HTML.

Non penso sia un grosso problema avere una visione che chiama solo un parziale. È ancora ASCIUTTO e consente di utilizzare la logica del parziale in due scenari.

Molte persone non amano frammentare i percorsi di chiamata della propria azione Request.IsAjaxRequest(), e posso apprezzarlo. Ma IMO, se tutto ciò che stai facendo è decidere se chiamare View()o PartialView()la filiale non è un grosso problema ed è facile da mantenere (e testare). Se ti ritrovi a utilizzare IsAjaxRequest()per determinare grandi parti di come si svolge la tua azione, probabilmente fare un'azione AJAX separata è probabilmente migliore.


13

Creare due layout: 1. layout vuoto, 2. layout principale e quindi scrivere nel file _viewStart questo codice:

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

certo, forse non è la soluzione migliore


8

Non è necessario creare una vista vuota per questo.

Nel controller:

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

la restituzione di un PartialViewResult sovrascriverà la definizione del layout durante il rendering della risposta.


2

Con ASP.NET 5 non è più disponibile una variabile di richiesta. Puoi accedervi ora con Context.Request

Inoltre non esiste più alcun metodo IsAjaxRequest (), devi scriverlo da solo, ad esempio 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");
        }
    }
}

Ho cercato per un po 'di tempo su questo e spero che possa aiutare anche alcuni altri;)

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


-5

Per un'applicazione Ruby on Rails, sono stato in grado di impedire il caricamento di un layout specificando render layout: falsenell'azione del controller che volevo rispondere con ajax html.


6
tags: c # asp.net, non rubino
MrKekson
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.