【发布时间】:2013-09-10 00:49:25
【问题描述】:
这是一个关于如何为大中型应用程序构建 ASP.NET MVC 项目的问题。
我以为我了解 MVC 的概念,但在研究了中型和大型应用程序的架构后,我感到困惑。 (尽量考虑可扩展性、可扩展性和持续维护)
当我试图考虑如何按照“最佳实践”指南(来自包括印刷和网络的众多来源)构建应用程序时,我感到困惑
尽量尊重
- 控制器应该非常简单
- TDD 原则(或至少是一种使未来测试更容易的方法)
- 关注点分离
- 服务和存储库
- 依赖注入
现在,当创建小型(基本、简单)MVC 应用程序时,所有这些几乎都在同一个项目中完成(在这种情况下我说的是 Visual Studio 项目),以及 MVC“层”之间的分离几乎只是 VS 项目中的文件夹(完全独立的命名空间)。
在我们的其他一些项目中,我们采用了服务 -> 存储库样式,所以这个不会有任何不同。
我们使用实体框架作为数据库持久性(数据库优先方法)。
我们已经将我们的数据库访问(EF 的东西)分离到另一个 VS 项目中,所以我们在解决方案中有一个 Web 项目和模型(或数据)项目。
网络项目有控制器和视图,数据项目有服务、存储库和 EF 的东西。
我的困惑在于模型(或者可能是理解域模型与视图模型)
如果我要尝试遵循该方法(我认为),我将拥有一个域模型(EF 和存储库层处理的模型),然后我将拥有一个视图模型? (控制器和视图将处理的模型),现在这些不是 90% 相同吗?这种分离关注点的方式不是让你写两次模型代码吗?我确信我在某处读到控制器和视图不应该具有域模型?
我们处理它的一种方法是 EF 将其所有模型类设为部分。然后我们扩展同一个类并向它添加一个 MetaDataType 类以创建“视图模型”(将 DataAnnotations 添加到属性中),然后本质上相同的模型通过所有层传递,但这是“最佳”实践(那里在我心中是一个分裂,这是不对的)
例如
[MetadataType(typeof(Product_Metadata))]
public partial class Product
{
//Pretty much deliberately kept empty, just so
// the EF model class can have the attribute added
//The other side of this partial class is of course in the EF models
}
public class Product_Metadata
{
[Required]
[Display(Name = "Product name")]
public string Name { get; set; }
[Required]
[Display(Name = "Unit Cost")]
public decimal Cost { get; set; }
//etc... for the rest of the properties on the product EF model
}
也许这是攻击它的“最佳”方法,但我以前没有遇到过这种方法。
我们将所有服务和存储库创建为接口,并使用结构映射作为 IoC 容器。我承认的另一件事是,即使我们正在使用依赖注入,我仍然在努力接受 TDD,感觉必须将所有内容都写两次(我认为是 DI 的全部要点)
我想我最终会向 SO 的那些愿意在构建大型 ASP.NET MVC 应用程序方面比我了解更多的人寻求帮助和指导。那里似乎有大量的信息,但一切似乎都非常概念化。当我最终谈到实现时,我迷失在概念中。
编辑
回应卡尔·安德森先生
- 视图中的数据分页 - 是的,完全同意这是视图模型相关且有意义的地方,但同样是具有 List 属性的 CategoryListViewModel,它是视图模型类别的列表还是域模型类别的列表
- 批量分配漏洞 - 我认为此漏洞将存在于域模型或视图模型中(毕竟如果确实需要设置 IsAdmin,您将如何设置,当然它仍然会在 ViewModel 上)。我认为这需要在不同的层(即授权)处理,因此只有使用窗帘角色才能设置 IsAdmin
- 以特定格式显示视图信息 - 当然这只是与模型绑定和/或用于格式化的视图 html 帮助器有关 - 即仅视图和模型绑定问题。毕竟,所有通过视图渲染的模型,其属性都以html结尾并且此时都是字符串,因此无论如何都必须解析返回值,这是模型绑定的主要原则,所以如果我需要一个自定义的,只需编写一个新的模型绑定器。
- 使用域模型不仅仅是数据传输对象 (DTO) - 实际上我尽量避免这种情况,并试图坚持模型就是这样的事实,即 DTO。但是如果出现这种情况,我可能会在域模型上编写一个扩展方法,毕竟所有方法都不会被序列化,或者是添加一个视图模型,但它可能包含一个域模型
- 对同一领域模型信息有不同的抽象 - 部分同意。我将有一个 PagedAccountListViewModel(仍将包含域模型),但我只会将一个模型用于新帐户和更新帐户(我将新帐户视为更新,只是预填充的),它将是域模型
【问题讨论】:
标签: c# asp.net entity-framework asp.net-mvc-4 architecture