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 Remove
metodi 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 page
parametro può essere nullo, ma non riesco a capire il modo migliore per risolverlo. Il mio design è povero per cominciare? Ho pensato di estendere Method #1
la firma per includere i parametri di ricerca e spostare la logica in Method #2
un 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 Person
ha 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] != null
invece di controllerContext.RequestContext.RouteData.Values.ContainsKey(value)
; ma comunque un bel lavoro.