Using DTO and ViewModel in ASP.Net MVC Project

12

I have an ASP NET MVC 4 project with the following projects:

  • Domain
  • Repository
  • Contracts (interfaces)
  • DTO's
  • And the web project

The web project "sees" only the repository project and it is responsible for executing the business rules. This project always returns DTO's to the web layer and in the web layer (controllers) I transform the DTO into a viewmodel and return the viewmodel to the view.

I'm using DTO's because in most queries I do not need all entity data, so I do not need to expose my entire entity to the view (and I also think it's not a good practice).

The problem I'm seeing is that it's redundant to return a DTO for my web layer and in the web layer transform the DTO into viewmodel. Here is an example:

Suppose that in the repository there is a method that returns user data (login and email) by id:

Method return DTO:

public class UsuarioDto{
   public string Login {get; set;}
   public string Email {get set;}
}

Method in repository that returns user to web layer

public class UsuarioRepositorio : IUsuarioRepository
{
   public UsuarioDto GetUsuario(int usuarioId){
      using(var context = new dbContext()) //instancia do contexto do entity
      {
          return context.Usuario.Select(x => new UsuarioDto{
                                                 Login = x.Login,
                                                 Email = x.Email
                                              }
                                       ).FirstOrDefault(x.id == usuarioId);
      }
   }
}

At the point below I think I'm being redundant when transforming the DTO into a viewmodel

ViewModel that represents the user (within the Models folder)

public class UsuarioViewModel{
   public string Login {get; set;}
   public string Email {get set;}
}

Controller

public class HomeController : Controller 
{ 
    public ActionResult User(int usuarioId)
    {
       UsuarioRepositorio usuarioRepositorio = new UsuarioRepositorio();
       var usuario = usuarioRepositorio.GetUsuario(usuarioId)
                                       .Select(x => new UsuarioViewModel{
                                                        Login = x.Login,
                                                        Email = x.Email
                                                    }
                                              );
      return View(usuario)
    }
}

Is there a way I can optimize this transformation from DTO to ViewModel? The impression I have is that I am duplicating code, because as far as I know, the DTO serves to traffic data between layers and the viewmodel is used to expose the data to the view.

    
asked by anonymous 18.09.2014 / 16:33

2 answers

10

Well, James, from what I understood his biggest problem is the work on turning Model into DTO, then DTO into ViewModel, ViewModel into DTO, then DTO into Model.

With AutoMapper, some of the work would be done and you'd have fewer problems, but before you can simply use a solution like that, you can rethink your model as a whole. There are several design patterns to suit needs similar to yours, of course no pattern is perfect. First I think you should think which points are most relevant to you: development speed, decoupling, maintainability, and so on.

There is no perfect pattern when we define an architecture, we always have to give up some things to get others, there is no efficient maintenance without testing, decoupling without layer separation and responsibilities, etc.

Why use Data Transfer Object (DTO)? As the name says, data transfer object, when you have a system where you need to perform multiple queries and bring complete entities into separate queries becomes a problem, it's time to use a DTO.

From what I've said, you're seeing as a problem repeating this code from turning one object into another, it's against using the standard on less complex screens, a simple example:

User Creation Screen:

DTO:

public Guid Id {get;set;}
public string Nome {get;set;}
public string Cpf {get;set;}
public string Telefone {get;set;}
public string Email {get;set;}
public string Senha {get;set;}

ENTITY:

public Guid Id {get;set;}
public string Nome {get;set;}
public string Cpf {get;set;}
public string Telefone {get;set;}
public string Email {get;set;}
public string Senha {get;set;}

On your screen you will have to perform validations, your ViewModel can not be the same as your DTO, you need the user to Confirm Email and Confirm the Password, you may need to send several other information to your screen.

Now imagine if tomorrow you realize that it's best to separate the User Entity into Credential for whatever reason. Your DTO traffics the data of the two entities between the layers, continues using a single screen, you do not need to change your application, just your data access layer.

With some tools like AutoMapper you can make your work of transforming a similar entity with an easy one, with just one line of code, and you can take advantage of this standard.

What you need to cherish always is the separation of responsibilities and simplicity, not always less is the simplest code, not always the most complex is the best, consider your needs. Basically:

Use AutoMapper to convert an object to another object with the same properties. Leave your business rule in your domain and let your repository just be your link to your database. In the rest try to evaluate what to do in each layer, and leave each one doing what is their responsibility.

    
24.09.2014 / 21:59
4
  

The web project "sees" only the repository project and it is responsible for executing the business rules ...

Ideally, you should rule the business on your Domain project rather than on the repository.

Repository isolates domain (business-related) objects from access code details and mapping these objects to the database. That is, it adds a layer of separation between the data access and domain layers. He should not be responsible for executing business rules.

Your web project can "exercise" your Domain project, its repository Interfaces, without problems.

Now focusing on your question, at least for the example you put in the question I do not see the need for DTO a not to make too many remote calls to retrieve too much data. So, I believe you can stop using DTO for some cases, where you are "not" subject to latency issues inherent in remote communication / queries.

Using DTO is interesting in cases where we need to reduce the number of remote calls.

Exemplo: You need to make multiple remote calls, which increases response time beyond acceptable levels. Here it is interesting to use DTO, making one consultation instead of several.

  

I'm using DTO's because in most queries I do not need all entity data, so I do not need to expose my entire entity to the view (and I also think it's not a good practice).

Do not get tied to using DTO for this reason alone, except in some specific case as I mentioned.

You can create a method (s) in your Repository that returns the information that will be used in the View, fill its ViewModel object (like the UserViewModel of your example) and render this information in View, without having to convert DTO to ViewModel.

Exemplo: You can return a User in your Repository method and populate your ViewModel:

public class UsuarioRepositorio : IUsuarioRepository
{
   //Retorna Usuario invés de UsuarioDto
   public Usuario GetUsuario(int usuarioId){
      ...
   }
}  
    
18.09.2014 / 16:59