目前在我的应用程序中使用工作单元模式和通用存储库,我的所有控制器都包含所有业务逻辑。我正在将所有东西都放在使用ViewModels而不是直接模型。
虽然这是一个好主意,但现在出现了一个可以在控制器中显着分离我的业务逻辑的问题。对于控制器和ViewModel,它应该包含大部分业务逻辑吗?
我尝试了几种方法让我的ViewModel实际上包含所有业务逻辑。但是,我必须在我的ViewModel的构造函数中有一个参数,它需要一个工作单元。这是个好主意吗?
我的代码气味告诉我它。但是,我有点担心这将与执行不需要ViewModel的操作的控制器保持一致。简单地说,不需要将Model / ViewModel传递给View的操作;这种情况发生在重定向到其他操作的操作上。这意味着,我的业务逻辑可以保留在该操作中,也可以将该业务逻辑分离为一个函数。
这里的最佳做法是什么?
答案 0 :(得分:10)
我不能说我的方法是最佳做法,但我更喜欢将任何业务逻辑放在单独的“服务”层中。
我倾向于使用ViewModel来存储特定视图所需的属性。如果ViewModel上有任何方法,它们可能只是检索与该视图相关的集合。
我通过尽可能地将它们限制为验证和重定向/显示视图来保持我的控制器的轻量级。
因此,如果我有任何复杂的逻辑,我将控制器操作调用一个单独的服务来处理该逻辑。这样,逻辑被隔离,这使得测试更容易,因为不再需要创建控制器或ViewModel来测试它。重用服务比分离ViewModel更容易。
希望这会有所帮助。祝你好运。
答案 1 :(得分:7)
对于控制器和ViewModel,它应该包含大部分业务逻辑吗?
没有。
我尝试了几种方法让我的ViewModel实际上包含所有业务逻辑。但是,我必须在我的ViewModel的构造函数中有一个参数,它需要一个工作单元。这是个好主意吗?
imho这是一个非常糟糕的主意。首先,你打破了几个SOLID原则。将所有代码捆绑到视图模型中会使测试变得困难。如果您想在另一个视图中使用某些业务逻辑,该怎么办?你复制了那段代码吗?
这里的最佳做法是什么?
让我们先回到MVC模式。这是一个相当广泛的定义,但知道它应该让你感觉到你应该放在哪里。
MVC中的“模型”实际上是用于将数据拉到一起的所有内容。它可以是webservices,业务层,存储库等。
该视图是生成HTML的所有代码(因为我们正在谈论网络)。
控制器应被视为模型和视图之间的粘合剂。因此,它应该从模型中获取信息并将其转换为视图可用的内容。
该结构的问题在于将层特定信息“泄漏”到模式的其他部分非常容易。因此,Microsoft将ViewModels引入了他们的MVC实现。
通过这种方式,我们可以从视图中删除所有渲染逻辑并将其放入ViewModel中。而不是在你的视图中这样做:
<span>@(model.Age == 0 ? "n/a" : model.Age)</span>
您将该代码放在ViewModel中,只需调用@model.Age
即可。这样,您就不必在使用视图模型的所有视图中复制该代码。
关于ViewModel的问题的答案是,它应该只包含用于正确呈现“模型”信息的逻辑。
对于控制器,我也不会将任何业务逻辑放入其中。首先,它很难测试你的逻辑。然后你向它添加更多的职责(并通过这样做打破SRP)。在控制器中唯一有效的逻辑是从ViewModel获取信息并将其转换为“模型”可用的内容,反之亦然。
希望能回答你的问题。
<强>更新
我会创建一个单独的项目并向其添加类。然后只需从webproject添加引用并在控制器中调用这些类。
我也会开始使用控件容器的反转来自动创建为我创建的依赖项。
Autofac可以为您发现您的服务(零配置)并将自身注入MVC。
要遵循分离的界面模式,请创建以下项目:
“规范”项目可用于使测试事物更容易,并且更容易切换实现(可能只是几个类,而不一定是整个业务层)。阅读“分离的接口模式”
答案 2 :(得分:3)
模型 - 视图 - 视图模型(MVVM)是用于构建用户界面的设计模式。您的视图模型是UI上数据和操作的纯代码表示。因此它应该包含与该UI相关的逻辑。
例如:
如果您正在实施列表编辑器,您的视图模型将是一个包含项目列表的对象,并公开添加和删除项目的方法。
来自维基百科:
ViewModel:ViewModel是一个“视图模型”,意思是它 View的抽象,也用于数据绑定之间 查看和模型。它可以被看作是什么的一个专门方面 将是一个充当数据的控制器(在MVC模式中) binder / converter将Model信息更改为View信息 并将命令从View传递到模型中。 ViewModel 公开属性,命令和抽象。 ViewModel 已被比作数据的概念状态而不是数据 模型中数据的真实状态。[7]
答案 3 :(得分:1)
您的控制器调用UoW来获取构建viewmodel所需的数据。 您可以调用UoW的多种方法
然后将所有需要的数据传递给viewmodel构造函数。 (将Uow传递给de viewmodel听起来真的很糟糕)
如果您的控制器上需要一些复杂的“逻辑”,从UoW等调用很多方法,您应该考虑创建另一个存储库或仅用于业务逻辑的图层来执行所有艰苦工作,并从控制器中调用它
SomeClass something = Uow.BLGoodName.DoSomeFancyStuff(params ..)
ViewData.model = new ControllerActionViewModel(something);
Return View();