design: in an MVC + SOA architecture I believe that the business logic goes in the controller. Why am I wrong?

I conceived and implemented this design (see below) for a small business process automation project (form + approval workflow). It worked well. I am planning a larger and more complex workflow and forms project, and I want to ensure that my architecture facilitates the construction of a reliable, high performance and easy to maintain solution.

The advice I found online contradicts my design. The consensus in the MVC programming forums is that business logic must be placed in the model. I would like to know your opinion on the subject, so let me expand my question on two more useful questions:

  1. Based on your experience in creating MVC + SOA applications, why should I caution against my design and advocate for business logic in the models? What is your justification and what is the pro / con compensation compared to my design?

  2. Have you created an application using the design I defend below?
    What were your experiences, good and bad?

I will begin by admitting that my design is influenced by my love for Refit, a REST proxy of C # sure for the type. One of the reasons why I do not want to put business logic into a model (or entity) is because I define interfaces and service entities in a contract DLL shared by the service (WebAPI) and the clients (MVC website or console application). 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 last major paradigm shift is causing the object-oriented design (OO) (where the object is everything) to enter our MVC + SOA world. Hence the advice to put 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