Ich habe zwei widersprüchliche Aktionsmethoden. Grundsätzlich möchte ich in der Lage sein, über zwei verschiedene Routen zur gleichen Ansicht zu gelangen, entweder anhand der ID eines Elements oder anhand des Namens des Elements und seiner übergeordneten Elemente (Elemente können über verschiedene übergeordnete Elemente hinweg denselben Namen haben). Ein Suchbegriff kann verwendet werden, um die Liste zu filtern.
Beispielsweise...
Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321
Hier sind meine Aktionsmethoden (es gibt auch Remove
Aktionsmethoden) ...
// 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) { ... }
Und hier sind die Routen ...
routes.MapRoute("AssignRemove",
"Items/{action}/{itemId}",
new { controller = "Items" }
);
routes.MapRoute("AssignRemovePretty",
"Items/{action}/{parentName}/{itemName}",
new { controller = "Items" }
);
Ich verstehe, warum der Fehler auftritt, da der page
Parameter null sein kann, aber ich kann nicht herausfinden, wie ich ihn am besten beheben kann. Ist mein Design anfangs schlecht? Ich habe darüber nachgedacht, Method #1
die Signatur um die Suchparameter zu erweitern und die Logik Method #2
auf eine private Methode zu verschieben, die beide aufrufen würden, aber ich glaube nicht, dass dies die Mehrdeutigkeit tatsächlich auflösen wird.
Jede Hilfe wäre sehr dankbar.
Tatsächliche Lösung (basierend auf Levis Antwort)
Ich habe die folgende Klasse hinzugefügt ...
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; }
}
Und dann die Aktionsmethoden dekoriert ...
[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 = ...
Abschnitt gegen contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
ActionResult DoSomething(Person p)
wo Person
verschiedene einfache Eigenschaften wie Name
und Anfragen dazu mit Eigenschaftsnamen direkt (zB /dosomething/?name=joe+someone&other=properties
) gestellt werden.
controllerContext.HttpContext.Request[value] != null
anstelle von verwenden controllerContext.RequestContext.RouteData.Values.ContainsKey(value)
. aber trotzdem ein schönes Stück Arbeit.