Mam dwie sprzeczne metody działania. Zasadniczo chcę mieć możliwość uzyskania tego samego widoku przy użyciu dwóch różnych tras, albo według identyfikatora elementu, albo według nazwy elementu i jego elementu nadrzędnego (elementy mogą mieć tę samą nazwę u różnych elementów nadrzędnych). Do filtrowania listy można użyć wyszukiwanego hasła.
Na przykład...
Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321
Oto moje metody akcji (są też Remove
metody akcji) ...
// 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) { ... }
A oto trasy ...
routes.MapRoute("AssignRemove",
"Items/{action}/{itemId}",
new { controller = "Items" }
);
routes.MapRoute("AssignRemovePretty",
"Items/{action}/{parentName}/{itemName}",
new { controller = "Items" }
);
Rozumiem, dlaczego występuje błąd, ponieważ page
parametr może być pusty, ale nie mogę znaleźć najlepszego sposobu rozwiązania tego problemu. Czy mój projekt jest kiepski? Myślałem o rozszerzeniu Method #1
podpisu tak, aby obejmował parametry wyszukiwania i przeniesieniu logiki Method #2
do prywatnej metody, którą obaj będą wywoływać, ale nie wierzę, że to faktycznie rozwiąże tę niejednoznaczność.
Każda pomoc byłaby bardzo mile widziana.
Rzeczywiste rozwiązanie (na podstawie odpowiedzi Levi's)
Dodałem następującą klasę ...
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; }
}
A potem udekorował metody działania ...
[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 = ...
sekcję na coś takiego:contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
ActionResult DoSomething(Person p)
gdzie Person
ma różne proste właściwości, takie jak Name
, a żądania do niego są wysyłane bezpośrednio z nazwami właściwości (np /dosomething/?name=joe+someone&other=properties
.).
controllerContext.HttpContext.Request[value] != null
zamiast controllerContext.RequestContext.RouteData.Values.ContainsKey(value)
; ale mimo wszystko niezła robota.