Overview
Please make sure that you have been looked them, those would provide you an overview (config and run hello sample), retrieving the list of staff (part 1 & part 2) and create new staff also.
As mentioned in previous article, the whole project will be split into multiple smaller modules/ domains. This raise new problem is "how could those modules/domains communicate each others", as some business flows span through more than 1 modules. Let investigate more detail, how can we solve this problem.
Note: In this series of articles, module and domain can be used interchangeable, except, a module can contain more than 1 domain run as monolithic application. So you can apply the rules both module and domain in similar way.
Let see this scenario: with new requirement, we want our staff can be logged into system, so it means that system should create new login account along with "create new staff" process.
And this login feature can be re-used for other in the future. such as, customer, .....
Update "Add new staff" feature
Let add 2 more fields email and password into "add new staff" screen:
We also need to update on StaffHandler also, change CreateStaffRequest as below:
public class CreateStaffRequest : IBaseCommand
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public CreateStaffRequest(string firstName, string lastName, string email, string password)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Email = email;
this.Password = password;
}
}
let update Handle(CreateStaffRequest request) in StaffCommandHandler class:
public CreateStaffResponse Handle(CreateStaffRequest command)
{
this.Validate(command);
IAccountFacade accountFacade = IoC.Container.Resolve<IAccountFacade>();
using (IUnitOfWork uow = this.CreateUnitOfWork<TinyERP.HRM.Aggregate.Staff>()) {
CreateAccountRequest createAccountRequest = new CreateAccountRequest(command.FirstName, command.LastName, command.Email, command.Password, command.Password);
createAccountRequest.Roles.Add(new Role(SecurityRoleType.Administrator, SecurityRoleType.Administrator, SecurityRoleType.Administrator, Modules.All, TinyERP.Common.ItemStatus.Active));
CreateAccountResponse createAccountResponse = accountFacade.CreateAccount(createAccountRequest);
TinyERP.HRM.Aggregate.Staff staff = new Aggregate.Staff();
staff.UpdateBasicInfo(command);
staff.UpdateAccount(createAccountResponse.AccountId);
IStaffRepository repository = IoC.Container.Resolve<IStaffRepository>(uow);
repository.Add(staff);
uow.Commit();
staff.PublishEvents();
return ObjectHelper.Cast<CreateStaffResponse>(staff);
}
}
With a minor change at line number 4,6,7,8. We call to security module for creating new login account with provided information from "CreateStaffRequest".
Then, and reference to this account will be updated as partial information of Staff aggregate. see line number 11.
We can see that, "creating new account" and "creating new staff" was not in the same transaction. We will talk again this in "Saga pattern".
For TinyERP.Security package, please install it from nuget package. see TinyERP.Security (https://www.nuget.org/packages/TinyERP.Security/) for more information.
Check the reference part of TinyERP.HRM project, we can see that, there are many sub-project added also:
Security was implemented as micro-service and also using CQRS pattern for high performance system.
System may throw some exception, ignore it for now. we will fix them in future. what we need to do now is providing the connection string for TinyERP.Security, as mentioned, this was implemented using CQRS, so we need to config both write (MSSQL) and read database (MongoDB), add below configuration into "configuration.debug.config\aggregates" sections:
<add name="TinyERP.Security.Share.Context.ISecurityQueryDbContext" repoType="MongoDb" connectionStringName="DefaultMongoDb"></add>
<add name="TinyERP.Security.Share.Context.ISecurityDbContext" repoType="MSSQL" connectionStringName="DefaultMSSQL"></add>
The result for this config file was similar as:
<aggregates>
<add name="TinyERP.HRM.Context.IHRMQueryContext" repoType="MongoDb" connectionStringName="DefaultMongoDb"></add>
<add name="TinyERP.HRM.Context.IHRMContext" repoType="MSSQL" connectionStringName="DefaultMSSQL"></add>
<add name="TinyERP.Security.Share.Context.ISecurityQueryDbContext" repoType="MongoDb" connectionStringName="DefaultMongoDb"></add>
<add name="TinyERP.Security.Share.Context.ISecurityDbContext" repoType="MSSQL" connectionStringName="DefaultMSSQL"></add>
</aggregates>
Please aware and input correct value for repoType, currently, value can be 1 of "MSSQL" or "MongoDb". We can support more repository later, such as: RavenDb, ElasticSearch, Json file, Azure Blob, ....
ISecurityQueryDbContext and ISecurityDbContext were used as read and write context into appropriated database.
We also install TinyERP.Security package into TinyERP.Api also.
Let compile and run the app again. the UI looks like this:
Please do not aware on missing "confirm password" field. It was not important at the moment.
Click on Save and navigate back to "Staffs" page:
It was the same as previous part. Let check MSSQL database, there were 2 new tables named App_Security_User_Roles and App_Security_Users.
Those was generated automatically by TinyERP.Security, open those tables we have:
There are 2 users:
- contact@tranthanhtu.vn was created by system, there are many roles attached to this user. See all roles with userId is "ECB06DF4-CC65-4134-9E44-EC1AFC9EF3EF".
- tu.tran@email.com: this was new login account was just created.
In mongodb, open AccountSummary, we have:
We can see that, 1 record for AccountSummary in mongodb (read-site) contains all necessary information related to account. So in the future, we do not need to join between tables to get this information, this also improve performance for you system.
There are some awareness for enterprise application development:
- The app should be divided into smaller modules/ domains.
- Each module/ domain should have a single purpose.
- Each module/ domain will manage its behavior/ data and should be isolated with others.
- Each module/ domain should access to data in other module/ domain through single public interface.
For more information about source-code for this part, please have a look at https://github.com/tranthanhtu0vn/TinyERP (in feature/module_communication).
Other articles in series
Thank you for reading,CodeProject