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
return View();
。例:return View("MyOverloadedName");
。
はい。私は、各コントローラーメソッドのHttpGet
/ HttpPost
(または同等のAcceptVerbs
属性)を何か別の(つまり、HttpGet
またはHttpPost
両方にではなく)に設定することで、これを行うことができました。こうすることで、要求のタイプに基づいて、どのメソッドを使用するかを判別できます。
[HttpGet]
public ActionResult Show()
{
...
}
[HttpPost]
public ActionResult Show( string userName )
{
...
}
私の提案の1つは、このような場合、両方のパブリックアクションメソッドがコードの重複を避けるために依存するプライベート実装を持つことです。
Show()
メソッドのシグネチャが異なるため、これが機能していることを確認してください。Getバージョンに情報を送信する必要がある場合、GetバージョンとPostバージョンは同じ署名で終了しActionName
、この投稿で言及されている属性または他の修正のいずれかが必要になります。
ActionNameAttribute
。実際には、それが事実であることはめったにありません。
ここにあなたができる他の何かがあります...あなたはパラメータを持つことができて、持たないことができるメソッドが欲しいです。
これを試してみませんか...
public ActionResult Show( string username = null )
{
...
}
これは私にとってはうまくいきました...そしてこの1つの方法では、実際に着信パラメーターがあるかどうかをテストすることができます。
string
nullにすることはできません。)
string
できないことはまだ本当nullable
です。しかしそれは可能null
です!どちらにしても、最初のコメントは誠意をもって投稿しました。
いいえ、いいえ、いいえ。「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");
}
}
したがって、「Customer / LoadCustomer」というURLを呼び出すと、「LoadCustomer」アクションが呼び出され、「Customer / LoadCustomerByName」というURL構造で「LoadCustomer(string str)」が呼び出されます。
私がこのコードプロジェクトの記事から取った上記の答え-> MVCアクションのオーバーロード
この問題を克服するには、各アクションのを調べ、投稿されたフォーム値と比較し、フォーム値が一致しないメソッドを拒否するを記述します(もちろん、ボタン名は除きます)。ActionMethodSelectorAttribute
MethodInfo
次に例を示します。- http : //blog.abodit.com/2010/02/asp-net-mvc-ambiguous-match/
しかし、これは良い考えではありません。
私が知る限り、異なるhttpメソッドを使用する場合、同じメソッドしか使用できません。
すなわち
[AcceptVerbs("GET")]
public ActionResult MyAction()
{
}
[AcceptVerbs("POST")]
public ActionResult MyAction(FormResult fm)
{
}
[HttpPost]
代わりに属性を使用します[AcceptVerbs("POST")]
。
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
メソッドに一致するシグネチャがある場合に役立ちます。
私はこの質問に出くわしました、そしてそれは今かなり古いですが、それでも非常に関連があります。皮肉なことに、このスレッドの正しいコメントは、MVCの自白初心者が投稿したときに投稿したものです。ASP.NETドキュメントでさえ完全に正しいわけではありません。大規模なプロジェクトがあり、アクションメソッドのオーバーロードに成功しました。
ルーティングを理解すれば、単純な{controller} / {action} / {id}のデフォルトルートパターンを超えて、一意のパターンを使用してコントローラーアクションをマッピングできることは明らかです。ここで誰かがポリモーフィズムについて話し、「HTTPはポリモーフィズムを理解しない」と言いましたが、ルーティングはHTTPとは何の関係もありません。簡単に言えば、文字列パターンマッチングのメカニズムです。
これを機能させる最善の方法は、ルーティング属性を使用することです。次に例を示します。
[RoutePrefix("cars/{country:length(3)}")]
public class CarHireController
{
[Route("{location}/{page:int=1}", Name = "CarHireLocation")]
public ActionResult Index(string country, string location, int page)
{
return Index(country, location, null, page);
}
[Route("{location}/{subLocation}/{page:int=1}", Name = "CarHireSubLocation")]
public ActionResult Index(string country, string location, string subLocation, int page)
{
//The main work goes here
}
}
これらのアクションはやなどのURLを処理/cars/usa/new-york
します/cars/usa/texas/dallas
、。これは、最初と2番目のIndexアクションにそれぞれマップされます。
このサンプルコントローラーを調べると、上記のデフォルトのルートパターンを超えていることがわかります。デフォルトは、URL構造がコードの命名規則と完全に一致する場合に適切に機能しますが、常にそうであるとは限りません。コードはドメインを説明するものである必要がありますが、URLのコンテンツはSEO要件などの他の基準に基づいている必要があるため、URLは多くの場合、さらに進む必要があります。
デフォルトのルーティングパターンの利点は、一意のルートが自動的に作成されることです。URLは一意のコントローラータイプとメンバーに一致するため、これはコンパイラーによって強制されます。独自のルートパターンを展開するには、一意性を確保し、それらが機能するように慎重に検討する必要があります。
重要な注意点 1つの欠点は、ルーティングを使用してオーバーロードされたアクションのURLを生成することが、UrlHelper.Actionを使用する場合など、アクション名に基づく場合は機能しないことです。ただし、UrlHelper.RouteUrlなどの名前付きルートを使用する場合は機能します。そして、名高いルートを使用することは、尊敬される情報源によると、とにかく行く方法です(http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/)。
幸運を!
[ActionName( "NewActionName")]を使用して、同じメソッドを別の名前で使用できます。
public class HomeController : Controller
{
public ActionResult GetEmpName()
{
return Content("This is the test Message");
}
[ActionName("GetEmpWithCode")]
public ActionResult GetEmpName(string EmpCode)
{
return Content("This is the test Messagewith Overloaded");
}
}
私は次のオーバーロードが必要でした:
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);
}
基本メソッドを仮想として作成する
public virtual ActionResult Index()
オーバーライドされたメソッドをオーバーライドとして作成する
public override ActionResult Index()
編集:これは明らかに、オーバーライドメソッドがOPの意図ではないように見える派生クラスにある場合にのみ適用されます。
私は別のスレッドに投稿されたこの回答が好きです
これは主に、別のコントローラーから継承し、ベースコントローラーからのアクションをオーバーライドする場合に使用されます。
各コントローラーメソッドに許可されているパブリックシグネチャは1つだけです。オーバーロードしようとすると、コンパイルされますが、経験したランタイムエラーが発生します。
別の動詞を使用したくない場合は([HttpGet]
および[HttpPost]
属性など)を使用してオーバーロードされたメソッド(機能する)を区別したり、ルーティングを変更したりしたくない場合は、別の名前の別のメソッドを提供するか、または既存のメソッド内でディスパッチします。ここに私がそれをした方法があります:
以前、下位互換性を維持しなければならない状況に陥りました。元のメソッドは2つのパラメーターを想定していましたが、新しいメソッドには1つしかありませんでした。MVCがエントリポイントを見つけられなくなったため、期待した方法でオーバーロードしても機能しませんでした。
それを解決するために、私は次のことをしました:
「ただ」2つの文字列パラメータを含む1つの新しいパブリックメソッドを作成しました。それはディスパッチャーとして機能しました、すなわち:
public ActionResult DoSomething(string param1, string param2)
{
if (string.IsNullOrEmpty(param2))
{
return DoSomething(ProductName: param1);
}
else
{
int oldId = int.Parse(param1);
return DoSomething(OldParam: param1, OldId: oldId);
}
}
private ActionResult DoSomething(string OldParam, int OldId)
{
// some code here
return Json(result);
}
private ActionResult DoSomething(string ProductName)
{
// some code here
return Json(result);
}
もちろん、これはハックであり、後でリファクタリングする必要があります。しかし、当分の間、それは私のために働いた。
次のようなディスパッチャーを作成することもできます。
public ActionResult DoSomething(string action, string param1, string param2)
{
switch (action)
{
case "update":
return UpdateAction(param1, param2);
case "remove":
return DeleteAction(param1);
}
}
ご覧のとおり、UpdateActionには2つのパラメーターが必要ですが、DeleteActionには1つだけ必要です。
遅れて申し訳ありません。私は同じ問題を抱えていて、良い答えとのリンクを見つけました、それは新しい人を助けることができますか
BinaryIntellect Webサイトと作成者のすべてのクレジット
基本的には、4つの状況があります:貴様の動詞を使用して、ルーティング使用して、過負荷属性[NOACTION]でマーキングし、[ACTIONNAME]とのaction属性名を変更します
だから、それはあなたの要件とあなたの状況に依存します。
ただし、リンクをクリックしてください:
リンク:http : //www.binaryintellect.net/articles/8f9d9a8f-7abf-4df6-be8a-9895882ab562.aspx
これが、異なるモデルの複数のアクションにPOSTする複数のビューに対して1つのGETアクションを使用する試みである場合、最初のGETにリダイレクトするPOSTアクションごとにGETアクションを追加して、更新時に404が発生しないようにします。
ロングショットですが、一般的なシナリオです。