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) { ... }
quelle
return ValueNames.All(v => controllerContext.RequestContext.RouteData.Values.ContainsKey(v));
contains = ...
Abschnitt gegencontains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
ActionResult DoSomething(Person p)
woPerson
verschiedene einfache Eigenschaften wieName
und Anfragen dazu mit Eigenschaftsnamen direkt (zB/dosomething/?name=joe+someone&other=properties
) gestellt werden.controllerContext.HttpContext.Request[value] != null
anstelle von verwendencontrollerContext.RequestContext.RouteData.Values.ContainsKey(value)
. aber trotzdem ein schönes Stück Arbeit.Antworten:
MVC unterstützt keine Methodenüberladung, die ausschließlich auf der Signatur basiert. Dies schlägt daher fehl:
Aber es tut Unterstützungsverfahren Überlastung basierend auf Attribut:
Im obigen Beispiel sagt das Attribut einfach "Diese Methode stimmt überein, wenn der Schlüssel xxx in der Anforderung vorhanden war." Sie können auch nach Informationen filtern, die in der Route enthalten sind (controllerContext.RequestContext), wenn dies Ihren Zwecken besser entspricht.
quelle
...RouteData.Values
stattdessen nach, aber das "funktioniert". Ob es sich um ein gutes Muster handelt oder nicht, steht zur Debatte. :)Die Parameter in Ihren Routen
{roleId}
,{applicationName}
und{roleName}
die Parameternamen nicht in den Aktionsmethoden entsprechen. Ich weiß nicht, ob das wichtig ist, aber es macht es schwieriger herauszufinden, was Ihre Absicht ist.Entspricht Ihre itemId einem Muster, das über Regex abgeglichen werden kann? Wenn ja, können Sie Ihrer Route eine Einschränkung hinzufügen, sodass nur URLs, die dem Muster entsprechen, eine itemId enthalten.
Wenn Ihre itemId nur Ziffern enthalten würde, würde dies funktionieren:
Bearbeiten: Sie können der
AssignRemovePretty
Route auch eine Einschränkung hinzufügen, sodass beide{parentName}
und{itemName}
erforderlich sind.Bearbeiten 2: Da Ihre erste Aktion nur zu Ihrer zweiten Aktion umleitet, können Sie Unklarheiten beseitigen, indem Sie die erste umbenennen.
Geben Sie dann die Aktionsnamen in Ihren Routen an, um den Aufruf der richtigen Methode zu erzwingen:
quelle
Ein anderer Ansatz besteht darin, eine der Methoden umzubenennen, damit kein Konflikt entsteht. Beispielsweise
Siehe http://www.asp.net/mvc/tutorials/getting-started-with-mvc3-part9-cs
quelle
Vor kurzem habe ich die Gelegenheit genutzt, die Antwort von @ Levi zu verbessern, um eine größere Bandbreite von Szenarien zu unterstützen, mit denen ich mich befassen musste, z. B.: Unterstützung mehrerer Parameter, Übereinstimmung mit einem von ihnen (anstelle von allen) und sogar mit keinem von ihnen.
Hier ist das Attribut, das ich jetzt verwende:
Weitere Informationen und Beispiele für die Implementierung finden Sie in diesem Blog-Beitrag , den ich zu diesem Thema geschrieben habe.
quelle
Erwägen Sie die Verwendung der MVC Contribs-Testroutenbibliothek, um Ihre Routen zu testen
quelle