سؤال

I'm having serious doubts about the design for my Web application.

I wanted to separate the business logic from the interface so I made a Web API that handles all the requests to the database.

It's an ASP.NET Web API with Entity framework and a unit of work and generic repository pattern. So far, everything is good.

PROBLEM

Where I need help is I can't figure out an efficient way of sharing objects between the API and the application.

I don't want to serialize directly the entity object, I thought it would be a bad practice because if the entity model changes, I could end up with serializing large objects for no reason.

How it's implemented now

Because my interface is ASP.NET Web application in C# and my API is in C#, I made a common library with the definition of all my classes I want to share between them.

I know that solution won't work when I will develop an android app, I will have to create my classes again in Java but that's not my biggest problem.

The problem is I feel like I'm always converting my objects.

EXAMPLE

Here's an example of my work flow :

I start with a model with all the objects and the data annotations for my form then user would POST that model to a controller.

In the controller I have to convert this model to a class in my common library then send that object to my API.

Then a controller in my API catch the call and convert that object to an entity object to update the database.

So I have 3 classes

  1. The model for the view with all the data annotation for the validation (Client)
  2. The common library classes to share the objects (DLL)
  3. The Entity classes (API)

I have a feeling that I do something really wrong. Is there something more elegant? I would like to make sure that I have a good solution for this problem before the project gets too big.

هل كانت مفيدة؟

المحلول

I know it may seem like you are converting objects back and forth all the time between your database objects, your data transfer objects, your client objects with validation logic and so on but I'd say that no, you're not doing anything wrong.

Each of these objects may represent the same unit of information, but they have very different responsibilities. The database object is your communication interface with the database and should be kept in the database layer since it may or may not have different database metadata annotations and/or unnecessary details about the database implementation in it.

Your data transfer object is the communication interface with your API consumers. These should be as clean as possible to facilitate easy consumption from different languages/platforms. This might impose certain restrictions on how these look and behave depending on what API consumers you wish to support.

Your client objects with validation logic is really not a part of your API project, they're part of your consumer project. These cannot be the same as the data transfer objects in this case since you are adding extra client-specific logic (in this case validation attributes) on them which the server knows nothing about (and should not know anything about!) You shouldn't count these objects as part of your API, because they're really not. They're highly consumer application specific and some applications that consume your API might actually not even need to create these object and could just as well survive on just your data transfer objects. For example, if you didn't have any need of validation you wouldn't need an extra layer of objects that are completely identical to your data transfer objects. Generally my strategy here is to evolve the project in stages, I start off by plainly using the data transfer objects as my consumer application objects and when I see the need for application specific handling of data (validation, implementing INotifyPropertyChanged, etc..) I do a quick refactoring and add in the new layer as needed.

To me, it seems like each of the three object types map very nicely to a single responsibility which is clean coding and good practice. Sadly, clean code and good practices sometimes means that you are writing a lot of extra code and jumping through extra hoops "just because". And while coding, it may be hard to appreciate the value that this is giving you - but as soon as you release your application and begin supporting it or adding new features for the next version then you will probably start appreciating that you took the time to separate these concerns properly in the first place. (Not to mention that you'll avoid certain problems that might occur due to improper separation of concerns - and since you have avoided these problems it might be hard to appreciate the mess that you can find yourself in when you have not separated your concerns.)

I also hate writing conversion code between different object types like this, but my solution is usually one of the following:

  • Use a library that does most of the object conversion heavy lifting for you - for example, if you use C# you can use the fantastic AutoMapper library (http://automapper.org/). I believe that there's a couple of other libraries like this, but AutoMapper is the most powerful one I've seen so far.
  • If you can't find a library help you with your object conversions, write a set of utility methods for converting between them. This might suck, but it's worth it in the long run, write the conversion method the first time you need to convert something - don't wait.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى softwareengineering.stackexchange
scroll top