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 RemoveAktionsmethoden) ...
// 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 pageParameter 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 #1die Signatur um die Suchparameter zu erweitern und die Logik Method #2auf 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 Personverschiedene einfache Eigenschaften wie Nameund Anfragen dazu mit Eigenschaftsnamen direkt (zB /dosomething/?name=joe+someone&other=properties) gestellt werden.
controllerContext.HttpContext.Request[value] != nullanstelle von verwenden controllerContext.RequestContext.RouteData.Values.ContainsKey(value). aber trotzdem ein schönes Stück Arbeit.