Domain-Driven Design Path | Pluralsight
Database
Update Connection Strings:
Project Configuration File Configuration Key ClassifiedAds.Migrator appsettings.json ConnectionStrings:ClassifiedAds ClassifiedAds.BackgroundServer appsettings.json ConnectionStrings:ClassifiedAds ClassifiedAds.IdentityServer appsettings.json ConnectionStrings:ClassifiedAds ClassifiedAds.WebAPI appsettings.json ConnectionStrings:ClassifiedAds ClassifiedAds.WebMVC appsettings.json ConnectionStrings:ClassifiedAds Run Migration:
- Option 1: Using dotnet cli:
- Install dotnet-ef cli:
dotnet tool install --global dotnet-ef --version="5.0" - Navigate to ClassifiedAds.Migrator and run these commands:
dotnet ef migrations add Init --context AdsDbContext -o Migrations/AdsDb dotnet ef migrations add Init --context ConfigurationDbContext -o Migrations/ConfigurationDb dotnet ef migrations add Init --context PersistedGrantDbContext -o Migrations/PersistedGrantDb dotnet ef database update --context AdsDbContext dotnet ef database update --context ConfigurationDbContext dotnet ef database update --context PersistedGrantDbContext
- Install dotnet-ef cli:
- Option 2: Using Package Manager Console:
- Set ClassifiedAds.Migrator as StartUp Project
- Open Package Manager Console, select ClassifiedAds.Migrator as Default Project
- Run these commands:
Add-Migration -Context AdsDbContext Init -OutputDir Migrations/AdsDb Add-Migration -Context ConfigurationDbContext Init -OutputDir Migrations/ConfigurationDb Add-Migration -Context PersistedGrantDbContext Init -OutputDir Migrations/PersistedGrantDb Update-Database -Context AdsDbContext Update-Database -Context ConfigurationDbContext Update-Database -Context PersistedGrantDbContext
- Option 1: Using dotnet cli:
Additional Configuration Sources
Open ClassifiedAds.WebMVC/appsettings.json and jump to ConfigurationSources section.
"ConfigurationSources": {"SqlServer": {"IsEnabled": false,"ConnectionString": "Server=.;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#","SqlQuery": "select [Key], [Value] from ConfigurationEntries"},"AzureKeyVault": {"IsEnabled": false,"VaultName": "https://xxx.vault.azure.net/"}},
Get from Sql Server database:
"ConfigurationSources": {"SqlServer": {"IsEnabled": true,"ConnectionString": "Server=.;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#","SqlQuery": "select [Key], [Value] from ConfigurationEntries"},},
Get from Azure Key Vault:
"ConfigurationSources": {"AzureKeyVault": {"IsEnabled": true,"VaultName": "https://xxx.vault.azure.net/"}},
Use Both:
"ConfigurationSources": {"SqlServer": {"IsEnabled": true,"ConnectionString": "Server=.;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#","SqlQuery": "select [Key], [Value] from ConfigurationEntries"},"AzureKeyVault": {"IsEnabled": true,"VaultName": "https://xxx.vault.azure.net/"}},
Storage
Open ClassifiedAds.WebMVC/appsettings.json, ClassifiedAds.WebAPI/appsettings.json and jump to Storage section.
"Storage": {"Provider": "Local",},
Use Local Files:
"Storage": {"Provider": "Local","Local": {"Path": "E:\\files"},},
Use Azure Blob:
"Storage": {"Provider": "Azure","Azure": {"ConnectionString": "xxx","Container": "classifiedadds"},},
Use Amazon S3:
"Storage": {"Provider": "Amazon","Amazon": {"AccessKeyID": "xxx","SecretAccessKey": "xxx","BucketName": "classifiedadds","RegionEndpoint": "ap-southeast-1"}},
Message Broker
Open below files and jump to MessageBroker section:
- ClassifiedAds.IdentityServer/appsettings.json
- ClassifiedAds.WebMVC/appsettings.json
- ClassifiedAds.WebAPI/appsettings.json
- ClassifiedAds.BackgroundServer/appsettings.json
"MessageBroker": {"Provider": "RabbitMQ",}
Use RabbitMQ
"MessageBroker": {"Provider": "RabbitMQ","RabbitMQ": {"HostName": "localhost","UserName": "guest","Password": "guest","ExchangeName": "amq.direct","RoutingKeys": {"FileUploadedEvent": "classifiedadds_fileuploaded","FileDeletedEvent": "classifiedadds_filedeleted","EmailMessageCreatedEvent": "classifiedadds_emailcreated","SmsMessageCreatedEvent": "classifiedadds_smscreated"},"QueueNames": {"FileUploadedEvent": "classifiedadds_fileuploaded","FileDeletedEvent": "classifiedadds_filedeleted","EmailMessageCreatedEvent": "classifiedadds_emailcreated","SmsMessageCreatedEvent": "classifiedadds_smscreated"}}}
Use Kafka:
"MessageBroker": {"Provider": "Kafka","Kafka": {"BootstrapServers": "localhost:9092","Topics": {"FileUploadedEvent": "classifiedadds_fileuploaded","FileDeletedEvent": "classifiedadds_filedeleted","EmailMessageCreatedEvent": "classifiedadds_emailcreated","SmsMessageCreatedEvent": "classifiedadds_smscreated"},}}
Use Azure Queue Storage:
"MessageBroker": {"Provider": "AzureQueue","AzureQueue": {"ConnectionString": "xxx","QueueNames": {"FileUploadedEvent": "classifiedadds-fileuploaded","FileDeletedEvent": "classifiedadds-filedeleted","EmailMessageCreatedEvent": "classifiedadds-emailcreated","SmsMessageCreatedEvent": "classifiedadds-smscreated"}}}
Use Azure Service Bus:
"MessageBroker": {"Provider": "AzureServiceBus","AzureServiceBus": {"ConnectionString": "xxx","QueueNames": {"FileUploadedEvent": "classifiedadds_fileuploaded","FileDeletedEvent": "classifiedadds_filedeleted","EmailMessageCreatedEvent": "classifiedadds_emailcreated","SmsMessageCreatedEvent": "classifiedadds_smscreated"}}}
Use Azure Event Grid:
"MessageBroker": {"Provider": "AzureEventGrid","AzureEventGrid": {"DomainEndpoint": "https://xxx.xxx-1.eventgrid.azure.net/api/events","DomainKey": "xxxx","Topics": {"FileUploadedEvent": "classifiedadds_fileuploaded","FileDeletedEvent": "classifiedadds_filedeleted""EmailMessageCreatedEvent": "classifiedadds_emailcreated","SmsMessageCreatedEvent": "classifiedadds_smscreated"}}}
Use Azure Event Hubs:
"MessageBroker": {"Provider": "AzureEventHub","AzureEventHub": {"ConnectionString": "Endpoint=sb://xxx.servicebus.windows.net/;SharedAccessKeyName=xxx;SharedAccessKey=xxx","Hubs": {"FileUploadedEvent": "classifiedadds_fileuploaded","FileDeletedEvent": "classifiedadds_filedeleted","EmailMessageCreatedEvent": "classifiedadds_emailcreated","SmsMessageCreatedEvent": "classifiedadds_smscreated"},"StorageConnectionString": "DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xxx;EndpointSuffix=core.windows.net","StorageContainerNames": {"FileUploadedEvent": "eventhub-fileuploaded","FileDeletedEvent": "eventhub-filedeleted","EmailMessageCreatedEvent": "eventhub-emailcreated","SmsMessageCreatedEvent": "eventhub-smscreated"}}}
Logging
- Open and jump to Logging section of below files:
- ClassifiedAds.WebAPI/appsettings.json
- ClassifiedAds.WebMVC/appsettings.json
- ClassifiedAds.IdentityServer/appsettings.json
- ClassifiedAds.BackgroundServer/appsettings.json
"Logging": {"LogLevel": {"Default": "Warning"},"File": {"MinimumLogEventLevel": "Information"},"Elasticsearch": {"IsEnabled": false,"Host": "http://localhost:9200","IndexFormat": "classifiedads","MinimumLogEventLevel": "Information"},"EventLog": {"IsEnabled": false,"LogName": "Application","SourceName": "ClassifiedAds.WebAPI"}},
- Write to Local file (./logs/log.txt). Always enabled.
"Logging": {"File": {"MinimumLogEventLevel": "Information"},},
- Write to Elasticsearch:
"Logging": {"Elasticsearch": {"IsEnabled": true,"Host": "http://localhost:9200","IndexFormat": "classifiedads","MinimumLogEventLevel": "Information"},},
- Write to Windows Event Log (Windows only):
"Logging": {"EventLog": {"IsEnabled": true,"LogName": "Application","SourceName": "ClassifiedAds.WebAPI"}},
- Enable all options:
"Logging": {"LogLevel": {"Default": "Warning"},"File": {"MinimumLogEventLevel": "Information"},"Elasticsearch": {"IsEnabled": true,"Host": "http://localhost:9200","IndexFormat": "classifiedads","MinimumLogEventLevel": "Information"},"EventLog": {"IsEnabled": true,"LogName": "Application","SourceName": "ClassifiedAds.WebAPI"}},
Caching
- Open and jump to Caching section of below files:
- ClassifiedAds.WebAPI/appsettings.json
- ClassifiedAds.WebMVC/appsettings.json
- ClassifiedAds.IdentityServer/appsettings.json
"Caching": {"InMemory": {},"Distributed": {}},
- Configure options for In Memory Cache:
"Caching": {"InMemory": {"SizeLimit": null},},
- Use In Memory Distributed Cache (For Local Testing):
"Caching": {"Distributed": {"Provider": "InMemory","InMemory": {"SizeLimit": null}}},
- Use Redis Distributed Cache:
"Caching": {"Distributed": {"Provider": "Redis","Redis": {"Configuration": "xxx.redis.cache.windows.net:6380,password=xxx,ssl=True,abortConnect=False","InstanceName": ""}}},
- Use Sql Server Distributed Cache:
dotnettoolinstall--globaldotnet-sql-cache--version="5.0"dotnetsql-cachecreate"Server=.;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#"dboCacheEntries
"Caching": {"Distributed": {"Provider": "SqlServer","SqlServer": {"ConnectionString": "Server=.;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#","SchemaName": "dbo","TableName": "CacheEntries"}}},
Monitoring
- Open and jump to Monitoring section of below files:
- ClassifiedAds.WebAPI/appsettings.json
- ClassifiedAds.WebMVC/appsettings.json
- ClassifiedAds.IdentityServer/appsettings.json
"Monitoring": {"MiniProfiler": {},"AzureApplicationInsights": {}},
- Use MiniProfiler:
"Monitoring": {"MiniProfiler": {"IsEnabled": true,"SqlServerStorage": {"ConectionString": "Server=.;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#;MultipleActiveResultSets=true","ProfilersTable": "MiniProfilers","TimingsTable": "MiniProfilerTimings","ClientTimingsTable": "MiniProfilerClientTimings"}},},
- Use Azure Application Insights:
"Monitoring": {"AzureApplicationInsights": {"IsEnabled": true,"InstrumentationKey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","EnableSqlCommandTextInstrumentation": true}},
- Use AppMetrics:
"Monitoring": {"AppMetrics": {"IsEnabled": true,"MetricsOptions": {"DefaultContextLabel": "ClassifiedAds.WebAPI","Enabled": true,"ReportingEnabled": true},"MetricsWebTrackingOptions": {"ApdexTrackingEnabled": true,"ApdexTSeconds": 0.1,"IgnoredHttpStatusCodes": [404],"IgnoredRoutesRegexPatterns": [],"OAuth2TrackingEnabled": true},"MetricEndpointsOptions": {"MetricsEndpointEnabled": true,"MetricsTextEndpointEnabled": true,"EnvironmentInfoEndpointEnabled": true}}},
- Use Both:
"Monitoring": {"MiniProfiler": {"IsEnabled": true,"SqlServerStorage": {"ConectionString": "Server=.;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#;MultipleActiveResultSets=true","ProfilersTable": "MiniProfilers","TimingsTable": "MiniProfilerTimings","ClientTimingsTable": "MiniProfilerClientTimings"}},"AzureApplicationInsights": {"IsEnabled": true,"InstrumentationKey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","EnableSqlCommandTextInstrumentation": true},"AppMetrics": {"IsEnabled": true,"MetricsOptions": {"DefaultContextLabel": "ClassifiedAds.WebAPI","Enabled": true,"ReportingEnabled": true},"MetricsWebTrackingOptions": {"ApdexTrackingEnabled": true,"ApdexTSeconds": 0.1,"IgnoredHttpStatusCodes": [404],"IgnoredRoutesRegexPatterns": [],"OAuth2TrackingEnabled": true},"MetricEndpointsOptions": {"MetricsEndpointEnabled": true,"MetricsTextEndpointEnabled": true,"EnvironmentInfoEndpointEnabled": true}}},
Interceptors
- Open and jump to Interceptors section of below files:
- ClassifiedAds.WebAPI/appsettings.json
- ClassifiedAds.WebMVC/appsettings.json
- ClassifiedAds.IdentityServer/appsettings.json
- ClassifiedAds.BackgroundServer/appsettings.json
"Interceptors": {"LoggingInterceptor": true,"ErrorCatchingInterceptor": false},
Security Headers
- Open ClassifiedAds.WebAPI/appsettings.json and jump to SecurityHeaders section:
"SecurityHeaders": {"Cache-Control": "no-cache, no-store, must-revalidate","Pragma": "no-cache","Expires": "0"},
- Open ClassifiedAds.WebMVC/appsettings.json and jump to SecurityHeaders section:
"SecurityHeaders": {"Content-Security-Policy": "form-action 'self'; frame-ancestors 'none'","Feature-Policy": "camera 'none'","Referrer-Policy": "strict-origin-when-cross-origin","X-Content-Type-Options": "nosniff","X-Frame-Options": "DENY","X-XSS-Protection": "1; mode=block","Cache-Control": "no-cache, no-store, must-revalidate","Pragma": "no-cache","Expires": "0"},
Cross-Origin Resource Sharing (CORS)
- Open ClassifiedAds.WebAPI/appsettings.json and jump to CORS section:
"CORS": {"AllowAnyOrigin": false,"AllowedOrigins": ["http://localhost:4200","http://localhost:3000","http://localhost:8080"]},
- Open ClassifiedAds.NotificationServer/appsettings.json and jump to CORS section:
"CORS": {"AllowedOrigins": ["https://localhost:44364","http://host.docker.internal:9003"]}
External Login
- Open ClassifiedAds.IdentityServer/appsettings.json and jump to ExternalLogin section:
"ExternalLogin": {"AzureActiveDirectory": {"IsEnabled": true,"Authority": "https://login.microsoftonline.com/<Directory (tenant) ID>","ClientId": "<Application (client) ID","ClientSecret": "xxx"},"Microsoft": {"IsEnabled": true,"ClientId": "<Application (client) ID","ClientSecret": "xxx"},"Google": {"IsEnabled": true,"ClientId": "xxx","ClientSecret": "xxx"},"Facebook": {"IsEnabled": true,"AppId": "xxx","AppSecret": "xxx"}},
Sending Email
- Open ClassifiedAds.BackgroundServer/appsettings.json and jump to Notification -> Email section:
"Notification": {"Email": {"Provider": "Fake",}}
- Use SmtpClient:
"Notification": {"Email": {"Provider": "SmtpClient","SmtpClient": {"Host": "localhost","Port": "","UserName": "","Password": "","EnableSsl": ""}}}
Sending SMS
- Open ClassifiedAds.BackgroundServer/appsettings.json and jump to Notification -> Sms section:
"Notification": {"Sms": {"Provider": "Fake",}}
- Use Twilio
"Notification": {"Sms": {"Provider": "Twilio","Twilio": {"AccountSId": "","AuthToken": "","FromNumber": ""}}}
Web MVC Home Page: https://localhost:44364/
Navigate to Health Checks UI https://localhost:44364/healthchecks-ui#/healthchecks and make sure everything is green.
Login on Identity Server:
- Option 1: Use default created account:
- User Name: phong@gmail.com
- Password: v*7Un8b4rcN@<-RN
- Option 2: Register new account at https://localhost:44367/Account/Register
- Option 1: Use default created account:
Open Blazor Home Page at: https://localhost:44331
Angular:
Navigate to folder: UIs/angular/
npm install ng serveUpdate environment.ts & environment.prod.ts
exportconstenvironment={OpenIdConnect: {Authority: "https://localhost:44367",ClientId: "ClassifiedAds.Angular"},ResourceServer: {Endpoint: "https://localhost:44312/api/"},CurrentUrl: "http://localhost:4200/"};
Go to http://localhost:4200/
React:
Navigate to folder: UIs/reactjs/
npm install npm run startUpdate environment.dev.js & environment.js
constenvironment={OpenIdConnect: {Authority: "https://localhost:44367",ClientId: "ClassifiedAds.React"},ResourceServer: {Endpoint: "https://localhost:44312/api/"},CurrentUrl: "http://localhost:3000/"};exportdefaultenvironment;
Go to http://localhost:3000/
Vue:
- Navigate to folder: UIs/vuejs/
npm install npm run serve - Update environment.dev.js & environment.dev.js
constenvironment={OpenIdConnect: {Authority: "https://localhost:44367",ClientId: "ClassifiedAds.Vue"},ResourceServer: {Endpoint: "https://localhost:44312/api/"},CurrentUrl: "http://localhost:8080/"};exportdefaultenvironment;
- Navigate to folder: UIs/vuejs/
Go to http://localhost:8080/
Before Login, go to Identity Server https://localhost:44367/Client to make sure application clients have been registered:
Add Migrations if you haven't done on previous steps:
- Install dotnet-ef cli:
dotnet tool install --global dotnet-ef --version="5.0" - Navigate to ClassifiedAds.Migrator and run these commands:
dotnet ef migrations add Init --context AdsDbContext -o Migrations/AdsDb dotnet ef migrations add Init --context ConfigurationDbContext -o Migrations/ConfigurationDb dotnet ef migrations add Init --context PersistedGrantDbContext -o Migrations/PersistedGrantDb
- Install dotnet-ef cli:
Navigate to Monolith and run:
docker-compose build docker-compose upOpen Web MVC Home Page at: http://host.docker.internal:9003
Navigate to Health Checks UI http://host.docker.internal:9003/healthchecks-ui#/healthchecks and make sure everything is green.
Login on Identity Server:
- Use default created account: phong@gmail.com / v*7Un8b4rcN@<-RN
- Register new account at http://host.docker.internal:9000/Account/Register
Open Blazor Home Page at: http://host.docker.internal:9008
Update ClassifiedAds.IntegrationTests/appsettings.json
{"OpenIdConnect": {"Authority": "https://localhost:44367","ClientId": "ClassifiedAds.WebMVC","ClientSecret": "secret","RequireHttpsMetadata": "true"},"WebAPI": {"Endpoint": "https://localhost:44312"},"GraphQL": {"Endpoint": "https://localhost:44392/graphql"},"Login": {"UserName": "phong@gmail.com","Password": "v*7Un8b4rcN@<-RN","Scope": "ClassifiedAds.WebAPI"}}
Download Chrome Driver
Update ClassifiedAds.EndToEndTests/appsettings.json
{"ChromeDriverPath": "D:\\Downloads\\chromedriver_win32\\72","Login": {"Url": "https://localhost:44364/Home/Login","UserName": "phong@gmail.com","Password": "v*7Un8b4rcN@<-RN"}}
https://github.com/phongnguyend/Practical.CleanArchitecture/wiki/Application-URLs
https://github.com/phongnguyend/Practical.CleanArchitecture/wiki/Roadmap




















