50

We are building a web app using AngularJS , C# , ASP.Net Web API and Fluent NHibernate. We have decided to use DTOs to transfer data to the presentation layer ( angular views). I had a few doubts regarding the general structuring and naming of DTOs. Here's an example to illustrate my scenario. Lets say I have a domain entity called Customer which looks like:

public class Customer
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Address Address { get; set; }
        public virtual ICollection<Account> Accounts { get; set; }
    }

Now, in my views/presentation layer I need to retrieve different flavors of Customer like :

1) Just Id and Name 2) Id , Name and Address 3) Id , Name , Address and Accounts

I have created a set of DTOs to accomplish this :

public class CustomerEntry
{
    public  int Id { get; set; }
    public  string Name { get; set; }
}

public class CustomerWithAddress : CustomerEntry
{
    public AddressDetails Address { get; set; }
}

public class CustomerWithAddressAndAccounts : CustomerWithAddress
{
    public ICollection<AccountDetails> Accounts { get; set; }
}

AddressDetails and AccountDetails are DTOs which have all the properties of their corresponding Domain entities.

This works fine for querying and data retrievals ; the question is what do I use for inserts and updates. During creation of a new customer record , name and address are mandatory and accounts are optional ..so in other words I need an object with all the customer properties. Hence the confusion :

1) What do I use for insert and updates? The CustomerWithAddressAndAccounts DTO has everything in it but its name seems a bit awkward to be used for insert/updates.

2) Do I create another DTO .. if I do , wouldn't that be duplication as the new DTO will exactly be like CustomerWithAddressAndAccounts ?

3) Last but not least , does the DTO inheritance strcuture described above seem like a good fit for the requirement ? Are there any other ways to model this ?

I have gone through other posts on this topic but couldn't make much headway. One thing that I did pickup was to avoid using the suffix "DTO" in the class names. I think it feels a bit superfluous.

Would love to hear your thoughts

Thanks

Sennin
  • 1,001
  • 2
  • 10
  • 17

2 Answers2

23

Recommendation is that you should just have one DTO class for each entity suffixed with DTO e.g. CustomerEntryDTO for the Customer entity (but you can certainly use inheritance hierarchies as per choice and requirements).

Moreover, Add a abstract DTOBase kind of base class or an interface; and do not use such deep inheritance heirarchies for each Address, Account and other properties to be included in child DTOs. Rather, include these properties in the same CustomerEntryDTO class (if possible) as below:

[Serializable]
public class CustomerEntryDTO : DTOBase, IAddressDetails, IAccountDetails
{
    public  int Id { get; set; }
    public  string Name { get; set; }
    public AddressDetails Address { get; set; } //Can remain null for some Customers
    public ICollection<AccountDetails> Accounts { get; set; } //Can remain null for some Customemer
}

Moreover, your DTOs should be serializable to be passed across process boundaries.

For more on the DTO pattern, refer below articles:

Data Transfer Object

MSDN

Edit: In case you don't want to send certain properties over the wire (I know you would need to that conditionally so would need to explore more on this), you can exclude them from the Serialization mechanism by using attributes such as NonSerialized (but it works only on fields and not properties, see workaround article for using with properties: NonSerialized on property). You can also create your own custom attribute such as ExcludeFromSerializationAttribute and apply it to properties you don't want to send every time over wire based on certain rules/conditions. Also see: Conditional xml serialization

Edit 2: Use interfaces for separating the different properties in the one CustomerEntryDTO class. See the Interface Segregation Principle on Google or MSDN. I will try to put a sample explanation later.

Community
  • 1
  • 1
