15

我刚刚开始在 MVC 中工作,我有一个疑问。

除了Nonaction方法,我们可以在控制器中创建私有方法,或者我们也可以在模型中编写方法并从控制器中调用它。

NonAction那么,在 MVC中使用公共方法的真正目的是什么?

4

6 回答 6

8

(我重组了答案以更好地解决评论中的问题)

我认为,该属性在这里只是为了更好的灵活性。作为一名框架设计者,人们希望尽可能地放松对最终用户的编码约束。不公开不采取行动的要求“总的来说”听起来不错,但对于某些项目来说可能过于严格。添加[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并且InternalsVisibleTo是推荐的方法。

于 2013-07-02T14:50:11.397 回答
1

这种情况可能是由某些测试框架的要求引起的,例如您需要对该方法进行单元测试然后您将其暴露出来,虽然它的设计很糟糕但无法改变这些,但必须坚持下去。

默认情况下,MVC 框架将控制器类的所有公共方法视为操作方法。如果您的控制器类包含公共方法并且您不希望它成为操作方法,则必须使用NonActionAttribute属性标记该方法。

使用 public NonAction 的真正目的

限制对非操作方法的访问,以通知 MVC 框架给定的控制器方法不是操作。

当您尝试通过 URL 运行具有NonAction属性的方法时,您会收到错误 404 作为对请求的响应。

参考:http: //msdn.microsoft.com/en-us/library/dd410269%28v=vs.90%29.aspx

详情:http ://weblogs.asp.net/gunnarpeipman/archive/2011/04/09/asp-net-mvc-using-nonactionattribute-to-restrict-access-to-public-methods-of-controller.aspx

于 2013-07-02T05:36:36.867 回答
0

当 URL 不区分大小写时,这很有用。因此,例如,如果您有请求Home/About这将转到HomeControllerAbout action,并且hOmE/AbOUT将转到相同的控制器和相同的操作方法。

像下面

public class HomeController:Controller
{
....
    public ViewResult About()
    {
        return View();
    }

    public ViewResult aBOut()
    {
        return View();
    }
}

框架无法确定about调用哪个函数,并抛出异常,告知调用不明确。

在此处输入图像描述

当然,解决此问题的一种方法是更改​​操作名称。

如果由于某种原因您不想更改动作名称,并且其中一个函数不是动作,那么您可以使用 NonAction 属性装饰这个非动作方法。例子:

[NonAction]
public ActionResult aBOut()
{
   return View();
}
于 2013-07-02T14:39:47.230 回答
0

我们使用控制器作为与自定义 ASP 管道的绑定驱动程序,每个驱动程序负责呈现结果页面的一部分(部分视图)。然后我们使用公共方法,例如:

[NonAction]
publi int GetOrder() 

解决页面上的部分顺序或其他解决当前用户的授权(例如,如果当前部分是可编辑的或只是只读的)。

因此,您不应限制自己将 Controller 视为处理请求的一种方式,同时也是构建用于呈现页面的自定义框架的工具。这样我们就可以让我们的控制器只负责一项任务,并且我们正在分离域关注点。

于 2013-07-02T15:25:02.470 回答
0

默认情况下,MVC 框架将控制器类的所有公共方法视为操作方法。如果您的控制器类包含公共方法并且您不希望它成为操作方法,则必须使用 NonActionAttribute 属性标记该方法。

于 2013-07-04T10:22:50.543 回答
0

ASP.NET 是高度可定制的。假设您要通过覆盖 MVC HTTP 处理程序来更改框架的默认行为。也许您想根据使用的控制器自定义日志记录逻辑。一些控制器使用 IControllerLogger GetLogger() 方法实现 ILoggingController 接口。对于此方法,您需要编写一个公共的非操作方法。

于 2014-06-26T13:08:04.250 回答