DTO management and mapping in a large .NET project

My team and I create great .NET WinForms applications. The application uses various "Services" to receive data in and out of our database. Each "service" lives in its own solution and processes a specific data type. So, for example, our "ContactsService" controls the extraction / saving of contacts in our database.

We typically create a DTO for each service. So we can have a "ContactDTO" that has simple string properties for each piece of data on the contact. Now we also have a business-class Contact class that has the same properties and possibly a few additional methods with some business logic. In addition, ContactService has its own Contact class, which is hydrated from ContactDTO.

This has become a huge pain for managing all our DTOs and mapping. Currently, sending a contact for storage in the database is as follows:

  • Card Client Contact ContactDTO
  • Contact card DTO for communication Contact
  • Save contact
  • Card service Contact ContactDTO
  • ContactDTO card to customer Contact

This is just shit. If we add a property to our Contact client class, we must add the property and mappings in 3-4 places.

What are we doing wrong and how can we make our life easier? Would it be easier to use something like Json.NET and have JSON DTO? We tested AutoMapper, but some team members thought it was too complicated.

+8
mapping dto
source share
3 answers

I came across this a lot, but in my case I decided to accept it because the decision to use DTO was intentional - I want my services, client, proxy servers and contractual assemblies to be clearly separated.

When using WCF, the layout I prefer is something like this (using your contact example):

  • Customer build
    • Contact (has customer-y features)
  • Collecting General Contracts
    • Contact (agreed common DTO)
  • Proxy assembly
    • Uses the contact from the general assembly of contracts.
  • Service assembly
    • Contact (it has service logical characteristics of a service, for example, it can be a type opened using an ORM level, such as Entity Framework).

Now I share the contracts between the service and the client. If I ever need a version of them myself, I can simply make a copy of the collection of general contracts and redirect the proxy assembly to use the copy, and then change the two contract assemblies myself. But in most cases with which I worked, I have both a client and a service, therefore it is convenient to share the assembly of contracts between them.

This is the only optimization that I can think of when you make an architectural decision to isolate your components with DTO, at least without using code generation tools (I don’t know any good, but I didn’t have to look at them).

Edit: if you are not using WCF, you will not need the "Proxy" assembly.

+2
source share

AutoMapper is not particularly complex. If you follow conventions, for example. Contact.Address1 becomes ContactAddress1 in the DTO, you do not need to write a lot of code except calling Mapper.Map. Alternatively, you can use code generation, but it will still be difficult to manage the changes.

May I ask why you feel the need to have both ContactDTO and business contact? Can you not just transfer the service? I knew this wasn’t the best practice, but it could save you from RSI

EDIT: ignore my last point - for some reason I thought you were mapping a service contact to a database object such as NHibernate / Entity Framework

0
source share

Some things to speed up the process to consider:

I wrote code generators so that you can select tables (tables) and columns from a database and generate C # DTO. This saves a lot of unnecessary input and can generate DTO much faster. A little time ahead, but when you have a table with 20 columns, you need to display a map, this helps.

I also wrote code generators for mapping DTOs to stored procedures for save, delete, and query operations. Again, a time delay, because many of them end up being very similar. If you have a lot of tedious grunt code written, consider a code generator to do this.

Use an entity framework or ORM card for the back. This can save a lot of time, but you need to invest in ORM knowledge and find out how it works.

Create a common set of DTOs that are used from the client to the database. This may be impractical in some situations where you need proxies or small DTOs for the client, but you can try to have some common DTOs that are passed from the client on the way back to the server.

Remove some layers. I know this sounds a bit anti-pattern, but in some cases the bow doesn't have to be so thick.

0
source share

All Articles