S2S2
  • 8,322
  • 5
  • 37
  • 65
  • Thanks for your reply. One of the motivations for using multiple DTO classes was to be a bit more expressive in defining what the DTO is used for. Also , if you just need Id and Name , should you really send the full fledged CustomerEntryDTO (which you have described) over the wire ? – Sennin Sep 16 '13 at 18:38
  • @Sennin I edited my answer based on your comment but I think my answer would be still incomplete for you. May be I will edit it later to add more on your above comment. – S2S2 Sep 16 '13 at 18:55
  • @Sennin On the projects I've been involved in we usually end up with 2 a `Foo` and a `FooDescriptor` that only has the name and id, the latter being used when we are displaying collections of items. – Yaur Sep 16 '13 at 21:06
  • 3
    Good reply but I don't think there's need to apply interfaces on DTOs. What's the use of that? ISP is good in pair with the other SOLIDs for objects having actual logic rather than for simple data structures. – Arman Jun 26 '14 at 13:28
  • 4
    In a .NET world is dumb to suffix your classes with DTO, there's simply to point. We tend to use Entities for repository objects and Models for objects returned from the API and as for service objects typically they dont use any prefixes. In fairness all those layers use DTOs, so should we start naming Entities XptoDtoEntities?! Drop that DTO name it's ugly. – MeTitus Oct 25 '16 at 09:23
  • 2
    @Marco the suffix is useful when mapping your view model to entities and you don't want name-conflicts when importing classes of both layers in the course of this process. – Felix K. Oct 13 '18 at 22:05
  • @B12Toaster I'm guessing you're using web api and EF and in that case if you're follow the naming convention for those libraries, you don't need to use the DTO suffix at all, because you'll have xxModel, xxEntity leaving xx free for your service classes. – MeTitus Oct 20 '18 at 22:57
  • @MeTitus Yes correct, but in "xxModel" you still have the "Model" suffix and "xxDTO" is just a shorter version, some guys also choose "xxVM" (VM for ViewModel) or "xxResource". The point is: having a suffix helps to separate classes from web layer and domain layer in your head and avoids having import-conflicts arising from same class names when mapping from web layer to domain layer. – Felix K. Oct 21 '18 at 14:49
  • @B12Toaster but model is the common use in web api, dto basically means everything. – MeTitus Oct 21 '18 at 18:26
  • @MeTitus DTO is also fairly often used. See official web api docs: https://learn.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5 – Personally I have to say that when working with MVC pattern the term "model" is refering to the business logic, so I try to avoid this or use the term "view model" instead of plain "model". – Felix K. Oct 22 '18 at 14:55
  • @B12Toaster The document you refered to, is from 2014, we don't use DTOs and models are not related to the business logic at all, they are just a visual representation of the data... but in the end, just use whatever you like, I just prefer to follow the conventions as of today.https://learn.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api – MeTitus Oct 23 '18 at 23:07
  • @MeTitus "*models are not related to the business logic at all*" → please go to: https://learn.microsoft.com/en-us/aspnet/core/mvc/overview?view=aspnetcore-2.1 where it clearly says "*The Model in an MVC application represents the state of the application and any business logic or operations that should be performed by it. Business logic should be encapsulated in the model.*" ... "but in the end, just use whatever you like" – agreed :) – Felix K. Oct 24 '18 at 07:09
  • @B12Toaster oh, you're talking abou N-tier applications, where all the logic is in the controllers, but who does that in the XXI century anyways? sorry but now I see where the confusion is, you're talking about something which by todays standards is wrong, logic should not be in the controllers, but even in that case is wrong to say that Models represent the state of an application. And posting Microsoft links doesn't help either, MVC as a pattern has been defined since the 70s and I was first exposed to it in the late 90s with Java. Having DTO as a prefix is a bad practice. – MeTitus Oct 25 '18 at 13:39
  • 3
    I simply quoted you and proved you wrong. end of discussion. – Felix K. Oct 25 '18 at 17:28
2

What do I use for insert and updates?

  1. Service operations are usually defined in very close relation to business operations. Business language doesn't speak in terms of "inserts" and "updates", neither do services.

  2. Customer management service is likely to have some Register operation that takes customer name and maybe some other optional parameters.

Do I create another DTO?

Yes, you should create another DTO.

Sometimes service operation contract may be enough and there is no need to define a separate DTO for a particular operation:

function Register(UserName as String, Address as Maybe(of String)) as Response

But most of the time it is better to define a separate DTO class even for only a single service operation:

class RegisterCommand
    public UserName as String
    public Address as Maybe(of String)
end class

function Register(Command as RegisterCommand) as Response

RegisterCommand DTO may look very similar to CustomerWithAddress DTO because it has the same fields but in fact these 2 DTOs have very different meanings and do not substitute each other.

For example, CustomerWithAddress contains AddressDetails, while a simple String address representation may be enough to register a customer.

Using a separate DTO for each service operation takes more time to write but easier to maintain.

Lightman
  • 1,078
  • 11
  • 22