Think Before You Use The DTO Pattern
Let me preface this blog post by saying that there are still times when a DTO makes sense. Also, this post is written from a .NET perspective, so some things may be different on your platform. What I want to address though is the tendency of many developers to just automatically create a set of DTOs for each layer for each domain model. As I mentioned in other blog posts, you should always think about why you are doing something before you are doing it.
Reasons like “this is the way we have always done it” or “this is the best practice” do not stand up to scrutiny. A dispassionate assessment of an approach should be taken before engaging in a practice. You should also be able to defend your choice in a technical debate without falling back on regurgitated lines like “I’m all about clean code.”
The DTO Pattern is an Anti-Pattern in Most Cases
I used to use DTOs a lot too about 4 or 5 years ago along with the repository pattern. I had been conditioned to never allow your domain models to cross layers and to keep everything separated. I was one of the lemmings following after what everyone had done before me, never thinking about why I was doing it. Automapper was the life blood of the application as I mapped to view models, data models, api models, and so on and so forth. New layer? New set of DTOs! All those duplicated classes, all that mapping, all that suffering and pain wrought upon the application in the name of the holy grail: separation.
Thankfully, my approach evolved over time and I began to question why I was going through all of this. Was it really worth while to incur the cost of extra classes and mapping just so I could say I wasn’t using my domain models with entity framework? How about my API? Should I really be calling everything a DTO? Is half my application calling Automapper really a good practice?
View Models vs DTOs
I don’t consider View Models to be DTOs. View Models can encapsulate logic, validation, or anything else you might include that is specific to the view. Your view model may very well end up with most, if not all of the properties of the domain model that it is built on. More often than not though, the view model only contains what is needed for the view to function. I have, however, seen people use DTOs as their view models. A view model is not a DTO, and you especially don’t need to map from a view model to a DTO and then to a Domain model. When MVC and Razor were still all the rage, it was very common to use automapper to map from a View Model to a Domain Model. This is a perfectly valid approach that still makes sense if you are using Razor. Just as you should not use a DTO for your view, you should not use a domain model either.
Most new applications have a harder separation between the server and the client. The rise of React, Angular, and Vue now removes the old approach of a C# view model that could be directly mapped to a domain model. In addition, the rise of JSON based ASP.NET Web Api and the subsequent decline of WCF have further reduced the need for DTOs.
ASP.NET Web Api and WCF
In the days of WCF, there was a rational argument for the usage of DTOs. You probably didn’t see the DTO suffix on these objects and instead are more familiar with the typical Request and Response suffixes for WCF endpoints. On this note, I want to digress for a moment and discuss the DTO suffix in general: it sucks. It is perhaps the least descriptive suffix ever created. There was a certain fortune 100 that I worked with a number of years ago who decided to suffix all of their WCF requests and responses with “DTO.” Unfortunately these WCF services all worked with the same domain, and they had a lot of them. So what happened when an application ended up using multiple WCF services in the same class? Name collisions everywhere followed by aliasing everything.
At the time I tried to explain the problem with the situation with my Harry Potter example. Imagine if the author of Harry Potter had gotten lazy and decided to name all the characters Harry Potter. She needed a way to differentiate between them though so she prefixed each one with a number. That is essentially what you are doing when you suffix all your DTOs as “DTO.” Writing software is just like writing a book. It needs to be descriptive, and ultimately it needs to tell a story. The solution name is your book title, the projects your volumes, the classes your chapters, and the methods your paragraphs. Reading a book with everyone named HarryPotterDTO is just as annoying as having to read your class that has six different OrderDTOs from six different WCF service proxies.
Web Api is a Medium to Interact With the Domain
I advocate using your domain classes directly in your API. The reason is that if someone is interacting with your API then they are ultimately interacting with your business and all actions on the API represent that. Using your domain class does not mean that you have to allow all properties to be modifiable. You still have complete control over everything, and in terms of publishing what your API accepts, tools like swagger let you control what parts of the domain are published as your contract. There are a number of different ways to control this including using something like request post processing with ASP.NET filters. The only time I advocate the usage of a DTO is when calling third party APIs or APIs that reside outside of the domain that your application is providing.
What About Persistence Ignorance?
Simply using your domain models as your entities with Entity Framework does not automatically pollute the domain with persistence implementation details. As long as you keep your entity framework configuration and context in a separate assembly, then there is no reason your domain needs to be aware of its existence. As I have discussed before, Entity Framework is already an abstraction of your persistence implementation that provides you a generic repository pattern and a unit of work pattern. I have seen certain blogs advocate that your data model is not your domain model. From a principle standpoint, this is true, but from a practical standpoint having a completely separate list of data models that map to your domain has little gain in today’s world. In the event you have a table that truly has no representation in your domain, then by all means create a DataModel for it. Don’t resort to a DTO suffix and don’t blindly do it for every table. Use DTOs responsibly and you’ll be happier for it.
mhOctober 16, 2019
If all domain models are fully encapsulated (private setters), and exposed only via constructors and public methods. Now I cannot use my domain models as parameters for post/put end points, right?
I cannot trust incoming payloads, and asp.net core model binding won’t access private setters, thous would be defeating the purpose anyway!
So i find myself compelled to use DTOs in this scenario! And am thinking now, if i am accepting DTOs inbound, should i use them outbound (in Get end points)?!
Sean LeitzingerOctober 16, 2019
Well, if you went that route then yes you have no choice but to use DTOs in this case. This post wasn’t about how you should never use DTOs, but more about how you should think before you use them. They shouldn’t be some sort of standard knee jerk reaction every time we cross an internal layer. That being said, can’t say I agree with the whole private setters for domain models approach. I can understand it for value objects, but all domain models? To me that feels like a design choice I wouldn’t personally make.
AndrewMay 6, 2020
I rarely have a situation where my domain class has the same shape as something I need to return to the client. For example, take a data grid which contains data from 5 database tables (and thus, something like 5 domain entities are involved). I flatten that out as a list of DTOs which I return to the client. That’s just one example of many in the apps I have been creating.
If you want to avoid an explosion of DTOs, you can now use ValueTuples. Especially if the DTO would only have a handful of properties. But no, using domain models in your view (even if an API) is most definitely a code smell.
Sean LeitzingerMay 7, 2020
I think it depends on your design and your technology. If you’re using an ORM, you don’t need to create DTOs when you can return dynamic from an API. Everything you return is going to be converted to JSON anyway. Take a look at my CQRS with Entity Framework Core post if you want to see where I’m going with that. Also, I specifically mention in the article that domain models are not view models. See the section “View Models vs DTOs” to see my explanation on that. I have seen your set up where you are using your data layer to basically return view DTOs, and I’m not a fan. View models are not DTOs.
DanJuly 9, 2020
If you allow direct to domain, it causes two issues. First, it could get into an invalid state. You can validate that the dto would invalidate the domain ahead of time. Second, you would be exposing all properties to the client. A user could figure this out and start updating values you were not intending and get into dangerous situations. With a specific dto (or request) they can only do what that dto allows. That is why you should never expose your domain directly to the client. You have no idea what future changes to that domain could cause it to be vulnerable to all the endpoints that interact with it.
Sean LeitzingerJuly 9, 2020
I think it depends on your set up. Your concerns are valid, but your domain should have domain validation. I’m not sure why the DTO would have validation but your domain wouldn’t. You can read more about my approach to validation here: https://edgesidesolutions.com/dealing-with-validation-domain-vs-contextual/ I also use a number of other techniques that I’ve written about that would prevent many of the issues you have risen from occurring.
EnginyrJanuary 30, 2021
I think DTO is useful when you need to structure your response differently to different queries. For example, a User domain model has fields that are considered confidential and should only be visible to the authorized users. In this case, a separate DTO is needed to expose these confidential fields and you cannot simply return the domain model to the client.
ViewModels in MVC / MVVM / Separation of layers- best practices? – w3toppers.comJune 20, 2022
[…] a note: here’s a nice article on how DTO (which is not a viewmodel), can be omitted in some scenario’s […]
Richard MooreJuly 21, 2022
There is no such thing as an “anti-pattern”, just using the wrong tool for the wrong job.
Sean LeitzingerJuly 21, 2022
Yes, I would agree with that for the most part. In hindsight I probably shouldn’t have referred to it as an anti-pattern.