构建Asp.net MVC控制器文件夹以获得更好的内聚力

时间:2010-10-01 15:50:08

标签: c# asp.net asp.net-mvc

在构建复杂的应用程序时,控制器可能会开始变得笨拙且非常大,这可能意味着您将它们拆分为单独的控制器。这可能不合适,因为它将反映在用户体验中。 IE浏览器。他们将在URI中看到控制器名称。

例如:MVC附带的默认项目有一个AccountController,它具有登录,注销,注册等操作..这似乎违反了Single Responsibility Principle.

所以问题是如何解决这个问题并将问题分开?初始响应可能只是创建单独的控制器。即

AccountLoginController

AccountRegisterController

但从客户的角度来看,这不是一个很好的体验,因为它会在请求资源时影响URI。

解决方案可能是为每个控制器设置单独的文件夹,其中包含操作的单独类文件,每个文件夹都有一个类似的责任。

Controllers (folder)
    Account  (folder)
        Register.cs
        Login.cs
        Logout.cs
    AnotherController (folder)
        Actionfile.cs
        Actionfile.cs

以上将分离出功能,并highly cohesive

所以,这是一个很长的解释,但我的问题是..

  • 有没有人以前实现过这个?

  • 如果是这样,你怎么去呢?

  • 您对此模式有何看法?

4 个答案:

答案 0 :(得分:3)

你看过Areas吗?

“区域允许您将大型项目组织成多个较小的部分,以便管理大型Web应用程序的复杂性。每个部分(”区域“)通常代表大型Web站点的单独部分并使用对相关的控制器和视图集进行分组。“

简而言之,区域是项目中的一个文件夹,它有自己的控制器,模型和视图子文件夹。

答案 1 :(得分:2)

这取决于单一责任的含义。

如果你认为身份验证是一种责任,那么开箱即用的控制器就是完美无缺的。登录,注销和注册都是同一件事 - 身份验证。因此,他们的代码在同一个控制器中是有意义的。

如果你将单一责任原则置于荒谬的极端,那么在单个文件中,单个函数永远不会超过单个类。

您必须在可读性/可维护性与关注点分离之间找到平衡点。在这种情况下,它太过分了。

另外,请记住MVC完全是关于 Convention over Configuration ,这意味着如果您根据惯例命名控制器和视图,那么它们将是可发现的,您将拥有更少的配置和路由问题。

话虽如此,如果您决定使用非传统的控制器命名约定,可以这么说,您可以实现自己的控制器发现代码,这将允许您使用不同的约定。从上面链接的文章:

public class ControllerConvention : TypeRules, ITypeScanner {
  public void Process(Type type, PluginGraph graph) {
     if (CanBeCast(typeof (IController), type)) {
     string name = type.Name.Replace("Controller", "").ToLower();
      graph.AddType(typeof(IController), type, name);
    }
  }
}

答案 2 :(得分:0)

对于快速站起来,或者对于长期意义上的URI无关紧要的后端应用而言,围绕配置的约定非常有效。但对于任何面向公众的网站,我已经在MVC上做过,基于会议的路线已经出现了零,原因如下:

  • 您的网址是您的API。你应该控制它们并知道你在哪里发布。
  • 我有点偏执狂,我不喜欢通过url skullduggery泄漏到我的应用中的可能性。

自定义路由还允许您根据操作执行诸如has / Foo同时访问FooFooController和FooBarController的操作。您甚至可以利用区域,向公众公开。

答案 3 :(得分:0)

你提出了一个很好的观点,但我认为这里的混乱是控制器的真正含义。在MVC模式中,您的控制器可以被视为一组操作方法的命名空间。

让我们以.NET的“System”命名空间为例。 “System.Data”和“System.Core”有两个非常不同的职责,但是在“系统”包装器下分组。

访问控制器的操作时,您通常会使用{controller} / {action}等路由。

“AccountController”的“帐户”部分映射到{controller},“AccountController”中的方法映射到{action}。

我建议您构建一个类库来处理业务逻辑,并将您的操作路由到此库。您可以完全按照上述说明构建类,将操作的路由值传递给库并返回视图模型。

Register.cs可以是一个静态类,您可以通过AccountController中的action方法调用它。

例如:

“/ account / register” - >

控制器:

public class AccountController : Controller
{
     public ActionResult Register()
     {
         return View("Register", Register.RegisterUser());
     }
}

控制器逻辑:

public static class Register
{
     public static RegisterModel RegisterUser()
     {
         // Handle application logic here and build your model
         return new RegisterModel() { PasswordLength = 12 };
     }
}

型号:

public class RegisterModel
{
    public int PasswordLength { get; set; }
}