Domanda

Voglio evitare di avere un sacco di if Request.IsAjaxRequest() nei miei controllori. Stavo pensando che se avessi potuto condensare questa logica a un ActionFilter sarebbe facile ad adottare una convenzione nella mia richiesta di fornire una seconda azione per qualsiasi richiesta che possono usare Ajax, fornendo al contempo una caduta indietro se JavaScript è disabilitato.

public ActionResult Details(int id)
{
  // called normally, show full page
}

public ActionResult Details_Ajax(int id)
{
  // called through ajax, return a partial view
}

ho inizialmente pensato che avrei potuto fare qualcosa di simile:

public class AjaxRenameAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.RouteData.Values["action"] = filterContext.RouteData.Values["action"] + "_Ajax";

    }

Ma questo non funziona perché l'azione di invocare è deciso e poi i filtri su di esso vengono elaborati.

Non voglio davvero tornare un RedirectResult ogni volta che qualcuno chiama un'azione, sembra un po 'inutile raddoppiare la quantità di richieste HTTP.

C'è un modo diverso di percorso attraverso la richiesta di un'azione diversa? O è quello che sto facendo sconsigliabile e devo cercare un modo migliore di fare le cose?

Saluti

È stato utile?

Soluzione

AcceptAjaxAttribute è probabilmente è ciò che è necessario qui; tuttavia, vorrei proporre un modo diverso di pensare a questo problema.

Non tutte le richieste Ajax sono uguali. Una richiesta Ajax potrebbe essere cercando di realizzare una delle seguenti cose:

  • Binding dati JSON una ricca griglia (come jqGrid);
  • Analisi / trasformazione di dati XML, come ad esempio un feed RSS;
  • Caricamento parziale HTML in un'area della pagina;
  • in modo asincrono il caricamento di uno script (google.load può farlo);
  • Gestione di un messaggio a senso unico dal client;
  • E probabilmente un paio di più che sto dimenticando.

Quando si "seleziona" una specifica "azione alternativa" basata esclusivamente sul metodo IsAjaxRequest, si sta legando qualcosa di molto generico - una richiesta asincrona - per funzionalità specifiche sul server. E 'in ultima analisi, andando a fare il vostro disegno più fragili e anche fare il controller più difficile test di unità (anche se ci sono modi per farlo, si può deridere il contesto).

A ben progettato azione dovrebbe essere consistente , che dovrebbe preoccuparsi solo cosa la richiesta era per e non come la richiesta è stata fatta. Si potrebbe puntare ad altri attributi come AuthorizeAttribute come eccezioni, ma vorrei fare una distinzione per i filtri, che il più delle volte descrivere il comportamento che deve accadere sia un "prima" o "dopo" l'azione si svolge, non "al posto di. "

Come arrivare al punto qui, l'obiettivo dichiarato nella domanda è una buona; si dovrebbe sicuramente hanno metodi diversi per quanto siano correttamente descritto come diverse azioni:

public ActionResult Details(int id)
{
    return View("Details", GetDetails(id));
}

public ActionResult JsonDetails(int id)
{
    return Json(GetDetails(id));
}

public ActionResult PartialDetails(int id)
{
    return PartialView("DetailTable", GetDetails(id));
}

E così via. Tuttavia, utilizzando un selettore un'azione Ajax scegliere tra questi metodi sta seguendo la pratica di "degradazione elegante" , che è stato sostanzialmente sostituita (almeno IMO) da progressive enhancement .

Questo è il motivo per cui, anche se mi piace ASP.NET MVC, Io per lo più evitano il AjaxHelper, perché non trovo che esprime questo concetto che ben; si cerca di nascondere troppo da voi. Invece di avere il concetto di un "form Ajax" o un "Ajax Azione", facciamo finita con la distinzione e bastone per HTML dritto, poi iniettare la funzionalità Ajax a parte una volta che siamo certi che il client è in grado di gestirlo .

Ecco un esempio in jQuery - anche se si può fare questo in MS AJAX troppo:

$(function() {
    $("#showdetails").click(function() {
        $("#details").load("PartialDetails", { id: <%= Record.ID %> });
        return false;
    }
});

Questo è tutto quello che serve per iniettare l'Ajax in una pagina MVC. Inizia con un semplice collegamento HTML vecchio e sostituirlo con un chiamata Ajax che va a una diversa azione di controllo .

Ora, se da qualche altra parte sul vostro sito si decide di utilizzare una griglia, invece, ma non si vuole rompere le pagine utilizzando il rendering parziale, è possibile scrivere qualcosa di simile (diciamo che si dispone di un unico master- pagina di dettaglio con un elenco di "ordini" sul lato sinistro e una tabella di dettaglio a destra):

$(".detaillink").click(function() {
    $('#detailGrid').setGridParam({
        url: $(this).attr("href").replace(/\/order\/details/i,
            "/order/jsondetails")
    }); 
    $("#detailGrid").trigger("reloadGrid");  
});

Questo approccio disaccoppia completamente il comportamento client dal comportamento del server. Il server è effettivamente dicendo al cliente: Se si desidera la versione JSON, Chiedimi per la versione JSON, e oh, a proposito, ecco uno script per convertire i collegamenti se si sa come per eseguirlo. non ci sono selettori d'azione e finagling con metodo sovraccarichi, non beffardo quello che dovete fare per poter eseguire un semplice test speciale, nessuna confusione su quale azione fa cosa e quando. Solo un paio di righe di JavaScript. Le azioni di controllo sono brevi e dolci, esattamente come dovrebbero essere.

Questo non è l'unico approccio. Ovviamente, esistono classi come AcceptAjaxAttribute perché prevede alcuni sviluppatori di utilizzare il metodo di richiesta di rilevamento. Ma dopo aver sperimentato un po 'con entrambi, trovo questo modo molto più facile ragionare su e quindi più facile da progettare / codice correttamente.

Altri suggerimenti

Come su Accetta Ajax attributo MVC Futures?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top