Should a service layer return view models for an MVC application?
Asked Answered
M

6

67

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?

Moth answered 8/6, 2010 at 23:45 Comment(3)
You might also want to have a look at weblogs.asp.net/scottgu/archive/2009/04/28/…Jolee
The NerdDinner tutorial is the worst place to go for this information. It's great for demonstrating MVC features but the architecture it implies is horrible.Foreside
@Foreside since you're apparently an expert, where's your in-depth tutorial on correct MVC architecture?Jolee
E
53

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.

Entirely answered 9/6, 2010 at 0:18 Comment(7)
Tom: In the example, the controller's Index() method builds the view it returns from ListContacts() method shown above, which returns an IEnumberable<Contact>, so isn't the viewmodel already leaking into the "service layer"? Is this a poor example? And if so, where is the appropriate place to initialize viewmodels for consumption by the controller's various views?Moth
@erg39: Isn't Contact a domain model type? If so, then no. You may have something looks like a Contact for your view model but may also have additional information specific to a single view or set of views. Contact doesn't (or shouldn't) know anything about any particular details for a view.Entirely
@erg39: As far as initializing view models, the controller has the responsibility of building new view models instances and validating/validating view models received from the view.Entirely
Thanks everybody, very helpfulMoth
I know this is old, but what do you do if you need to aggregate data for views. For example, if you want to show how many Users belong to a Role in an n-m relationship... Your options are to return the roles, then access the Users.Count resulting in 1+n queries, or to aggregate it using a single query into a RoleSummary view model.Soke
In most circumstances, should a Service consume` ViewModels` or should we map it to the corresponding entity in the Controller before passing the Post data to the Service?Upkeep
I was curious about this as well. Does the controller take the viewmodel and map to the domain model somehow and send to service layer as a parameter?Mischief
D
26

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.

Donoghue answered 9/6, 2010 at 0:7 Comment(0)
C
26

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.

Capitulum answered 4/7, 2012 at 9:50 Comment(5)
Isnt introducing an Application layer the correct move here? it would map viewmodels and domain entities, keeping each other independent and happy.Ochoa
Viewmodels and domain entities are independent anyways. Is "application layer" a new layer just to map entities? also have you thought about UI layer & service accessing this application layer? becuase at the end they still need to access their models. Or in otherwords what would an extra layer solve ?Capitulum
What a great explaination..perfect. It means that a service layer can either return a viewmodel or it can also return DTO. Because we will create ViewModel only when we need to club multiple DTOs. Am I right @BlueClouds ?Sig
@AnkushJain "we will create ViewModel only when we need to club multiple DTOs" No. we will create ViewModel when view needs it. DTO is a carrier (Data transfer object) from DB object to ViewModel. ViewModel can be a copy of DTO. "And the UI layer ViewModel(if we use Microsoft.Web.Mvc.DataAnnotations.dll) is just to copy the data from DTO, with some 'behaviour'/attributes added to it." if we do not use UI specific attribute/code in viewmodel then we dont need a viewmodel at all, we can use DTO itself as viewmodel. In this perspective , clubbing multiple DTOs will become another new DTO.Capitulum
@AnkushJain also Clubbing logic resides in service(not outside). First we need to assign responsibilities to each layer. Clubbing multiple service calls is an important responsibility, is your view doing it , or is it the service layer who does it?Capitulum
P
6

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?'

Preamble answered 25/7, 2013 at 14:42 Comment(1)
If you keep DTO in Service layer and use it as a ViewModel in UI where do you put validation (DataAnnotation, FluentValidation or something else)? I'm in the same situation of "80% 1:1 DTO to VM" so not sure what should I do.Fielder
F
5

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.

Foreside answered 8/6, 2010 at 23:49 Comment(7)
In the sample, the "service layer" is an abstraction between the controller and a repository layer whose stated intent is to be used for validation before passing data to the repository. It also contains the ListContacts() method above as well as a GetContact() method to get a single Contact object which are used by the controller for binding views. So it sounds like it seems appropriate for said service layer to know about the list of viewmodels that might be needed by a fully fleshed out controller, correct?Moth
@erg39: If your service is doing validation then it's fundamentally part of the model. It does not handle presentation logic and should not be coupled with view models.Foreside
@Aaronaught: Where would you say the appropriate place to initialize viewmodels would be? Should it just be a separate abstraction, like a "viewmodel service layer"?Moth
@erg39: It's normally part of the controller logic. If the logic is very complex then it's usually delegated to a mapping layer (or AutoMapper).Foreside
There's little value in describing a software layer as physically separate. A layer separated via SOAP method calls to a Web Service versus the same memory space is irrelevant, and is an architectural detail. While it may affect the topology of the layer, it shouldn't affect the logical separation.Jolee
@Robert: I don't know how you can possibly say that. Physically-separated components do not behave the same way as logically-separated components. Latency is different. Error conditions are different. Asynchronous operations are completely different. You can't perform lazy-loading over a web service. The architecture of a system comes before the code and affects how the code must be written, it is not some afterthought or trivial "detail".Foreside
OP didn't appear to understand what a service (layer) was, and your answer wasn't particularly helpful in that regard. What I said was that implementation concerns shouldn't affect the (logical) separation of software layers. Flavour of architecture certainly affects the code, but I never said architecture wasn't important, so please don't put words in my mouth. Good day.Jolee
F
0

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.

Filtration answered 10/11, 2020 at 8:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.