2009-12-14 9 views
2

Je veux éviter d'avoir beaucoup de if Request.IsAjaxRequest() dans mes contrôleurs. Je pensais que si je pouvais condenser cette logique à un ActionFilter, il serait facile d'adopter une convention dans mon application pour fournir une seconde action pour toute demande que peut utiliser utiliser Ajax, tout en fournissant une solution de repli si JavaScript est désactivé.Utiliser un filtre pour exécuter une action différente?

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

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

je d'abord pensé que je pouvais faire quelque chose comme ceci:

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

    } 

Mais ça ne marchera pas parce que l'action d'invoquer est décidé et les filtres sur elle sont traitées.

Je ne veux pas vraiment retourner un RedirectResult chaque fois que quelqu'un appelle une action, il semble un peu inutile de doubler le nombre de requêtes Http.

Existe-t-il une manière différente de router la requête vers une action différente? Ou est ce que je fais déconseillé et je devrais chercher une meilleure façon de faire les choses?

Vive

Répondre

1

AcceptAjaxAttribute est probablement ce qui est nécessaire ici; Cependant, j'aimerais proposer une façon différente de penser à ce problème.

Toutes les requêtes Ajax ne sont pas égales. Une requête Ajax peut être en train d'essayer d'accomplir l'une des choses suivantes:

  • Liaison de données JSON à une grille riche (comme jqGrid);
  • Analyse/transformation de données XML, telles qu'un flux RSS;
  • Chargement de HTML partiel dans une zone de la page;
  • Chargement asynchrone d'un script (google.load peut le faire);
  • Traitement d'un message unidirectionnel provenant du client;
  • Et probablement un peu plus que j'oublie.

Lorsque vous «sélectionnez » une « action alternative » spécifique basée uniquement sur la méthode IsAjaxRequest, vous liez quelque chose de très générique - une requête asynchrone - à des fonctionnalités spécifiques sur le serveur. Cela finira par rendre votre conception plus fragile et rendra votre contrôleur plus difficile à tester (bien qu'il existe des moyens de le faire, vous pouvez vous moquer du contexte).

Un programme bien conçu l'action devrait être cohérente , il doit seulement prendre soin ce la demande était et non comment la demande a été faite. On pourrait pointer vers d'autres attributs comme AuthorizeAttribute comme exceptions, mais je ferais une distinction pour les filtres, qui décrivent la plupart du temps un comportement qui doit se produire soit avant ou après l'action, non pas au lieu de."

Obtenir au point ici, l'objectif déclaré dans la question est bonne, vous devriez certainement ont des méthodes différentes pour ce qui sont correctement décrits comme des actions différentes:

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)); 
} 

Et ainsi de suite. Cependant, en utilisant un sélecteur d'action Ajax de choisir entre ces méthodes est la suite de la pratique de « dégradé », qui a essentiellement été remplacée (au moins OMI) par amélioration progressive.

C'est pourquoi, bien que j'adore ASP.NET MVC, j'évite surtout le AjaxHelper, car je ne trouve pas qu'il exprime bien ce concept; il essaie de vous cacher trop de choses. Au lieu d'avoir le concept d'un "Formulaire Ajax" ou d'une "Action Ajax", supprimons la distinction et nous en tenons au HTML, puis injecter la fonctionnalité Ajax séparément une fois que nous sommes certains que le client peut le gérer.

Voici un exemple dans jQuery - bien que vous pouvez le faire en MS AJAX trop:

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

Ceci est tout ce qu'il faut pour injecter Ajax dans une page MVC. Commencez par un simple lien HTML ancien et remplacez-le par un appel Ajax qui va à une autre action du contrôleur. Maintenant, si à un autre endroit sur votre site vous décidez d'utiliser une grille à la place, mais que vous ne voulez pas casser les pages en utilisant un rendu partiel, vous pouvez écrire quelque chose comme ça (disons que vous avez un seul maître). Page -detail une liste des « ordres » sur le côté gauche et une table de détail à droite):

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

Cette approche découple complètement le comportement des clients du comportement du serveur. Le serveur dit effectivement au client: Si vous voulez la version JSON, demander pour la version JSON, et oh, en passant, voici un script pour convertir vos liens si vous savez comment l'exécuter. Pas de sélecteurs d'action et finagling avec des surcharges de méthode, pas de moquerie spéciale que vous avez à faire pour exécuter un test simple, pas de confusion sur quelle action fait quoi et quand. Juste quelques lignes de JavaScript. Les actions du contrôleur sont courtes et douces, exactement comme elles devraient l'être.

Ce n'est pas la seule approche. De toute évidence, les classes telles que AcceptAjaxAttribute existent car ils s'attendaient à ce que certains développeurs utilisent la méthode de détection de requête. Mais après avoir beaucoup expérimenté avec les deux, je trouve beaucoup plus facile à raisonner et donc plus facile à concevoir/coder correctement.

2

Que diriez-vous à AcceptAjaxAttribute MvcFutures?

+0

Je ne veux pas restreindre une action pour accepter uniquement les appels Ajax, je veux que l'action se comporte différemment s'il s'agit d'une requête ajax, de cette façon si javascript est désactivé, les trucs chics passent et font une page normale poste/actualiser – Kirschstein

+0

Je suis désolé, je l'ai mal compris. – takepara

+1

C'est en fait * exactement * ce que fait AcceptAjax. Ce n'est pas un filtre d'action, c'est un sélecteur de méthode d'action. Appliquez l'attribut à votre méthode AJAX et ne placez aucun attribut sur votre méthode no-AJAX. ASP.NET MVC utilisera l'attribut pour déterminer laquelle des deux méthodes à appeler. Cela me semble être exactement ce que vous voulez. Essayez-le et faites le nous savoir. – Eilon

Questions connexes