Handlers
The framework uses the mediator architectural principle: Request -> Handler -> Response. Handler is a small piece of business logic, completely independent of other logic, thus allows you to change it without the need to make changes to other components of the project. A handler should be responsible for one certain task. A handler must comply with SOLID principles.
-
Single-responsibility principle. A class should only have a single responsibility, that is, only changes to one part of the software's specification should be able to affect the specification of the class.
-
Open-closed principle. Software entities should be open for extension, but closed for modification.
-
Liskov substitution principle. Objects in a program should be replaceable with instances of their sub-types without altering the correctness of that program.
-
Interface segregation principle. Many client-specific interfaces are better than one general-purpose interface.
-
Dependency inversion principle. One should depend upon abstractions, not concretions.
The Handler accepts a Request - this is a specific data format that tells the handler about what actions it needs to perform and what data to process. Having completed all the necessary actions, the handler returns a Response with the processing results, or a report of the problems encountered. Also, a request and handler may have configurations, which provides additional information for executing the request, for example, the connection string to the database or the maximum number of records to load.
-
Id - unique identifier of the request. This field is mandatory.
-
InvokerId - request identifier that caused the current request. This field is optional. If this field is set in all requests, then you can build a chain of invocations.
-
CorrelationId - request group identifier. This field is optional. If this field is set in all requests, then you can track all requests that relate to a particular web page, data import or calculation.
-
Timeout - the maximum time to complete the request. This field is optional. If this time is exceeded, the request will be aborted.
-
Id - unique response identifier, corresponds to the request identifier. This field is mandatory.
-
InvokerId - request identifier that caused the current request. This field is optional. If this field is set in all requests, then you can build a chain of calls.
-
CorrelationId - request group identifier. This field is optional. If this field is set in all requests, then you can track all requests that relate to a particular web page, data import or calculation.
-
IsCanceled - mark that the execution of the request was interrupted.
-
IsSucceeded - mark that the request was completed successfully.
-
Exception - if an error occurred during the execution of the request, information about it will be contained in this field.
The handler that implements the basic functionality is called InternalHandler. Other handlers are inherited from base handler: SqlHandler, ElasticSearchHandler, ApplicationHandler, etc. Each layer uses its own base handler, from which all handlers of the corresponding layer should be inherited. Handlers have associated requests, responses and configurations. The main essence of the handler is that it performs a strictly defined task, has a minimum number of dependencies and in no way depends on the implementation of other handlers. The only thing that links the handlers to each other are requests and responses. One handler can call another, passing it a request of a certain type. The are two types of requests and responses in the framework:
-
InternalRequest, InternalResponse - internal request is processed by InternalHandler withing the application, an internal response is returned. InternalRequest and InternalResponse can't leave application boundaries, because they may contain non-serializable properties.
-
ExternalRequest, ExternalResponse - are not processed by handler directly. At first a request should be converted into InternalRequest, processed by InternalHandler, then an InternalResponse will be converted to ExternalResponse. ExternalRequest and ExternalResponse contain serializable data only, so they may leave application boundaries.
The framework contains several predefined handlers, that simplify the development for common case scenarios:
- Application handlers
-
CreateRecordApplicationHandler - creates new records or clones existing records. It creates, validates, saves new records and returns a certain projection to a caller.
-
LoadRecordApplicationHandler - loads records. This handler doesn't load data directly. Instead it is used as a hub, that may request to load data from different databases or services and join it.
-
ReadRecordFromExcelApplicationHandler - reads records from excel seed files.
-
SaveRecordApplicationHandler - saves records. This handler doesn't save data directly. Instead it is used as a hub, that may save data to different databases or services. It may validate, save records and returns a certain projection to a caller.
-
SeedRecordFromExcelApplicationHandler - executes read handler and saves received records.
-
ValidateRecordApplicationHandler - validates records and returns a certain projection to a caller.
-
- Sql handlers
-
LoadRecordSqlHandler - loads records from a SQL database.
-
SaveRecordSqlHandler - saves records to a SQL database.
-
QueryRecordSqlHandler - constructs a query with filter and permissions.
-