27

Lately I've been hearing a lot about DTOs and how useful they are but I can't find a good example of using it in ASP.NET context.

Let's say I use three tier architecture:

  1. Data layer(using Entity Framework)
  2. Business Layer(WCF Service)
  3. Presentation Layer (MVC 4.0 web application)

Where should I convert from the EF Employee object to an EmployeeDTO POCO?

Lets say I do the conversion in the Data Access layer but what happens in the WCF service? Should it then be converted to another DataMember object and when it get's to the UI layer(MVC web app) should it then be converted for the third time to a model? I would appreciate it if someone could please clear this for me

Denys Wessels
  • 16,829
  • 14
  • 80
  • 120
  • 2
    I am currently researching for new web applications, stumbled upon this good article http://www.codeproject.com/Articles/493389/Four-ways-of-passing-data-between-layers , just want to share – kite Jul 28 '15 at 10:26

6 Answers6

10

In similar situation I used to put dto's into Core which is known to all three. So you have

     Core
       |
 ------------
 |     |    |
DAL   BL   PL

Each layer can operate with Core.Dto.Employee. Each layer also exposes Core.Dto.Employee externally in its API. But internally each layer can transform/adapt Core.Dto.Employee, e.g. you read from database EF.Employee and later convert it to Core.Dto.Employee. Transformation is contained by the layer's boundary.

If you have several different models to represent same thing throughout the layers, for example PL wants PL.Employee and DAL operates on EF.Employee, you will end up with a mess.

oleksii
  • 35,458
  • 16
  • 93
  • 163
  • 2
    That looks better and where do you do the conversion from EF object to a DTO? – Denys Wessels Feb 03 '15 at 13:00
  • 1
    A bit late with the reply. I'd usually try to contain the conversion inside a single project. Usually that conversion is only relevant to that particular project, e.g EF object to DTO will likely to be in DAL. In some cases it make sense to reuse it in several projects - in this case I migrate code to core so that I can reuse it and not duplicate – oleksii Aug 05 '15 at 11:23
7

Your service layer exposes DTO's. This means that in the service layer you define data contracts as you would like them to be exposed to the outside world. In most cases they are flattened entities that not necessarily have the same structure as your database entities.

It is the responsibility of your service layer to use business/data layer and construct the DTO's that you expose to the outside world.

What you use in your business and data layer depends on the architecture. You could have a domain model that is mapped with code first. In that case, the service layer maps domain entities to data contracts (DTO's). If you don't have a domain model (anemic model), then you could as well just map the database directly to your DTO's.

The ASP.NET MVC site consumes the service, and maps the DTO's it receives to dedicates view models that are then passed to the specific view.

In addition, you may decide to also split queries from commands. This is a good approach because the DTO's that you get back as the reqult of a query are totally different than commands that you send to the service. A command only contains what's needed to execute the command and contain the business intend what you want to achieve, while a query returns a flattened model of what you need in the UI.

Other remarks:

  • Don't expose your database entities.
  • Don't convert in business layer, as it's not business logic.
L-Four
  • 13,345
  • 9
  • 65
  • 109
  • 8
    I would entirely disagree with the last bullet point. Conversion to dto from domain entity is very often business logic. The data layer should access, persist and return domain objects. The bll should decide what to return back to the UI depending on current page variables, business rules, etc. You do not want your data layer making decisions based on business logic it needs to be as dumb and loosely coupled as possible. – TheMook Nov 14 '16 at 10:24
  • It's fine to disagree :) However, mapping logic to me does not belong in business layer, as mapping may even be different depending on what service operation is called, while business logic is the same; therefore this mapping belongs in the service layer. – L-Four Nov 14 '16 at 10:39
  • 1
    Ah, your caveat there is "where there's a service layer" and the OP specified 3 layers without a separate service layer, therefore I was working from the perspective that the BLL contained the service layer. Yes, in the architecture you describe, I concur that the service layer is the place. With the OP's structure I thought you were advocating using the DAL. – TheMook Nov 14 '16 at 11:38
  • 1
    Ok, I think we have the same reasoning then :) My mistake, as a service layer is missing here. – L-Four Nov 14 '16 at 11:57
3

Have a look at https://stackoverflow.com/a/6310507/1771365 added here as I don’t have enough reputation to add comments.

Personally I would pass entitys between your Persistence layer and your business layer. As you are using MVC chances are your are going pass view models to your controllers. At which point I would map your view model to your DTOs(s).

If you plan to use DTO between all of your layers then create a cross cutting project which you can then reference.

Community
  • 1
  • 1
Stig
  • 1,169
  • 1
  • 9
  • 12
2

An approach that I'm particularly fond of is to the DTO conversion in your Business Layer.

Scenario: Your Presentation Layer calls your Business Layer passing a DTO. You do some logic & validation, then convert the DTO to an entity and send it to your Data Access Layer.

i.e. UI --> Bus. Layer (convert to Entity) --> Data Layer

I like this approach as I believe the Data Layer should not have any conversion logic and should receive and handle entities as needed. Another reason why this is effective is that you can now define specific business rules / validation logic during the conversion process before sending it to the Data Layer. Here's an old MSDN article, but has some great details explaining a similar approach.

Niels Filter
  • 4,430
  • 3
  • 28
  • 42
  • And using your approach where is the DTO created? In The UI Layer? – Denys Wessels Feb 03 '15 at 12:38
  • You can approach creation in 2 ways, either you expose a method in your Business Layer for creating a DTO: `UserDTO CreateUserDTO()` which returns a freshly initialised DTO. The other way (which I prefer) is to simply instantiate it in the UI layer: `var dto = new UserDTO()`. Since your DTO is available to your UI, you can simply instantiate the DTO, fill it up in the UI and then send it off the Business Layer for saving or whatever else. And lastly when you populate the DTO from your db, your Business Layer will simply return a filled DTO instance: `UserDTO GetUserByID(int id)` – Niels Filter Feb 03 '15 at 12:44
1

I use a project named Shared for such purposes, spesifically to share object with all layers. Regardless of the name, it should be visible by all layers.

user3021830
  • 2,784
  • 2
  • 22
  • 43
-3

There should not be any conversion. You would just use Poco Objects as DTO.

EF works with Poco and they can be serialized by WCF.

They should be defined in an assembly that is refernced by all projects.

In ASP.NET MVC you would mapp to a ViewModel by using the Poco - DTO.

Mathias F
  • 15,906
  • 22
  • 89
  • 159
  • 3
    Unfortunately this is a brittle approach as you cannot change your objects to suit internal needs of your application because external consumers of your services depend on their current structure. By having separate DTOs exposed via WCF/Web APIs you enable your internal model to evolve while ensuring external contracts are kept. – ssmith Mar 01 '18 at 17:33