Tengo dos métodos de acción que son conflictivos. Básicamente, quiero poder llegar a la misma vista usando dos rutas diferentes, ya sea por la ID de un elemento o por el nombre del elemento y el de su elemento primario (los elementos pueden tener el mismo nombre en diferentes elementos primarios). Se puede usar un término de búsqueda para filtrar la lista.
Por ejemplo...
Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321
Aquí están mis métodos de acción (también hay Remove
métodos de acción) ...
// 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) { ... }
Y aquí están las rutas ...
routes.MapRoute("AssignRemove",
"Items/{action}/{itemId}",
new { controller = "Items" }
);
routes.MapRoute("AssignRemovePretty",
"Items/{action}/{parentName}/{itemName}",
new { controller = "Items" }
);
Entiendo por qué se produce el error, ya que el page
parámetro puede ser nulo, pero no puedo encontrar la mejor manera de resolverlo. ¿Es mi diseño pobre para empezar? He pensado en extender Method #1
la firma para incluir los parámetros de búsqueda y trasladar la lógica Method #2
a un método privado que ambos llamarían, pero no creo que eso realmente resuelva la ambigüedad.
Cualquier ayuda sería muy apreciada.
Solución real (basada en la respuesta de Levi)
Agregué la siguiente clase ...
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; }
}
Y luego decoró los métodos de acción ...
[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 = ...
sección por algo como esto:contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
ActionResult DoSomething(Person p)
donde Person
tiene varias propiedades simples como Name
, y las solicitudes se realizan con nombres de propiedad directamente (por ejemplo, /dosomething/?name=joe+someone&other=properties
).
controllerContext.HttpContext.Request[value] != null
lugar de controllerContext.RequestContext.RouteData.Values.ContainsKey(value)
; pero un buen trabajo de todos modos.