我刚刚开始在MVC工作,我有一个疑问。
我们可以在控制器中创建私有方法,也可以在模型中编写方法并从控制器中调用,而不是Nonaction
方法。
那么,在MVC中使用公共NonAction
方法的真正目的是什么?
答案 0 :(得分:6)
(我重新组织了答案以更好地解决评论中的问题)
我认为,该属性仅用于提高灵活性。作为框架设计者,人们希望尽可能地放松最终用户的编码约束。没有公开不采取行动的要求听起来可能“一般”,但对某些项目来说可能过于严格。添加[NonAction]
解决了他们的问题(尽管他们的设计很糟糕) - 显然你并没有被迫使用这个属性,所以从框架设计师的角度看它是双赢的。
另一个原因可能是遗留问题 - 在早期的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
和{ {1}}是推荐的方法。
答案 1 :(得分:1)
这种情况可能是由某些测试框架的要求引起的,例如你需要对该方法进行单元测试,然后你暴露它,虽然它设计不好但不能改变它们必须承担它。
默认情况下,MVC框架将控制器类的所有公共方法视为操作方法。如果您的控制器类包含公共方法,并且您不希望它成为操作方法,则必须使用NonActionAttribute属性标记该方法。
使用公开NonAction的真正目的
限制访问非操作方法以通知MVC框架,给定控制器方法不是动作。
当您尝试通过URL运行NonAction
属性的方法时,您会收到错误404作为对请求的响应。
参考:http://msdn.microsoft.com/en-us/library/dd410269%28v=vs.90%29.aspx
答案 2 :(得分:0)
当Url不区分大小写时,这很有用。因此,例如,如果您有主页/关于请求,则会转到 HomeController 和关于操作,以及 hOmE / AbOUT 将使用相同的控制器和相同的操作方法。
如下所示
public class HomeController:Controller
{
....
public ViewResult About()
{
return View();
}
public ViewResult aBOut()
{
return View();
}
}
框架无法确定调用哪个about
函数,并抛出异常,告知调用不明确。
当然,修复此问题的一种方法是更改操作名称。
如果由于某种原因您不想更改操作名称,并且其中一个函数不是操作,则可以使用NonAction属性修饰此非操作方法。例如:
[NonAction]
public ActionResult aBOut()
{
return View();
}
答案 3 :(得分:0)
我们使用控制器作为自定义ASP管道的绑定驱动程序,每个驱动程序负责渲染结果页面的一个部分(部分视图)。然后我们使用公共方法,如:
[NonAction]
publi int GetOrder()
解决页面上的部分顺序或其他部分以解析当前用户的授权(例如,如果当前部分是可编辑的或只是只读的)。
因此,您不应该限制自己将Controller视为处理请求的一种方式,而是将其作为构建自定义框架以呈现页面的工具。这样我们就可以让控制器完成一项任务,并且我们正在分离域关注点。
答案 4 :(得分:0)
默认情况下,MVC框架将控制器类的所有公共方法视为操作方法。如果您的控制器类包含一个公共方法,并且您不希望它是一个操作方法,则必须使用NonActionAttribute属性标记该方法。
答案 5 :(得分:0)
ASP.NET可高度自定义。假设您要通过覆盖MVC HTTP处理程序来更改框架的默认行为。您可能希望根据所使用的控制器自定义日志记录逻辑。一些控制器使用方法IControllerLogger GetLogger()实现ILoggingController接口。对于此方法,您需要编写一个公共非操作方法。