服务层是否应该返回 MVC 应用程序的视图模型?

发布于 2024-09-04 09:44:49 字数 661 浏览 7 评论 0原文

假设您有一个 ASP.NET MVC 项目并且正在使用服务层,例如 asp.net 站点上的联系人管理器教程: http://www.asp.net/mvc/tutorials/iteration-4-make-the-application-loosely- Coupled-cs

如果您的视图有视图模型,那么服务层是否是提供每个视图模型的适当位置?例如,在服务层代码示例中,有一个方法

    public IEnumerable<Contact> ListContacts()
    {
        return _repository.ListContacts();
    }

如果您想要一个 IEnumerable,那么它应该放在服务层中,还是有其他地方是“正确”的地方?

也许更合适的是,如果与 ContactController 关联的每个视图都有一个单独的视图模型,那么 ContactManagerService 是否应该有一个单独的方法来返回每个视图模型?如果服务层不是合适的位置,那么视图模型对象应该在哪里初始化以供控制器使用?

Say you have an ASP.NET MVC project and are using a service layer, such as in this contact manager tutorial on the asp.net site: http://www.asp.net/mvc/tutorials/iteration-4-make-the-application-loosely-coupled-cs

If you have viewmodels for your views, is the service layer the appropriate place to provide each viewmodel? For instance, in the service layer code sample there is a method

    public IEnumerable<Contact> ListContacts()
    {
        return _repository.ListContacts();
    }

If instead you wanted a IEnumerable, should it go in the service layer, or is there somewhere else that is the "correct" place?

Perhaps more appropriately, if you have a separate viewmodel for each view associated with ContactController, should ContactManagerService have a separate method to return each viewmodel? If the service layer is not the proper place, where should viewmodel objects be initialized for use by the controller?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

蓝眼泪 2024-09-11 09:44:49

一般来说,不会。

视图模型旨在向视图提供信息以及从视图提供信息,并且应该特定于应用程序,而不是一般域。控制器应该协调与存储库、服务(我在这里对服务的定义做出一些假设)等的交互,并处理构建和验证视图模型,并且还包含确定要渲染的视图的逻辑。

通过将视图模型泄漏到“服务”层,您会模糊您的层,现在可能将特定于应用程序和表示的内容与应该关注域级职责的内容混合在一起。

Generally, no.

View models are intended to provide information to and from views and should be specific to the application, as opposed to the general domain. Controllers should orchestrate interaction with repositories, services (I am making some assumptions of the definition of service here), etc and handle building and validating view models, and also contain the logic of determining views to render.

By leaking view models into a "service" layer, you are blurring your layers and now have possible application and presentation specific mixed in with what should focused with domain-level responsibilities.

无人接听 2024-09-11 09:44:49

不,我不这么认为。服务应该只关心问题域,而不是呈现结果的视图。返回值应该用域对象而不是视图来表示。

No, I don't think so. Services should care only about the problem domain, not the view that renders results. Return values should be expressed in terms of domain objects, not views.

離殇 2024-09-11 09:44:49

根据传统方法或理论,ViewModel 应该是用户界面层的一部分。至少名字是这么说的。

但是,当您开始使用实体框架、MVC、存储库等自行实现它时,您就会意识到一些其他的事情。

必须有人将实体/数据库模型与视图模型(最后提到的 DTO)进行映射。这应该在 [A] UI 层(由控制器)完成,还是在 [B] 服务层完成?

我选择选项 B。选项 A 是不行的,因为一个简单的事实是,多个实体模型组合在一起形成一个 ViewModel。我们可能不会将不必要的数据传递到 UI 层,而在选项 B 中,服务可以处理数据并在映射(到 ViewModel)后仅将所需/最小值传递到 UI 层。

但仍然让我们选择选项 A,将 ViewModel 放在 UI 层(将实体模型放在 Service 层)。

如果Service层需要映射到ViewModel,那么Service层需要访问UI层的ViewModel。哪个库/项目? Viewmodel应该在UI层的一个单独的项目中,并且这个项目需要被Service层引用。如果 ViewModel 不在单独的项目中,则存在循环引用,因此不进行。让 Service 层访问 UI 层看起来很尴尬,但我们仍然可以应对它。

