18

I have an ASP.NET MVC 2 application with a POCO domain model and an NHibernate repository layer. My domain model has no awareness of my viewmodels so I use automapper to go from viewmodel to entity and vice/versa.

When I introduced WCF to my project (a late requirement), I started having to deal with disconnected objects. That is, I retrieve an entity from the database with NHibernate and once that entity is serialized it becomes disconnected and each child collection is loaded regardless of whether or not I plan on using it meaning I'm doing alot of unnecessary database work.

After reading up on this, I see that it is highly recommended that you not expose your entities outside of your domain project and you should instead use DTOs.

I see the reason for this but I'm having trouble figuring out how to implement it.

Do I map from viewmodel to DTO in ASP.NET MVC, send DTOs through the service layer, and map from DTO to entity in the service layer? Where should I define my DTOs?

Mayo
  • 10,544
  • 6
  • 45
  • 90

4 Answers4

17

I like to have my service layer keep entities encapsulated within it, and return/receive only DTOs. I keep the service contracts as well as the DTO's in a separate assembly which both the MVC project and the Service implementation reference.

Inside the service call implementation, the service maps dto's to entities, then does the interaction with repositories and other entities as it needs to.

On the app/mvc project I sometimes will get lazy and just use DTO's as the models for certain actions (especially CRUDy ones). If i need a projection or something like that, then I'll make a viewmodel and convert between DTO and viewmodel with automapper etc.

How exposed your entities are is a subject of much debate. Some people will push them all the way to the view/app layer. I prefer to keep them in the service layer. I find that when the entities leave the service layer, you find yourself doing business logic type stuff anywhere where they're interacted with, stuff that should probably reside in a service.

Brook
  • 5,949
  • 3
  • 31
  • 45
  • This is certainly the most applicable to my situation - I didn't realize there was debate on the issue. I'm just finding that exposing my entities beyond my service layer is causing me grief - but I didn't start experiencing these problems until I added WCF to the project. – Mayo Mar 17 '11 at 02:03
  • 1
    I think that if your application is not distributed (no network gap between the application and service layer) then it's much less of an issue. I've seen MS articles where they advocate having the entities used in all layers of the application. I've also seen the structure above more often in the "alt.net" type articles, and it's worked better for me. It also simplifies my thinking about the app, the service truly is the entry point to the domain. – Brook Mar 17 '11 at 02:38
2

I treat my DTOs like ViewModels because the UI layer ( MVC app ) is requesting them. You could go Entity -> DTO -> ViewModel but I think thats over engineering if the only consumer of your service is an MVC application. If somehow the DTOs will actually be used for data and not simply screen specifications then you should probably use additional mapping.

I've also simply returned entities from my WCF layer and let the automatically generated proxy objects on the client be the DTO. The entities almost become DTOs because of the proxy classes and no business logic comes over to the client.

And of course, this is all "It Depends" what your architectural goals are. This question is borderline subjective and argumentative IMHO.

John Farrell
  • 24,673
  • 10
  • 77
  • 110
1

I like defining the DTO in the MVC project and then creating extension methods to transform from domain entity to DTO (and vice-versa).

The transformation would take place in the mvc functions.

yamspog
  • 18,173
  • 17
  • 63
  • 95
0

I just wrote a post about a way of getting around all this DTO <-> DO transformation. Maybe you check it out http://codeblock.engio.net/?p=17

bennidi
  • 2,092
  • 21
  • 27