ASP.NET MVC 中的基本控制器类都有哪些好的候选者?

Posted

技术标签:

【中文标题】ASP.NET MVC 中的基本控制器类都有哪些好的候选者?【英文标题】:What are good candidates for base controller class in ASP.NET MVC?ASP.NET MVC 中的基本控制器类有哪些好的候选者? 【发布时间】:2011-09-01 10:19:18 【问题描述】:

我看到很多人谈论在他们的 ASP.NET MVC 项目中使用基本控制器。我见过的典型示例用于日志记录或 CRUD 脚手架。控制器基类还有哪些其他好的用途?

【问题讨论】:

【参考方案1】:

基本控制器类没有很好的用途。

现在听我说完。

Asp.Net MVC,尤其是 MVC 3 有大量的可扩展性钩子,它们提供了一种更加解耦的方式来向所有控制器添加功能。由于您的控制器类对应用程序非常重要和核心,因此保持它们轻巧、敏捷并与其他所有内容松散耦合非常重要。

日志记录基础设施属于 构造函数并且应该被注入 通过 DI 框架。

CRUD 脚手架应由 代码生成或自定义 模型元数据提供者。

全局异常处理应该是 由自定义 ActionInvoker 处理。

全局视图数据和授权 应该由动作过滤器处理。 使用全局操作过滤器更容易 在 MVC3 中。

常量可以放在另一个名为 ApplicationConstants 的类/文件中。

基本控制器通常由缺乏经验的 MVC 开发人员使用,他们不了解 MVC 的所有不同可扩展性部分。现在不要误会我的意思,我不是在判断并与出于所有错误原因使用它们的人一起工作。它只是经验,为您提供了更多解决常见问题的工具。

我几乎可以肯定,除了基本控制器类之外,没有一个问题是您无法使用另一个可扩展性挂钩解决的。不要采用最紧密的耦合形式(继承),除非有重要的生产力原因并且您不违反 Liskov。我宁愿花不到 1 秒的时间在我的控制器(如 public ILogger Logger get; set; )上输入 20 次属性,而不是引入以更重要的方式影响应用程序的紧密耦合。

甚至像 userId 或多租户密钥这样的东西也可以进入 ControllerFactory 而不是基本控制器。基本控制器类的耦合成本是不值得的。

【讨论】:

好的,我们可以在不使用基本控制器的情况下做一些事情。你能说说使用基本控制器的一些缺点吗 @Tassadaque - 耦合,耦合,耦合和耦合。 我不相信。您更喜欢在所有控制器中使用相同的代码而不是使用基本控制器,因此这一定有优势。你说优点是“松耦合”,但这究竟是什么意思,它解决了哪些问题,除了为了解耦而解耦还有什么作用? 我不确定我是否同意这里,但这里有很多值得深思的地方,所以 +1。我倾向于认为基本控制器可以与动作过滤器等​​结合使用。如果子类想要覆盖所述方法,没有什么可以阻止它。 我不明白这里的论点。当然,不必要的耦合是要避免的,但与其他所有事情一样,它是一种取决于当前情况的选择,并且会出现收益大于成本的情况。继承可以为您提供低成本的单点通用逻辑并减少人为错误的代码和表面积,如果这种概括确实有意义。我认为没有人认为您应该尝试将基类用于您可以使用属性进行的所有事情【参考方案2】:

我喜欢使用基本控制器进行授权。

我没有用“Authorize”属性装饰每个动作,而是在基本控制器中进行授权。从数据库中为登录用户获取授权操作列表。

请阅读以下链接以获取有关授权的更多信息。 Good practice to do common authorization in a custom controller factory?

【讨论】:

您可以只添加一个全局过滤器或装饰控制器本身吗?如果您需要粒度,请使用策略。编辑:哦,这个答案来自 2011 年 :-) 对不起。【参考方案3】:

我用它来访问会话、应用程序数据等。

我还有一个应用程序对象,它包含应用程序名称等内容,我从基类访问它

基本上我将它用于我经常重复的事情

哦,我应该提一下,我不将它用于业务逻辑或数据库访问。我猜对于基类来说,常量也是一个不错的选择。

【讨论】:

【参考方案4】:

