J'ai deux méthodes d'action qui sont contradictoires. Fondamentalement, je veux pouvoir accéder à la même vue en utilisant deux itinéraires différents, 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 dans différents parents). 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
des 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, car le page
paramètre peut être nul, mais je ne peux pas trouver le meilleur moyen de le résoudre. Ma conception est-elle médiocre pour commencer? J'ai pensé à étendre Method #1
la signature de pour inclure les paramètres de recherche et à déplacer la logique 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ée 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 puis 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) { ... }
return ValueNames.All(v => controllerContext.RequestContext.RouteData.Values.ContainsKey(v));
contains = ...
section par quelque chose comme ceci:contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
ActionResult DoSomething(Person p)
where Person
a diverses propriétés simples comme Name
, et les requêtes qui lui sont adressées sont faites directement avec les noms de propriétés (par exemple, /dosomething/?name=joe+someone&other=properties
).
controllerContext.HttpContext.Request[value] != null
place de controllerContext.RequestContext.RouteData.Values.ContainsKey(value)
; mais un beau travail néanmoins.