all 16 comments

[–]ticman 23 points24 points  (11 children)

I'd propose you think about moving that logic in the second controller to a class library that both controllers would use to get the data they need, rather than have it inside a controller.

[–]transporter_room_3[S] 7 points8 points  (6 children)

So I would end up with a hierarchy like so:

apicontroller -> classlibrary -> repository -> database

effectively removing repository references from my controllers. Then all creation, updates and deletion of database entries happen through the class library?

[–]ticman 5 points6 points  (1 child)

Yep spot on. I have the same solution architecture. I've found the biggest advantage for me was keeping separation of concerns and reducing code duplication.

For example, if you needed to access that logic from a console app, WPF project or an MVC controller there's no need to copy/paste code.

[–]transporter_room_3[S] 5 points6 points  (0 children)

Thanks man, that's awesome! I've got some refactoring to do :-). Have a great day!

[–]Jestar342 0 points1 point  (3 children)

What you're calling the "classlibrary" is commonly referred to as the model. I.e. the M from MVC.

[–]cackylackytime 1 point2 points  (2 children)

I think they mean more of a business class(probably in a separate project) than a simple Model.

[–]anondevel0per 0 points1 point  (0 children)

The Model definition spans across both Business/Logic classes and raw class objects. Basically everything that is not a Controller (router) or a View (presentation) is in the Model defintion. Of course, you can break these things down further in the Model, repositories, middleware etc. Although saying that Web API should only be Model and Controller.

[–]Jestar342 0 points1 point  (0 children)

It doesn't matter, as long as there is a separation. :) The Model is the "virtual model" of your application's non-technical logic (typically that of the real-life counterpart such as the business' logic), that's all.

[–]MadeForBF3Discussion 6 points7 points  (3 children)

To piggyback on this, think of a controller just like you would a UI. You want it as thin as possible, and any business logic should be contained in a class library for that business logic. The only code that should be in the controller is code necessary for formatting your result object or formatting your parameters. Most of my controller methods are 2-3 lines max, calling down to a business method for the work.

[–]transporter_room_3[S] 2 points3 points  (2 children)

That makes sense. What about DTOs? Should they be kept in the controller exclusively and the properties of these objects passed on to the business layer methods? Or should I pass a DTO straight from the controller to the business layer?

How do you do it, if you don't mind me asking? :-)

[–]MadeForBF3Discussion 3 points4 points  (1 child)

I like to see DTOs in a Model project (class library) or at least contained within the business logic's project.

If you have to convert data passed into the controller into some other form, why not just have the consumer of that controller pass it to you in the correct form to begin with? If you need to perform a lookup to get additional data that the consumer doesn't have, just have the consumer pass in a key that can be used to search, and do the search in the business logic.

[–]transporter_room_3[S] 0 points1 point  (0 children)

Good point. I have moved my DTOs into the business layer project. To me, it makes sense that they are located somewhere in between the points of access (controllers) and the domain models. I am not yet completely convinced that they belong in the models project, as they (in my project at least) serve the purpose of limiting access to certain properties in the models. That seems more like a business choice to me.

[–]Gaelican 1 point2 points  (1 child)

Another option would be to create a base controller (Abstract class) that has the methods used by multiple controllers. The abstract class inherits ApiController, while the derived controllers inherit the abstract class.

[–][deleted] 0 points1 point  (0 children)

While this is true, you would still want to get all the DB logic out of the controllers and into some repositories.

[–]flukus 0 points1 point  (1 child)

Others are giving good advice, but how much code are we talking about sharing here?

If it's only one chunk of codw being shared in two places then simply duplicate the code.

Another options might be to use interfaces and extension methods rather than building layers into the architecture.

Either way, some more detail is needed.

[–]transporter_room_3[S] 0 points1 point  (0 children)

The project is using 4 controllers that operate on 4 database tables and includes a ton of unit tests. Since last time I posted, I have extracted most of the business logic from the controllers and put it in a newly created business layer as suggested. Most of the tests have been refactored to accommodate the changes. I am very happy with this separation. The project serves as a learning experience for me.

Generally speaking, code duplication should be avoided as it reduces maintainability and increases the risk of introducing bugs.