我在我的许多项目中都使用了基本控制器,并且效果非常好。我主要用于

异常记录 通知(成功、错误、添加..) 调用 HTTP404 错误处理

【讨论】:

您能否将我重定向到几篇文章,例如如何通过基本控制器处理您的情况。情况就像Exception logging, Notification (success, error, adding..) and HTTP404 error handling谢谢【参考方案5】:

根据我的经验,您希望放入基本控制器的大部分逻辑理想情况下会放入动作过滤器中。动作过滤器只能用常量初始化,所以在某些情况下你不能这样做。在某些情况下,您需要将操作应用于系统中的每个操作方法,在这种情况下,将您的逻辑放在基础中可能比使用新的 actionFilter 属性注释每个操作方法更有意义。

我还发现将引用服务的属性(否则将与控制器分离)放入基础中很有帮助,使它们易于访问和一致地初始化。

【讨论】:

ActionFilters 只能用常量初始化是不对的。常量的初始化是Attributes的一个特性,而不是IActionFilter接口。您可以创建您的操作过滤器,然后将其分配给您的过滤器配置中的 GlobalFilterCollection,或者您处理此类事情的任何地方。在您的过滤器中,您只需检查是否存在您创建的单独属性,然后继续执行过滤器的逻辑。【参考方案6】:

我所做的是使用通用控制器基类来处理:

我创建了 BaseCRUDController<Key,Model>,它需要一个 ICRUDService<TModel> 对象作为构造函数参数,因此基类将处理 Create / Edit / Delete .并确保在虚拟模式下处理自定义情况 ICRUDService<TModel> 具有 Save / Update / Delete / Find / ResetChache 等方法 /...我为我创建的每个存储库实现它,以便我可以向它添加更多功能。 使用这种结构,我可以添加一些通用功能,例如 PagedList / AutoComplete / ResetCache / IncOrder&DecOrder(如果该模型是 IOrderable)

错误 / 通知消息处理:布局中的一部分,带有@TempData["MHError"] 代码和基本控制器中的属性,如

公共通知错误 设置 TempData [“MHError”] = 值; 获取返回(通知)TempData.Peek(“MHError”);

有了这个抽象类,我可以轻松处理每次必须编写或使用代码生成器创建的方法。 但是这种方法也有它的弱点。

【讨论】:

【参考方案7】:

我们将 BaseController 用于两件事:

    应该应用于所有控制器的属性。 重写重定向,通过检查重定向 URL 是否为本地 URL 来防止开放重定向攻击。这样一来,所有调用 Redirect 的控制器都会受到保护。

【讨论】:

你的第二点不是很清楚。如何覆盖基本控制器中的重定向?会想出一些例子,比如如何做到这一点。如果可能的话,我会告诉我开放重定向攻击是如何发生的,以及如何通过基类来预防它。谢谢 1) 这可以用globally registered filters 代替。更好的是,自定义过滤器可以使用自定义属性有条件地排除它们(这将是在具有覆盖的基本控制器中维护的噩梦)。 2)这个孤立的逻辑可以放在Controller类的扩展方法中。无需到处继承自定义基本控制器(也不担心最终会忘记在某处这样做)。【参考方案8】:

我现在使用基本控制器通过i18N 库进行国际化。它提供了一种方法,我可以使用它来本地化控制器中的任何字符串。

【讨论】:

【参考方案9】:

过滤器不是线程安全的,数据库访问和依赖注入的情况,使用它时数据库连接可能被其他线程关闭。

【讨论】:

【参考方案10】:

我们使用了基本控制器:

    覆盖.User 属性,因为我们使用自己的用户对象,该对象应该有我们自己的自定义属性。 添加全局OnActionExecuted 逻辑并添加一些全局操作过滤器

【讨论】:

以上是关于ASP.NET MVC 中的基本控制器类都有哪些好的候选者?的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET Core 中替换硬编码字符串都有哪些好的做法?

ASP.NET MVC - 用不同的参数覆盖一个动作

模拟 Asp.net-mvc 控制器上下文

ASP.NET MVC 5 中的基本身份验证

ASP.NET MVC 如何链接视图和控制器?

在 ASP.Net-MVC 中的控制器之间传递信息