但是如果有另一个 UI 应用程序使用此服务怎么办?如果有移动应用程序怎么办? ViewModel 有何不同?服务是否应该访问相同的视图模型项目?所有 UI 项目都会访问同一个 ViewModel 项目还是有自己的项目?

经过这些考虑后,我的答案是将 Viewmodel 项目放在服务层中。无论如何,每个 UI 层都必须访问服务层!并且可能有很多类似的 ViewModels 他们都可以使用(因此服务层的映射变得更容易)。如今,映射是通过 linq 完成的,这是另一个优点。

最后,还有关于 DTO 的讨论。还有关于 ViewModel 中的数据注释。带有数据注释的ViewModel(Microsoft.Web.Mvc.DataAnnotations.dll)不能驻留在服务层,而是驻留在UI层(但ComponentModel.DataAnnotations.dll可以驻留在服务层)。如果所有项目都在一个解决方案(.sln)中,那么放在哪一层并不重要。在企业应用中,每一层都会有自己的解决方案。

所以 DTO 实际上是一个 ViewModel,因为大多数情况下两者之间会有一对一的映射(比如使用 AutoMapper)。同样,DTO 仍然具有 UI(或多个应用程序)所需的逻辑并驻留在服务层中。 UI层ViewModel(如果我们使用Microsoft.Web.Mvc.DataAnnotations.dll)只是从DTO复制数据,并添加一些“行为”/属性。

[现在这个讨论即将发生有趣的转变,请继续阅读...:I]

并且不要认为数据注释属性仅适用于 UI。如果使用 System.ComponentModel.DataAnnotations.dll 限制验证
那么同样的ViewModel也可以用于前端和前端。后端验证(从而删除 UI-resideing-ViewModel-copy-of-DTO)。此外,属性也可以在实体模型中使用。例如:使用 .tt,可以使用验证属性自动生成实体框架数据模型,以在发送到后端之前执行一些数据库验证,例如最大长度。这可以节省从 UI 到后端进行验证的往返次数。它还允许后端出于安全原因重新验证。因此,模型是一个自力更生的验证器,您可以轻松地传递它。另一个优点是,如果数据库中的后端验证发生更改,则 .tt(读取数据库详细信息并为实体类创建属性)将自动选取该更改。这也可以迫使 UI 验证单元测试失败,这是一个很大的优点(因此我们可以纠正它并通知所有 UI/消费者,而不是意外忘记和失败)。是的,讨论正在朝着良好的框架设计方向发展。正如您所看到的,它们都是相关的:分层验证、单元测试策略、缓存策略等。

尽管与问题没有直接关系。本文中提到的“ViewModel Façade”必须观看频道 9 链接 也值得探索。恰好从视频中的 11 分 49 秒开始。因为一旦解决了上面给出的当前问题,这将是下一步/想法:“如何组织 ViewModel?”

最后,许多模型与逻辑问题都可以通过 REST 来解决。因为每个客户端都可以智能地查询数据并仅获取其需要的数据。并且它将模型保留在 UI 中,没有服务器/服务层模型/逻辑。唯一的重复将是每个客户端需要执行的自动化测试。此外,如果数据发生变化,那么一些客户端如果不适应变化就会失败。那么问题是,您是完全删除服务层(及其承载的模型)还是将服务层推送到调用 REST API 的 UI 项目(因此模型问题仍然存在)。但就Service层的职责而言,它们是一样的。

另外,在您的示例中,“_repository.ListContacts()”正在从存储库返回 ViewModel。这不是一个成熟的方式。存储库应该提供实体模型或数据库模型。这将转换为视图模型,并且服务层返回的正是该视图模型。

As per the traditional approach or theory wise, ViewModel should be part of User interface layer. At least the name says so.

But when you get down to implementing it yourself with Entity Framework, MVC, Repository etc, then you realise something else.

Someone has to map Entity/DB Models with ViewModels(DTO mentioned in the end). Should this be done in [A] the UI layer (by the Controller), or in [B] the Service layer?

