ASP.NET MVC でコントローラー メソッドをオーバーロードできるかどうかを知りたいです。試行するたびに、以下のエラーが発生します。2 つのメソッドは異なる引数を受け入れます。これは仕方のないことでしょうか?
コントローラー タイプ 'MyController' のアクション 'MyMethod' に対する現在の要求は、次のアクション メソッド間であいまいです:
ASP.NET MVC でコントローラー メソッドをオーバーロードできるかどうかを知りたいです。試行するたびに、以下のエラーが発生します。2 つのメソッドは異なる引数を受け入れます。これは仕方のないことでしょうか?
コントローラー タイプ 'MyController' のアクション 'MyMethod' に対する現在の要求は、次のアクション メソッド間であいまいです:
コードでオーバーロードを行う場合は、属性を使用できます。
[ActionName("MyOverloadedName")]
ただし、同じ http メソッドには別のアクション名を使用する必要があります (他の人が言っているように)。したがって、それはその時点での単なるセマンティクスです。コードと属性のどちらに名前を入れますか?
Phil にはこれに関連する記事があります: http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx
はい。HttpGet
これは、各コントローラー メソッドの/ HttpPost
(または同等のAcceptVerbs
属性) を別のもの、つまりHttpGet
orに設定することで実現できましたが、HttpPost
両方には設定できませんでした。そうすれば、リクエストのタイプに基づいて、どのメソッドを使用するかを判断できます。
[HttpGet]
public ActionResult Show()
{
...
}
[HttpPost]
public ActionResult Show( string userName )
{
...
}
私が持っている 1 つの提案は、このような場合、コードの重複を避けるために両方のパブリック Action メソッドが依存するプライベート実装を持つことです。
他にできることは次のとおりです...パラメーターを持つことができるメソッドとできないメソッドが必要です。
これを試してみませんか...
public ActionResult Show( string username = null )
{
...
}
これは私にとってはうまくいきました...そして、この1つの方法で、実際に着信パラメーターがあるかどうかをテストできます。
いいえ、いいえ、いいえ。「LoadCustomer」がオーバーロードされている以下のコントローラー コードを試してみてください。
public class CustomerController : Controller
{
//
// GET: /Customer/
public ActionResult LoadCustomer()
{
return Content("LoadCustomer");
}
public ActionResult LoadCustomer(string str)
{
return Content("LoadCustomer with a string");
}
}
「LoadCustomer」アクションを呼び出そうとすると、次の図に示すようなエラーが発生します。
ポリモーフィズムは C# プログラミングの一部ですが、HTTP はプロトコルです。HTTP はポリモーフィズムを理解していません。HTTP は概念または URL で機能し、URL は一意の名前のみを持つことができます。したがって、HTTP はポリモーフィズムを実装していません。
これを修正するには、「ActionName」属性を使用する必要があります。
public class CustomerController : Controller
{
//
// GET: /Customer/
public ActionResult LoadCustomer()
{
return Content("LoadCustomer");
}
[ActionName("LoadCustomerbyName")]
public ActionResult LoadCustomer(string str)
{
return Content("LoadCustomer with a string");
}
}
したがって、URL「Customer/LoadCustomer」を呼び出すと、「LoadCustomer」アクションが呼び出され、URL 構造「Customer/LoadCustomerByName」で「LoadCustomer(string str)」が呼び出されます。
このコードプロジェクトの記事から取った上記の回答 --> MVC アクションのオーバーロード
この問題を克服するために、 for each アクションを調べてポストされた Form 値と比較し、フォーム値が一致しないメソッドを拒否する を書くことができます (もちろん、ボタン名は除きます)。ActionMethodSelectorAttribute
MethodInfo
例を次に示します 。
しかし、これは良い考えではありません。
私の知る限り、異なる http メソッドを使用する場合は、同じメソッドしか使用できません。
すなわち
[AcceptVerbs("GET")]
public ActionResult MyAction()
{
}
[AcceptVerbs("POST")]
public ActionResult MyAction(FormResult fm)
{
}
MVC5の属性ルーティングの助けを借りてこれを達成しました。確かに、私は WebForms を使用した 10 年間の Web 開発から来て、MVC を初めて使用しましたが、次の方法でうまくいきました。受け入れられた回答とは異なり、これにより、オーバーロードされたすべてのアクションを同じビュー ファイルでレンダリングできます。
まず、App_Start/RouteConfig.cs で属性ルーティングを有効にします。
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
必要に応じて、コントローラー クラスをデフォルトのルート プレフィックスで装飾します。
[RoutePrefix("Returns")]
public class ReturnsController : BaseController
{
//.......
次に、共通のルートとパラメーターを使用して相互にオーバーロードするコントローラー アクションを装飾します。型制約パラメーターを使用すると、異なる型の ID で同じ URI 形式を使用できます。
[HttpGet]
// Returns
public ActionResult Index()
{
//.....
}
[HttpGet]
[Route("View")]
// Returns/View
public ActionResult View()
{
// I wouldn't really do this but it proves the concept.
int id = 7026;
return View(id);
}
[HttpGet]
[Route("View/{id:int}")]
// Returns/View/7003
public ActionResult View(int id)
{
//.....
}
[HttpGet]
[Route("View/{id:Guid}")]
// Returns/View/99300046-0ba4-47db-81bf-ba6e3ac3cf01
public ActionResult View(Guid id)
{
//.....
}
これが助けになり、誰かを間違った道に導いていないことを願っています. :-)
ActionResult
と の両方を処理するためPost
に単一を使用できますGet
。
public ActionResult Example() {
if (Request.HttpMethod.ToUpperInvariant() == "GET") {
// GET
}
else if (Request.HttpMethod.ToUpperInvariant() == "POST") {
// Post
}
}
Get
とPost
メソッドのシグネチャが一致する場合に便利です。
次のオーバーロードが必要でした:
public ActionResult Index(string i);
public ActionResult Index(int groupId, int itemId);
私がこれを行うことになったのに十分な議論はほとんどありませんでした:
public ActionResult Index(string i, int? groupId, int? itemId)
{
if (!string.IsNullOrWhitespace(i))
{
// parse i for the id
}
else if (groupId.HasValue && itemId.HasValue)
{
// use groupId and itemId for the id
}
}
特に多くの議論がある場合、これは完璧な解決策ではありませんが、私にとってはうまくいきます。
私のアプリケーションでも同じ問題に直面しました。メソッド情報を変更せずに、アクション ヘッドに [ActionName("SomeMeaningfulName")] を指定しました。問題は解決された
[ActionName("_EmployeeDetailsByModel")]
public PartialViewResult _EmployeeDetails(Employee model)
{
// Some Operation
return PartialView(model);
}
}
[ActionName("_EmployeeDetailsByModelWithPagination")]
public PartialViewResult _EmployeeDetails(Employee model,int Page,int PageSize)
{
// Some Operation
return PartialView(model);
}
別のスレッドに投稿されたこの回答が好きです
これは主に、別のコントローラーから継承し、ベース コントローラーからのアクションをオーバーライドする場合に使用されます。
同じ問題に苦しんでいる人のためのこの答え。ActionMethodSelectorAttribute に基づいて独自のカスタム フィルターを実装できます。ここで、あなたの質問を解決するための最良の解決策を見つけました。.net 5 プロジェクトで正常に動作します。
Web API コントローラーと同じロジックを実装しようとする場合は、Microsoft.AspNetCore.Mvc.WebApiCompatShim を使用します。この nuget パッケージは、ASP.NET Core MVC と ASP.NET Web API 2 との互換性を提供し、既存の Web API 実装の移行を簡素化します。この回答を確認してください。ただし、ASP.NET Core 3.0 以降、Microsoft.AspNetCore.Mvc.WebApiCompatShim パッケージは利用できなくなっていることを考慮してください。
基本メソッドを仮想として作成する
public virtual ActionResult Index()
オーバーライドされたメソッドをオーバーライドとして作成します
public override ActionResult Index()
編集:これは明らかに、オーバーライド メソッドが OP の意図ではないように見える派生クラスにある場合にのみ適用されます。
これが、異なるモデルの複数のアクションに POST する複数のビューに対して 1 つの GET アクションを使用しようとする場合は、最初の GET にリダイレクトする POST アクションごとに GET アクションを追加して、更新時の 404 を防止してください。
ロングショットだが一般的なシナリオ。