Ho due metodi d'azione in conflitto. Fondamentalmente, voglio essere in grado di accedere alla stessa vista utilizzando due percorsi diversi, tramite l'ID di un articolo o il nome dell'articolo e i suoi genitori (gli articoli possono avere lo stesso nome tra genitori diversi). È possibile utilizzare un termine di ricerca per filtrare l'elenco.
Per esempio...
Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321
Ecco i miei metodi di azione (ci sono anche Removemetodi di azione) ...
// 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) { ... }
Ed ecco i percorsi ...
routes.MapRoute("AssignRemove",
"Items/{action}/{itemId}",
new { controller = "Items" }
);
routes.MapRoute("AssignRemovePretty",
"Items/{action}/{parentName}/{itemName}",
new { controller = "Items" }
);
Capisco perché si sta verificando l'errore, poiché il pageparametro può essere nullo, ma non riesco a capire il modo migliore per risolverlo. Il mio design è povero per cominciare? Ho pensato di estendere Method #1la firma per includere i parametri di ricerca e spostare la logica in Method #2un metodo privato che entrambi chiamerebbero, ma non credo che risolverà effettivamente l'ambiguità.
Qualsiasi aiuto sarebbe molto apprezzato.
Soluzione effettiva (basata sulla risposta di Levi)
Ho aggiunto la seguente classe ...
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; }
}
E poi decorato i metodi di azione ...
[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 = ...sezione con qualcosa del genere:contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
ActionResult DoSomething(Person p)dove Personha varie proprietà semplici come Name, e le richieste vengono fatte direttamente con i nomi delle proprietà (ad esempio, /dosomething/?name=joe+someone&other=properties).
controllerContext.HttpContext.Request[value] != nullinvece di controllerContext.RequestContext.RouteData.Values.ContainsKey(value); ma comunque un bel lavoro.