design: in MVC + SOA Architecture, what is the reason for placing business logic in the models?

When writing web applications I put business logic in the controllers. This has worked well for my small team of application developers: our applications run reliably, work well and the code is easy to maintain. See below an explanation of my design.

Contrary to my architecture, the advice I find in the programming forums often advocate putting the business logic in the models. I would like to understand why.

Based on your experience in creating MVC + SOA applications, why
warns against the placement of logic in controllers and advocates
Putting logic in the models? What is its justification and what is the pro /
Compensation regarding my design?

I admit that my design is influenced by my use of Refit, a secure REST proxy for the C # type. One of the reasons why I do not want to place the business logic in a model (or entity) is because I define the interfaces and the service entities in a contract DLL shared by the service (WebAPI) and the clients (web sites). MVC or console applications). I do not want the details of data persistence to be leaked to the client (through the methods Load, Save, Approve, Reject, etc. in the entity).

Another influence comes from my desire to resolve the contradiction in these familiar design principles:

  • Entities must be persistent-agnostic. That is, they must not know how they are stored in a database or in a Content Management System (CMS).
  • In MVC, place the business logic in the model.

If the "business logic" includes SQL or CMS statements, the principles are contradictory. If the "business logic" does not include SQL or CMS statements, this implies the introduction of another layer: the data transfer object (DTO). Oh God, not another layer.

Also, I feel that the inertia of the latest popular paradigm is causing the object-oriented design (OO) (where the object is everything) to enter our MVC + SOA world. Hence the advice to place the business logic in the model (the object).

OK, enough introduction. Here is my MVC + SOA architecture (for a Microsoft stack):

MVC + SOA Design

MVC = Model View Controller, SOA = Service Oriented Architecture

  • A model transfers data and UI (validation rules, selection of selection lists,
    etc) between a controller and a view.
  • A view receives a model and represents HTML using the Razor syntax.
  • A controller receives a model (through the link of the ASP.NET model) and executes the business logic, either locally (2-level architecture) or externally (3-level architecture).
    • If it is locally, the controller communicates directly with a data warehouse
      (database or file).
    • If externally, the controller communicates with a
      External service (s) used by the Refit proxy (and the service is communicated)
      directly with a data warehouse).
  • Minimizes business logic in views and models. A view must be thin, hence the name "Razor".
  • Maximize business logic in controllers.
  • Note the difference between SOA and OO.
    • SOA emphasizes the encapsulation logic in service controllers, separated from the data.
      • Exposed through HTTP / JSON / Refit interfaces.
      • Models and entities are used for validation and data transfer.
    • OO emphasizes encapsulating logic in objects, close to the data.

Business entities

  • Similar to the models, it minimizes the business logic in the entities.
  • Separate models of entities.
    • A model transfers data and UI between a controller and a view (see above).
    • A model makes do not transfer data between a controller and a data warehouse or service.
      • This prevents excessive publication (the hacker adds additional form fields to override the default values ​​of the model).
      • This facilitates step by step forms of several pages with different fields required on each page. Define a model for each page. The union of all fields in all models = set of properties in the entity.
    • An entity transfers data between a controller and a data warehouse or service.
    • An entity does not contain any UI (validation rules, selection of selection lists, etc.).
  • An entity can do not reference a model
  • A model can refer to an entity.
    • The constructor accepts the entity parameter, assigns the properties of the entity to the properties of the model.
    • The ToEntity () method creates an entity, assigns the properties of the model to the properties of the entity.
  • The dependencies flow in one direction:
    • MVC website – (depends on) -> Entity
    • If the local data store (2-level architecture), MVC website – (depends on) -> ORM (such as Dapper or Entity Framework Core)
    • If it is an external data warehouse (3-level architecture), MVC website – (depends on) -> Reconditioning service proxy

Fundamental reason

  1. Prevention of attacks of over publication and flexibility of the user interface (present as a complex form or form divided into several pages) independent of the entity.
  2. Separation of concerns: the models specify validation rules and transfer data to / from the user interface, the entities transfer data to / from the service, the controllers sequence the tasks and apply the business logic.
  3. The change of backup services or data stores does not affect the model or the view, only the controller.
  4. The logic in the service controllers is reusable: it is exposed through HTTP endpoints and can be called from any client written in any language.
  5. My use of Refit C # proxies in no way prevents AJAX. In fact, we make many UI updates through jQuery calls to service controllers, secured by JWT tokens.