I go with Option B. Option A is a no no because of the simple fact that several entity models combine together to form a ViewModel. We may not pass unnecessary data to UI layer, whereas in option B, the service can play with data and pass only the required/minimum to the UI layer after mapping (to the ViewModel).

But still, let us go with option A, put ViewModel in the UI layer(and entity model in Service layer).

If the Service layer needs to map to the ViewModel, then the Service layer need to access ViewModel in UI layer. Which library/project? The Viewmodel should be in a separate project in the UI layer, and this project needs to be referenced by Service Layer. If the ViewModel is not in a separate project, then there is circular reference, so no go. It looks awkward to have Service layer accessing UI layer but still we could cope with it.

But what if there is another UI app using this service? What if there is a mobile app? How different can the ViewModel be? Should the Service access the same view model project? Will all UI projects access the same ViewModel project or they have their own?

After these considerations my answer would be to put the Viewmodel project in Service Layer. Every UI layer has to access the Service layer anyways! And there could be a lot of similar ViewModels that they all could use (hence mapping becomes easier for service layer). Mappings are done through linq these days, which is another plus.

Lastly, there is this discussion about DTO. And also about data annotation in ViewModels. ViewModels with data annotations(Microsoft.Web.Mvc.DataAnnotations.dll) cannot reside in service layer instead they reside in UI layer(but ComponentModel.DataAnnotations.dll can reside in service layer). If all projects are in one solution(.sln), then it doesn't matter which layer you put it. In enterprise applications, each layer will have its own solution.

So DTO actually is a ViewModel because mostly there will be one on one mapping between the two(say with AutoMapper). Again DTO still has the logic needed for the UI(or multiple applications) and resides in Service Layer. And the UI layer ViewModel(if we use Microsoft.Web.Mvc.DataAnnotations.dll) is just to copy the data from DTO, with some 'behavior'/attributes added to it.

[Now this discussion is about to take an interesting turn read on...:I]

And don't think data-annotation attributes are just for UI. If you limit the validation using System.ComponentModel.DataAnnotations.dll
then the same ViewModel can also be used for front-end & backend validation(thus removing UI-residing-ViewModel-copy-of-DTO). Moreover attributes can also be used in entity models. Eg: using .tt, Entity Framework data models can be autogenerated with validation attributes to do some DB validations like max-length before sending to the back end. This saves round-trips from UI to backend for validation. It also enables back-end to re-validate for security reasons. So a model is a self-reliant validator and you can pass it around easily. Another advantage is that if backend validation changes in DB then .tt (reads DB specifics and create the attribute for entity class) will automatically pick that up. This can force UI validation unit tests to fail as well, which is a big plus(so we can correct it and inform all UIs/consumers instead of accidentally forgetting and failing). Yes, the discussion is moving towards a good framework design. As you can see it is all related: tier-wise validation, unit test strategy, caching strategy, etc.

Although not directly related to the question. 'ViewModel Façade' mentioned in this must watch channel 9 link is also worth exploring. It starts exactly at 11 minutes 49 seconds in the video. Because this would be the next step/thought once your current question given above is sorted out: 'How to organize ViewModels?'

And Lastly, many of these model vs logic issues could be resolved with REST. Because every client can have the intelligence to query the data and get only the data that it needs. And it keeps the model in UI, there is no server/service layer model/logic. The only duplication then will be on the automated tests that each client need to perform. Also if there are changes in data then some clients fail if they do not adapt to the change. The question then is, are you removing service layer altogether(and the models they carry) or pushing the service layer up to your UI project(so model issue still persists) which calls the REST API. But in terms of the responsibility of Service layer, they are the same regardless.

Also in your example "_repository.ListContacts()" is returning a ViewModel from repository. This is not a mature way. Repositories should provide entity models or DB models. This gets converted to view models and it is this view model that is returned by the service layer.

谁的新欢旧爱 2024-09-11 09:44:49

这在我工作的地方有点“取决于”——我们通常有一个控制器消耗一些服务——然后将返回的 DTO 组合成一个“ViewModel”,然后通过 JSON 结果传递给客户端,或绑定在 Razor 模板中。

