ASP.NET MVCでコントローラーメソッドをオーバーロードできますか?

StackOverflow https://stackoverflow.com/questions/436866

  •  22-07-2019
  •  | 
  •  

質問

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 または HttpPost 、ただし両方ではありません。そうすれば、リクエストのタイプに基づいてどのメソッドを使用するかを判断できます。

[HttpGet]
public ActionResult Show()
{
   ...
}

[HttpPost]
public ActionResult Show( string userName )
{
   ...
}

私が持っている提案の1つは、このような場合、パブリックアクションメソッドの両方がコードの重複を避けるために依存するプライベート実装を持つことです。

他にできることがあります...パラメータを持ち、持たないメソッドが必要です。

これを試してみませんか...

public ActionResult Show( string username = null )
{
   ...
}

これは私にとってはうまくいきました...そしてこの1つの方法では、着信パラメータがあるかどうかを実際にテストできます。


文字列の無効なNULL可能構文を削除し、デフォルトのパラメーター値を使用するように更新されました。

いいえ、いいえ、いいえ。次のコントローラーコードを試してください。オーバーロード。

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アクションのオーバーロード

この問題を克服するために、各アクションの MethodInfo を調べ、それを投稿されたフォーム値と比較する ActionMethodSelectorAttribute 書くことができます。フォームの値が一致しないメソッドを拒否します(もちろん、ボタン名を除く)。

例を次に示します。- http:// blog。 abodit.com/2010/02/asp-net-mvc-ambiguous-match/

しかし、これは良い考えではありません。

私が知る限り、異なるHTTPメソッドを使用する場合にのみ同じメソッドを使用できます。

i.e。

[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 メソッドに一致する署名がある場合に便利です。

この質問に出くわしたばかりで、今ではかなり古くなっていますが、それでも非常に重要です。皮肉なことに、このスレッドの1つの正しいコメントは、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
    }
}

これらのアクションは、 / cars / usa / new-york / cars / usa / texas / dallas などのURLを処理します。それぞれ2番目のインデックスアクション。

このコントローラ例を調べると、上記のデフォルトのルートパターンを超えていることが明らかです。 URL構造がコードの命名規則と完全に一致する場合、デフォルトはうまく機能しますが、常にそうであるとは限りません。コードはドメインを説明する必要がありますが、URLは多くの場合、コンテンツがSEO要件などの他の基準に基づいている必要があるため、さらに先へ進む必要があります。

デフォルトのルーティングパターンの利点は、一意のルートを自動的に作成することです。 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の意図ではないように見える派生クラスにある場合にのみ適用されます。

別のスレッドに投稿されたこの回答が好きです

これは主に、別のコントローラーから継承し、ベースコントローラーからのアクションをオーバーライドする場合に使用されます

ASP.NET MVC-異なるパラメーターでアクションをオーバーライドする

各コントローラーメソッドに許可されるパブリック署名は1つだけです。オーバーロードしようとするとコンパイルされますが、実行時エラーが発生します。

異なる動詞( [HttpGet] [HttpPost] 属性など)を使用して、オーバーロードされたメソッド(機能する)を区別したくない場合、またはルーティングを変更すると、別のメソッドを別の名前で指定するか、既存のメソッド内でディスパッチすることができます。方法は次のとおりです。

以前、下位互換性を維持しなければならない状況に陥りました。元の方法では2つのパラメーターが必要でしたが、新しいパラメーターには1つしかありませんでした。 MVCがエントリポイントを見つけられなかったため、期待した方法でオーバーロードしても機能しませんでした。

それを解決するために、次のことを行いました:

  1. 2つのオーバーロードされたアクションメソッドをパブリックからプライベートに変更しました
  2. " just"を含む1つの新しいパブリックメソッドを作成しました2つの文字列パラメーター。その人はディスパッチャとして行動しました、つまり:

    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つのパラメーターしか必要ないことがわかります。

これが、異なるモデルの複数のアクションにPOSTする複数のビューに対して1つのGETアクションを使用する試みである場合、最初のGETにリダイレクトする各POSTアクションにGETアクションを追加して、更新時の404を防ぎます。

ロングショットだが一般的なシナリオ。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top