1. ホーム
  2. c#

[解決済み] ASP.NET MVCのあいまいなアクションメソッド

2022-06-15 23:27:59

質問

2つのアクションメソッドが競合しています。 基本的には、アイテムのID、またはアイテムの名前とその親(アイテムは異なる親にわたって同じ名前を持つことができます)によって、2つの異なるルートを使用して同じビューに到達できるようにしたいと思っています。 検索語は、リストをフィルタリングするために使用することができます。

例えば...

Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321

以下は、私のアクション・メソッドです(他にも Remove アクションメソッドもあります)...

// 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) { ... }

そして、これがルートです...

routes.MapRoute("AssignRemove",
                "Items/{action}/{itemId}",
                new { controller = "Items" }
                );

routes.MapRoute("AssignRemovePretty",
                "Items/{action}/{parentName}/{itemName}",
                new { controller = "Items" }
                );

エラーが発生する理由は理解しています。 page パラメータがnullになる可能性があるため、エラーが発生する理由は理解しているのですが、解決するための最良の方法がわかりません。 そもそも私の設計が悪いのでしょうか? を拡張することは考えたのですが Method #1 のシグネチャを拡張して、検索パラメータを含むようにし、ロジックを Method #2 のロジックを両方とも呼び出すプライベートメソッドに移動させますが、それが実際にあいまいさを解決するとは思えません。

どんな助けでも非常に感謝されます。


実際の解決策 (リヴァイの回答より)

以下のようなクラスを追加してみました...

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; }
}

そして、アクションメソッドを装飾して...

[RequireRouteValues(new[] { "parentName", "itemName" })]
public ActionResult Assign(string parentName, string itemName) { ... }

[RequireRouteValues(new[] { "itemId" })]
public ActionResult Assign(string itemId) { ... }

どのように解決するのですか?

MVCはシグネチャのみに基づくメソッドのオーバーロードをサポートしていませんので、これは失敗します。

public ActionResult MyMethod(int someInt) { /* ... */ }
public ActionResult MyMethod(string someString) { /* ... */ }

しかし、それは は属性に基づくメソッドのオーバーロードをサポートしています。

[RequireRequestValue("someInt")]
public ActionResult MyMethod(int someInt) { /* ... */ }

[RequireRequestValue("someString")]
public ActionResult MyMethod(string someString) { /* ... */ }

public class RequireRequestValueAttribute : ActionMethodSelectorAttribute {
    public RequireRequestValueAttribute(string valueName) {
        ValueName = valueName;
    }
    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
        return (controllerContext.HttpContext.Request[ValueName] != null);
    }
    public string ValueName { get; private set; }
}

上記の例では、属性は単に "このメソッドは、キー xxx がリクエストに存在した場合、このメソッドがマッチします。