事实是,大约 80% 的时间 - DTO 到 ViewModel 的映射是 1-1。我们开始朝着“在需要的地方直接使用 DTO,但是当 DTO 和我们的客户端/视图中需要的内容不匹配时 - 然后我们创建一个 ViewModel 并根据需要在对象之间进行映射”。

尽管我仍然不相信这是最好或正确的解决方案 - 因为它最终导致了一些激烈的讨论“我们只是在 DTO 中添加 X 来满足视图的需求吗?”

This has come a bit of an "it depends" where I work - we have generally had a controller consuming some service(s) - then combining returned DTO's into a 'ViewModel' that would then get passed to the client - either via JSON result, or bound in the Razor Template.

Thing is, about 80% of the time - the mapping of DTO to ViewModel has been 1-1. We are starting to move towards 'Where needed, just consume the DTO directly, but when the DTO and what we need in our client/view don't match up - then we create a ViewModel and do the mapping between objects as needed'.

Although I'm still not convinced that this is the best or right solution - as it ends up leading to some heated discussions of 'are we just adding X to the DTO to meet the needs of the view?'

浸婚纱 2024-09-11 09:44:49

我想这取决于您认为“服务”是什么。我从来没有真正喜欢过在单个类的上下文中使用术语服务;它非常模糊,并没有告诉你太多关于课程的实际目的。

如果“服务层”是物理层,例如Web服务,那么绝对不是; SOA 上下文中的服务应该公开域/业务操作,而不是数据和表示逻辑。但是,如果服务只是用作进一步封装的抽象概念,那么我认为按照您所描述的方式使用它没有任何问题。

只是不要混淆概念。如果您的服务处理视图模型,那么它应该是一个表示服务,并且位于实际模型之上,永远不要直接接触数据库或任何业务逻辑。

I suppose that depends on what you consider the "services" to be. I've never really liked the term service in the context of a single class; it's incredibly vague and doesn't tell you much about the actual purpose of the class.

If the "service layer" is a physical layer, such as a web service, then absolutely not; services in an SOA context should expose domain/business operations, not data and not presentation logic. But if service is just being used as an abstract concept for a further level of encapsulation, I don't see any problem with using it the way you desribe.

Just don't mix concepts. If your service deals with view models then it should be a presentation service and be layered over top of the actual Model, never directly touching the database or any business logic.

折戟 2024-09-11 09:44:49

嗨,我在这里看到非常好的答案。
对于我自己,我采取了另一种方法。
我有多种模型,一种是视图模型,另一种是共享模型。视图模型保留在 UI 层,共享模型保留在单独的项目中。
理论上,共享模型可以在任何软件上使用,因为它们是独立的。
如果您想从服务层返回特定数据或者需要存储库中的特定内容,则此模型提供一些抽象。
我真的不知道这是否是一个好方法,但它在我的项目中效果很好。例如
当我需要提供一些信息来向数据库创建新对象时,我可以直接在服务层使用共享模型,这节省了一些复杂性。
有时需要映射共享模型,但您可以确保您的服务不会将无关数据泄漏到 UI。
您可以将共享模型视为扩展,但不能用它来构建 UI 逻辑,您应该使用视图模型来做到这一点。
您可以将视图模型与此共享模型结合起来,以节省使用继承的时间。
共享模型必须是中立的,不应该有任何逻辑。

Hi I see very good answers here.
And for myself I do an other aproach.
I have to kinds of models , one is viewmodel and the other is shared models. The viewmodels stays on the UI layer and the shared models stays on a separate project.
The shared models can theoretically be used anyware because those are standalone.
This models provides some abstraction if you want to return specific data from your service layer or if you need something specific from your repository.
I don't really know if this is a good aproach but it works so well on my projects. For example
When I need to provide some information to create new objects to the database i can use the shared models directly to the service layer it saves me some complexity.
The shared models needs to be mapped sometimes , but you can ensure that your service is not leaking inesssary data to the UI.
You can see shared models as an extension but not to build your UI logic with it, you should have viewmodels to do that.
You can combine viewmodels with this shared models to save you time you can use inheritance.
The shared models has to be neutral and should not have any kind of logic.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文