J'ai deux méthodes d'action qui sont en conflit. En fait, je veux pouvoir accéder à la même vue en utilisant deux routes différentes, soit par l'ID d'un élément, soit par le nom de l'élément et celui de son parent (les éléments peuvent avoir le même nom avec des parents différents). Un terme de recherche peut être utilisé pour filtrer la liste.
Par exemple...
Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321
Voici mes méthodes d'action (il y a aussi Remove
méthodes d'action)...
// Method #1
public ActionResult Assign(string parentName, string itemName) {
// Logic to retrieve item's ID here...
string itemId = ...;
return RedirectToAction("Assign", "Items", new { itemId });
}
// Method #2
public ActionResult Assign(string itemId, string searchTerm, int? page) { ... }
Et voici les itinéraires...
routes.MapRoute("AssignRemove",
"Items/{action}/{itemId}",
new { controller = "Items" }
);
routes.MapRoute("AssignRemovePretty",
"Items/{action}/{parentName}/{itemName}",
new { controller = "Items" }
);
Je comprends pourquoi l'erreur se produit, puisque la page
peut être nul, mais je n'arrive pas à trouver la meilleure façon de résoudre ce problème. Ma conception est-elle mauvaise pour commencer ? J'ai pensé à étendre Method #1
afin d'inclure les paramètres de recherche et de déplacer la logique dans la signature de l'utilisateur. Method #2
vers une méthode privée qu'ils appelleraient tous les deux, mais je ne pense pas que cela résoudra réellement l'ambiguïté.
Toute aide serait grandement appréciée.
Solution réelle (basé sur la réponse de Levi)
J'ai ajouté la classe suivante...
public class RequireRouteValuesAttribute : ActionMethodSelectorAttribute {
public RequireRouteValuesAttribute(string[] valueNames) {
ValueNames = valueNames;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
bool contains = false;
foreach (var value in ValueNames) {
contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value);
if (!contains) break;
}
return contains;
}
public string[] ValueNames { get; private set; }
}
Et ensuite décoré les méthodes d'action...
[RequireRouteValues(new[] { "parentName", "itemName" })]
public ActionResult Assign(string parentName, string itemName) { ... }
[RequireRouteValues(new[] { "itemId" })]
public ActionResult Assign(string itemId) { ... }
4 votes
Incroyable ! Suggestion de changement mineur : (imo vraiment utile) 1) params string[] valueNames pour rendre la déclaration d'attribut plus concise et (préférence) 2) remplacer le corps de la méthode IsValidForRequest par
return ValueNames.All(v => controllerContext.RequestContext.RouteData.Values.ContainsKey(v));
0 votes
Salut Jon, je pense que je n'ai pas compris quelque chose, car où sont les paramètres de requête dans RouteData ?
2 votes
J'ai eu le même problème avec le paramètre querystring. Si vous avez besoin que ces paramètres soient pris en compte pour l'exigence, remplacez le paramètre
contains = ...
pour quelque chose comme ça :contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
3 votes
Un avertissement à ce sujet : les paramètres requis doivent être envoyés exactement comme ils sont nommés. Si votre paramètre de méthode d'action est un type complexe rempli en passant ses propriétés par nom (et en laissant MVC les masser dans le type complexe), ce système échoue parce que le nom n'est pas dans les clés de la chaîne de requête. Par exemple, ceci ne fonctionnera pas :
ActionResult DoSomething(Person p)
, dondePerson
a diverses propriétés simples commeName
et les requêtes qui lui sont adressées le sont directement avec les noms de propriétés (par exemple,/dosomething/?name=joe+someone&other=properties
).4 votes
Si vous utilisez MVC4 ou une version ultérieure, vous devez utiliser la méthode suivante
controllerContext.HttpContext.Request[value] != null
au lieu decontrollerContext.RequestContext.RouteData.Values.ContainsKey(value)
mais c'est tout de même un beau travail.