当前位置: 首页 > 软件库 > 大数据 > 数据查询 >

Practical.CleanArchitecture

授权协议 Readme
开发语言 Java
所属分类 大数据、 数据查询
软件类型 开源软件
地区 不详
投 递 者 巫新知
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

Domain-Driven Design Path | Pluralsight

Database Centric vs Domain Centric Architecture

(open on draw.io)

Hexagonal Architecture

(open on draw.io)

Onion Architecture

(open on draw.io)

The Clean Architecture

(open on draw.io)

Classic Three-layer Architecture

(open on draw.io)

Modern Four-layer Architecture

(open on draw.io)

Layer Dependencies

(open on draw.io)

Layer Examples

(open on draw.io)

Solution Structure

How to Run:

Update Configuration

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
        
    • 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
        
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:

    "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:
    "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:
    "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:
    dotnet tool install --global dotnet-sql-cache --version="5.0"
    dotnet sql-cache create "Server=.;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#" dbo CacheEntries
    "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:
    "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
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)
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": ""
        }
      }
    }

Set Startup Projects

Run or Debug the Solution

How to Build and Run Single Page Applications:

  • Angular:

    • Navigate to folder: UIs/angular/

      npm install
      ng serve
      
    • Update environment.ts & environment.prod.ts

      export const environment = {
        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 start
      
    • Update environment.dev.js & environment.js

      const environment = {
          OpenIdConnect: {
              Authority: "https://localhost:44367",
              ClientId: "ClassifiedAds.React"
          },
          ResourceServer: {
              Endpoint: "https://localhost:44312/api/"
          },
          CurrentUrl: "http://localhost:3000/"
      };
      export default environment;
    • Go to http://localhost:3000/

  • Vue:

    • Navigate to folder: UIs/vuejs/
      npm install
      npm run serve
      
    • Update environment.dev.js & environment.dev.js
      const environment = {
          OpenIdConnect: {
              Authority: "https://localhost:44367",
              ClientId: "ClassifiedAds.Vue"
          },
          ResourceServer: {
              Endpoint: "https://localhost:44312/api/"
          },
          CurrentUrl: "http://localhost:8080/"
      };
      export default environment;

How to Run on Docker Containers:

How to Run Integration & End to End Tests:

  • 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"
      }
    }

Application URLs:

https://github.com/phongnguyend/Practical.CleanArchitecture/wiki/Application-URLs

Roadmap:

https://github.com/phongnguyend/Practical.CleanArchitecture/wiki/Roadmap