I couple of months ago, I shared a simple and partial solution showing how use ADO.Net with CQRS using technologies representing a sort of “base” on a DDD approach.
So I decided to invest a bit of time, that is foundamentally a relative concept ;) to share a beta working solution. I will not spent too much time to edulcorate this story but I wish to use this space and your time to share some interest points.
First of all, let me say that this solution allow you to create a company organization add employees, contacts and other stuff and here below you can find the technology stack
Front End : Typescript, Redux, Router, Axios, Toast, Formik, Yup, Material-Ui
Back End : NetCore 3.1, EF Core, Dapper, Autofac, MediaR
The DB is a sql server 2019 instance and here below a simple diagram displaying tables relationship. As you can see there’s few type columns populated using relative reference tables.
The solution is based on different projects : Api, Application, Domain and Infrastructure.
Let’s take a quick tour starting from Crm.Api project and its startup file.
In the ConfigureServices there’s a Initialize call to a function exposed by infrastructure project in which some parameters are used to create instances invoked by other projects i.e. the connection string.
The Crm.Infrastructure receive these parameters and uses them to register in the container builder all the interfaces and relative concrete classes required by solution.
UseQuerySplittingBehavior to split queries and increase EF Core performances.
Take a look at row 35. Here you have the possibilily to improve the EF Core performances using this specific behavior that split the execution queries instead use a single one. The impact is relevant as displayed in the execution plan in which timing and rows selected are two simples indicators about differences.
Moving on Crm.Api project lets verify which are the differences between read and write operations.
Is useful look at this simple Get that return a list of addresses.
From route it get the Company Id and create a new instance of GetCompanyAddressesQuery type which implement IRequest interface.
The mediator send this request to a single handler.
Basically the mediator use the resolve method to select the class that implement IRequestHandler with a specific type. The implementation of the handler function contains the relative logic.
If everything works , this should be “the one” :)
The ISqlConnectionFactory is injected and used to open a connection. Dapper execute an async query returning a list of addresses.
In the other side we have commands : create, update, delete.
The logic is basically similar for both commands so let’s take a look at create command.
Also in this case the http post function get from route the Company Id, create a new RegisterCompanyEmployeeCommand type and send it to mediator.
Classes implementing ICommandHandler should use the repository pattern to access at db as shown by the RegisterCompanyEmployeeCommandHandler class above.
The Handle function call the GetByIdAsync receiving a domain entity object Company exposing some public functions as the CreateEmployee that add to a private property _employee a new employee
The function return a Id used by the api to create a 201 HttpStatus response.
The GUI is pretty simple, is a scratch from a standard dashboard customized with material-UI components. Here below you can find a simple interactions.
For this project could be interesting take a took at the following topics.
The store creation pass through the call of ConfigureStore in which is passed an object contains all reducers
Now we can see how a reducer works.
At the top is declared an interface ContactTypeState that basically contains an array of ContactType and then is set its initial state.
Use CreateSlice to define some functions that interact with our store objects that become accessible destructuring the ContactTypesSlice.actions (row 45)
Starting from row 51 the getContactTypes invoke using Axios client an end-point and dispatching actions that modify objects status.
At the end we can use contactTypesSelector to retrieve objects and status from store.
The view is the component used to render something. In this case we can see how a ActivityCompanyView is structured and which are the material ui components used.
The toolbar is the component used to create new Activities . Use Formik to create a form with all components required and assign to a fab component the responsibility to submit all values.
The submit invoke the onAddActivity
that dispatch a new action addCompanyActivity and manage the animation modify its status using setSuccess and setSaveLoading.
If you are tired to read here you can find the whole source code :)
Contribute to massimomannoni/CRM_BE development by creating an account on GitHub.
Contribute to massimomannoni/CRM_FE development by creating an account on GitHub.