在构建复杂的应用程序时,控制器可能会开始变得笨拙且非常大,这可能意味着您将它们拆分为单独的控制器。这可能不合适,因为它将反映在用户体验中。 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。
所以,这是一个很长的解释,但我的问题是..
有没有人以前实现过这个?
如果是这样,你怎么去呢?
您对此模式有何看法?
答案 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上做过,基于会议的路线已经出现了零,原因如下:
自定义路由还允许您根据操作执行诸如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; }
}