How to organize and name DTOs that are used as Data Contracts in a WCF web service
Asked Answered
M

1

18

We are using DTOs as Data Contracts in our WCF web service. The purpose for these DTOs is to expose only the information that is relevant for a specific API method.

What I am seeking from you guys is some advise on the best practices here.

For example, consider the following simple model:

class Order
{
    int CreatedBy { get; set; }
    DateTime CreatedOn { get; set; }
    string Description { get; set; }
    int Id { get; set; }
    string Name { get; set; }
}

Assuming our API allows a consumer to Create, Update and Get an Order, we have created the following DTOs. DataMember and DataContract attributes are eliminated for simplicity.

Create method: A user cannot specify the Id and CreatedOn properties, so the DTO looks like this:

class CreateOrderData
{
    int CreatedBy { get; set; }
    string Description { get; set; }
    string Name { get; set; }
}

Update method: A user cannot specify the Id, CreatedOn and CreatedBy properties, so the DTO looks like this:

class UpdateOrderData
{
    string Description { get; set; }
    string Name { get; set; }
}

Get method: A user should be able to see everything for the Order, so the DTO looks like this:

class OrderData
{
    int CreatedBy { get; set; }
    DateTime CreatedOn { get; set; }
    string Description { get; set; }
    int Id { get; set; }
    string Name { get; set; }
}

So here are my questions:

  • Assuming there are more properties in Order model and lot of those properties are shared between "Create" and "Update" DTOs, does it make sense to have these classes extend from a common base class? If yes, should the "Get" DTO (OrderData) also extend from that class? If we do that, doesn't it leave these DTOs too dependent on each other?

  • If all the properties are common between "Create" and "Update" DTOs, should we still create two different DTOs? If yes, why? If not, (this is just a naming question now) what should the "CreateOrUpdate" DTO be called so that the name is obviously different from the "Get" DTO?

  • Is it OK to suffix all the DTOs with something like "Data" or "DataObject" or "Dto"?

  • Are we on the right track here? If not, how can be make this design better?

Update:

I think I don't like the inheritance in DTOs because the base class will also be exposed in the WSDL and the client will be able to see it and instantiate it which seems dirty to me (see this: WCF Serialization with object inheritance?). How about using Interfaces in DTOs to enforce common properties instead of inheritance? Since DTOs should not have any behavior in them, we are not losing much by replacing inheritance.

Mima answered 16/8, 2012 at 1:54 Comment(2)
+1 I think its up to personal preference. When I find myself in this situation I tend to go base class or combine both into one and go for the name Upsert. I'd leave out any suffix like the hungarian dto notation as you can easily identify the type and IMHO its better to use namespace like Project.Data.DataObjects rather than suffix's. Just my 2 centsBoothe
Thanks for your response Jeremy. I agree that most of it is personal preference but I would still like someone to validate these questions and concerns and present some arguments regarding best practices and possible pitfalls. Also, if I understand it correctly, Upsert should mean "update if present and insert if not". While that is an interesting thought, it is not the intention of these APIs. The consumers of these APIs will know specifically when to Insert or Update.Mima
C
6

Since this is a lot about personal preferences, I would do this ..

  1. I would not create a common base class since that would not adhere to L in SOLID. If you are concerned about DRY, then you could create a aggregation instead.

  2. If all properties are common, then it just makes sense to create a Save that takes that object, the order Dto class will have a key property(ies) that would indicate if its an existing order or not.

  3. I would suffix all with Dto, because a lot of Dto class names are same as domain classes, they get confusing since they will exist in the same method together. Then you can decorate your Dtos with DataContract(Name="Order", Namespace="htp://yourdomain/.."]. This way they will be exposed to outside world according to your own preference.

I have been in multiple projects that use the same general architecture, i generally use AutoMapper to map dtos to domain. It has worked great for me !

Circumlunar answered 16/8, 2012 at 18:48 Comment(1)
I like your suggestions especially your mention of the SOLID principle and the common base class. Regarding AutoMapper, I have used it in the past and liked it, but since our objects are not all that complex, we are using extension methods for the conversions.Mima

© 2022 - 2024 — McMap. All rights reserved.