Search code examples
c#asp.net-mvcn-tier-architectureasp.net-mvc-viewmodel

N tier architecture c# mvc ViewModels


Assuming i have tables like this:

Users
------
UserId
Email
...

People
------
PersonId
UserId
Name
Country
...

With the corresponding models:

public class User{
   ...
}

public class Person{
   ...
}

I want to have a view in my MVC application showing all people including their email address.

My solution is structured in different projects like:

Comp.App.Services
Comp.App.Dal
Comp.App.Web

Ideally i create a viewmodel in my controller to populate my view later like this:

public class PersonListItemViewModel{
    public string Name { get; set; }
    public string Country { get; set; }
    public string Email { get; set; }
}

Now the problem. I want to get the data with 1 query in my service layer, but the service layer must not know about the viewmodel, and the query should not return any extra field. Only the fields i specified in my viewmodel.

I red many best practices for N-tier applications, but i cant seem to figure out how to implement this without letting my service layer know about view models. Which seems not to be correct. I am always assuming my service layer can only know about domain models, but in real world applications i always walk into the issue that i want to limit my query to for example only 2 fields. This cant be done if my service only talks domain models.

Have i misunderstood something about this approach?

PS. Im using Dapper in my Dal project.

EDIT: Its not a duplicate of Converting DTOs to View Models . Im aware of automapper. Let me ask the question a little different. What should my service return, when i have a method there called: GetPeopleWithEmail() ???

According to what im reading now in the anwsers it should return a DTO, and convert the DTO to a ViewModel in my controller. Correct?


Solution

  • [...] and the query should not return any extra field. Only the fields i specified in my viewmodel.

    Actually returning an instance of some model, domain object or whatever in your domain layer which has 10, 20 or 100 properties shouldn't mean that all properties must be set.

    In the other hand, the same rule can be applied to data-transfer objects (DTO).

    Usually you use JSON serialization format and default ASP.NET Web API JSON serialization works with JSON.NET library, which supports DataContractAttribute and DataMemberAttribute attributes.

    At the end of the day, you can send an object over the wire from the API using a DTO class with 20 properties, but only ones with a non-default value will be serialized:

    [DataContract]
    public class Dto
    {
         [DataMember(EmitDefaultValue = false)]
         public string PropertyA { get; set; }
    }
    

    If you instantiate Dto and you set no property, the serialization result will be just {} (a blank literal object). Now you can extrapolate this rule to large DTOs and you can be sure that you're not transmitting unwanted properties over the wire. Or in other words, you can use serialization attributes to produce many different DTO from the same class!.

    You should care about what properties are being set rather than how many properties exposes some class when working in an n-tier scenario. An use case A may set 3 properties and use case B may set other 2 properties different than use case A. And maybe use case C sets other properties plus ones set by use case A and B.

    Sometimes things go harder and you can't use one class to rule them all, and then you implement many data-transfer objects to cover different use cases, where you implement a sub-set of properties required by a concrete client view.

    An important point here is ViewModel != DTO. A view model provides behavior and data to views, while a DTO is just an object to transfer a sub-set of data given by some service in order to optimize network performance and usage, and avoid sending unrelated data to other tiers.