c# - 見つかり - ASP.NET MVCでコントローラメソッドをオーバーロードできますか?




要求 に 一致 する 複数 の アクション が 見つかり まし た (11)

私はあなたがASP.NET MVCのコントローラメソッドをオーバーロードできるかどうかを知りたいのです。 私が試してみると、私は以下のエラーが表示されます。 2つの方法は異なる引数を受け入れます。 これはできないことですか?

コントローラータイプ 'MyController'でのアクション 'MyMethod'の現在の要求は、以下のアクションメソッド間であいまいです。


MVC5のAttribute Routingの助けを借りてこれを達成しました。 確かに、私は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)
{
    //.....
}

これが助けてくれることを願って、誰かを間違った方向へ導いてはいません。 :-)


[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");
    }
}

いいえ、いいえ、いいえ。「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)"が呼び出されます。

上記の答えは、このcodeprojectの記事から取った - > MVCアクションのオーバーロード


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

なぜこれを試してみてください...

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

これは私のために働いています...そして、この1つの方法では、実際に入力パラメータがあるかどうかを調べることができます。

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


これが異なるモデルでいくつかのアクションにPOSTするいくつかのビューに対して1つのGETアクションを使用しようとしている場合は、最初のGETにリダイレクトするPOSTアクションごとにGETアクションを追加して、リフレッシュ時404を防ぎます。

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


はい。 これを行うには、各コントローラメソッドのHttpGet / HttpPost (またはそれに相当するAcceptVerbs属性)を、 HttpGetまたはHttpPostような異なるものに設定します。 このようにして、使用するメソッドのタイプに基づいて伝えることができます。

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

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

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


単一のActionResultを使用して、 PostGet両方を処理できます。

public ActionResult Example() {
   if (Request.HttpMethod.ToUpperInvariant() == "GET") {
    // GET
   }
   else if (Request.HttpMethod.ToUpperInvariant() == "POST") {
     // Post  
   }
}

GetメソッドとPostメソッドが一致するシグネチャを持つ場合に便利です。


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

オーバーロードされたメソッドを区別するために( [HttpGet][HttpPost]属性のような)別の動詞を使用したくない場合や、ルーティングを変更する場合は、別のメソッドを提供するか、別の名前を使用するか、既存のメソッドの内部にディスパッチすることができます。 ここで私はそれをやった:

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

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

  1. 2つのオーバーロードされたアクションメソッドを公開から非公開に変更
  2. "ちょうど" 2つの文字列パラメータを含む新しいパブリックメソッドを1つ作成しました。 その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には2つのパラメータが必要です。



私はちょうどこの質問に遭遇しました、そして、今はかなり古くても、それはまだまだ関連性があります。 皮肉なことに、このスレッドの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構造があなたのコード命名規則と完全に一致するなら、デフォルトはうまくいくが、これは必ずしもそうではない。 コードはドメインを説明する必要がありますが、コンテンツはSEO要件などの他の基準に基づいている必要があるため、URLはしばしばさらに進む必要があります。

デフォルトのルーティングパターンの利点は、独自のルートを自動的に作成することです。 これは、URLが一意のコントローラタイプとメンバーに一致するため、コンパイラによって強制されます。 独自のルートパターンをローリングするには、一意性を確保するために注意深く考えなければなりません。

重要な点 1つの欠点は、オーバーロードされたアクションのURLを生成するためにルーティングを使用すると、UrlHelper.Actionを使用するなど、アクション名に基づいて動作しないことです。 しかし、UrlHelper.RouteUrlなどの名前付きルートを使用するとうまくいきます。 名前付きルートを使用することは、尊敬されている情報源によれば、とにかく行く方法です( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/ )。

がんばろう!


私は過負荷が必要でした:

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

これは完璧な解決策ではありません。特に議論が多いのであれば、私にとってはうまくいきます。





overloading