私はMVCで働き始めたばかりですが、疑問が1つあります。
Nonaction
メソッドの代わりに、コントローラーでプライベートメソッドを作成するか、モデルにメソッドを記述してコントローラーから呼び出すこともできます。
では、MVCでpublic NonAction
メソッドを使用する本当の目的は何ですか?
(コメント内の質問により適切に対処するために、回答を再構成しました)
この属性は、柔軟性を高めるためだけのものだと思います。フレームワークの設計者として、エンドユーザーのコーディングの制約を可能な限り緩和したいと考えています。公の非行動を持たないという要件は、「一般的に」良いように聞こえるかもしれませんが、一部のプロジェクトには制限が強すぎる可能性があります。 [NonAction]
を追加すると、問題が解決します(ただし、設計が悪いために発生します)。もちろん、属性の使用を強制されないため、フレームワーク設計者の観点からは双方にメリットがあります。
もう1つの理由は、レガシーである可能性があります。以前のMVCバージョンでは、アクションと見なされる場合、[Action]
でマークされたメソッドのみが使用されていました。したがって、要件を緩和したとき(およびすべてのパブリックメソッドがアクションとして扱われるようになったとき)、開発者が混乱しすぎないように[NonAction]
を維持しました。
一般に、NonAction
を使用することは悪い習慣です-まさにあなたが述べた理由のためです。何かがアクションであってはならない場合、そもそもpublic
であってはなりません。
コントローラー上のパブリック非アクションメソッドの問題は、共通のロジックを分離するのではなく、コントローラーをインスタンス化してメソッドを呼び出したくなることです。
比較する
public class MyController : IController
{
public ActionResult Foo(long orderId)
{
var order = new OrdersController().GetOrder(orderId); //GetOrder is public
...
}
}
と
public class MyController : IController
{
public ActionResult Foo(long orderId)
{
var order = _orderService.GetOrder(orderId);
...
}
}
最初のアプローチは、アクション内のコントローラーと非単純なコード間の結合の増加につながります。コードの追跡とリファクタリングが困難になり、モック/テストが面倒になります。
結合の増加に加えて、パブリック非アクションメソッドはセキュリティホールです-[NonAction]
でマークするのを忘れた場合(または、パブリックから変更することをお勧めします)-通常のアクションとして扱われ、外部から呼び出すことができるためです。元の質問は、必要に応じて属性を添付することを決して忘れないことを意味していることを私は知っていますが、そうすると何が起こるかを理解することも重要です;)まあ、これについては、私にはそう思われます「属性を忘れる」ことは、「メソッドをプライベートにすることを忘れること」と比較して、理論的には可能性が高くなります。
ユニットテストにはpublic
の非アクションが必要だと言われることもありますが、アクションでない場合は、別のクラスに分離して別々にテストできる可能性があります。さらに、偶数何らかの理由で実行できない場合は、メソッドにpublic
テスト目的のみをマークするのは悪い習慣です-internal
を使用しますInternalsVisibleTo
が推奨される方法です。
この種の状況は、そのメソッドで単体テストを実行する必要があるなど、一部のテストフレームワークの要件によって引き起こされる可能性があります。そのため、設計は不適切ですが、変更することはできません。
デフォルトでは、MVCフレームワークはコントローラークラスのすべてのパブリックメソッドをアクションメソッドとして扱います。コントローラクラスにパブリックメソッドが含まれていて、それをアクションメソッドにしたくない場合は、そのメソッドを NonActionAttribute attributeでマークする必要があります。
パブリックNonActionを使用する本当の目的
非アクションメソッドへのアクセスを制限して、指定されたコントローラーメソッドがアクションではないことをMVCフレームワークに通知します。
URLに対してNonAction
属性を使用してメソッドを実行しようとすると、リクエストへの応答としてエラー404が発生します。
参照: http://msdn.Microsoft.com/en-us/library/dd410269%28v=vs.90%29.aspx
これは、URLで大文字と小文字が区別されない場合に役立ちます。たとえば、リクエストがある場合Home/AboutこれはHomeControllerとAbout action、およびhOmE/AbOUTは同じコントローラーと同じアクションメソッドに行きます。
以下のように
public class HomeController:Controller
{
....
public ViewResult About()
{
return View();
}
public ViewResult aBOut()
{
return View();
}
}
フレームワークは、呼び出すabout
関数を決定できず、呼び出しがあいまいであることを示す例外をスローします。
もちろん、この問題を解決する1つの方法は、アクション名を変更することです。
何らかの理由でアクション名を変更したくなく、これらの関数の1つがアクションではない場合は、この非アクションメソッドをNonAction属性で装飾できます。例:
[NonAction]
public ActionResult aBOut()
{
return View();
}
カスタムASPパイプラインのバインディングドライバーとしてコントローラーを使用しています。各ドライバーは、結果ページの1つのセクション(部分ビュー)のレンダリングを担当します。次に、次のようなパブリックメソッドを使用します。
[NonAction]
publi int GetOrder()
ページ上のセクションの順序を解決するため、または現在のユーザーの承認を解決するため(たとえば、現在のセクションが編集可能であるか、読み取り専用である場合)。
したがって、コントローラーをリクエストを処理する方法としてだけでなく、ページをレンダリングするためのカスタムフレームワークを構築するためのツールとして考えることを制限しないでください。そうすることで、コントローラーが1つのタスクのみを担当し、ドメインの懸念を分離します。
ASP.NETは高度にカスタマイズ可能です。 MVC HTTPハンドラーをオーバーライドして、フレームワークのデフォルトの動作を変更するとします。使用するコントローラーに応じて、ロギングロジックをカスタマイズしたい場合があります。一部のコントローラーは、メソッドIControllerLogger GetLogger()を使用してILoggingControllerインターフェイスを実装します。このメソッドでは、パブリック非アクションメソッドを作成する必要があります。
デフォルトでは、MVCフレームワークはコントローラークラスのすべてのパブリックメソッドをアクションメソッドとして扱います。コントローラクラスにパブリックメソッドが含まれていて、それをアクションメソッドにしたくない場合は、そのメソッドをNonActionAttribute属性でマークする必要があります。