From 0aa9a2b7f183d5d066a5a8cbf7061568782a0773 Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Sat, 20 Jan 2024 13:51:18 +0700 Subject: [PATCH 1/2] update mix mq --- src/Mixcore.sln | 14 +- .../mixcore.host.aspire.AppHost/Program.cs | 11 +- .../Properties/launchSettings.json | 4 +- .../mixcore.host.aspire.AppHost.csproj | 7 +- .../Extensions.cs | 2 +- ...mixcore.host.aspire.ServiceDefaults.csproj | 8 +- .../mixcore/Controllers/HomeController.cs | 148 +- .../Controllers/ModuleDataController.cs | 2 +- .../Controllers/PageContentApiController.cs | 2 +- .../Controllers/PostContentApiController.cs | 2 +- .../mixcore/Controllers/SecurityController.cs | 8 +- src/applications/mixcore/Dockerfile | 82 +- src/applications/mixcore/Dockerfile_linux | 41 + .../mixcore/Domain/Protos/mixmq.proto | 30 + src/applications/mixcore/Program.cs | 39 +- .../mixcore/Properties/launchSettings.json | 6 +- src/applications/mixcore/Readme.md | 54 + .../mixcore/Views/Portal/Index.cshtml | 2 +- .../mixcore/appsettings.Production.json | 8 + src/applications/mixcore/mixcore.csproj | 39 +- .../mixcore/mixcore.gateway.csproj | 34 + src/applications/mixcore/mixcore.gateway.http | 6 + .../mixcore/runtimeconfig.template.json | 12 + .../Controllers/PostContentApiController.cs | 2 +- .../Controllers/SettingApiController.cs | 2 +- .../Controllers/SharedApiController.cs | 10 +- .../Controllers/SharedTenantApiController.cs | 2 +- src/modules/mix.grpc/Domain/StartupService.cs | 1 + .../Controllers/MixAuditLogController.cs | 2 +- .../Controllers/MixQueueLogController.cs | 2 +- src/modules/mix.log/StartupService.cs | 3 +- .../mix.messenger/Domain/StartupService.cs | 1 + .../Controllers/CommonController.cs | 2 +- .../Controllers/MixApplicationController.cs | 4 +- .../Controllers/MixConfigurationController.cs | 2 +- .../Controllers/MixCultureController.cs | 2 +- .../MixDatabaseAssociationController.cs | 2 +- .../MixDatabaseColumnPortalController.cs | 2 +- .../MixDatabaseContextController.cs | 2 +- .../Controllers/MixDatabaseController.cs | 13 +- .../MixDatabaseRelationshipController.cs | 2 +- .../mix.portal/Controllers/MixDbController.cs | 117 +- .../Controllers/MixDomainController.cs | 2 +- .../Controllers/MixLanguageController.cs | 2 +- .../Controllers/MixModuleContentController.cs | 2 +- .../Controllers/MixModuleController.cs | 2 +- .../Controllers/MixModuleDataController.cs | 2 +- .../MixModulePostPortalController.cs | 2 +- .../Controllers/MixPageContentController.cs | 2 +- .../Controllers/MixPageController.cs | 2 +- .../Controllers/MixPageModuleController.cs | 2 +- .../MixPagePostPortalController.cs | 2 +- .../Controllers/MixPostContentController.cs | 2 +- .../Controllers/MixPostController.cs | 2 +- .../Controllers/MixPostPostController.cs | 2 +- .../Controllers/MixTemplateController.cs | 2 +- .../Controllers/MixTenantController.cs | 2 +- .../Controllers/MixThemeController.cs | 2 +- .../Controllers/MixUrlAliasController.cs | 2 +- .../Controllers/MixViewTemplateController.cs | 2 +- .../Domain/Services/MixApplicationService.cs | 6 +- .../mix.portal/Domain/StartupService.cs | 3 +- src/modules/mix.portal/Program.cs | 7 +- .../Domain/Jobs/KeepPoolAliveJob.cs | 29 +- .../Domain/Jobs/PublishScheduledPostsJob.cs | 2 +- .../Domain/Jobs/SendMessageQueueJob.cs | 6 +- .../Domain/Jobs/SendPortalMessageJob.cs | 2 +- .../mix.scheduler/Domain/StartupService.cs | 1 + .../Controllers/FileSystemController.cs | 2 +- .../Controllers/StorageController.cs | 2 +- .../mix.storage/Domain/StartupService.cs | 3 +- .../mix.tenancy/Controllers/InitController.cs | 3 +- src/platform/core/mix-heart | 2 +- .../Services/MixDbEventService.cs | 29 +- .../Constants/MixDatabaseNames.cs | 2 + .../mix.constant/Constants/MixFolders.cs | 1 + .../Enums/MixDatabaseNamingConvention.cs | 8 + .../MixDatabaseContextConfiguration.cs | 7 + .../Entities/Cms/MixDatabaseContext.cs | 1 + .../Entities/Quartz/_MySqlQuartzDbContext.cs | 7 +- .../Quartz/_PostgresSqlQuartzDbContext.cs | 5 +- .../Entities/Quartz/_QuartzDbContext.cs | 5 +- .../Entities/Quartz/_SQliteQuartzDbContext.cs | 5 +- .../Quartz/_SqlServerQuartzDbContext.cs | 5 +- .../20231016051353_UpdateMixAppBaseHref.cs | 2 +- ...5_AddDbContextNamingConvention.Designer.cs | 2741 +++++++++++++++++ ...0116112435_AddDbContextNamingConvention.cs | 29 + .../PostgresqlMixCmsContextModelSnapshot.cs | 7 +- .../mix.database/Services/DatabaseService.cs | 30 +- .../Attributes/MixAuthorizeAttribute.cs | 9 +- .../mix.library/Base/MixApiControllerBase.cs | 4 +- .../Base/MixApiTenantControllerBase.cs | 4 +- .../Base/MixAssociationApiControllerBase.cs | 2 +- .../Base/MixBaseContentController.cs | 2 +- .../Base/MixQueryApiControllerBase.cs | 2 +- .../Base/MixQueryEntityApiControllerBase.cs | 2 +- .../Base/MixRestApiControllerBase.cs | 2 +- .../Base/MixRestEntityApiControllerBase.cs | 10 +- .../Base/MixRestfulApiControllerBase.cs | 6 +- .../Base/SiteDataWithContentViewModelBase.cs | 2 + ...utoGenerateAuthorizedQueryApiController.cs | 2 +- ...AutoGenerateAuthorizedRestApiController.cs | 2 +- .../MixAutoGenerateQueryApiController.cs | 2 +- .../MixAutoGenerateRestApiController.cs | 2 +- .../mix.library/Helpers/MixCmsHelper.cs | 53 +- .../mix.library/Interfaces/IMixEdmService.cs | 1 + .../Middlewares/AuditlogMiddleware.cs | 1 + .../Publishers/MixBackgroundTaskPublisher.cs | 2 +- .../Publishers/MixDbCommandPublisher.cs | 2 +- .../mix.library/Publishers/MixPublisher.cs | 2 +- .../MixViewModelChangedPublisher.cs | 2 +- .../Repositories/TemplateRepository.cs | 1 + .../mix.library/Services/MixEdmService.cs | 48 +- .../Services/MixIdentityService.cs | 14 +- .../mix.library/Services/MixTenantService.cs | 1 + .../Services/MixThemeImportService.cs | 31 +- .../mix.library/Services/RestApiService.cs | 25 +- .../AuthServiceCollectionExtensions.cs | 24 +- src/platform/mix.library/Startup/Cors.cs | 3 +- .../mix.library/Startup/GenerateRestApi.cs | 5 +- src/platform/mix.library/Startup/Migration.cs | 2 +- .../mix.library/Startup/MixCommonService.cs | 13 +- src/platform/mix.library/Startup/MixTenant.cs | 20 +- src/platform/mix.library/Startup/Queue.cs | 2 +- .../Startup/_ServiceCollectionExtensions.cs | 73 +- .../MixBackgroundTaskSubscriber.cs | 22 +- .../Subscribers/MixDbCommandSubscriber.cs | 6 +- .../MixViewModelChangedSubscriber.cs | 7 +- .../ViewModels/MixDatabaseContextViewModel.cs | 1 + .../ViewModels/MixDatabaseViewModel.cs | 38 +- src/platform/mix.library/mix.library.csproj | 1 + .../mix.log/Publishers/MixLogPublisher.cs | 2 +- .../mix.log/ServiceCollectionExtension.cs | 15 + .../mix.log/Services/AuditLogService.cs | 6 +- .../mix.log/Services/MixQueueLogService.cs | 6 +- .../mix.log/Services/MixTenantService.cs | 77 + .../mix.log/Subscribers/MixLogSubscriber.cs | 30 +- .../Extensions/ServiceCollectionExtensions.cs | 2 +- src/platform/mix.quartz/Jobs/MixJobBase.cs | 4 +- .../mix.quartz/Services/QuartzService.cs | 12 +- .../Engines/Mix/MixQueuePublisher.cs | 6 +- .../Engines/Mix/MixQueueSubscriber.cs | 60 +- .../mix.queue/Engines/PublisherBase.cs | 6 +- .../mix.queue/Engines/QueueEngineFactory.cs | 2 +- .../mix.queue/Engines/SubscriberBase.cs | 87 +- .../Interfaces/IMemoryQueueService.cs | 20 + .../mix.queue/Interfaces/IQueueService.cs | 19 - .../mix.queue/Models/MixTopicModel.cs | 17 +- src/platform/mix.queue/Protos/mixmq.proto | 1 + ...{QueueService.cs => MemoryQueueService.cs} | 35 +- .../mix.repodb/Helpers/MixDbHelper.cs | 118 +- .../mix.repodb/Interfaces/IMixDbService.cs | 9 +- .../Publishers/MixRepoDbPublisher.cs | 2 +- .../Repositories/MixRepoDbRepository.cs | 7 +- .../mix.repodb/ServiceCollectionExtensions.cs | 3 +- .../mix.repodb/Services/MixDbDataService.cs | 4 +- .../mix.repodb/Services/MixDbService.cs | 689 ++--- .../Subscribers/MixRepoDbSubscriber.cs | 70 +- .../MixDatabaseContextReadViewModel.cs | 2 + .../ViewModels/RepoDbMixDatabaseViewModel.cs | 3 +- .../Services/BaseHubClientService.cs | 3 +- .../mix.service/Services/FieldNameService.cs | 91 + .../Services/TenantConfigService.cs | 6 +- src/platform/mix.shared/MixAssemblyFinder.cs | 8 +- src/platform/mix.shared/mix.shared.csproj | 3 +- .../mix.signalr.hub/Hubs/MixDbCommandHub.cs | 8 +- .../Engines/Mix/MixUploader.cs | 6 +- .../Services/MixStorageService.cs | 4 +- .../StorageBackgroundTaskSubscriber.cs | 6 +- .../EcommerceServiceProviderExtensions.cs | 2 + .../Controllers/ApiEcommerceController.cs | 7 +- .../Controllers/ApiOrderDetailController.cs | 3 +- .../mix.services.ecommerce/Program.cs | 2 +- .../mix.services.ecommerce/StartupService.cs | 6 +- .../graphql/mix.services.graphql/Program.cs | 2 +- .../StartupService.cs | 1 - .../Controllers/MixMetadataController.cs | 3 +- .../Controllers/MixPermissionController.cs | 3 +- .../Controllers/MixUserDataController.cs | 3 +- .../mix.services.databases.csproj | 134 - .../Controllers/MixAccountController.cs | 2 +- .../Controllers/MixRoleController.cs | 14 +- .../Controllers/OAuthClientController.cs | 2 +- .../mix-auth-service/mix.auth.api/Dockerfile | 47 + .../Dockerfile_linux} | 12 +- .../Domain/Protos/mixmq.proto | 0 .../Domain/StartupService.cs | 0 .../Domain/ViewModels/MixRoleViewModel.cs | 0 .../Program.cs | 15 +- .../Properties/launchSettings.json | 2 +- .../appsettings.Development.json | 0 .../mix.auth.api.csproj} | 15 +- .../mix.auth.api.http} | 0 .../mix.auth.api/runtimeconfig.template.json | 8 + .../mix.mq.lib/mix.mq.lib.csproj | 21 + .../mix.mq.server/Controllers/MqController.cs | 61 + .../mix.mq.server/Dockerfile | 45 + .../mix.mq.server/Dockerfile_linux | 41 + .../mix.mq.server/Domain/Protos/mixmq.proto | 1 + .../Domain/Services/GrpcStreamingService.cs | 153 + .../Domain/Services/MixMqService.cs | 57 +- .../Services/MixMqSubscriptionService.cs | 33 + .../mix.mq.server/Domain/StartupService.cs | 1 + .../mix.mq.server/Program.cs | 48 +- .../Properties/launchSettings.json | 49 +- .../mix.mq.server/mix.mq.server.csproj | 11 +- .../mix.mq.server/runtimeconfig.template.json | 12 + src/test/locustfile.py | 16 +- 208 files changed, 5141 insertions(+), 1315 deletions(-) create mode 100644 src/applications/mixcore/Dockerfile_linux create mode 100644 src/applications/mixcore/Domain/Protos/mixmq.proto create mode 100644 src/applications/mixcore/Readme.md create mode 100644 src/applications/mixcore/appsettings.Production.json create mode 100644 src/applications/mixcore/mixcore.gateway.csproj create mode 100644 src/applications/mixcore/mixcore.gateway.http create mode 100644 src/applications/mixcore/runtimeconfig.template.json create mode 100644 src/platform/mix.constant/Enums/MixDatabaseNamingConvention.cs create mode 100644 src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/20240116112435_AddDbContextNamingConvention.Designer.cs create mode 100644 src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/20240116112435_AddDbContextNamingConvention.cs create mode 100644 src/platform/mix.log/Services/MixTenantService.cs create mode 100644 src/platform/mix.queue/Interfaces/IMemoryQueueService.cs delete mode 100644 src/platform/mix.queue/Interfaces/IQueueService.cs rename src/platform/mix.queue/Services/{QueueService.cs => MemoryQueueService.cs} (69%) create mode 100644 src/platform/mix.service/Services/FieldNameService.cs rename src/platform/{mix.library => mix.service}/Services/TenantConfigService.cs (89%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/Controllers/MixAccountController.cs (99%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/Controllers/MixRoleController.cs (73%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/Controllers/OAuthClientController.cs (83%) create mode 100644 src/services/mix-auth-service/mix.auth.api/Dockerfile rename src/services/mix-auth-service/{mix.auth.service/Dockerfile => mix.auth.api/Dockerfile_linux} (84%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/Domain/Protos/mixmq.proto (100%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/Domain/StartupService.cs (100%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/Domain/ViewModels/MixRoleViewModel.cs (100%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/Program.cs (81%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/Properties/launchSettings.json (94%) rename src/services/mix-auth-service/{mix.auth.service => mix.auth.api}/appsettings.Development.json (100%) rename src/services/mix-auth-service/{mix.auth.service/mix.auth.service.csproj => mix.auth.api/mix.auth.api.csproj} (85%) rename src/services/mix-auth-service/{mix.auth.service/mix.auth.service.http => mix.auth.api/mix.auth.api.http} (100%) create mode 100644 src/services/mix-auth-service/mix.auth.api/runtimeconfig.template.json create mode 100644 src/services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj create mode 100644 src/services/mix-message-queue/mix.mq.server/Controllers/MqController.cs create mode 100644 src/services/mix-message-queue/mix.mq.server/Dockerfile create mode 100644 src/services/mix-message-queue/mix.mq.server/Dockerfile_linux create mode 100644 src/services/mix-message-queue/mix.mq.server/Domain/Services/GrpcStreamingService.cs create mode 100644 src/services/mix-message-queue/mix.mq.server/Domain/Services/MixMqSubscriptionService.cs create mode 100644 src/services/mix-message-queue/mix.mq.server/runtimeconfig.template.json diff --git a/src/Mixcore.sln b/src/Mixcore.sln index 15391384b..80b39793d 100644 --- a/src/Mixcore.sln +++ b/src/Mixcore.sln @@ -121,10 +121,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mix-message-queue", "mix-me EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mix-auth-service", "mix-auth-service", "{EC933357-1D95-4CDD-B290-7A5984FC1AA2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mix.auth.service", "services\mix-auth-service\mix.auth.service\mix.auth.service.csproj", "{D503F737-90E6-438F-ACB2-1074CACEE407}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mix.mq.server", "services\mix-message-queue\mix.mq.server\mix.mq.server.csproj", "{7C5101F3-E3E6-42DB-8585-D08C2BE5E30C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mix.auth.api", "services\mix-auth-service\mix.auth.api\mix.auth.api.csproj", "{9C04921A-38D5-4EC9-8FF5-0E0D74681049}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -279,14 +279,14 @@ Global {F5D4C70F-DD2E-4EC9-A191-56A717B1B5EE}.Debug|Any CPU.Build.0 = Debug|Any CPU {F5D4C70F-DD2E-4EC9-A191-56A717B1B5EE}.Release|Any CPU.ActiveCfg = Release|Any CPU {F5D4C70F-DD2E-4EC9-A191-56A717B1B5EE}.Release|Any CPU.Build.0 = Release|Any CPU - {D503F737-90E6-438F-ACB2-1074CACEE407}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D503F737-90E6-438F-ACB2-1074CACEE407}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D503F737-90E6-438F-ACB2-1074CACEE407}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D503F737-90E6-438F-ACB2-1074CACEE407}.Release|Any CPU.Build.0 = Release|Any CPU {7C5101F3-E3E6-42DB-8585-D08C2BE5E30C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7C5101F3-E3E6-42DB-8585-D08C2BE5E30C}.Debug|Any CPU.Build.0 = Debug|Any CPU {7C5101F3-E3E6-42DB-8585-D08C2BE5E30C}.Release|Any CPU.ActiveCfg = Release|Any CPU {7C5101F3-E3E6-42DB-8585-D08C2BE5E30C}.Release|Any CPU.Build.0 = Release|Any CPU + {9C04921A-38D5-4EC9-8FF5-0E0D74681049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C04921A-38D5-4EC9-8FF5-0E0D74681049}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C04921A-38D5-4EC9-8FF5-0E0D74681049}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C04921A-38D5-4EC9-8FF5-0E0D74681049}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -350,8 +350,8 @@ Global {F5D4C70F-DD2E-4EC9-A191-56A717B1B5EE} = {B4C40E02-E06A-4359-BDC5-349E103366AD} {C93898B7-2001-4C29-9BBE-33A2E61C350A} = {C0A05428-767E-46C5-A31F-0D220E41F7C5} {EC933357-1D95-4CDD-B290-7A5984FC1AA2} = {C0A05428-767E-46C5-A31F-0D220E41F7C5} - {D503F737-90E6-438F-ACB2-1074CACEE407} = {EC933357-1D95-4CDD-B290-7A5984FC1AA2} {7C5101F3-E3E6-42DB-8585-D08C2BE5E30C} = {C93898B7-2001-4C29-9BBE-33A2E61C350A} + {9C04921A-38D5-4EC9-8FF5-0E0D74681049} = {EC933357-1D95-4CDD-B290-7A5984FC1AA2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0143C230-7F40-44B2-8BA3-EF5B92D55848} diff --git a/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/Program.cs b/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/Program.cs index fa1d8e413..0b5433986 100644 --- a/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/Program.cs +++ b/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/Program.cs @@ -1,13 +1,10 @@ var builder = DistributedApplication.CreateBuilder(args); -var mixcore = builder.AddProject("mixcore"); - -builder.AddProject("mixcore.gateway") - .WithReference(mixcore) - ; +var mixmq = builder.AddProject("mix.mq.server"); -builder.AddProject("mix.mq.server"); +var mixcore = builder.AddProject("mixcore"); -builder.AddProject("mix.auth.service"); +builder.AddProject("mix.auth.api"); +builder.AddProject("mixcore.gateway"); builder.Build().Run(); diff --git a/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/Properties/launchSettings.json b/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/Properties/launchSettings.json index 67bb2c5d9..606cc3684 100644 --- a/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/Properties/launchSettings.json +++ b/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/Properties/launchSettings.json @@ -1,11 +1,11 @@ { "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "http": { + "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "http://localhost:15173", + "applicationUrl": "https://localhost:15173", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_ENVIRONMENT": "Development", diff --git a/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/mixcore.host.aspire.AppHost.csproj b/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/mixcore.host.aspire.AppHost.csproj index 5998a459e..61bf092d4 100644 --- a/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/mixcore.host.aspire.AppHost.csproj +++ b/src/applications/mixcore.host.aspire/mixcore.host.aspire.AppHost/mixcore.host.aspire.AppHost.csproj @@ -1,4 +1,4 @@ - + Exe @@ -9,11 +9,12 @@ - + - + + diff --git a/src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/Extensions.cs b/src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/Extensions.cs index 88963623b..bbe43d57a 100644 --- a/src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/Extensions.cs +++ b/src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/Extensions.cs @@ -89,7 +89,7 @@ public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicati { builder.Services.AddHealthChecks() // Add a default liveness check to ensure app is responsive - .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + .AddCheck("self", () => HealthCheckResult.Healthy(), new[] { "live" }); return builder; } diff --git a/src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj b/src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj index 0e3ef55a0..07112a618 100644 --- a/src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj +++ b/src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj @@ -10,16 +10,20 @@ + + - + - + + + diff --git a/src/applications/mixcore/Controllers/HomeController.cs b/src/applications/mixcore/Controllers/HomeController.cs index f280554d1..ddd5412eb 100644 --- a/src/applications/mixcore/Controllers/HomeController.cs +++ b/src/applications/mixcore/Controllers/HomeController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using Mix.Database.Services; +using Mix.Heart.Exceptions; using Mix.Heart.Extensions; using Mix.Lib.Interfaces; using Mix.Lib.Services; @@ -66,86 +67,101 @@ public async Task Index() private async Task LoadPage(string seoName = null) { - var pageRepo = PageContentViewModel.GetRepository(Uow, CacheService); - Expression> predicate = p => p.MixTenantId == CurrentTenant.Id - && p.Specificulture == Culture; - predicate = predicate.AndAlsoIf(string.IsNullOrEmpty(seoName), m => m.Type == MixPageType.Home); - predicate = predicate.AndAlsoIf(!string.IsNullOrEmpty(seoName), m => m.SeoName == seoName); - var page = await pageRepo.GetFirstAsync(predicate); - - if (page != null) + try { - await page.LoadDataAsync(_repoDbRepository, _metadataService, new(Request) + var pageRepo = PageContentViewModel.GetRepository(Uow, CacheService); + Expression> predicate = p => p.MixTenantId == CurrentTenant.Id + && p.Specificulture == Culture; + predicate = predicate.AndAlsoIf(string.IsNullOrEmpty(seoName), m => m.Type == MixPageType.Home); + predicate = predicate.AndAlsoIf(!string.IsNullOrEmpty(seoName), m => m.SeoName == seoName); + var page = await pageRepo.GetFirstAsync(predicate); + + if (page != null) { - SortBy = MixQueryColumnName.Priority - }, CacheService); + await page.LoadDataAsync(_repoDbRepository, _metadataService, new(Request) + { + SortBy = MixQueryColumnName.Priority + }, CacheService); - ViewData["Tenant"] = CurrentTenant; - ViewData["Title"] = page.SeoTitle; - ViewData["Description"] = page.SeoDescription; - ViewData["Keywords"] = page.SeoKeywords; - ViewData["Image"] = page.Image; - ViewData["Layout"] = page.Layout?.FilePath; - ViewData["BodyClass"] = page.ClassName; - ViewData["ViewMode"] = MixMvcViewMode.Page; - ViewData["Keyword"] = page.SeoKeywords; + ViewData["Tenant"] = CurrentTenant; + ViewData["Title"] = page.SeoTitle; + ViewData["Description"] = page.SeoDescription; + ViewData["Keywords"] = page.SeoKeywords; + ViewData["Image"] = page.Image; + ViewData["Layout"] = page.Layout?.FilePath; + ViewData["BodyClass"] = page.ClassName; + ViewData["ViewMode"] = MixMvcViewMode.Page; + ViewData["Keyword"] = page.SeoKeywords; + + ViewData["ViewMode"] = MixMvcViewMode.Page; + } - ViewData["ViewMode"] = MixMvcViewMode.Page; + return page; + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.Badrequest, ex); } - return page; } private async Task LoadAlias(string seoName = null) { - var alias = await MixUrlAliasViewModel.GetRepository(Uow, CacheService).GetSingleAsync(m => m.MixTenantId == CurrentTenant.Id && m.Alias == seoName); - if (alias != null) + try { - switch (alias.Type) + var alias = await MixUrlAliasViewModel.GetRepository(Uow, CacheService).GetSingleAsync(m => m.MixTenantId == CurrentTenant.Id && m.Alias == seoName); + if (alias != null) { - case MixUrlAliasType.Page: - var pageRepo = PageContentViewModel.GetRepository(Uow, CacheService); - pageRepo.CacheService = CacheService; - var page = await pageRepo.GetSingleAsync(m => m.Id == alias.SourceContentId); - if (page != null) - { - await page.LoadDataAsync(_repoDbRepository, _metadataService, new(Request) + switch (alias.Type) + { + case MixUrlAliasType.Page: + var pageRepo = PageContentViewModel.GetRepository(Uow, CacheService); + pageRepo.CacheService = CacheService; + var page = await pageRepo.GetSingleAsync(m => m.Id == alias.SourceContentId); + if (page != null) { - SortBy = MixQueryColumnName.Priority - }, CacheService); - ViewData["Tenant"] = CurrentTenant; - ViewData["Title"] = page.SeoTitle; - ViewData["Description"] = page.SeoDescription; - ViewData["Keywords"] = page.SeoKeywords; - ViewData["Image"] = page.Image; - ViewData["Layout"] = page.Layout?.FilePath; - ViewData["BodyClass"] = page.ClassName; - ViewData["ViewMode"] = MixMvcViewMode.Page; - ViewData["Keyword"] = page.SeoKeywords; + await page.LoadDataAsync(_repoDbRepository, _metadataService, new(Request) + { + SortBy = MixQueryColumnName.Priority + }, CacheService); + ViewData["Tenant"] = CurrentTenant; + ViewData["Title"] = page.SeoTitle; + ViewData["Description"] = page.SeoDescription; + ViewData["Keywords"] = page.SeoKeywords; + ViewData["Image"] = page.Image; + ViewData["Layout"] = page.Layout?.FilePath; + ViewData["BodyClass"] = page.ClassName; + ViewData["ViewMode"] = MixMvcViewMode.Page; + ViewData["Keyword"] = page.SeoKeywords; - ViewData["ViewMode"] = MixMvcViewMode.Page; - return View("Page", page); - } - break; - case MixUrlAliasType.Post: - var postRepo = PostContentViewModel.GetRepository(Uow, CacheService); - postRepo.CacheService = CacheService; - var post = await postRepo.GetSingleAsync(m => m.Id == alias.SourceContentId); - if (post != null) - return View("Post", post); - break; - case MixUrlAliasType.Module: - break; - case MixUrlAliasType.ModuleData: - break; - case MixUrlAliasType.MixApplication: - var appRepo = ApplicationViewModel.GetRepository(Uow, CacheService); - appRepo.CacheService = CacheService; - var app = await appRepo.GetSingleAsync(m => m.Id == alias.SourceContentId); - if (app != null) - return View("App", app); - break; + ViewData["ViewMode"] = MixMvcViewMode.Page; + return View("Page", page); + } + break; + case MixUrlAliasType.Post: + var postRepo = PostContentViewModel.GetRepository(Uow, CacheService); + postRepo.CacheService = CacheService; + var post = await postRepo.GetSingleAsync(m => m.Id == alias.SourceContentId); + if (post != null) + return View("Post", post); + break; + case MixUrlAliasType.Module: + break; + case MixUrlAliasType.ModuleData: + break; + case MixUrlAliasType.MixApplication: + var appRepo = ApplicationViewModel.GetRepository(Uow, CacheService); + appRepo.CacheService = CacheService; + var app = await appRepo.GetSingleAsync(m => m.Id == alias.SourceContentId); + if (app != null) + return View("App", app); + break; + } } + return NotFound(); + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.Badrequest, ex); } - return NotFound(); } } } diff --git a/src/applications/mixcore/Controllers/ModuleDataController.cs b/src/applications/mixcore/Controllers/ModuleDataController.cs index 282d24dc5..9b4f96d96 100644 --- a/src/applications/mixcore/Controllers/ModuleDataController.cs +++ b/src/applications/mixcore/Controllers/ModuleDataController.cs @@ -17,7 +17,7 @@ public ModuleDataController(IHttpContextAccessor httpContextAccessor, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/applications/mixcore/Controllers/PageContentApiController.cs b/src/applications/mixcore/Controllers/PageContentApiController.cs index a6c225ced..5e8993dc8 100644 --- a/src/applications/mixcore/Controllers/PageContentApiController.cs +++ b/src/applications/mixcore/Controllers/PageContentApiController.cs @@ -23,7 +23,7 @@ public PageContentApiController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, MixRepoDbRepository mixRepoDbRepository, IMixMetadataService metadataService, IPortalHubClientService portalHub, diff --git a/src/applications/mixcore/Controllers/PostContentApiController.cs b/src/applications/mixcore/Controllers/PostContentApiController.cs index 544551324..3bfc89778 100644 --- a/src/applications/mixcore/Controllers/PostContentApiController.cs +++ b/src/applications/mixcore/Controllers/PostContentApiController.cs @@ -27,7 +27,7 @@ public PostContentApiController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, MixcorePostService postService, MixRepoDbRepository mixRepoDbRepository, IMixMetadataService metadataService, diff --git a/src/applications/mixcore/Controllers/SecurityController.cs b/src/applications/mixcore/Controllers/SecurityController.cs index 725ab598b..08f4e6a71 100644 --- a/src/applications/mixcore/Controllers/SecurityController.cs +++ b/src/applications/mixcore/Controllers/SecurityController.cs @@ -54,11 +54,11 @@ public IActionResult Index(string page) public ActionResult ExternalLogin([FromForm] string returnUrl, [FromForm] MixExternalLoginProviders provider) { // Request a redirect to the external login provider. - returnUrl ??= _mixEndpointService.DefaultDomain; - returnUrl = returnUrl.Contains(_mixEndpointService.DefaultDomain) || returnUrl.StartsWith("http") + returnUrl ??= _mixEndpointService.Mixcore; + returnUrl = returnUrl.Contains(_mixEndpointService.Mixcore) || returnUrl.StartsWith("http") ? returnUrl - : $"{_mixEndpointService.DefaultDomain.TrimEnd('/')}/{returnUrl.TrimStart('/')}"; - var redirectUrl = $"/security/external-login-result?returnUrl={returnUrl}"; + : $"{_mixEndpointService.Mixcore.TrimEnd('/')}/{returnUrl.TrimStart('/')}"; + var redirectUrl = $"{_mixEndpointService.Mixcore}/security/external-login-result"; var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider.ToString(), redirectUrl); return new ChallengeResult(provider.ToString(), properties); } diff --git a/src/applications/mixcore/Dockerfile b/src/applications/mixcore/Dockerfile index 361c5ab9f..fd5628b46 100644 --- a/src/applications/mixcore/Dockerfile +++ b/src/applications/mixcore/Dockerfile @@ -2,60 +2,54 @@ FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base USER app -WORKDIR /app EXPOSE 8080 EXPOSE 8081 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release -WORKDIR /src -COPY ["applications/mixcore/mixcore.csproj", "applications/mixcore/"] -COPY ["applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj", "applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/"] -COPY ["modules/mix.account/mix.account.csproj", "modules/mix.account/"] -COPY ["platform/mix.identity/mix.identity.csproj", "platform/mix.identity/"] -COPY ["platform/mix.auth/mix.auth.csproj", "platform/mix.auth/"] -COPY ["platform/mix.database/mix.database.csproj", "platform/mix.database/"] -COPY ["platform/mix.shared/mix.shared.csproj", "platform/mix.shared/"] -COPY ["platform/core/mix-heart/src/mix.heart/mix.heart.csproj", "platform/core/mix-heart/src/mix.heart/"] -COPY ["platform/mix.constant/mix.constant.csproj", "platform/mix.constant/"] -COPY ["platform/mix.library/mix.library.csproj", "platform/mix.library/"] -COPY ["platform/core/mix.mixdb.event/mix.mixdb.event.csproj", "platform/core/mix.mixdb.event/"] -COPY ["platform/mix.mixdb/mix.mixdb.csproj", "platform/mix.mixdb/"] -COPY ["platform/mix.service/mix.service.csproj", "platform/mix.service/"] -COPY ["platform/mix.quartz/mix.quartz.csproj", "platform/mix.quartz/"] -COPY ["platform/mix.queue/mix.queue.csproj", "platform/mix.queue/"] -COPY ["services/mix-message-queue/mix.mq/mix.mq.csproj", "services/mix-message-queue/mix.mq/"] -COPY ["services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj", "services/mix-message-queue/mix.mq.lib/"] -COPY ["platform/mix.signalr/mix.signalr.csproj", "platform/mix.signalr/"] -COPY ["platform/mix.repodb/mix.repodb.csproj", "platform/mix.repodb/"] -COPY ["platform/mix.communicator/mix.communicator.csproj", "platform/mix.communicator/"] -COPY ["platform/mix.signalr.hub/mix.signalr.hub.csproj", "platform/mix.signalr.hub/"] -COPY ["platform/mix.log/mix.log.lib.csproj", "platform/mix.log/"] -COPY ["modules/mix.grpc/mix.grpc.csproj", "modules/mix.grpc/"] -COPY ["modules/mix.common/mix.common.csproj", "modules/mix.common/"] -COPY ["modules/mix.messenger/mix.messenger.csproj", "modules/mix.messenger/"] -COPY ["modules/mix.portal/mix.portal.csproj", "modules/mix.portal/"] -COPY ["services/core/mix-databases/mix.services.databases.lib/mix.services.databases.lib.csproj", "services/core/mix-databases/mix.services.databases.lib/"] -COPY ["modules/mix.scheduler/mix.scheduler.csproj", "modules/mix.scheduler/"] -COPY ["modules/mix.log/mix.log.csproj", "modules/mix.log/"] -COPY ["modules/mix.storage/mix.storage.csproj", "modules/mix.storage/"] -COPY ["platform/mix.storage.lib/mix.storage.lib.csproj", "platform/mix.storage.lib/"] -COPY ["modules/mix.tenancy/mix.tenancy.csproj", "modules/mix.tenancy/"] -COPY ["services/core/ecommerces/mix.services.ecommerce/mix.services.ecommerce.csproj", "services/core/ecommerces/mix.services.ecommerce/"] -COPY ["services/core/ecommerces/mix.services.ecommerce.lib/mix.services.ecommerce.lib.csproj", "services/core/ecommerces/mix.services.ecommerce.lib/"] -COPY ["services/core/graphql/mix.services.graphql/mix.services.graphql.csproj", "services/core/graphql/mix.services.graphql/"] -COPY ["services/core/graphql/mix.services.graphql.lib/mix.services.graphql.lib.csproj", "services/core/graphql/mix.services.graphql.lib/"] -COPY ["services/core/mix-databases/mix.servives.databases/mix.services.databases.csproj", "services/core/mix-databases/mix.servives.databases/"] -RUN dotnet restore "./applications/mixcore/./mixcore.csproj" +COPY ["src/applications/mixcore/mixcore.csproj", "src/applications/mixcore/"] +COPY ["src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj", "src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/"] +COPY ["src/platform/mix.identity/mix.identity.csproj", "src/platform/mix.identity/"] +COPY ["src/platform/mix.database/mix.database.csproj", "src/platform/mix.database/"] +COPY ["src/platform/mix.shared/mix.shared.csproj", "src/platform/mix.shared/"] +COPY ["src/platform/core/mix-heart/src/mix.heart/mix.heart.csproj", "src/platform/core/mix-heart/src/mix.heart/"] +COPY ["src/platform/mix.constant/mix.constant.csproj", "src/platform/mix.constant/"] +COPY ["src/platform/mix.library/mix.library.csproj", "src/platform/mix.library/"] +COPY ["src/platform/core/mix.mixdb.event/mix.mixdb.event.csproj", "src/platform/core/mix.mixdb.event/"] +COPY ["src/platform/mix.mixdb/mix.mixdb.csproj", "src/platform/mix.mixdb/"] +COPY ["src/platform/mix.service/mix.service.csproj", "src/platform/mix.service/"] +COPY ["src/platform/mix.quartz/mix.quartz.csproj", "src/platform/mix.quartz/"] +COPY ["src/platform/mix.queue/mix.queue.csproj", "src/platform/mix.queue/"] +COPY ["src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj", "src/services/mix-message-queue/mix.mq/"] +COPY ["src/services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj", "src/services/mix-message-queue/mix.mq.lib/"] +COPY ["src/platform/mix.signalr/mix.signalr.csproj", "src/platform/mix.signalr/"] +COPY ["src/platform/mix.repodb/mix.repodb.csproj", "src/platform/mix.repodb/"] +COPY ["src/platform/mix.communicator/mix.communicator.csproj", "src/platform/mix.communicator/"] +COPY ["src/platform/mix.signalr.hub/mix.signalr.hub.csproj", "src/platform/mix.signalr.hub/"] +COPY ["src/platform/mix.log/mix.log.lib.csproj", "src/platform/mix.log/"] +COPY ["src/modules/mix.grpc/mix.grpc.csproj", "src/modules/mix.grpc/"] +COPY ["src/modules/mix.common/mix.common.csproj", "src/modules/mix.common/"] +COPY ["src/modules/mix.messenger/mix.messenger.csproj", "src/modules/mix.messenger/"] +COPY ["src/modules/mix.portal/mix.portal.csproj", "src/modules/mix.portal/"] +COPY ["src/services/core/mix-databases/mix.services.databases.lib/mix.services.databases.lib.csproj", "src/services/core/mix-databases/mix.services.databases.lib/"] +COPY ["src/modules/mix.scheduler/mix.scheduler.csproj", "src/modules/mix.scheduler/"] +COPY ["src/modules/mix.log/mix.log.csproj", "src/modules/mix.log/"] +COPY ["src/modules/mix.storage/mix.storage.csproj", "src/modules/mix.storage/"] +COPY ["src/platform/mix.storage.lib/mix.storage.lib.csproj", "src/platform/mix.storage.lib/"] +COPY ["src/modules/mix.tenancy/mix.tenancy.csproj", "src/modules/mix.tenancy/"] +COPY ["src/services/core/ecommerces/mix.services.ecommerce/mix.services.ecommerce.csproj", "src/services/core/ecommerces/mix.services.ecommerce/"] +COPY ["src/services/core/ecommerces/mix.services.ecommerce.lib/mix.services.ecommerce.lib.csproj", "src/services/core/ecommerces/mix.services.ecommerce.lib/"] +COPY ["src/services/core/graphql/mix.services.graphql/mix.services.graphql.csproj", "src/services/core/graphql/mix.services.graphql/"] +COPY ["src/services/core/graphql/mix.services.graphql.lib/mix.services.graphql.lib.csproj", "src/services/core/graphql/mix.services.graphql.lib/"] +COPY ["src/services/core/mix-databases/mix.servives.databases/mix.services.databases.csproj", "src/services/core/mix-databases/mix.servives.databases/"] +RUN dotnet restore "/src/applications/mixcore/mixcore.csproj" COPY . . -WORKDIR "/src/applications/mixcore" -RUN dotnet build "./mixcore.csproj" -c $BUILD_CONFIGURATION -o /app/build +RUN dotnet build "/src/applications/mixcore/mixcore.csproj" -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Release -RUN dotnet publish "./mixcore.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false +RUN dotnet publish "/src/applications/mixcore/mixcore.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final -WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "mixcore.dll"] \ No newline at end of file diff --git a/src/applications/mixcore/Dockerfile_linux b/src/applications/mixcore/Dockerfile_linux new file mode 100644 index 000000000..d6d19806e --- /dev/null +++ b/src/applications/mixcore/Dockerfile_linux @@ -0,0 +1,41 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +COPY ["src/applications/mixcore.gateway/mixcore.gateway.csproj", "src/applications/mixcore.gateway/"] +COPY ["src/platform/mix.library/mix.library.csproj", "src/platform/mix.library/"] +COPY ["src/platform/core/mix.mixdb.event/mix.mixdb.event.csproj", "src/platform/core/mix.mixdb.event/"] +COPY ["src/platform/mix.mixdb/mix.mixdb.csproj", "src/platform/mix.mixdb/"] +COPY ["src/platform/mix.database/mix.database.csproj", "src/platform/mix.database/"] +COPY ["src/platform/mix.shared/mix.shared.csproj", "src/platform/mix.shared/"] +COPY ["src/platform/core/mix-heart/src/mix.heart/mix.heart.csproj", "src/platform/core/mix-heart/src/mix.heart/"] +COPY ["src/platform/mix.constant/mix.constant.csproj", "src/platform/mix.constant/"] +COPY ["src/platform/mix.service/mix.service.csproj", "src/platform/mix.service/"] +COPY ["src/platform/mix.identity/mix.identity.csproj", "src/platform/mix.identity/"] +COPY ["src/platform/mix.auth/mix.auth.csproj", "src/platform/mix.auth/"] +COPY ["src/platform/mix.quartz/mix.quartz.csproj", "src/platform/mix.quartz/"] +COPY ["src/platform/mix.queue/mix.queue.csproj", "src/platform/mix.queue/"] +COPY ["src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj", "src/services/mix-message-queue/mix.mq/"] +COPY ["src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj", "src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/"] +COPY ["src/services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj", "src/services/mix-message-queue/mix.mq.lib/"] +COPY ["src/platform/mix.signalr/mix.signalr.csproj", "src/platform/mix.signalr/"] +COPY ["src/platform/mix.repodb/mix.repodb.csproj", "src/platform/mix.repodb/"] +COPY ["src/platform/mix.communicator/mix.communicator.csproj", "src/platform/mix.communicator/"] +COPY ["src/platform/mix.signalr.hub/mix.signalr.hub.csproj", "src/platform/mix.signalr.hub/"] +COPY ["src/platform/mix.log/mix.log.lib.csproj", "src/platform/mix.log/"] +RUN dotnet restore "src/applications/mixcore.gateway/mixcore.gateway.csproj" +COPY . . +RUN dotnet build "/src/applications/mixcore.gateway/mixcore.gateway.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "/src/applications/mixcore.gateway/mixcore.gateway.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "mixcore.gateway.dll"] \ No newline at end of file diff --git a/src/applications/mixcore/Domain/Protos/mixmq.proto b/src/applications/mixcore/Domain/Protos/mixmq.proto new file mode 100644 index 000000000..359260311 --- /dev/null +++ b/src/applications/mixcore/Domain/Protos/mixmq.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +option csharp_namespace = "Mix.Mq"; +import "google/protobuf/empty.proto"; + +package mixmq; + +// The greeting service definition. +service MixMq { + // Sends a greeting + rpc Subscribe (SubscribeRequest) returns (stream SubscribeReply); + rpc Disconnect (SubscribeRequest) returns (google.protobuf.Empty); + rpc Publish (PublishMessageRequest) returns (google.protobuf.Empty); +} + +// The request message containing the user's name. +message SubscribeRequest { + string topicId = 1; + string subsctiptionId = 2; +} + +message PublishMessageRequest { + string topicId = 1; + string message = 2; +} + +// The response message containing the greetings. +message SubscribeReply { + repeated string messages = 1; +} diff --git a/src/applications/mixcore/Program.cs b/src/applications/mixcore/Program.cs index 9bd3a4f38..e2eaca7dc 100644 --- a/src/applications/mixcore/Program.cs +++ b/src/applications/mixcore/Program.cs @@ -7,20 +7,13 @@ using Microsoft.Extensions.FileProviders; using Mix.Lib.Middlewares; using Mix.Shared.Services; -using Mix.Shared.Helpers; - -var mixContentFolder = new DirectoryInfo(MixFolders.StaticFiles); +using Mix.Shared.Models.Configurations; +var builder = MixCmsHelper.CreateWebApplicationBuilder(args); -// Clone Settings from shared folder -if (!mixContentFolder.Exists) +if (builder.Environment.IsDevelopment()) { - MixHelper.CopyFolder($"{Environment.CurrentDirectory}/{MixFolders.DefaultMixContentFolder}", MixFolders.MixContentFolder); - Console.WriteLine("Clone Settings from shared folder completed."); + builder.AddServiceDefaults(); } -var builder = MixCmsHelper.CreateWebApplicationBuilder(args); - -builder.AddServiceDefaults(); - // Add services to the container. builder.Services.AddControllersWithViews(); @@ -29,8 +22,11 @@ { options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All); }); - +var globalConfig = builder.Configuration.GetSection(MixAppSettingsSection.GlobalSettings) + .Get(); +builder.Services.AddEndpointsApiExplorer(); builder.Services.AddMixServices(Assembly.GetExecutingAssembly(), builder.Configuration); +builder.Services.ApplyMigrations(globalConfig); builder.Services.AddMixCors(); builder.Services.AddScoped(); builder.Services.AddMixLog(builder.Configuration); @@ -52,7 +48,7 @@ void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfiguration // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } - + app.UseHttpsRedirection(); app.UseMixTenant(); app.UseMiddleware(); @@ -61,12 +57,7 @@ void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfiguration // Typically, UseStaticFiles is called before UseCors. Apps that use JavaScript to retrieve static files cross site must call UseCors before UseStaticFiles. app.UseMixStaticFiles(env.ContentRootPath); - app.UseStaticFiles(); - app.UseStaticFiles(new StaticFileOptions - { - FileProvider = new PhysicalFileProvider( - Path.Combine(env.ContentRootPath, MixFolders.TemplatesFolder)) - }); + // UseCors must be placed after UseRouting and before UseAuthorization. This is to ensure that CORS headers are included in the response for both authorized and unauthorized calls. app.UseMixCors(); @@ -75,16 +66,16 @@ void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfiguration app.UseMixAuth(); app.UseMixApps(Assembly.GetExecutingAssembly(), configuration, env.ContentRootPath, env.IsDevelopment()); - + app.UseMixSwaggerApps(env.IsDevelopment(), Assembly.GetExecutingAssembly()); app.UseResponseCompression(); app.UseMixResponseCaching(); - if (GlobalConfigService.Instance.AppSettings.IsHttps) - { - app.UseHttpsRedirection(); - } + //if (GlobalConfigService.Instance.AppSettings.IsHttps) + //{ + // app.UseHttpsRedirection(); + //} } \ No newline at end of file diff --git a/src/applications/mixcore/Properties/launchSettings.json b/src/applications/mixcore/Properties/launchSettings.json index 404026c2d..044c36913 100644 --- a/src/applications/mixcore/Properties/launchSettings.json +++ b/src/applications/mixcore/Properties/launchSettings.json @@ -7,7 +7,7 @@ "ASPNETCORE_ENVIRONMENT": "Development" }, "dotnetRunMessages": true, - "applicationUrl": "https://localhost:5010;http://localhost:5154" + "applicationUrl": "https://localhost:5010;http://localhost:5011" }, "IIS Express": { "commandName": "IISExpress", @@ -21,8 +21,8 @@ "launchBrowser": true, "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", "environmentVariables": { - "ASPNETCORE_HTTPS_PORTS": "8081", - "ASPNETCORE_HTTP_PORTS": "8080" + "ASPNETCORE_HTTPS_PORTS": "5010", + "ASPNETCORE_HTTP_PORTS": "5011" }, "publishAllPorts": true, "useSSL": true diff --git a/src/applications/mixcore/Readme.md b/src/applications/mixcore/Readme.md new file mode 100644 index 000000000..373a66487 --- /dev/null +++ b/src/applications/mixcore/Readme.md @@ -0,0 +1,54 @@ +*Notes:* +### Ref: https://learn.microsoft.com/en-us/dotnet/core/runtime-config/garbage-collector#affinitize +# Run module as a microservice : +## 1. Remove Reference to module from Mixcore project +## 2. Copy MixContent to Module's source code +## 3. Update ocelot.json.(Ref: https://ocelot.readthedocs.io/en/latest/features/configuration.html). +Ex: +``` +git reset HEAD src/platform/core/mix-heart + +{ + "Routes": [ + { + "DownstreamPathTemplate": "/api/v2/rest/mix-portal/{catchALl}", + "DownstreamScheme": "https", + "DownstreamHostAndPorts": [ + { + "Host": "localhost", + "Port": 5006 + } + ], + "UpstreamPathTemplate": "/api/v2/rest/mix-portal/{catchALl}", + "UpstreamHttpMethod": [ "Get", "Post", "Put", "Patch", "Delete" ], + "RateLimitOptions": { + "ClientWhitelist": [], + "EnableRateLimiting": true, + "Period": "1s", + "PeriodTimespan": 1, + "Limit": 1000 + } + } + ], + "GlobalConfiguration": { + "BaseUrl": "https://localhost:5010" + } +} + +``` +## 4. Remove Config Http2 from appsettings if exist. +``` +"Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + } +``` +## 5. Update "EnableOcelot" in mixcore -> global.json = true. + +**Make sure the enpoints in MixContent/AppConfigs/endpoints.json are correct (when deploy to from local to production, must change the localhost to real endpoints)** +## 5. Update Enpoints to production domain when golive (/MixContent/AppConfigs/enpoints.json) + +## 6.Add migration +** Move to mix.database folder +** dotnet ef --startup-project ../../applications/Mixcore migrations add Init --context PostgresqlmixcmsContext --output-dir Migrations/Cms/PostgresqlMixCms \ No newline at end of file diff --git a/src/applications/mixcore/Views/Portal/Index.cshtml b/src/applications/mixcore/Views/Portal/Index.cshtml index 592378c45..7ec95f5ab 100644 --- a/src/applications/mixcore/Views/Portal/Index.cshtml +++ b/src/applications/mixcore/Views/Portal/Index.cshtml @@ -78,7 +78,7 @@ - + \ No newline at end of file diff --git a/src/applications/mixcore/appsettings.Production.json b/src/applications/mixcore/appsettings.Production.json new file mode 100644 index 000000000..04f5eda0b --- /dev/null +++ b/src/applications/mixcore/appsettings.Production.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Critical", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/applications/mixcore/mixcore.csproj b/src/applications/mixcore/mixcore.csproj index b2e91100d..b38c61430 100644 --- a/src/applications/mixcore/mixcore.csproj +++ b/src/applications/mixcore/mixcore.csproj @@ -2,20 +2,21 @@ net8.0 + false + en disable enable aeea975a-4fec-4193-846d-3a3d92606bd7 Linux ..\.. + false + true - - - @@ -57,7 +58,39 @@ + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + PreserveNewest + true + PreserveNewest + + + PreserveNewest + true + PreserveNewest + + + PreserveNewest + true + PreserveNewest + + + + diff --git a/src/applications/mixcore/mixcore.gateway.csproj b/src/applications/mixcore/mixcore.gateway.csproj new file mode 100644 index 000000000..008722f7c --- /dev/null +++ b/src/applications/mixcore/mixcore.gateway.csproj @@ -0,0 +1,34 @@ + + + + net8.0 + false + true + false + enable + enable + true + Mixcore.Gateway + bbdd7c53-6dfa-4f6f-ab46-5ecda7005ed0 + Linux + ..\.. + + + + + + + + + + + + + + + + + + + + diff --git a/src/applications/mixcore/mixcore.gateway.http b/src/applications/mixcore/mixcore.gateway.http new file mode 100644 index 000000000..32ea4bf3d --- /dev/null +++ b/src/applications/mixcore/mixcore.gateway.http @@ -0,0 +1,6 @@ +@mixcore.gateway_HostAddress = http://localhost:5025 + +GET {{mixcore.gateway_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/src/applications/mixcore/runtimeconfig.template.json b/src/applications/mixcore/runtimeconfig.template.json new file mode 100644 index 000000000..cbbea1422 --- /dev/null +++ b/src/applications/mixcore/runtimeconfig.template.json @@ -0,0 +1,12 @@ +{ + "configProperties": { + "System.GC.RetainVM": false, + "System.GC.NoAffinitize": false, + "System.GC.ConserveMemory": 5, + "System.GC.Server": false, + "System.GC.Concurrent": true, + "System.GC.HeapCount": 12, + "System.Threading.Thread.EnableAutoreleasePool": true + } + } + \ No newline at end of file diff --git a/src/modules/mix.common/Controllers/PostContentApiController.cs b/src/modules/mix.common/Controllers/PostContentApiController.cs index b8de34f0f..7aea967e7 100644 --- a/src/modules/mix.common/Controllers/PostContentApiController.cs +++ b/src/modules/mix.common/Controllers/PostContentApiController.cs @@ -24,7 +24,7 @@ public PostContentApiController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, MixRepoDbRepository mixRepoDbRepository, IPortalHubClientService portalHub, IMixTenantService mixTenantService) diff --git a/src/modules/mix.common/Controllers/SettingApiController.cs b/src/modules/mix.common/Controllers/SettingApiController.cs index 1d12e8466..74bcc966c 100644 --- a/src/modules/mix.common/Controllers/SettingApiController.cs +++ b/src/modules/mix.common/Controllers/SettingApiController.cs @@ -23,7 +23,7 @@ public SettingApiController( MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - IQueueService queueService, + IMemoryQueueService queueService, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, queueService, mixTenantService) diff --git a/src/modules/mix.common/Controllers/SharedApiController.cs b/src/modules/mix.common/Controllers/SharedApiController.cs index 765f61ddd..f30df7b33 100644 --- a/src/modules/mix.common/Controllers/SharedApiController.cs +++ b/src/modules/mix.common/Controllers/SharedApiController.cs @@ -39,7 +39,7 @@ public SharedApiController( IActionDescriptorCollectionProvider routeProvider, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, ApplicationLifetime applicationLifetime, MixCacheService cacheService, IHttpContextAccessor httpContextAccessor, @@ -84,9 +84,15 @@ public ActionResult DecryptMessage(CryptoMessageDto encryptMessage) [HttpGet] [MixAuthorize(roles: $"{MixRoles.SuperAdmin},{MixRoles.Owner}")] [Route("stop-application")] - public void StopApplication() + public async Task StopApplication() { _applicationLifetime.StopApplication(); + string _currentProcess = Path.GetFullPath(Process.GetCurrentProcess().MainModule.FileName); + + Process.Start(_currentProcess); + + await Task.FromResult(0); + return Ok(DateTime.UtcNow); } [HttpGet] diff --git a/src/modules/mix.common/Controllers/SharedTenantApiController.cs b/src/modules/mix.common/Controllers/SharedTenantApiController.cs index 7b5176da7..4a95cb3aa 100644 --- a/src/modules/mix.common/Controllers/SharedTenantApiController.cs +++ b/src/modules/mix.common/Controllers/SharedTenantApiController.cs @@ -29,7 +29,7 @@ public SharedTenantApiController( MixIdentityService mixIdentityService, AuthConfigService authConfigService, MixCmsContext context, - IQueueService queueService, + IMemoryQueueService queueService, IMixTenantService mixTenantService, MixEndpointService endpointService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.grpc/Domain/StartupService.cs b/src/modules/mix.grpc/Domain/StartupService.cs index 34516f3b3..53e294e40 100644 --- a/src/modules/mix.grpc/Domain/StartupService.cs +++ b/src/modules/mix.grpc/Domain/StartupService.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Mix.Grpc.Domain.Services; +using Mix.Lib.Interfaces; using Mix.Shared.Interfaces; namespace Mix.Grpc.Domain diff --git a/src/modules/mix.log/Controllers/MixAuditLogController.cs b/src/modules/mix.log/Controllers/MixAuditLogController.cs index b16f90fff..a7017c9e9 100644 --- a/src/modules/mix.log/Controllers/MixAuditLogController.cs +++ b/src/modules/mix.log/Controllers/MixAuditLogController.cs @@ -35,7 +35,7 @@ public AuditLogController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.log/Controllers/MixQueueLogController.cs b/src/modules/mix.log/Controllers/MixQueueLogController.cs index ed54490db..a9a2c5ff0 100644 --- a/src/modules/mix.log/Controllers/MixQueueLogController.cs +++ b/src/modules/mix.log/Controllers/MixQueueLogController.cs @@ -35,7 +35,7 @@ public MixQueueLogController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base( diff --git a/src/modules/mix.log/StartupService.cs b/src/modules/mix.log/StartupService.cs index 9a61939dd..2839b485d 100644 --- a/src/modules/mix.log/StartupService.cs +++ b/src/modules/mix.log/StartupService.cs @@ -1,4 +1,5 @@ -using Mix.Shared.Interfaces; +using Mix.Lib.Interfaces; +using Mix.Shared.Interfaces; namespace Mix.Log { diff --git a/src/modules/mix.messenger/Domain/StartupService.cs b/src/modules/mix.messenger/Domain/StartupService.cs index 41caf1988..b39709884 100644 --- a/src/modules/mix.messenger/Domain/StartupService.cs +++ b/src/modules/mix.messenger/Domain/StartupService.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Mix.Lib.Interfaces; using Mix.Shared.Interfaces; namespace Mix.Messenger.Domain diff --git a/src/modules/mix.portal/Controllers/CommonController.cs b/src/modules/mix.portal/Controllers/CommonController.cs index 615b94131..6f5ed462b 100644 --- a/src/modules/mix.portal/Controllers/CommonController.cs +++ b/src/modules/mix.portal/Controllers/CommonController.cs @@ -23,7 +23,7 @@ public CommonController( MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - IQueueService queueService, + IMemoryQueueService queueService, TenantUserManager userManager, MixRepoDbRepository repoDbRepository, IMixTenantService mixTenantService) diff --git a/src/modules/mix.portal/Controllers/MixApplicationController.cs b/src/modules/mix.portal/Controllers/MixApplicationController.cs index a0c3dae93..1fc9865e8 100644 --- a/src/modules/mix.portal/Controllers/MixApplicationController.cs +++ b/src/modules/mix.portal/Controllers/MixApplicationController.cs @@ -23,7 +23,7 @@ public MixApplicationController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService, IMixApplicationService applicationService) @@ -44,7 +44,7 @@ public ActionResult Install([FromBody] MixApplicationViewModel app, Cancellation { return BadRequest($"BaseHref: \"{app.BaseHref}\" existed"); } - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.InstallMixApplication, app); + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.InstallMixApplication, app); return NoContent(); } diff --git a/src/modules/mix.portal/Controllers/MixConfigurationController.cs b/src/modules/mix.portal/Controllers/MixConfigurationController.cs index 8eae23fe9..c2dbb6853 100644 --- a/src/modules/mix.portal/Controllers/MixConfigurationController.cs +++ b/src/modules/mix.portal/Controllers/MixConfigurationController.cs @@ -22,7 +22,7 @@ public MixConfigurationController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixCultureController.cs b/src/modules/mix.portal/Controllers/MixCultureController.cs index e27c01065..61f8d93f1 100644 --- a/src/modules/mix.portal/Controllers/MixCultureController.cs +++ b/src/modules/mix.portal/Controllers/MixCultureController.cs @@ -22,7 +22,7 @@ public MixCultureController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixDatabaseAssociationController.cs b/src/modules/mix.portal/Controllers/MixDatabaseAssociationController.cs index d1f463dc9..e188b4300 100644 --- a/src/modules/mix.portal/Controllers/MixDatabaseAssociationController.cs +++ b/src/modules/mix.portal/Controllers/MixDatabaseAssociationController.cs @@ -19,7 +19,7 @@ public MixDatabaseAssociationController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixDatabaseColumnPortalController.cs b/src/modules/mix.portal/Controllers/MixDatabaseColumnPortalController.cs index eb50c5216..13dfd2270 100644 --- a/src/modules/mix.portal/Controllers/MixDatabaseColumnPortalController.cs +++ b/src/modules/mix.portal/Controllers/MixDatabaseColumnPortalController.cs @@ -20,7 +20,7 @@ public MixDatabaseColumnPortalController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixDatabaseContextController.cs b/src/modules/mix.portal/Controllers/MixDatabaseContextController.cs index 1e8bb14be..3efe6a8da 100644 --- a/src/modules/mix.portal/Controllers/MixDatabaseContextController.cs +++ b/src/modules/mix.portal/Controllers/MixDatabaseContextController.cs @@ -15,7 +15,7 @@ public class MixDatabaseContextController : MixRestfulApiControllerBase { private readonly IMixDbService _mixDbService; - public MixDatabaseContextController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IQueueService queueService, + public MixDatabaseContextController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService, IMixDbService mixDbService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixDatabaseController.cs b/src/modules/mix.portal/Controllers/MixDatabaseController.cs index f867a2bb0..04ba479ac 100644 --- a/src/modules/mix.portal/Controllers/MixDatabaseController.cs +++ b/src/modules/mix.portal/Controllers/MixDatabaseController.cs @@ -3,6 +3,7 @@ using Mix.Lib.Interfaces; using Mix.Mq.Lib.Models; using Mix.RepoDb.Interfaces; +using Mix.RepoDb.ViewModels; using Mix.SignalR.Interfaces; namespace Mix.Portal.Controllers @@ -21,7 +22,7 @@ public MixDatabaseController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, IMixDbService mixDbService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) @@ -62,7 +63,9 @@ public async Task> Duplicate(int id, Cancella public async Task Migrate(string name) { //await _mixDbService.BackupDatabase(name); - var result = await _mixDbService.MigrateDatabase(name); + RepoDbMixDatabaseViewModel database = await RepoDbMixDatabaseViewModel + .GetRepository(Uow, CacheService).GetSingleAsync(m => m.SystemName == name); + var result = await _mixDbService.MigrateDatabase(database); //await _mixDbService.RestoreFromLocal(name); return result ? Ok() : BadRequest(); } @@ -72,7 +75,7 @@ public async Task Migrate(string name) public ActionResult Backup(string name) { var msg = new MessageQueueModel(CurrentTenant.Id, MixQueueTopics.MixRepoDb, MixRepoDbQueueAction.Backup, name); - QueueService.PushQueue(msg); + QueueService.PushMemoryQueue(msg); return Ok(); } @@ -81,7 +84,7 @@ public ActionResult Backup(string name) public ActionResult RestoreAsync(string name) { var msg = new MessageQueueModel(CurrentTenant.Id, MixQueueTopics.MixRepoDb, MixRepoDbQueueAction.Restore, name); - QueueService.PushQueue(msg); + QueueService.PushMemoryQueue(msg); return Ok(); } @@ -90,7 +93,7 @@ public ActionResult RestoreAsync(string name) public ActionResult UpdateAsync(string name) { var msg = new MessageQueueModel(CurrentTenant.Id, MixQueueTopics.MixRepoDb, MixRepoDbQueueAction.Update, name); - QueueService.PushQueue(msg); + QueueService.PushMemoryQueue(msg); return Ok(); } diff --git a/src/modules/mix.portal/Controllers/MixDatabaseRelationshipController.cs b/src/modules/mix.portal/Controllers/MixDatabaseRelationshipController.cs index 191e63115..4f4c9c6ed 100644 --- a/src/modules/mix.portal/Controllers/MixDatabaseRelationshipController.cs +++ b/src/modules/mix.portal/Controllers/MixDatabaseRelationshipController.cs @@ -19,7 +19,7 @@ public MixDatabaseRelationshipController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixDbController.cs b/src/modules/mix.portal/Controllers/MixDbController.cs index 02b88f918..da92e0c75 100644 --- a/src/modules/mix.portal/Controllers/MixDbController.cs +++ b/src/modules/mix.portal/Controllers/MixDbController.cs @@ -28,21 +28,6 @@ namespace Mix.Portal.Controllers public class MixDbController : MixTenantApiControllerBase { ILogger _logger; - private const string CreatedByFieldName = "CreatedBy"; - private const string ModifiedByFieldName = "ModifiedBy"; - private const string LastModifiedFieldName = "LastModified"; - private const string CreatedDateFieldName = "CreatedDateTime"; - private const string PriorityFieldName = "Priority"; - private const string IdFieldName = "Id"; - private const string GuidParentIdFieldName = "GuidParentId"; - private const string ParentIdFieldName = "ParentId"; - private const string ParentNameFieldName = "ParentDatabaseName"; - private const string ChildNameFieldName = "ChildDatabaseName"; - private const string GuidChildIdFieldName = "GuidChildId"; - private const string ChildIdFieldName = "ChildId"; - private const string TenantIdFieldName = "MixTenantId"; - private const string StatusFieldName = "Status"; - private const string IsDeletedFieldName = "IsDeleted"; private readonly UnitOfWorkInfo _cmsUow; private readonly MixRepoDbRepository _repository; private readonly IMixMemoryCacheService _memoryCache; @@ -55,13 +40,14 @@ public class MixDbController : MixTenantApiControllerBase private const string AssociationTableName = nameof(MixDatabaseAssociation); private IMixDbCommandHubClientService _mixDbCommandHubClientService; private RepoDbMixDatabaseViewModel _mixDb; + private FieldNameService _fieldNameService; public MixDbController( IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - IQueueService queueService, + IMemoryQueueService queueService, MixRepoDbRepository repository, IMixMemoryCacheService memoryCache, UnitOfWorkInfo cmsUow, @@ -93,6 +79,7 @@ public override async Task OnActionExecutionAsync(ActionExecutingContext context { _tableName = RouteData?.Values["name"].ToString(); _mixDb = await GetMixDatabase(); + _fieldNameService = new FieldNameService(_mixDb.NamingConvention); if (_mixDb.MixDatabaseContextId.HasValue) { _repository.Init(_tableName, _mixDb.MixDatabaseContext.DatabaseProvider, _mixDb.MixDatabaseContext.ConnectionString); @@ -170,7 +157,7 @@ public async Task Import([FromForm] IFormFile file) List lstDto = new(); foreach (var item in data) { - lstDto.Add(await MixDbHelper.ParseImportDtoToEntityAsync(item, _mixDb.Columns, CurrentTenant.Id, _idService.GetClaim(User, MixClaims.Username))); + lstDto.Add(await MixDbHelper.ParseImportDtoToEntityAsync(item, _mixDb.Columns, _fieldNameService, CurrentTenant.Id, _idService.GetClaim(User, MixClaims.Username))); } var result = await _repository.InsertManyAsync(lstDto, _mixDb); @@ -183,7 +170,7 @@ public async Task> GetSingle(int id, [FromQuery] bool load { var result = await _mixDbService.GetById(_tableName, id, loadNestedData); string username = _idService.GetClaim(User, MixClaims.Username); - QueueService.PushQueue(CurrentTenant.Id, + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent , new MixDbEventCommand(username, "GET", _tableName, result)); @@ -200,25 +187,25 @@ public async Task> UpdatePriority(string dbName, int id, [ return NotFound(); } - var min = Math.Min((int)data[PriorityFieldName], dto.Priority); - var max = Math.Max((int)data[PriorityFieldName], dto.Priority); + var min = Math.Min((int)data[_fieldNameService.Priority], dto.Priority); + var max = Math.Max((int)data[_fieldNameService.Priority], dto.Priority); var queryFields = new List { - new SearchQueryField(IdFieldName, id, MixCompareOperator.NotEqual), - new SearchQueryField(PriorityFieldName, max, MixCompareOperator.LessThanOrEqual), - new SearchQueryField(PriorityFieldName, max, MixCompareOperator.LessThanOrEqual) + new SearchQueryField(_fieldNameService.Id, id, MixCompareOperator.NotEqual), + new SearchQueryField(_fieldNameService.Priority, max, MixCompareOperator.LessThanOrEqual), + new SearchQueryField(_fieldNameService.Priority, max, MixCompareOperator.LessThanOrEqual) }; var query = await _repository.GetListByAsync(queryFields); int start = min; if (dto.Priority == min) { - data[PriorityFieldName] = dto.Priority; + data[_fieldNameService.Priority] = dto.Priority; start++; } - foreach (var item in query.OrderBy(m => m[PriorityFieldName])) + foreach (var item in query.OrderBy(m => m[_fieldNameService.Priority])) { item.Priority = start; await _repository.UpdateAsync(item, _mixDb); @@ -227,7 +214,7 @@ public async Task> UpdatePriority(string dbName, int id, [ if (dto.Priority == max) { - data[PriorityFieldName] = start; + data[_fieldNameService.Priority] = start; } await _repository.UpdateAsync(data, _mixDb); @@ -253,9 +240,9 @@ public async Task> GetSingleByParent(MixContentType parent var associations = await _associationRepository.GetListByAsync(queries); if (associations is { Count: > 0 }) { - var nestedIds = JArray.FromObject(associations).Select(m => m.Value(ChildIdFieldName)).ToList(); + var nestedIds = JArray.FromObject(associations).Select(m => m.Value(_fieldNameService.ChildId)).ToList(); _repository.InitTableName(item.DestinateDatabaseName); - List query = new() { new(IdFieldName, Operation.In, nestedIds) }; + List query = new() { new(_fieldNameService.Id, Operation.In, nestedIds) }; var nestedData = await _repository.GetListByAsync(query); if (nestedData != null) { @@ -303,9 +290,9 @@ public async Task> GetSingleByGuidParent(MixContentType pa var associations = await _associationRepository.GetListByAsync(queries); if (associations is { Count: > 0 }) { - var nestedIds = JArray.FromObject(associations).Select(m => m.Value(ChildIdFieldName)).ToList(); + var nestedIds = JArray.FromObject(associations).Select(m => m.Value(_fieldNameService.ChildId)).ToList(); _repository.InitTableName(item.DestinateDatabaseName); - List query = new() { new(IdFieldName, Operation.In, nestedIds) }; + List query = new() { new(_fieldNameService.Id, Operation.In, nestedIds) }; var nestedData = await _repository.GetListByAsync(query); if (nestedData != null) { @@ -344,7 +331,7 @@ public ActionResult CreateHub(object dto) Body = JObject.FromObject(dto), MixDbName = _tableName }; - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixDbCommand, MixDbCommandQueueActions.Create, obj); + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixDbCommand, MixDbCommandQueueActions.Create, obj); return Ok(); } @@ -353,17 +340,17 @@ public ActionResult CreateHub(object dto) public async Task> Create(JObject dto) { string username = _idService.GetClaim(User, MixClaims.Username); - JObject obj = await MixDbHelper.ParseDtoToEntityAsync(dto, _mixDb.Columns, CurrentTenant.Id, username); + JObject obj = await MixDbHelper.ParseDtoToEntityAsync(dto, _mixDb.Columns, _fieldNameService, CurrentTenant.Id, username); var id = await _repository.InsertAsync(obj, _mixDb); - var resp = await _repository.GetSingleAsync(id); + var resp = await _repository.GetSingleAsync(new QueryField(_fieldNameService.Id, id)); - if (obj.ContainsKey(ParentIdFieldName)) + if (obj.ContainsKey(_fieldNameService.ParentId)) { - await CreateDataRelationship(obj.Value(ParentNameFieldName), obj.Value(ParentIdFieldName), obj.Value(ChildNameFieldName), id.ToString(), username); + await CreateDataRelationship(obj.Value(_fieldNameService.ParentDatabaseName), obj.Value(_fieldNameService.ParentId), obj.Value(_fieldNameService.ChildDatabaseName), id.ToString(), username); } var result = resp != null ? ReflectionHelper.ParseObject(resp) : obj; - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent, + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent, new MixDbEventCommand(username, "POST", _tableName, result)); return Ok(result); } @@ -373,13 +360,13 @@ public async Task> Create(JObject dto) [HttpPut("{id}")] public async Task> Update(int id, [FromBody] JObject dto) { - JObject obj = await MixDbHelper.ParseDtoToEntityAsync(dto, _mixDb.Columns, CurrentTenant.Id, _idService.GetClaim(User, MixClaims.Username)); + JObject obj = await MixDbHelper.ParseDtoToEntityAsync(dto, _mixDb.Columns, _fieldNameService, CurrentTenant.Id, _idService.GetClaim(User, MixClaims.Username)); var data = await _repository.UpdateAsync(obj, _mixDb); if (data != null) { - var result = await _repository.GetSingleAsync(id); + var result = await _repository.GetSingleAsync(new QueryField(_fieldNameService.Id, id)); var resp = result != null ? ReflectionHelper.ParseObject(result) : obj; await NotifyResult(id, resp); return Ok(ReflectionHelper.ParseObject(resp)); @@ -392,7 +379,7 @@ private async Task NotifyResult(int id, JObject obj) try { string username = _idService.GetClaim(User, MixClaims.Username); - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent, + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent, new MixDbEventCommand(username, "PUT", _tableName, obj)); var modifiedEnties = new List() { @@ -447,7 +434,7 @@ public async Task> Delete(int id) await _repository.DeleteAsync(childAssociationsQueries); await _repository.DeleteAsync(parentAssociationsQueries); string username = _idService.GetClaim(User, MixClaims.Username); - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent, + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent, new MixDbEventCommand(username, "DELETE", _tableName, new(new JProperty("data", id)))); return data > 0 ? Ok() : NotFound(); } @@ -481,7 +468,8 @@ private async Task CreateDataRelationship(string parentName, string parentId, st string relDbName = GetRelationshipDbName(); _repository.InitTableName(relDbName); var relDb = await GetMixDatabase(relDbName); - var obj = await MixDbHelper.ParseDtoToEntityAsync(JObject.FromObject(rel), relDb.Columns, CurrentTenant.Id, username); + var fieldNameService = new FieldNameService(relDb.NamingConvention); + var obj = await MixDbHelper.ParseDtoToEntityAsync(JObject.FromObject(rel), relDb.Columns, fieldNameService, CurrentTenant.Id, username); await _repository.InsertAsync(obj, relDb); } @@ -489,7 +477,7 @@ private string GetRelationshipDbName() { return _mixDb.MixDatabaseContextId.HasValue ? $"{_mixDb.MixDatabaseContext.SystemName}_{MixDatabaseNames.DATA_RELATIONSHIP}" - : MixDatabaseNames.DATA_RELATIONSHIP; + : $"sys{MixDatabaseNames.DATA_RELATIONSHIP}"; } private async Task PatchManyHandler(IEnumerable lstObj, CancellationToken cancellationToken) @@ -516,7 +504,7 @@ private async Task PatchHandler(JObject objDto, CancellationToken cancellationTo try { var id = objDto.Value("id"); - var data = await _repository.GetSingleAsync(id); + var data = await _repository.GetSingleAsync(new QueryField(_fieldNameService.Id, id)); if (data == null) { throw new MixException(MixErrorStatus.NotFound); @@ -530,7 +518,7 @@ private async Task PatchHandler(JObject objDto, CancellationToken cancellationTo foreach (var prop in objDto.Properties()) { - var propName = prop.Name.ToTitleCase(); + var propName = prop.Name; if (obj.ContainsKey(propName)) { obj[propName] = prop.Value; @@ -538,7 +526,7 @@ private async Task PatchHandler(JObject objDto, CancellationToken cancellationTo } await _repository.UpdateAsync(objDto, _mixDb); - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent, + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.MixDbEvent, new MixDbEventCommand(username, "PATCH", _tableName, objDto)); } catch (Exception ex) @@ -594,11 +582,11 @@ private async Task> GetResult(IEnumerable 0 }) { JArray nestedDataList = new(); - var nestedIds = JArray.FromObject(associations).Select(m => m.Value(ChildIdFieldName)).ToList(); + var nestedIds = JArray.FromObject(associations).Select(m => m.Value(_fieldNameService.ChildId)).ToList(); _repository.InitTableName(rel.DestinateDatabaseName); - List query = new() { new(IdFieldName, Operation.In, nestedIds) }; + List query = new() { new(_fieldNameService.Id, Operation.In, nestedIds) }; var nestedData = await _repository.GetListByAsync(query); foreach (var nestedId in nestedIds) { @@ -649,22 +637,23 @@ private async Task FilterByIntegerId(List queries, SearchMixDbReques { if (_mixDb.Type == MixDatabaseType.AdditionalData) { - queries.Add(new(ParentIdFieldName, request.ParentId)); + queries.Add(new(_fieldNameService.ParentId, request.ParentId)); } else { _repository.InitTableName(GetRelationshipDbName()); + var relQuery = new List() { - new QueryField(ParentNameFieldName, request.ParentName), - new QueryField(ChildNameFieldName, _tableName) + new QueryField(_fieldNameService.ParentDatabaseName, request.ParentName), + new QueryField(_fieldNameService.ChildDatabaseName, _tableName) }; if (request.ParentId.HasValue) { - relQuery.Add(new(ParentIdFieldName, request.ParentId.Value)); + relQuery.Add(new(_fieldNameService.ParentId, request.ParentId.Value)); } var allowsIds = await _repository.GetListByAsync(relQuery); - queries.Add(new(IdFieldName, Operation.In, allowsIds.Select(m => m.ChildId))); + queries.Add(new(_fieldNameService.Id, Operation.In, allowsIds.Select(m => m.ChildId))); _repository.InitTableName(_tableName); } } @@ -673,22 +662,29 @@ private async Task FilterByGuidId(List queries, SearchMixDbRequestDt { if (_mixDb.Type == MixDatabaseType.GuidAdditionalData) { - queries.Add(new(ParentIdFieldName, request.GuidParentId)); + queries.Add(new(_fieldNameService.ParentId, request.GuidParentId)); } else { _repository.InitTableName(GetRelationshipDbName()); var relQuery = new List() { - new QueryField(ParentNameFieldName, request.ParentName), - new QueryField(ChildNameFieldName, _tableName) + new QueryField(_fieldNameService.ParentDatabaseName, request.ParentName), + new QueryField(_fieldNameService.ChildDatabaseName, _tableName) }; if (request.GuidParentId.HasValue) { - relQuery.Add(new(GuidParentIdFieldName, request.GuidParentId.Value)); + relQuery.Add(new(_fieldNameService.ParentId, request.GuidParentId.Value)); } var allowsIds = await _repository.GetListByAsync(relQuery); - queries.Add(new(IdFieldName, Operation.In, allowsIds.Select(m => m.GuildChildId))); + if (request.ParentName == "Role" || request.ParentName == "User") + { + queries.Add(new(_fieldNameService.Id, Operation.In, allowsIds.Select(m => m.ChildId))); + } + else + { + queries.Add(new(_fieldNameService.Id, Operation.In, allowsIds.Select(m => m.GuildChildId))); + } _repository.InitTableName(_tableName); } } @@ -726,10 +722,11 @@ private Operation ParseOperator(MixCompareOperator compareOperator) private IEnumerable BuildSearchPredicate(SearchMixDbRequestDto req) { + req.OrderBy = ReflectionHelper.GetPropertyValue(_fieldNameService, req.OrderBy).ToString(); var operation = ParseSearchOperation(req.SearchMethod); var queries = new List() { - new QueryField(TenantIdFieldName, CurrentTenant.Id) + new QueryField(_fieldNameService.TenantId, CurrentTenant.Id) }; if (!string.IsNullOrEmpty(req.SearchColumns) && !string.IsNullOrEmpty(req.Keyword)) { @@ -795,11 +792,11 @@ private List GetAssociationQueries(string parentDatabaseName = null, } if (parentId.HasValue) { - queries.Add(new QueryField(ParentIdFieldName, parentId)); + queries.Add(new QueryField(_fieldNameService.ParentId, parentId)); } if (childId.HasValue) { - queries.Add(new QueryField(ChildIdFieldName, childId)); + queries.Add(new QueryField(_fieldNameService.ChildId, childId)); } return queries; } diff --git a/src/modules/mix.portal/Controllers/MixDomainController.cs b/src/modules/mix.portal/Controllers/MixDomainController.cs index a60173b84..882012500 100644 --- a/src/modules/mix.portal/Controllers/MixDomainController.cs +++ b/src/modules/mix.portal/Controllers/MixDomainController.cs @@ -16,7 +16,7 @@ public MixDomainController( IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, - TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IQueueService queueService, + TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixLanguageController.cs b/src/modules/mix.portal/Controllers/MixLanguageController.cs index 18ee0f1d3..ee86c5a9e 100644 --- a/src/modules/mix.portal/Controllers/MixLanguageController.cs +++ b/src/modules/mix.portal/Controllers/MixLanguageController.cs @@ -12,7 +12,7 @@ namespace Mix.Portal.Controllers public class MixLanguageController : MixRestfulApiControllerBase { - public MixLanguageController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IQueueService queueService, + public MixLanguageController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixModuleContentController.cs b/src/modules/mix.portal/Controllers/MixModuleContentController.cs index 8990d6882..9f513ddae 100644 --- a/src/modules/mix.portal/Controllers/MixModuleContentController.cs +++ b/src/modules/mix.portal/Controllers/MixModuleContentController.cs @@ -18,7 +18,7 @@ public MixModuleController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) diff --git a/src/modules/mix.portal/Controllers/MixModuleController.cs b/src/modules/mix.portal/Controllers/MixModuleController.cs index 56f993966..7458051f9 100644 --- a/src/modules/mix.portal/Controllers/MixModuleController.cs +++ b/src/modules/mix.portal/Controllers/MixModuleController.cs @@ -18,7 +18,7 @@ public MixModuleContentController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) diff --git a/src/modules/mix.portal/Controllers/MixModuleDataController.cs b/src/modules/mix.portal/Controllers/MixModuleDataController.cs index 128f36d01..eb18b3a04 100644 --- a/src/modules/mix.portal/Controllers/MixModuleDataController.cs +++ b/src/modules/mix.portal/Controllers/MixModuleDataController.cs @@ -18,7 +18,7 @@ public MixModuleDataController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, IMixDbService mixDbService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) diff --git a/src/modules/mix.portal/Controllers/MixModulePostPortalController.cs b/src/modules/mix.portal/Controllers/MixModulePostPortalController.cs index 0d7847e98..ef1a05614 100644 --- a/src/modules/mix.portal/Controllers/MixModulePostPortalController.cs +++ b/src/modules/mix.portal/Controllers/MixModulePostPortalController.cs @@ -19,7 +19,7 @@ public MixModulePostController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixPageContentController.cs b/src/modules/mix.portal/Controllers/MixPageContentController.cs index caf99edf2..e1c559100 100644 --- a/src/modules/mix.portal/Controllers/MixPageContentController.cs +++ b/src/modules/mix.portal/Controllers/MixPageContentController.cs @@ -20,7 +20,7 @@ public MixPageContentController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(MixContentType.Page, identityService, userManager, diff --git a/src/modules/mix.portal/Controllers/MixPageController.cs b/src/modules/mix.portal/Controllers/MixPageController.cs index ad6e2c4bf..d76077877 100644 --- a/src/modules/mix.portal/Controllers/MixPageController.cs +++ b/src/modules/mix.portal/Controllers/MixPageController.cs @@ -18,7 +18,7 @@ public MixPageController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) diff --git a/src/modules/mix.portal/Controllers/MixPageModuleController.cs b/src/modules/mix.portal/Controllers/MixPageModuleController.cs index 9215fa5ff..63486514d 100644 --- a/src/modules/mix.portal/Controllers/MixPageModuleController.cs +++ b/src/modules/mix.portal/Controllers/MixPageModuleController.cs @@ -19,7 +19,7 @@ public MixPageModuleController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixPagePostPortalController.cs b/src/modules/mix.portal/Controllers/MixPagePostPortalController.cs index 1695136ce..d70e07996 100644 --- a/src/modules/mix.portal/Controllers/MixPagePostPortalController.cs +++ b/src/modules/mix.portal/Controllers/MixPagePostPortalController.cs @@ -12,7 +12,7 @@ public class MixPagePostController { private readonly UnitOfWorkInfo _cmsUow; - public MixPagePostController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, IQueueService queueService, + public MixPagePostController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixPostContentController.cs b/src/modules/mix.portal/Controllers/MixPostContentController.cs index 5765bba56..95084ced0 100644 --- a/src/modules/mix.portal/Controllers/MixPostContentController.cs +++ b/src/modules/mix.portal/Controllers/MixPostContentController.cs @@ -25,7 +25,7 @@ public MixPostContentController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, MixRepoDbRepository mixRepoDbRepository, PortalPostService postService, IPortalHubClientService portalHub, diff --git a/src/modules/mix.portal/Controllers/MixPostController.cs b/src/modules/mix.portal/Controllers/MixPostController.cs index 320a6608b..33cab372f 100644 --- a/src/modules/mix.portal/Controllers/MixPostController.cs +++ b/src/modules/mix.portal/Controllers/MixPostController.cs @@ -18,7 +18,7 @@ public MixPostController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) diff --git a/src/modules/mix.portal/Controllers/MixPostPostController.cs b/src/modules/mix.portal/Controllers/MixPostPostController.cs index 9784a2ea6..0bca50bac 100644 --- a/src/modules/mix.portal/Controllers/MixPostPostController.cs +++ b/src/modules/mix.portal/Controllers/MixPostPostController.cs @@ -12,7 +12,7 @@ public class MixPostPostController { private readonly UnitOfWorkInfo _cmsUow; - public MixPostPostController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, IQueueService queueService, + public MixPostPostController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixTemplateController.cs b/src/modules/mix.portal/Controllers/MixTemplateController.cs index c909723b3..31bf0d139 100644 --- a/src/modules/mix.portal/Controllers/MixTemplateController.cs +++ b/src/modules/mix.portal/Controllers/MixTemplateController.cs @@ -19,7 +19,7 @@ public MixTemplateController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.portal/Controllers/MixTenantController.cs b/src/modules/mix.portal/Controllers/MixTenantController.cs index 2796f26a3..0925d37e2 100644 --- a/src/modules/mix.portal/Controllers/MixTenantController.cs +++ b/src/modules/mix.portal/Controllers/MixTenantController.cs @@ -30,7 +30,7 @@ public MixTenantController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) diff --git a/src/modules/mix.portal/Controllers/MixThemeController.cs b/src/modules/mix.portal/Controllers/MixThemeController.cs index eb960fbb4..eb99a7db3 100644 --- a/src/modules/mix.portal/Controllers/MixThemeController.cs +++ b/src/modules/mix.portal/Controllers/MixThemeController.cs @@ -35,7 +35,7 @@ public MixThemeController( IMixThemeImportService importService, IMixThemeExportService exportService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, HttpService httpService, IHubContext hubContext, MixConfigurationService configService, diff --git a/src/modules/mix.portal/Controllers/MixUrlAliasController.cs b/src/modules/mix.portal/Controllers/MixUrlAliasController.cs index 96df5efa0..b02ed0f2b 100644 --- a/src/modules/mix.portal/Controllers/MixUrlAliasController.cs +++ b/src/modules/mix.portal/Controllers/MixUrlAliasController.cs @@ -18,7 +18,7 @@ public MixUrlAliasController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) diff --git a/src/modules/mix.portal/Controllers/MixViewTemplateController.cs b/src/modules/mix.portal/Controllers/MixViewTemplateController.cs index 7c5307c88..578dcf067 100644 --- a/src/modules/mix.portal/Controllers/MixViewTemplateController.cs +++ b/src/modules/mix.portal/Controllers/MixViewTemplateController.cs @@ -18,7 +18,7 @@ public MixViewTemplateController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) diff --git a/src/modules/mix.portal/Domain/Services/MixApplicationService.cs b/src/modules/mix.portal/Domain/Services/MixApplicationService.cs index 711dc33ea..33752eb7f 100644 --- a/src/modules/mix.portal/Domain/Services/MixApplicationService.cs +++ b/src/modules/mix.portal/Domain/Services/MixApplicationService.cs @@ -22,7 +22,7 @@ public sealed class MixApplicationService : TenantServiceBase, IMixApplicationSe { static string[] excludeFileNames = { "jquery", "index" }; static string allowExtensionsPattern = "json|js|css|webmanifest|ico|png|jpg|jpeg|gif|svg|webm|mp3|mp4|wmv"; - private readonly IQueueService _queueService; + private readonly IMemoryQueueService _queueService; private readonly IThemeService _themeService; private readonly IMixThemeImportService _importService; private readonly MixIdentityService _mixIdentityService; @@ -36,7 +36,7 @@ public MixApplicationService( HttpService httpService, MixIdentityService mixIdentityService, IThemeService themeService, - IQueueService queueService, + IMemoryQueueService queueService, MixCacheService cacheService, IMixTenantService mixTenantService, IMixThemeImportService importService) @@ -237,7 +237,7 @@ private async Task ModifyFilesAndFolders(string deployUrl, string topFolder, str template.Content = indexFile.Content.Replace("@", "@@") .Replace("", "
@Model.AppSettings.ToString()
"); await template.SaveAsync(); - _queueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixViewModelChanged, MixRestAction.Post.ToString(), template); + _queueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixViewModelChanged, MixRestAction.Post.ToString(), template); MixFileHelper.SaveFile(indexFile); _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Status", 200, $"Modified {name}.cshtml successfully"); return template.Id; diff --git a/src/modules/mix.portal/Domain/StartupService.cs b/src/modules/mix.portal/Domain/StartupService.cs index 92741ee7a..8f4dddbce 100644 --- a/src/modules/mix.portal/Domain/StartupService.cs +++ b/src/modules/mix.portal/Domain/StartupService.cs @@ -1,4 +1,5 @@ -using Mix.Portal.Domain.Interfaces; +using Mix.Lib.Interfaces; +using Mix.Portal.Domain.Interfaces; using Mix.Portal.Domain.Services; using Mix.Shared.Interfaces; diff --git a/src/modules/mix.portal/Program.cs b/src/modules/mix.portal/Program.cs index 67400da0a..73350b7cd 100644 --- a/src/modules/mix.portal/Program.cs +++ b/src/modules/mix.portal/Program.cs @@ -6,9 +6,10 @@ using Mix.Lib.Middlewares; var builder = MixCmsHelper.CreateWebApplicationBuilder(args); - -builder.AddServiceDefaults(); - +if (builder.Environment.IsDevelopment()) +{ + builder.AddServiceDefaults(); +} if (!Directory.Exists(MixFolders.MixContentSharedFolder)) { MixFileHelper.CopyFolder(MixFolders.MixCoreConfigurationFolder, MixFolders.MixContentSharedFolder); diff --git a/src/modules/mix.scheduler/Domain/Jobs/KeepPoolAliveJob.cs b/src/modules/mix.scheduler/Domain/Jobs/KeepPoolAliveJob.cs index 05882281d..ad667e0dd 100644 --- a/src/modules/mix.scheduler/Domain/Jobs/KeepPoolAliveJob.cs +++ b/src/modules/mix.scheduler/Domain/Jobs/KeepPoolAliveJob.cs @@ -8,6 +8,9 @@ using Mix.Quartz.Models; using NuGet.Packaging.Signing; using Mix.Mq.Lib.Models; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using System.Collections.Immutable; namespace Mix.Scheduler.Domain.Jobs { @@ -17,7 +20,7 @@ public class KeepPoolAliveJob : MixJobBase public KeepPoolAliveJob( HttpService httpService, IServiceProvider serviceProvider, - IQueueService queueService) + IMemoryQueueService queueService) : base(serviceProvider, queueService) { _httpService = httpService; @@ -32,19 +35,23 @@ public KeepPoolAliveJob( public override async Task ExecuteHandler(IJobExecutionContext context) { - if (context.Trigger.JobDataMap.ContainsKey("domain")) + if (context.Trigger.JobDataMap.ContainsKey("data")) { - try + var objData = JObject.Parse(context.Trigger.JobDataMap.GetString("data") ?? "{}"); + var domains = objData.Value("domains"); + foreach (var domain in domains) { - string domain = context.Trigger.JobDataMap.GetString("domain"); - var now = DateTime.UtcNow; - var ping = await _httpService.GetStringAsync($"{domain.TrimEnd('/')}"); + try + { + var now = DateTime.UtcNow; + var ping = await _httpService.GetStringAsync($"{domain.ToString().TrimEnd('/')}"); - Console.WriteLine($"Ping at {now}: {(DateTime.Now - now).TotalMilliseconds}"); - } - catch (Exception ex) - { - Console.WriteLine("Cannot Ping: " + ex.Message); + Console.WriteLine($"Ping {domain} at {now}: {(DateTime.Now - now).TotalMilliseconds}"); + } + catch (Exception ex) + { + Console.WriteLine($"Cannot Ping: {domain}" + ex.Message); + } } } Console.WriteLine(DateTime.UtcNow); diff --git a/src/modules/mix.scheduler/Domain/Jobs/PublishScheduledPostsJob.cs b/src/modules/mix.scheduler/Domain/Jobs/PublishScheduledPostsJob.cs index 04f5a07c2..97a826a96 100644 --- a/src/modules/mix.scheduler/Domain/Jobs/PublishScheduledPostsJob.cs +++ b/src/modules/mix.scheduler/Domain/Jobs/PublishScheduledPostsJob.cs @@ -11,7 +11,7 @@ public class PublishScheduledPostsJob : MixJobBase { public PublishScheduledPostsJob( IServiceProvider serviceProvider, - IQueueService queueService) : base(serviceProvider, queueService) + IMemoryQueueService queueService) : base(serviceProvider, queueService) { } diff --git a/src/modules/mix.scheduler/Domain/Jobs/SendMessageQueueJob.cs b/src/modules/mix.scheduler/Domain/Jobs/SendMessageQueueJob.cs index b5c5e0d17..d81a91bc6 100644 --- a/src/modules/mix.scheduler/Domain/Jobs/SendMessageQueueJob.cs +++ b/src/modules/mix.scheduler/Domain/Jobs/SendMessageQueueJob.cs @@ -11,7 +11,7 @@ namespace Mix.Scheduler.Domain.Jobs public class SendMessageQueueJob : MixJobBase { public SendMessageQueueJob( - IQueueService queueService, + IMemoryQueueService queueService, IServiceProvider serviceProvider) : base(serviceProvider, queueService) { } @@ -19,7 +19,7 @@ public SendMessageQueueJob( public override Task ExecuteHandler(IJobExecutionContext context) { var objData = JObject.Parse(context.Trigger.JobDataMap.GetString("data") ?? "{}"); - int tenantId = objData.Value("tenantId"); + int tenantId = objData.Value("tenantId") ?? 1; var msg = new MessageQueueModel(tenantId) { @@ -29,7 +29,7 @@ public override Task ExecuteHandler(IJobExecutionContext context) Data = objData.Value("data").ToString() }; - QueueService.PushQueue(msg); + QueueService.PushMemoryQueue(msg); return Task.CompletedTask; } diff --git a/src/modules/mix.scheduler/Domain/Jobs/SendPortalMessageJob.cs b/src/modules/mix.scheduler/Domain/Jobs/SendPortalMessageJob.cs index 38b38815a..a315adb33 100644 --- a/src/modules/mix.scheduler/Domain/Jobs/SendPortalMessageJob.cs +++ b/src/modules/mix.scheduler/Domain/Jobs/SendPortalMessageJob.cs @@ -15,7 +15,7 @@ public class SendPortalMessageJob : MixJobBase private readonly IPortalHubClientService _portalHub; public SendPortalMessageJob( IServiceProvider serviceProvider, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub) : base(serviceProvider, queueService) { diff --git a/src/modules/mix.scheduler/Domain/StartupService.cs b/src/modules/mix.scheduler/Domain/StartupService.cs index 468ed469e..488868f19 100644 --- a/src/modules/mix.scheduler/Domain/StartupService.cs +++ b/src/modules/mix.scheduler/Domain/StartupService.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Mix.Lib.Interfaces; using Mix.Shared.Interfaces; namespace Mix.Scheduler.Domain diff --git a/src/modules/mix.storage/Controllers/FileSystemController.cs b/src/modules/mix.storage/Controllers/FileSystemController.cs index 8fbb90cf2..cefc3f4fb 100644 --- a/src/modules/mix.storage/Controllers/FileSystemController.cs +++ b/src/modules/mix.storage/Controllers/FileSystemController.cs @@ -18,7 +18,7 @@ public FileSystemController( MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - IQueueService queueService, + IMemoryQueueService queueService, MixStorageService storageService, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.storage/Controllers/StorageController.cs b/src/modules/mix.storage/Controllers/StorageController.cs index 56b64b08c..2c1b5358e 100644 --- a/src/modules/mix.storage/Controllers/StorageController.cs +++ b/src/modules/mix.storage/Controllers/StorageController.cs @@ -12,7 +12,7 @@ public class StorageController : MixRestfulApiControllerBase uow, IQueueService queueService, + public StorageController(MixStorageService storageService, IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/modules/mix.storage/Domain/StartupService.cs b/src/modules/mix.storage/Domain/StartupService.cs index e1f01114b..7efc09874 100644 --- a/src/modules/mix.storage/Domain/StartupService.cs +++ b/src/modules/mix.storage/Domain/StartupService.cs @@ -1,4 +1,5 @@ -using Mix.Shared.Interfaces; +using Mix.Lib.Interfaces; +using Mix.Shared.Interfaces; using Mix.Storage.Lib.Extensions; namespace Mix.Storage.Domain diff --git a/src/modules/mix.tenancy/Controllers/InitController.cs b/src/modules/mix.tenancy/Controllers/InitController.cs index dc9f4f0ff..673860b36 100644 --- a/src/modules/mix.tenancy/Controllers/InitController.cs +++ b/src/modules/mix.tenancy/Controllers/InitController.cs @@ -42,7 +42,7 @@ public InitController( TranslatorService translator, IInitCmsService initCmsService, MixIdentityService mixIdentityService, - IQueueService queueService, + IMemoryQueueService queueService, IMixThemeImportService importService, IQuartzService quartzService, HttpService httpService, @@ -97,6 +97,7 @@ public async Task> InitTenant([FromBody] InitCmsDto model) await _mixTenantService.Reload(); Session.Put(MixRequestQueryKeywords.Tenant, _mixTenantService.AllTenants.First()); _mixEndpointService.SetDefaultDomain($"https://{model.PrimaryDomain}"); + return Ok(); } catch (Exception ex) diff --git a/src/platform/core/mix-heart b/src/platform/core/mix-heart index fb6e57bcb..01a0d0a28 160000 --- a/src/platform/core/mix-heart +++ b/src/platform/core/mix-heart @@ -1 +1 @@ -Subproject commit fb6e57bcb4506dea2f9fc89579fa962e5f204fd5 +Subproject commit 01a0d0a28b6e3e10be5b7cb34eca198338a366c9 diff --git a/src/platform/core/mix.mixdb.event/Services/MixDbEventService.cs b/src/platform/core/mix.mixdb.event/Services/MixDbEventService.cs index a630bdf82..c0a44dbab 100644 --- a/src/platform/core/mix.mixdb.event/Services/MixDbEventService.cs +++ b/src/platform/core/mix.mixdb.event/Services/MixDbEventService.cs @@ -47,22 +47,36 @@ public MixDbEventService(DatabaseService databaseService, HttpService httpServic IServiceProvider servicesProvider, IConfiguration configuration) { + ServicesProvider = servicesProvider; + PortalHub = portalHub; _databaseService = databaseService; _globalConfig = configuration.GetSection(MixAppSettingsSection.GlobalSettings).Get()!; LoadEvents(); _httpService = httpService; - PortalHub = portalHub; _mixPermissionService = mixPermissionService; - ServicesProvider = servicesProvider; } - public void LoadEvents() + public void LoadEvents(IServiceScope? serviceScope = null) { if (!_globalConfig.IsInit) { - var repo = MixDbEventSubscriberViewModel.GetRootRepository(new MixDbDbContext(_databaseService), null); - Subscribers = repo.GetAllAsync(m => !m.IsDeleted).GetAwaiter().GetResult(); - repo.UowInfo.Complete(); + try + { + var _serviceScope = serviceScope ?? ServicesProvider.CreateScope(); + var mixDbDbContext = _serviceScope.ServiceProvider.GetRequiredService(); + var repo = MixDbEventSubscriberViewModel.GetRootRepository(mixDbDbContext, null); + Subscribers = repo.GetAllAsync(m => !m.IsDeleted).GetAwaiter().GetResult(); + + if (serviceScope == null) + { + repo.UowInfo.Complete(); + _serviceScope.Dispose(); + } + } + catch (Exception ex) + { + + } } } @@ -79,7 +93,7 @@ public async Task HandleMessage(MixDbEventCommand model) else if (model.MixDbName == MixDbDatabaseNames.MixDbEvent || model.MixDbName == MixDbDatabaseNames.MixDbEventSubscriber) { - LoadEvents(); + LoadEvents(serviceScope); } else { @@ -99,6 +113,7 @@ public async Task HandleMessage(MixDbEventCommand model) } } } + serviceScope.Dispose(); } } diff --git a/src/platform/mix.constant/Constants/MixDatabaseNames.cs b/src/platform/mix.constant/Constants/MixDatabaseNames.cs index 500f47559..217e19887 100644 --- a/src/platform/mix.constant/Constants/MixDatabaseNames.cs +++ b/src/platform/mix.constant/Constants/MixDatabaseNames.cs @@ -2,6 +2,7 @@ { public class MixDatabaseNames { + public const string ROLE = "Role"; public const string PAGE_COLUMN = "sysPageColumn"; public const string POST_COLUMN = "sysPostColumn"; public const string MODULE_COLUMN = "sysModuleColumn"; @@ -16,6 +17,7 @@ public class MixDatabaseNames public const string SYSTEM_PERMISSION = "sysPermission"; public const string SYSTEM_PERMISSION_ENDPOINT = "sysPermissionEndpoint"; public const string SYSTEM_USER_PERMISSION = "sysUserPermission"; + public const string SYSTEM_DATA_RELATIONSHIP = "sysMixDatabaseAssociation"; public const string DATA_RELATIONSHIP = "MixDatabaseAssociation"; } } \ No newline at end of file diff --git a/src/platform/mix.constant/Constants/MixFolders.cs b/src/platform/mix.constant/Constants/MixFolders.cs index c383089cd..fb63b6a1a 100644 --- a/src/platform/mix.constant/Constants/MixFolders.cs +++ b/src/platform/mix.constant/Constants/MixFolders.cs @@ -20,6 +20,7 @@ public class MixFolders public const string MixLogsFolder = "mixcontent/logs"; public const string ExportFolder = "mixcontent/staticfiles/exports"; public const string ImportFolder = "mixcontent/staticfiles/imports/themes"; + public const string BackupFolder = "mixcontent/backup"; public const string UploadsFolder = "uploads"; public const string SiteContentAssetsFolder = "mixcontent/assets"; public const string DefaultMixContentFolder = "wwwroot/default-mixcontent"; diff --git a/src/platform/mix.constant/Enums/MixDatabaseNamingConvention.cs b/src/platform/mix.constant/Enums/MixDatabaseNamingConvention.cs new file mode 100644 index 000000000..cda0fcd3e --- /dev/null +++ b/src/platform/mix.constant/Enums/MixDatabaseNamingConvention.cs @@ -0,0 +1,8 @@ +namespace Mix.Constant.Enums +{ + public enum MixDatabaseNamingConvention + { + TitleCase, + SnakeCase + } +} \ No newline at end of file diff --git a/src/platform/mix.database/Entities/Cms/EntityConfigurations/MixDatabaseContextConfiguration.cs b/src/platform/mix.database/Entities/Cms/EntityConfigurations/MixDatabaseContextConfiguration.cs index bd4ed438a..c42c48317 100644 --- a/src/platform/mix.database/Entities/Cms/EntityConfigurations/MixDatabaseContextConfiguration.cs +++ b/src/platform/mix.database/Entities/Cms/EntityConfigurations/MixDatabaseContextConfiguration.cs @@ -30,6 +30,13 @@ public override void Configure(EntityTypeBuilder builder) .HasConversion(new EnumToStringConverter()) .HasColumnType($"{Config.NString}{Config.SmallLength}") .HasCharSet(Config.CharSet); + + builder.Property(e => e.NamingConvention) + .IsRequired() + .HasConversion(new EnumToStringConverter()) + .HasColumnType($"{Config.NString}{Config.SmallLength}") + .HasCharSet(Config.CharSet); + } } } diff --git a/src/platform/mix.database/Entities/Cms/MixDatabaseContext.cs b/src/platform/mix.database/Entities/Cms/MixDatabaseContext.cs index a87144453..ecc29624a 100644 --- a/src/platform/mix.database/Entities/Cms/MixDatabaseContext.cs +++ b/src/platform/mix.database/Entities/Cms/MixDatabaseContext.cs @@ -5,5 +5,6 @@ public class MixDatabaseContext : TenantEntityUniqueNameBase public MixDatabaseProvider DatabaseProvider { get; set; } public string ConnectionString { get; set; } public string Schema { get; set; } + public MixDatabaseNamingConvention NamingConvention { get; set; } } } diff --git a/src/platform/mix.database/Entities/Quartz/_MySqlQuartzDbContext.cs b/src/platform/mix.database/Entities/Quartz/_MySqlQuartzDbContext.cs index e0edffea9..2a04c0a9b 100644 --- a/src/platform/mix.database/Entities/Quartz/_MySqlQuartzDbContext.cs +++ b/src/platform/mix.database/Entities/Quartz/_MySqlQuartzDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Mix.Database.EntityConfigurations.MYSQL.Quartz; using Mix.Database.Services; @@ -7,8 +8,8 @@ namespace Mix.Database.Entities.Quartz { public partial class MySQLQuartzDbContext : QuartzDbContext { - public MySQLQuartzDbContext(IHttpContextAccessor httpContextAccessor, DatabaseService databaseService) - : base(httpContextAccessor) + public MySQLQuartzDbContext(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, DatabaseService databaseService) + : base(httpContextAccessor, configuration) { DbProvider = MixDatabaseProvider.MySQL; ConnectionString = databaseService.GetConnectionString(MixConstants.CONST_QUARTZ_CONNECTION); @@ -20,7 +21,7 @@ public MySQLQuartzDbContext(string connectionString) ConnectionString = connectionString; } - public MySQLQuartzDbContext(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor) + public MySQLQuartzDbContext(IHttpContextAccessor httpContextAccessor, IConfiguration configuration) : base(httpContextAccessor, configuration) { } diff --git a/src/platform/mix.database/Entities/Quartz/_PostgresSqlQuartzDbContext.cs b/src/platform/mix.database/Entities/Quartz/_PostgresSqlQuartzDbContext.cs index 5d113f810..38649f024 100644 --- a/src/platform/mix.database/Entities/Quartz/_PostgresSqlQuartzDbContext.cs +++ b/src/platform/mix.database/Entities/Quartz/_PostgresSqlQuartzDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Mix.Database.EntityConfigurations.POSTGRES.Quartz; using Mix.Database.Services; @@ -7,8 +8,8 @@ namespace Mix.Database.Entities.Quartz { public partial class PostgresSQLQuartzDbContext : QuartzDbContext { - public PostgresSQLQuartzDbContext(IHttpContextAccessor httpContextAccessor, DatabaseService databaseService) - : base(httpContextAccessor) + public PostgresSQLQuartzDbContext(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, DatabaseService databaseService) + : base(httpContextAccessor, configuration) { DbProvider = MixDatabaseProvider.PostgreSQL; ConnectionString = databaseService.GetConnectionString(MixConstants.CONST_QUARTZ_CONNECTION); diff --git a/src/platform/mix.database/Entities/Quartz/_QuartzDbContext.cs b/src/platform/mix.database/Entities/Quartz/_QuartzDbContext.cs index 5ccc01612..629f9d22c 100644 --- a/src/platform/mix.database/Entities/Quartz/_QuartzDbContext.cs +++ b/src/platform/mix.database/Entities/Quartz/_QuartzDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Mix.Database.Services; @@ -7,10 +8,10 @@ namespace Mix.Database.Entities.Quartz public abstract class QuartzDbContext : DbContext { protected IHttpContextAccessor _httpContextAccessor; - public QuartzDbContext(IHttpContextAccessor httpContextAccessor) + public QuartzDbContext(IHttpContextAccessor httpContextAccessor, IConfiguration configuration) { _httpContextAccessor = httpContextAccessor; - var databaseService = new DatabaseService(_httpContextAccessor); + var databaseService = new DatabaseService(_httpContextAccessor, configuration); DbProvider = databaseService.DatabaseProvider; ConnectionString = databaseService.GetConnectionString(MixConstants.CONST_QUARTZ_CONNECTION); } diff --git a/src/platform/mix.database/Entities/Quartz/_SQliteQuartzDbContext.cs b/src/platform/mix.database/Entities/Quartz/_SQliteQuartzDbContext.cs index 05198374a..ea520dbbd 100644 --- a/src/platform/mix.database/Entities/Quartz/_SQliteQuartzDbContext.cs +++ b/src/platform/mix.database/Entities/Quartz/_SQliteQuartzDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Mix.Database.EntityConfigurations.SQLITE.Quartz; using Mix.Database.Services; @@ -7,8 +8,8 @@ namespace Mix.Database.Entities.Quartz { public partial class SQLiteQuartzDbContext : QuartzDbContext { - public SQLiteQuartzDbContext(IHttpContextAccessor httpContextAccessor, DatabaseService databaseService) - : base(httpContextAccessor) + public SQLiteQuartzDbContext(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, DatabaseService databaseService) + : base(httpContextAccessor, configuration) { DbProvider = MixDatabaseProvider.SQLITE; ConnectionString = databaseService.GetConnectionString(MixConstants.CONST_QUARTZ_CONNECTION); diff --git a/src/platform/mix.database/Entities/Quartz/_SqlServerQuartzDbContext.cs b/src/platform/mix.database/Entities/Quartz/_SqlServerQuartzDbContext.cs index 6888ceaf4..a29c121f5 100644 --- a/src/platform/mix.database/Entities/Quartz/_SqlServerQuartzDbContext.cs +++ b/src/platform/mix.database/Entities/Quartz/_SqlServerQuartzDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Mix.Database.EntityConfigurations.SQLSERVER.Quartz; using Mix.Database.Services; @@ -7,8 +8,8 @@ namespace Mix.Database.Entities.Quartz { public partial class SQLServerQuartzDbContext : QuartzDbContext { - public SQLServerQuartzDbContext(IHttpContextAccessor httpContextAccessor, DatabaseService databaseService) - : base(httpContextAccessor) + public SQLServerQuartzDbContext(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, DatabaseService databaseService) + : base(httpContextAccessor, configuration) { DbProvider = MixDatabaseProvider.SQLSERVER; ConnectionString = databaseService.GetConnectionString(MixConstants.CONST_QUARTZ_CONNECTION); diff --git a/src/platform/mix.database/Migrations/Cms/MySqlMixCms/20231016051353_UpdateMixAppBaseHref.cs b/src/platform/mix.database/Migrations/Cms/MySqlMixCms/20231016051353_UpdateMixAppBaseHref.cs index 20f402080..ee4ef42d4 100644 --- a/src/platform/mix.database/Migrations/Cms/MySqlMixCms/20231016051353_UpdateMixAppBaseHref.cs +++ b/src/platform/mix.database/Migrations/Cms/MySqlMixCms/20231016051353_UpdateMixAppBaseHref.cs @@ -15,7 +15,7 @@ protected override void Up(MigrationBuilder migrationBuilder) table: "MixApplication", newName: "DeployUrl"); } - + /// protected override void Down(MigrationBuilder migrationBuilder) { diff --git a/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/20240116112435_AddDbContextNamingConvention.Designer.cs b/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/20240116112435_AddDbContextNamingConvention.Designer.cs new file mode 100644 index 000000000..fbba176de --- /dev/null +++ b/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/20240116112435_AddDbContextNamingConvention.Designer.cs @@ -0,0 +1,2741 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Mix.Database.Entities.Cms; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Mix.Database.Migrations.PostgresqlMixCms +{ + [DbContext(typeof(PostgresqlMixCmsContext))] + [Migration("20240116112435_AddDbContextNamingConvention")] + partial class AddDbContextNamingConvention + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AppSettings") + .HasColumnType("text") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("BaseApiUrl") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("BaseHref") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DeployUrl") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Domain") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Image") + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixDatabaseName") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("MixDbId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("TemplateId") + .HasColumnType("integer"); + + b.HasKey("Id") + .HasName("PK_MixApplication"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixApplication"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixConfiguration"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixConfiguration"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixConfigurationContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Content") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DataType") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DefaultContent") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Icon") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsPublic") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixConfigurationId") + .HasColumnType("integer"); + + b.Property("MixCultureId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Specificulture") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixConfigurationContent"); + + b.HasIndex("MixConfigurationId"); + + b.HasIndex("MixCultureId"); + + b.ToTable("MixConfigurationContent"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixContributor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("GuidContentId") + .HasColumnType("uuid"); + + b.Property("IntContentId") + .HasColumnType("integer"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsOwner") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id") + .HasName("PK_MixContributor"); + + b.ToTable("MixContributor"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixCulture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Alias") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Icon") + .HasColumnType("varchar(4000)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("Lcid") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Specificulture") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixCulture"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixCulture"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatePermissions") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletePermissions") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixDatabaseContextId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("ReadPermissions") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SelfManaged") + .HasColumnType("boolean"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("UpdatePermissions") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixDatabase"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixDatabase"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabaseAssociation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("ChildDatabaseName") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("ChildId") + .HasColumnType("integer"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("GuidChildId") + .HasColumnType("uuid"); + + b.Property("GuidParentId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("ParentDatabaseName") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixDatabaseAssociation"); + + b.ToTable("MixDatabaseAssociation"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabaseColumn", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Configurations") + .HasColumnType("varchar(4000)"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DataType") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DefaultValue") + .HasColumnType("text") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixDatabaseId") + .HasColumnType("integer"); + + b.Property("MixDatabaseName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("ReferenceId") + .HasColumnType("integer"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixDatabaseColumn"); + + b.HasIndex("MixDatabaseId"); + + b.ToTable("MixDatabaseColumn"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabaseContext", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ConnectionString") + .IsRequired() + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DatabaseProvider") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("NamingConvention") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Schema") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixDatabaseContext"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixDatabaseContext"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabaseRelationship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChildId") + .HasColumnType("integer"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DestinateDatabaseName") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("SourceDatabaseName") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixDatabaseRelationship"); + + b.HasIndex("ChildId"); + + b.HasIndex("ParentId"); + + b.ToTable("MixDatabaseRelationship"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDiscussion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Content") + .IsRequired() + .HasColumnType("text") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("GuidContentId") + .HasColumnType("uuid"); + + b.Property("IntContentId") + .HasColumnType("integer"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id") + .HasName("PK_MixDiscussion"); + + b.ToTable("MixDiscussion"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDomain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Host") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixDomain"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixDomain"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixLanguage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixLanguage"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixLanguage"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixLanguageContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Content") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DataType") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DefaultContent") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Icon") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsPublic") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixCultureId") + .HasColumnType("integer"); + + b.Property("MixLanguageId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Specificulture") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixLanguageContent"); + + b.HasIndex("MixCultureId"); + + b.HasIndex("MixLanguageId"); + + b.ToTable("MixLanguageContent"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasDefaultValueSql("gen_random_uuid()"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Extension") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("FileFolder") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("FileName") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("FileProperties") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("FileType") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Source") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Tags") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("TargetUrl") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Title") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixMedia"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixMedia"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixModule"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixModule"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModuleContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClassName") + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Content") + .HasColumnType("text") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Excerpt") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Icon") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Image") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsPublic") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LayoutId") + .HasColumnType("int"); + + b.Property("MixCultureId") + .HasColumnType("integer"); + + b.Property("MixDatabaseName") + .HasColumnType("text"); + + b.Property("MixDbId") + .HasColumnType("integer"); + + b.Property("MixModuleId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("PageSize") + .HasColumnType("integer"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("PublishedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("SeoDescription") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoKeywords") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoName") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoTitle") + .HasColumnType("text"); + + b.Property("SimpleDataColumns") + .HasColumnType("text"); + + b.Property("Source") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Specificulture") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .HasColumnType("varchar(250)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("TemplateId") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixModuleContent"); + + b.HasIndex("MixCultureId"); + + b.HasIndex("MixModuleId"); + + b.ToTable("MixModuleContent"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModuleData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Content") + .HasColumnType("text") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Excerpt") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Icon") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Image") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsPublic") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LayoutId") + .HasColumnType("int"); + + b.Property("MixCultureId") + .HasColumnType("integer"); + + b.Property("MixModuleContentId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("PublishedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("SeoDescription") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoKeywords") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoName") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoTitle") + .HasColumnType("text"); + + b.Property("SimpleDataColumns") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Source") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Specificulture") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("TemplateId") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Value") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixModuleData"); + + b.HasIndex("MixCultureId"); + + b.HasIndex("MixModuleContentId"); + + b.ToTable("MixModuleData"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModulePostAssociation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChildId") + .HasColumnType("integer"); + + b.Property("CreatedBy") + .HasColumnType("text"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixModuleContentId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("Status") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("MixModuleContentId"); + + b.ToTable("MixModulePostAssociation"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixPostContentId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixPage"); + + b.HasIndex("MixPostContentId"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixPage"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPageContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClassName") + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Content") + .HasColumnType("text") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Excerpt") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Icon") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Image") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsPublic") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LayoutId") + .HasColumnType("int"); + + b.Property("MixCultureId") + .HasColumnType("integer"); + + b.Property("MixDatabaseName") + .HasColumnType("text"); + + b.Property("MixDbId") + .HasColumnType("integer"); + + b.Property("MixPageId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("PageSize") + .HasColumnType("integer"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("PublishedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("SeoDescription") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoKeywords") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoName") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoTitle") + .HasColumnType("text"); + + b.Property("Source") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Specificulture") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("TemplateId") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixPageContent"); + + b.HasIndex("MixCultureId"); + + b.HasIndex("MixPageId"); + + b.ToTable("MixPageContent"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPageModuleAssociation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChildId") + .HasColumnType("integer"); + + b.Property("CreatedBy") + .HasColumnType("text"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixPageContentId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("Status") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("MixPageContentId"); + + b.ToTable("MixPageModuleAssociation"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPagePostAssociation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChildId") + .HasColumnType("integer"); + + b.Property("CreatedBy") + .HasColumnType("text"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixPageContentId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("Status") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("MixPageContentId"); + + b.ToTable("MixPagePostAssociation"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPost", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixPost"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixPost"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPostContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClassName") + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Content") + .HasColumnType("text") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Excerpt") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Icon") + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Image") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsPublic") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LayoutId") + .HasColumnType("int"); + + b.Property("MixCultureId") + .HasColumnType("integer"); + + b.Property("MixDatabaseName") + .HasColumnType("text"); + + b.Property("MixDbId") + .HasColumnType("integer"); + + b.Property("MixPostContentId") + .HasColumnType("integer"); + + b.Property("MixPostId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("PublishedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("SeoDescription") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoKeywords") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoName") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SeoTitle") + .HasColumnType("text"); + + b.Property("Source") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Specificulture") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("TemplateId") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixPostContent"); + + b.HasIndex("MixCultureId"); + + b.HasIndex("MixPostContentId"); + + b.HasIndex("MixPostId"); + + b.ToTable("MixPostContent"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPostPostAssociation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChildId") + .HasColumnType("integer"); + + b.Property("CreatedBy") + .HasColumnType("text"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("Status") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("MixPostPostAssociation"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Content") + .HasColumnType("text") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Extension") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("FileFolder") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("FolderType") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("MixThemeId") + .HasColumnType("integer"); + + b.Property("MixThemeName") + .IsRequired() + .HasColumnType("varchar(50)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Scripts") + .IsRequired() + .HasColumnType("text") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Styles") + .IsRequired() + .HasColumnType("text") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixTemplate"); + + b.HasIndex("MixThemeId"); + + b.ToTable("MixViewTemplate"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixTenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("PrimaryDomain") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixTenant"); + + b.ToTable("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AssetFolder") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("ImageUrl") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixDatabaseName") + .HasColumnType("text"); + + b.Property("MixDbId") + .HasColumnType("integer"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("PreviewUrl") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("SystemName") + .HasColumnType("text"); + + b.Property("TemplateFolder") + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PK_MixTheme"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixTheme"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixUrlAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Alias") + .HasColumnType("text"); + + b.Property("CreatedBy") + .HasColumnType("varchar(250)"); + + b.Property("CreatedDateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("varchar(4000)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("varchar(250)") + .UseCollation("und-x-icu") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("MixTenantId") + .HasColumnType("integer"); + + b.Property("ModifiedBy") + .HasColumnType("varchar(250)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("SourceContentGuidId") + .HasColumnType("uuid"); + + b.Property("SourceContentId") + .HasColumnType("integer"); + + b.Property("Status") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id") + .HasName("PK_MixUrlAlias"); + + b.HasIndex("MixTenantId"); + + b.ToTable("MixUrlAlias"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixApplication", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixConfiguration", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixConfigurationContent", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixConfiguration", "MixConfiguration") + .WithMany("MixConfigurationContents") + .HasForeignKey("MixConfigurationId"); + + b.HasOne("Mix.Database.Entities.Cms.MixCulture", "MixCulture") + .WithMany() + .HasForeignKey("MixCultureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixConfiguration"); + + b.Navigation("MixCulture"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixCulture", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabase", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", null) + .WithMany("MixDatabases") + .HasForeignKey("MixTenantId"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabaseColumn", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixDatabase", "MixDatabase") + .WithMany("MixDatabaseColumns") + .HasForeignKey("MixDatabaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixDatabase"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabaseContext", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabaseRelationship", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixDatabase", "DestinateDatabase") + .WithMany("DestinateRelationships") + .HasForeignKey("ChildId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Mix.Database.Entities.Cms.MixDatabase", "SourceDatabase") + .WithMany("SourceRelationships") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("DestinateDatabase"); + + b.Navigation("SourceDatabase"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDomain", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixLanguage", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixLanguageContent", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixCulture", "MixCulture") + .WithMany() + .HasForeignKey("MixCultureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mix.Database.Entities.Cms.MixLanguage", "MixLanguage") + .WithMany("MixLanguageContents") + .HasForeignKey("MixLanguageId"); + + b.Navigation("MixCulture"); + + b.Navigation("MixLanguage"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixMedia", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModule", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany("MixModules") + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModuleContent", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixCulture", "MixCulture") + .WithMany() + .HasForeignKey("MixCultureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mix.Database.Entities.Cms.MixModule", "MixModule") + .WithMany("MixModuleContents") + .HasForeignKey("MixModuleId"); + + b.Navigation("MixCulture"); + + b.Navigation("MixModule"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModuleData", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixCulture", "MixCulture") + .WithMany() + .HasForeignKey("MixCultureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mix.Database.Entities.Cms.MixModuleContent", "MixModuleContent") + .WithMany() + .HasForeignKey("MixModuleContentId"); + + b.Navigation("MixCulture"); + + b.Navigation("MixModuleContent"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModulePostAssociation", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixModuleContent", null) + .WithMany("MixPostContents") + .HasForeignKey("MixModuleContentId"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPage", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixPostContent", null) + .WithMany("MixPages") + .HasForeignKey("MixPostContentId"); + + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany("MixPages") + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPageContent", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixCulture", "MixCulture") + .WithMany() + .HasForeignKey("MixCultureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mix.Database.Entities.Cms.MixPage", "MixPage") + .WithMany("MixPageContents") + .HasForeignKey("MixPageId"); + + b.Navigation("MixCulture"); + + b.Navigation("MixPage"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPageModuleAssociation", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixPageContent", null) + .WithMany("MixModuleContents") + .HasForeignKey("MixPageContentId"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPagePostAssociation", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixPageContent", null) + .WithMany("MixPostContents") + .HasForeignKey("MixPageContentId"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPost", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany("MixPosts") + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPostContent", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixCulture", "MixCulture") + .WithMany() + .HasForeignKey("MixCultureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mix.Database.Entities.Cms.MixPostContent", null) + .WithMany("MixPostContents") + .HasForeignKey("MixPostContentId"); + + b.HasOne("Mix.Database.Entities.Cms.MixPost", "MixPost") + .WithMany("MixPostContents") + .HasForeignKey("MixPostId"); + + b.Navigation("MixCulture"); + + b.Navigation("MixPost"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixTemplate", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTheme", "MixTheme") + .WithMany("MixViewTemplates") + .HasForeignKey("MixThemeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTheme"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixTheme", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixUrlAlias", b => + { + b.HasOne("Mix.Database.Entities.Cms.MixTenant", "MixTenant") + .WithMany() + .HasForeignKey("MixTenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MixTenant"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixConfiguration", b => + { + b.Navigation("MixConfigurationContents"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixDatabase", b => + { + b.Navigation("DestinateRelationships"); + + b.Navigation("MixDatabaseColumns"); + + b.Navigation("SourceRelationships"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixLanguage", b => + { + b.Navigation("MixLanguageContents"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModule", b => + { + b.Navigation("MixModuleContents"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixModuleContent", b => + { + b.Navigation("MixPostContents"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPage", b => + { + b.Navigation("MixPageContents"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPageContent", b => + { + b.Navigation("MixModuleContents"); + + b.Navigation("MixPostContents"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPost", b => + { + b.Navigation("MixPostContents"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixPostContent", b => + { + b.Navigation("MixPages"); + + b.Navigation("MixPostContents"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixTenant", b => + { + b.Navigation("MixDatabases"); + + b.Navigation("MixModules"); + + b.Navigation("MixPages"); + + b.Navigation("MixPosts"); + }); + + modelBuilder.Entity("Mix.Database.Entities.Cms.MixTheme", b => + { + b.Navigation("MixViewTemplates"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/20240116112435_AddDbContextNamingConvention.cs b/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/20240116112435_AddDbContextNamingConvention.cs new file mode 100644 index 000000000..b6cd0bcdf --- /dev/null +++ b/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/20240116112435_AddDbContextNamingConvention.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Mix.Database.Migrations.PostgresqlMixCms +{ + /// + public partial class AddDbContextNamingConvention : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "NamingConvention", + table: "MixDatabaseContext", + type: "varchar(50)", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "NamingConvention", + table: "MixDatabaseContext"); + } + } +} diff --git a/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/PostgresqlMixCmsContextModelSnapshot.cs b/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/PostgresqlMixCmsContextModelSnapshot.cs index 7cc5855b3..2985fe804 100644 --- a/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/PostgresqlMixCmsContextModelSnapshot.cs +++ b/src/platform/mix.database/Migrations/Cms/PostgresqlMixCms/PostgresqlMixCmsContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.9") + .HasAnnotation("ProductVersion", "8.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -670,6 +670,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ModifiedBy") .HasColumnType("varchar(250)"); + b.Property("NamingConvention") + .IsRequired() + .HasColumnType("varchar(50)") + .HasAnnotation("MySql:CharSet", "utf8"); + b.Property("Priority") .HasColumnType("int"); diff --git a/src/platform/mix.database/Services/DatabaseService.cs b/src/platform/mix.database/Services/DatabaseService.cs index f8b6804be..3f4fafc85 100644 --- a/src/platform/mix.database/Services/DatabaseService.cs +++ b/src/platform/mix.database/Services/DatabaseService.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Mix.Database.Entities.Account; using Mix.Database.Entities.MixDb; using Mix.Database.Entities.Quartz; @@ -7,6 +8,8 @@ using Mix.Heart.Services; using Mix.Shared.Models.Configurations; using Mix.Shared.Services; +using Newtonsoft.Json.Linq; +using System.Linq; using System.Threading.Tasks; namespace Mix.Database.Services @@ -15,9 +18,11 @@ public class DatabaseService : ConfigurationServiceBase { public MixDatabaseProvider DatabaseProvider => AppSettings.DatabaseProvider; protected IHttpContextAccessor HttpContextAccessor; - public DatabaseService(IHttpContextAccessor httpContextAccessor) : base(MixAppConfigFilePaths.Database, true) + protected IConfiguration Configuration; + public DatabaseService(IHttpContextAccessor httpContextAccessor, IConfiguration configuration) : base(MixAppConfigFilePaths.Database, true) { HttpContextAccessor = httpContextAccessor; + Configuration = configuration; AesKey = GlobalConfigService.Instance.AppSettings.ApiEncryptKey; } @@ -40,7 +45,8 @@ public string GetConnectionString(string name) case MixConstants.CONST_QUARTZ_CONNECTION: return AppSettings.ConnectionStrings?.MixQuartzConnection; default: - return string.Empty; + return RawSettings.Value("connectionStrings").Value(name) + ?? Configuration.GetConnectionString(name); } } @@ -120,10 +126,10 @@ public QuartzDbContext GetQuartzDbContext() { return DatabaseProvider switch { - MixDatabaseProvider.SQLSERVER => new SQLServerQuartzDbContext(HttpContextAccessor, this), - MixDatabaseProvider.MySQL => new MySQLQuartzDbContext(HttpContextAccessor, this), - MixDatabaseProvider.SQLITE => new SQLiteQuartzDbContext(HttpContextAccessor, this), - MixDatabaseProvider.PostgreSQL => new PostgresSQLQuartzDbContext(HttpContextAccessor, this), + MixDatabaseProvider.SQLSERVER => new SQLServerQuartzDbContext(HttpContextAccessor, Configuration, this), + MixDatabaseProvider.MySQL => new MySQLQuartzDbContext(HttpContextAccessor, Configuration, this), + MixDatabaseProvider.SQLITE => new SQLiteQuartzDbContext(HttpContextAccessor, Configuration, this), + MixDatabaseProvider.PostgreSQL => new PostgresSQLQuartzDbContext(HttpContextAccessor, Configuration, this), _ => null, }; } @@ -176,13 +182,17 @@ public void ResetConnectionStrings() public void UpdateMixCmsContext() { using var ctx = GetDbContext(); - ctx.Database.Migrate(); + if (ctx.Database.GetPendingMigrations().Count() > 0) + ctx.Database.Migrate(); using var cacheCtx = GetCacheDbContext(); - cacheCtx.Database.Migrate(); + if (cacheCtx.Database.GetPendingMigrations().Count() > 0) + cacheCtx.Database.Migrate(); using var accCtx = GetAccountDbContext(); - accCtx.Database.Migrate(); + if (accCtx.Database.GetPendingMigrations().Count() > 0) + accCtx.Database.Migrate(); using var mixdbCtx = GetMixDbDbContext(); - mixdbCtx.Database.Migrate(); + if (mixdbCtx.Database.GetPendingMigrations().Count() > 0) + mixdbCtx.Database.Migrate(); } public async Task InitQuartzContextAsync() diff --git a/src/platform/mix.library/Attributes/MixAuthorizeAttribute.cs b/src/platform/mix.library/Attributes/MixAuthorizeAttribute.cs index 89b1769cc..22747b2cf 100644 --- a/src/platform/mix.library/Attributes/MixAuthorizeAttribute.cs +++ b/src/platform/mix.library/Attributes/MixAuthorizeAttribute.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; using Mix.Auth.Constants; using Mix.Lib.Services; using System.Security.Claims; @@ -19,6 +20,7 @@ public class AuthorizeActionFilter : IAuthorizationFilter { public string[] AllowedRoles { get; set; } public string[] UserRoles { get; set; } + protected readonly ILogger _logger; protected readonly MixIdentityService _idService; protected readonly MixPermissionService _permissionService; private readonly TenantUserManager _userManager; @@ -27,11 +29,13 @@ public AuthorizeActionFilter( string roles, MixIdentityService idService, MixPermissionService permissionService, - TenantUserManager userManager) + TenantUserManager userManager, + ILogger logger) { _idService = idService; _permissionService = permissionService; _userManager = userManager; + _logger = logger; AllowedRoles = roles.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(r => r.Trim()).ToArray(); } @@ -43,8 +47,10 @@ public void OnAuthorization(AuthorizationFilterContext context) { if (!IsInRoles()) { + _logger.LogError("Not in role"); if (!ValidEnpointPermission(context)) { + _logger.LogError("forbidden"); context.Result = new ForbidResult(); return; } @@ -52,6 +58,7 @@ public void OnAuthorization(AuthorizationFilterContext context) } else { + _logger.LogError("Invalid Token"); context.Result = new UnauthorizedResult(); return; } diff --git a/src/platform/mix.library/Base/MixApiControllerBase.cs b/src/platform/mix.library/Base/MixApiControllerBase.cs index 6a7f7c0ed..df38c6e03 100644 --- a/src/platform/mix.library/Base/MixApiControllerBase.cs +++ b/src/platform/mix.library/Base/MixApiControllerBase.cs @@ -9,7 +9,7 @@ namespace Mix.Lib.Base { public abstract class MixApiControllerBase : Controller { - protected readonly IQueueService QueueService; + protected readonly IMemoryQueueService QueueService; protected readonly IConfiguration Configuration; protected readonly IMixCmsService MixCmsService; protected readonly IHttpContextAccessor HttpContextAccessor; @@ -23,7 +23,7 @@ protected MixApiControllerBase( MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - IQueueService queueService) : base() + IMemoryQueueService queueService) : base() { HttpContextAccessor = httpContextAccessor; CacheService = cacheService; diff --git a/src/platform/mix.library/Base/MixApiTenantControllerBase.cs b/src/platform/mix.library/Base/MixApiTenantControllerBase.cs index d6b4fa308..e26dbbb05 100644 --- a/src/platform/mix.library/Base/MixApiTenantControllerBase.cs +++ b/src/platform/mix.library/Base/MixApiTenantControllerBase.cs @@ -16,7 +16,7 @@ public abstract class MixTenantApiControllerBase : Controller protected ISession Session; protected string Lang; protected MixCulture Culture; - protected readonly IQueueService QueueService; + protected readonly IMemoryQueueService QueueService; protected readonly IConfiguration Configuration; protected readonly MixIdentityService MixIdentityService; protected readonly TranslatorService Translator; @@ -28,7 +28,7 @@ protected MixTenantApiControllerBase( MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - IQueueService queueService, + IMemoryQueueService queueService, IMixTenantService mixTenantService) { HttpContextAccessor = httpContextAccessor; diff --git a/src/platform/mix.library/Base/MixAssociationApiControllerBase.cs b/src/platform/mix.library/Base/MixAssociationApiControllerBase.cs index 0d9b56913..ab3af0373 100644 --- a/src/platform/mix.library/Base/MixAssociationApiControllerBase.cs +++ b/src/platform/mix.library/Base/MixAssociationApiControllerBase.cs @@ -17,7 +17,7 @@ public class MixAssociationApiControllerBase where TEntity : AssociationBase where TView : AssociationViewModelBase { - public MixAssociationApiControllerBase(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IQueueService queueService, + public MixAssociationApiControllerBase(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/platform/mix.library/Base/MixBaseContentController.cs b/src/platform/mix.library/Base/MixBaseContentController.cs index a5ed50819..001fdf01b 100644 --- a/src/platform/mix.library/Base/MixBaseContentController.cs +++ b/src/platform/mix.library/Base/MixBaseContentController.cs @@ -31,7 +31,7 @@ protected MixBaseContentController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo cmsUow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/platform/mix.library/Base/MixQueryApiControllerBase.cs b/src/platform/mix.library/Base/MixQueryApiControllerBase.cs index f0c2cc4c7..f737f3351 100644 --- a/src/platform/mix.library/Base/MixQueryApiControllerBase.cs +++ b/src/platform/mix.library/Base/MixQueryApiControllerBase.cs @@ -23,7 +23,7 @@ public MixQueryApiControllerBase( MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - UnitOfWorkInfo uow, IQueueService queueService, + UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/platform/mix.library/Base/MixQueryEntityApiControllerBase.cs b/src/platform/mix.library/Base/MixQueryEntityApiControllerBase.cs index 346685bbb..320151d60 100644 --- a/src/platform/mix.library/Base/MixQueryEntityApiControllerBase.cs +++ b/src/platform/mix.library/Base/MixQueryEntityApiControllerBase.cs @@ -30,7 +30,7 @@ public MixQueryEntityApiControllerBase( TranslatorService translator, MixIdentityService mixIdentityService, TDbContext context, - IQueueService queueService, MixCacheDbContext cacheDbContext, + IMemoryQueueService queueService, MixCacheDbContext cacheDbContext, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, queueService, mixTenantService) diff --git a/src/platform/mix.library/Base/MixRestApiControllerBase.cs b/src/platform/mix.library/Base/MixRestApiControllerBase.cs index 334bea5be..c2cb5235f 100644 --- a/src/platform/mix.library/Base/MixRestApiControllerBase.cs +++ b/src/platform/mix.library/Base/MixRestApiControllerBase.cs @@ -27,7 +27,7 @@ public MixRestHandlerApiControllerBase( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/platform/mix.library/Base/MixRestEntityApiControllerBase.cs b/src/platform/mix.library/Base/MixRestEntityApiControllerBase.cs index 0436fd210..daf99f2e6 100644 --- a/src/platform/mix.library/Base/MixRestEntityApiControllerBase.cs +++ b/src/platform/mix.library/Base/MixRestEntityApiControllerBase.cs @@ -23,7 +23,7 @@ public MixRestEntityApiControllerBase( MixIdentityService mixIdentityService, MixCacheDbContext cacheDbContext, TDbContext context, - IQueueService queueService, + IMemoryQueueService queueService, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, context, queueService, cacheDbContext, mixTenantService) @@ -106,7 +106,7 @@ public async Task SaveMany([FromBody] List data) protected virtual async Task CreateHandlerAsync(TEntity data) { await Repository.CreateAsync(data); - QueueService.PushMessage(CurrentTenant.Id, data, MixRestAction.Post.ToString(), true); + QueueService.PushMessageToMemoryQueue(CurrentTenant.Id, data, MixRestAction.Post.ToString(), true); return data.Id; } @@ -114,14 +114,14 @@ protected virtual async Task UpdateHandler(string id, TEntity data) { await Repository.UpdateAsync(data); await CacheService.RemoveCacheAsync(id, typeof(TEntity).FullName); - QueueService.PushMessage(CurrentTenant.Id, data, MixRestAction.Put.ToString(), true); + QueueService.PushMessageToMemoryQueue(CurrentTenant.Id, data, MixRestAction.Put.ToString(), true); } protected virtual async Task DeleteHandler(TEntity data) { await Repository.DeleteAsync(data); await CacheService.RemoveCacheAsync(data.Id.ToString(), typeof(TEntity).FullName); - QueueService.PushMessage(CurrentTenant.Id, data, MixRestAction.Delete.ToString(), true); + QueueService.PushMessageToMemoryQueue(CurrentTenant.Id, data, MixRestAction.Delete.ToString(), true); } @@ -129,7 +129,7 @@ protected virtual async Task PatchHandler(TPrimaryKey id, TEntity data, IEnumera { await Repository.SaveFieldsAsync(data, properties); await CacheService.RemoveCacheAsync(id.ToString(), typeof(TEntity).FullName); - QueueService.PushMessage(CurrentTenant.Id, data, MixRestAction.Patch.ToString(), true); + QueueService.PushMessageToMemoryQueue(CurrentTenant.Id, data, MixRestAction.Patch.ToString(), true); } protected virtual async Task SaveManyHandler(List data) diff --git a/src/platform/mix.library/Base/MixRestfulApiControllerBase.cs b/src/platform/mix.library/Base/MixRestfulApiControllerBase.cs index b939d1a45..e98720ae8 100644 --- a/src/platform/mix.library/Base/MixRestfulApiControllerBase.cs +++ b/src/platform/mix.library/Base/MixRestfulApiControllerBase.cs @@ -20,7 +20,7 @@ public class MixRestfulApiControllerBase { private UnitOfWorkInfo uow; - private IQueueService queueService; + private IMemoryQueueService queueService; private IPortalHubClientService portalHub; public MixRestfulApiControllerBase( @@ -28,7 +28,7 @@ public MixRestfulApiControllerBase( IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - UnitOfWorkInfo uow, IQueueService queueService, + UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, @@ -36,7 +36,7 @@ public MixRestfulApiControllerBase( { } - public MixRestfulApiControllerBase(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, UnitOfWorkInfo accUow, IQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) + public MixRestfulApiControllerBase(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, UnitOfWorkInfo accUow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) { diff --git a/src/platform/mix.library/Base/SiteDataWithContentViewModelBase.cs b/src/platform/mix.library/Base/SiteDataWithContentViewModelBase.cs index b62391c53..59dc141d3 100644 --- a/src/platform/mix.library/Base/SiteDataWithContentViewModelBase.cs +++ b/src/platform/mix.library/Base/SiteDataWithContentViewModelBase.cs @@ -50,6 +50,7 @@ public override async Task ExpandView(CancellationToken cancellationToken = defa using (var contentRepository = ViewModelBase.GetRepository(UowInfo, CacheService)) { Contents = await contentRepository.GetListAsync(m => m.ParentId.Equals(Id), cancellationToken); + contentRepository.Dispose(); } } @@ -73,6 +74,7 @@ protected override async Task DeleteHandlerAsync(CancellationToken cancellationT { await contentRepository.DeleteManyAsync(m => m.ParentId.Equals(Id), cancellationToken); await base.DeleteHandlerAsync(cancellationToken); + contentRepository.Dispose(); } } #endregion diff --git a/src/platform/mix.library/Controllers/MixAutoGenerateAuthorizedQueryApiController.cs b/src/platform/mix.library/Controllers/MixAutoGenerateAuthorizedQueryApiController.cs index f2cd26551..f48b99c3f 100644 --- a/src/platform/mix.library/Controllers/MixAutoGenerateAuthorizedQueryApiController.cs +++ b/src/platform/mix.library/Controllers/MixAutoGenerateAuthorizedQueryApiController.cs @@ -23,7 +23,7 @@ public MixAutoGenerateAuthorizedQueryApiController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/platform/mix.library/Controllers/MixAutoGenerateAuthorizedRestApiController.cs b/src/platform/mix.library/Controllers/MixAutoGenerateAuthorizedRestApiController.cs index a79774a26..5e6b767c7 100644 --- a/src/platform/mix.library/Controllers/MixAutoGenerateAuthorizedRestApiController.cs +++ b/src/platform/mix.library/Controllers/MixAutoGenerateAuthorizedRestApiController.cs @@ -25,7 +25,7 @@ public MixAutoGenerateAuthorizedRestApiController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/platform/mix.library/Controllers/MixAutoGenerateQueryApiController.cs b/src/platform/mix.library/Controllers/MixAutoGenerateQueryApiController.cs index 4d217fcdb..978f96461 100644 --- a/src/platform/mix.library/Controllers/MixAutoGenerateQueryApiController.cs +++ b/src/platform/mix.library/Controllers/MixAutoGenerateQueryApiController.cs @@ -22,7 +22,7 @@ public MixAutoGenerateQueryApiController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/platform/mix.library/Controllers/MixAutoGenerateRestApiController.cs b/src/platform/mix.library/Controllers/MixAutoGenerateRestApiController.cs index b8d3bdbc5..1cc5cd1a3 100644 --- a/src/platform/mix.library/Controllers/MixAutoGenerateRestApiController.cs +++ b/src/platform/mix.library/Controllers/MixAutoGenerateRestApiController.cs @@ -17,7 +17,7 @@ public class MixAutoGenerateRestApiController where TView : ViewModelBase { - public MixAutoGenerateRestApiController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IQueueService queueService, + public MixAutoGenerateRestApiController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/platform/mix.library/Helpers/MixCmsHelper.cs b/src/platform/mix.library/Helpers/MixCmsHelper.cs index 45cbae3d7..5ef2993b5 100644 --- a/src/platform/mix.library/Helpers/MixCmsHelper.cs +++ b/src/platform/mix.library/Helpers/MixCmsHelper.cs @@ -216,6 +216,7 @@ public static FileModel ExportJObjectToExcel(List lstData, string sheet workbook.SaveAs(stream); var content = stream.ToArray(); MixFileHelper.SaveFileBytes(folderPath, filename, content); + stream.Dispose(); return repositoryResponse; } } @@ -236,42 +237,46 @@ public static List LoadExcelFileData(IFormFile file) //create a new Excel package in a memorystream using (var stream = file.OpenReadStream()) - using (XLWorkbook excelPackage = new XLWorkbook(stream)) { - //loop all worksheets - foreach (var worksheet in excelPackage.Worksheets) + using (XLWorkbook excelPackage = new XLWorkbook(stream)) { - bool FirstRow = true; - //Range for reading the cells based on the last cell used. - string readRange = "1:1"; - List columnNames = new(); - foreach (IXLRow row in worksheet.RowsUsed()) + //loop all worksheets + foreach (var worksheet in excelPackage.Worksheets) { - //If Reading the First Row (used) then add them as column name - if (FirstRow) + bool FirstRow = true; + //Range for reading the cells based on the last cell used. + string readRange = "1:1"; + List columnNames = new(); + foreach (IXLRow row in worksheet.RowsUsed()) { - readRange = string.Format("{0}:{1}", 1, row.LastCellUsed().Address.ColumnNumber); - foreach (IXLCell cell in row.Cells(readRange)) + //If Reading the First Row (used) then add them as column name + if (FirstRow) { - columnNames.Add(cell.Value.ToString()); + readRange = string.Format("{0}:{1}", 1, row.LastCellUsed().Address.ColumnNumber); + foreach (IXLCell cell in row.Cells(readRange)) + { + columnNames.Add(cell.Value.ToString()); + } + FirstRow = false; } - FirstRow = false; - } - else - { - JObject obj = new JObject(); - int colIndex = 0; - foreach (IXLCell cell in row.Cells(readRange)) + else { - obj.Add(new JProperty(columnNames[colIndex], cell.Value.ToString())); - colIndex++; + JObject obj = new JObject(); + int colIndex = 0; + foreach (IXLCell cell in row.Cells(readRange)) + { + obj.Add(new JProperty(columnNames[colIndex], cell.Value.ToString())); + colIndex++; + } + excelData.Add(obj); } - excelData.Add(obj); } } + stream.Dispose(); + return excelData; } - return excelData; } + } } } diff --git a/src/platform/mix.library/Interfaces/IMixEdmService.cs b/src/platform/mix.library/Interfaces/IMixEdmService.cs index eb0e1ac05..2c74972e4 100644 --- a/src/platform/mix.library/Interfaces/IMixEdmService.cs +++ b/src/platform/mix.library/Interfaces/IMixEdmService.cs @@ -6,5 +6,6 @@ public interface IMixEdmService public void SetTenant(MixTenantSystemModel tenant); public Task GetEdmTemplate(string filename); public Task SendMailWithEdmTemplate(string subject, string templateName, JObject data, string to, string cc = null, string from = null); + Task SendMailWithTemplate(string subject, string template, JObject data, string to, string cc = null, string from = null); } } diff --git a/src/platform/mix.library/Middlewares/AuditlogMiddleware.cs b/src/platform/mix.library/Middlewares/AuditlogMiddleware.cs index 33e70690e..8b5d869c4 100644 --- a/src/platform/mix.library/Middlewares/AuditlogMiddleware.cs +++ b/src/platform/mix.library/Middlewares/AuditlogMiddleware.cs @@ -72,6 +72,7 @@ public async Task InvokeAsync(HttpContext context) await responseBody.CopyToAsync(originalBodyStream); _auditlogService.QueueRequest(_auditlogData); + responseBody.Dispose(); } } } diff --git a/src/platform/mix.library/Publishers/MixBackgroundTaskPublisher.cs b/src/platform/mix.library/Publishers/MixBackgroundTaskPublisher.cs index 21fad9011..a4d6c70b9 100644 --- a/src/platform/mix.library/Publishers/MixBackgroundTaskPublisher.cs +++ b/src/platform/mix.library/Publishers/MixBackgroundTaskPublisher.cs @@ -10,7 +10,7 @@ public class MixBackgroundTaskPublisher : PublisherBase private const string TopicId = MixQueueTopics.MixBackgroundTasks; public MixBackgroundTaskPublisher( - IQueueService queueService, + IMemoryQueueService queueService, IConfiguration configuration, MixEndpointService mixEndpointService, ILogger logger) diff --git a/src/platform/mix.library/Publishers/MixDbCommandPublisher.cs b/src/platform/mix.library/Publishers/MixDbCommandPublisher.cs index 151ab249e..b293c26fd 100644 --- a/src/platform/mix.library/Publishers/MixDbCommandPublisher.cs +++ b/src/platform/mix.library/Publishers/MixDbCommandPublisher.cs @@ -10,7 +10,7 @@ public class MixDbCommandPublisher : PublisherBase private const string TopicId = MixQueueTopics.MixDbCommand; public MixDbCommandPublisher( - IQueueService queueService, + IMemoryQueueService queueService, IConfiguration configuration, MixEndpointService mixEndpointService, ILogger logger) diff --git a/src/platform/mix.library/Publishers/MixPublisher.cs b/src/platform/mix.library/Publishers/MixPublisher.cs index 8a31e0950..fdfc33581 100644 --- a/src/platform/mix.library/Publishers/MixPublisher.cs +++ b/src/platform/mix.library/Publishers/MixPublisher.cs @@ -13,7 +13,7 @@ public class MixPublisher : PublisherBase { static string topicId = typeof(T).FullName; public MixPublisher( - IQueueService queueService, + IMemoryQueueService queueService, IConfiguration configuration, IWebHostEnvironment environment, MixEndpointService mixEndpointService, ILogger logger) diff --git a/src/platform/mix.library/Publishers/MixViewModelChangedPublisher.cs b/src/platform/mix.library/Publishers/MixViewModelChangedPublisher.cs index cdcc1e593..963711609 100644 --- a/src/platform/mix.library/Publishers/MixViewModelChangedPublisher.cs +++ b/src/platform/mix.library/Publishers/MixViewModelChangedPublisher.cs @@ -12,7 +12,7 @@ public class MixViewModelChangedPublisher : PublisherBase private const string TopicId = MixQueueTopics.MixViewModelChanged; public MixViewModelChangedPublisher( - IQueueService queueService, + IMemoryQueueService queueService, IConfiguration configuration, MixEndpointService mixEndpointService, ILogger logger) diff --git a/src/platform/mix.library/Repositories/TemplateRepository.cs b/src/platform/mix.library/Repositories/TemplateRepository.cs index fa924baa5..19234e41a 100644 --- a/src/platform/mix.library/Repositories/TemplateRepository.cs +++ b/src/platform/mix.library/Repositories/TemplateRepository.cs @@ -120,6 +120,7 @@ public bool SaveTemplate(TemplateModel file) using (var writer = File.CreateText(fileName)) { writer.WriteLine(file.Content); + writer.Dispose(); return true; } } diff --git a/src/platform/mix.library/Services/MixEdmService.cs b/src/platform/mix.library/Services/MixEdmService.cs index e6a0d1869..40e8e9855 100644 --- a/src/platform/mix.library/Services/MixEdmService.cs +++ b/src/platform/mix.library/Services/MixEdmService.cs @@ -7,15 +7,15 @@ namespace Mix.Lib.Services { public class MixEdmService : TenantServiceBase, IMixEdmService { - protected readonly IQueueService _queueService; + protected readonly IMemoryQueueService _queueService; protected readonly UnitOfWorkInfo _uow; public MixEdmService( IHttpContextAccessor httpContextAccessor, - UnitOfWorkInfo uow, - IQueueService queueService, - MixCacheService cacheService, - IMixTenantService mixTenantService) : base(httpContextAccessor, cacheService, mixTenantService) + IMemoryQueueService queueService, + MixCacheService cacheService = null, + IMixTenantService mixTenantService = null, + UnitOfWorkInfo uow = null) : base(httpContextAccessor, cacheService, mixTenantService) { _uow = uow; _queueService = queueService; @@ -23,6 +23,11 @@ public MixEdmService( public async Task GetEdmTemplate(string filename) { + if (_uow == null ) + { + return string.Empty; + } + var edmTemplate = await MixTemplateViewModel.GetRepository(_uow, CacheService).GetSingleAsync( m => m.FolderType == MixTemplateFolderType.Edms && m.FileName == filename); @@ -30,13 +35,13 @@ public async Task GetEdmTemplate(string filename) } public virtual async Task SendMailWithEdmTemplate( - string subject, string templateName, JObject data, - string to, + string subject, string templateName, JObject data, + string to, string cc = null, string from = null) { var template = await GetEdmTemplate(templateName); - if (template == null) + if (string.IsNullOrEmpty(template)) { throw new MixException(MixErrorStatus.Badrequest, $"Edm {templateName} not found"); } @@ -57,7 +62,32 @@ public virtual async Task SendMailWithEdmTemplate( CC = cc, To = to }; - _queueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.SendMail, msg); + _queueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.SendMail, msg); + } + + public virtual async Task SendMailWithTemplate( + string subject, string template, JObject data, + string to, + string cc = null, + string from = null) + { + foreach (var prop in data.Properties().ToList()) + { + if (data.ContainsKey(prop.Name)) + { + template = template.Replace($"[[{prop.Name}]]", data.GetValue(prop.Name).ToString()); + } + } + + EmailMessageModel msg = new() + { + Subject = subject, + Message = template, + From = from, + CC = cc, + To = to + }; + _queueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.SendMail, msg); } } } diff --git a/src/platform/mix.library/Services/MixIdentityService.cs b/src/platform/mix.library/Services/MixIdentityService.cs index 8c5758674..952754067 100644 --- a/src/platform/mix.library/Services/MixIdentityService.cs +++ b/src/platform/mix.library/Services/MixIdentityService.cs @@ -57,6 +57,10 @@ public MixTenantSystemModel CurrentTenant if (_currentTenant == null) { _currentTenant = Session.Get(MixRequestQueryKeywords.Tenant); + _currentTenant ??= new MixTenantSystemModel() + { + Id = 1 + }; } return _currentTenant; } @@ -255,7 +259,7 @@ public virtual async Task RegisterAsync(RegisterRequestModel model, int throw new MixException(MixErrorStatus.Badrequest, createResult.Errors.First().Description); } - public async Task GetOrCreateUserData(MixUser user, CancellationToken cancellationToken = default) + public virtual async Task GetOrCreateUserData(MixUser user, CancellationToken cancellationToken = default) { try { @@ -294,7 +298,7 @@ public async Task GetOrCreateUserData(MixUser user, CancellationToken c } } - public async Task GenerateAccessTokenAsync( + public virtual async Task GenerateAccessTokenAsync( MixUser user, bool isRemember, string aesKey, @@ -308,7 +312,7 @@ public async Task GenerateAccessTokenAsync( var dtRefreshTokenExpired = dtIssued.AddMinutes(AuthConfigService.AppSettings.RefreshTokenExpiration); var refreshTokenId = Guid.Empty; var refreshToken = Guid.Empty; - var userInfo = await GetOrCreateUserData(user, cancellationToken); + //var userInfo = await GetOrCreateUserData(user, cancellationToken); if (isRemember) { refreshToken = Guid.NewGuid(); @@ -329,11 +333,11 @@ public async Task GenerateAccessTokenAsync( var token = new TokenResponseModel() { - Info = userInfo, + Info = new(), EmailConfirmed = user.EmailConfirmed, IsActive = user.IsActived, AccessToken = await GenerateTokenAsync( - user, userInfo, dtExpired, refreshToken.ToString(), aesKey, rsaPublicKey, AuthConfigService.AppSettings), + user, new(), dtExpired, refreshToken.ToString(), aesKey, rsaPublicKey, AuthConfigService.AppSettings), RefreshToken = refreshTokenId, TokenType = AuthConfigService.AppSettings.TokenType, ExpiresIn = AuthConfigService.AppSettings.AccessTokenExpiration, diff --git a/src/platform/mix.library/Services/MixTenantService.cs b/src/platform/mix.library/Services/MixTenantService.cs index 3b9bf3b9b..1b318043b 100644 --- a/src/platform/mix.library/Services/MixTenantService.cs +++ b/src/platform/mix.library/Services/MixTenantService.cs @@ -48,6 +48,7 @@ public async Task Reload(CancellationToken cancellationToken = default) .ToList(); AllTenants = tenants; + dbContext.Dispose(); } } } diff --git a/src/platform/mix.library/Services/MixThemeImportService.cs b/src/platform/mix.library/Services/MixThemeImportService.cs index 4bc859640..deac2d95a 100644 --- a/src/platform/mix.library/Services/MixThemeImportService.cs +++ b/src/platform/mix.library/Services/MixThemeImportService.cs @@ -1,4 +1,5 @@ using DocumentFormat.OpenXml.Vml; +using DocumentFormat.OpenXml.Wordprocessing; using Google.Protobuf.WellKnownTypes; using Humanizer; using Microsoft.AspNetCore.Http; @@ -10,12 +11,14 @@ using Mix.Lib.Interfaces; using Mix.RepoDb.Interfaces; using Mix.RepoDb.Repositories; +using Mix.RepoDb.ViewModels; namespace Mix.Lib.Services { public class MixThemeImportService : IMixThemeImportService { private MixRepoDbRepository _repository { get; set; } + private MixCacheService _cacheService{ get; set; } private readonly CancellationTokenSource _cts; private readonly DatabaseService _databaseService; private readonly IDatabaseConstants _databaseConstant; @@ -60,10 +63,12 @@ public MixTenantSystemModel CurrentTenant public MixThemeImportService( IHttpContextAccessor httpContext, DatabaseService databaseService, - IServiceProvider serviceProvider) + IServiceProvider serviceProvider, + MixCacheService cacheService) { _cts = new CancellationTokenSource(); _session = httpContext.HttpContext?.Session; + _cacheService = cacheService; _databaseService = databaseService; _serviceProvider = serviceProvider; _databaseConstant = _databaseService.DatabaseProvider switch @@ -109,6 +114,7 @@ public async Task LoadSchema(string folder) var strSchema = MixFileHelper.GetFile(MixThemePackageConstants.SchemaFilename, MixFileExtensions.Json, folder); var siteStructures = JObject.Parse(strSchema.Content).ToObject(); await ValidateSiteData(siteStructures); + serviceScope.Dispose(); return siteStructures; } } @@ -123,6 +129,7 @@ public void ExtractTheme(IFormFile themeFile) var formFile = new FileModel(themeFile.FileName, fileStream, MixFolders.ThemePackage); var templateAsset = MixFileHelper.SaveFile(formFile); MixFileHelper.UnZipFile(formFile.FullPath, MixFolders.ThemePackage); + fileStream.Dispose(); } } else @@ -178,6 +185,7 @@ private async Task ImportSiteData() await _uow.CompleteAsync(); await mixdbUow.CompleteAsync(); + serviceScope.Dispose(); return _siteData; } } @@ -196,8 +204,9 @@ private async Task ImportMixDb() uow.Begin(); var mixDbService = serviceScope.ServiceProvider.GetRequiredService(); - await ImportMixDatabases(uow.DbContext, mixDbService); + await ImportMixDatabases(uow, _cacheService, mixDbService); await uow.CompleteAsync(); + serviceScope.Dispose(); } } catch (Exception ex) @@ -266,24 +275,28 @@ private async Task ImportConfigurations() await ImportContentDataAsync(_siteData.ConfigurationContents, _dicConfigurationContentIds, _dicConfigurationIds); } - private async Task ImportMixDatabases(MixCmsContext dbContext, IMixDbService mixDbService, CancellationToken cancellationToken = default) + private async Task ImportMixDatabases(UnitOfWorkInfo uow, MixCacheService cacheService, IMixDbService mixDbService, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - await ImportDatabaseContextsAsync(dbContext); - await ImportDatabasesAsync(dbContext); - await ImportDatabaseRelationshipsAsync(dbContext); - await MigrateMixDatabaseAsync(mixDbService); + await ImportDatabaseContextsAsync(uow.DbContext); + await ImportDatabasesAsync(uow.DbContext); + await ImportDatabaseRelationshipsAsync(uow.DbContext); + await MigrateMixDatabaseAsync(uow, cacheService, mixDbService); await MigrateSystemMixDatabaseAsync(mixDbService, cancellationToken); } - private async Task MigrateMixDatabaseAsync(IMixDbService mixDbService) + private async Task MigrateMixDatabaseAsync(UnitOfWorkInfo uow, MixCacheService cacheService, IMixDbService mixDbService) { foreach (var item in _siteData.MixDatabases) { if (_dicMixDatabaseNames.ContainsKey(item.SystemName)) { - await mixDbService.MigrateDatabase(_dicMixDatabaseNames[item.SystemName]); + + RepoDbMixDatabaseViewModel database = await RepoDbMixDatabaseViewModel + .GetRepository(uow, cacheService).GetSingleAsync(m => m.SystemName == _dicMixDatabaseNames[item.SystemName]); + + await mixDbService.MigrateDatabase(database); } } } diff --git a/src/platform/mix.library/Services/RestApiService.cs b/src/platform/mix.library/Services/RestApiService.cs index 4480bc36b..9ca280777 100644 --- a/src/platform/mix.library/Services/RestApiService.cs +++ b/src/platform/mix.library/Services/RestApiService.cs @@ -18,7 +18,7 @@ public class RestApiService : TenantSer where TView : ViewModelBase { protected readonly MixIdentityService MixIdentityService; - protected readonly IQueueService QueueService; + protected readonly IMemoryQueueService QueueService; protected readonly IPortalHubClientService PortalHub; protected UnitOfWorkInfo Uow; protected UnitOfWorkInfo CacheUow; @@ -29,7 +29,7 @@ public RestApiService( IHttpContextAccessor httpContextAccessor, MixIdentityService identityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, MixCacheService cacheService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) @@ -74,14 +74,14 @@ await PortalHub.SendMessageAsync(new SignalRMessageModel() Data = ReflectionHelper.ParseObject(data).ToString(), Type = MessageType.Success, }); - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixViewModelChanged, MixRestAction.Post.ToString(), data); + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixViewModelChanged, MixRestAction.Post.ToString(), data); return id; } public virtual async Task UpdateHandler(TPrimaryKey id, TView data, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - var currentId = ReflectionHelper.GetPropertyValue(data, "id").ToString(); + var currentId = ReflectionHelper.GetPropertyValue(data, "Id").ToString(); if (id.ToString() != currentId) { throw new MixException(MixErrorStatus.Badrequest, "Invalid Id"); @@ -97,7 +97,7 @@ await PortalHub.SendMessageAsync(new SignalRMessageModel() Data = ReflectionHelper.ParseObject(data).ToString(), Type = MessageType.Success, }); - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixViewModelChanged, MixRestAction.Put.ToString(), data); + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixViewModelChanged, MixRestAction.Put.ToString(), data); } public virtual async Task DeleteHandler(TView data, CancellationToken cancellationToken = default) @@ -114,7 +114,7 @@ await PortalHub.SendMessageAsync(new SignalRMessageModel() Data = ReflectionHelper.ParseObject(data).ToString(), Type = MessageType.Success, }); - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixViewModelChanged, MixRestAction.Delete.ToString(), data); + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixViewModelChanged, MixRestAction.Delete.ToString(), data); } @@ -124,7 +124,7 @@ public virtual async Task PatchHandler(TPrimaryKey id, TView data, IEnumerable data, CancellationToken cancellationToken = default) @@ -142,8 +142,15 @@ public virtual async Task SaveManyHandler(List data, CancellationToken ca #region Query Handlers public virtual async Task> SearchHandler(SearchRequestDto req, SearchQueryModel searchRequest, CancellationToken cancellationToken = default) { - cancellationToken.ThrowIfCancellationRequested(); - return await Repository.GetPagingAsync(searchRequest.Predicate, searchRequest.PagingData, cancellationToken); + try + { + cancellationToken.ThrowIfCancellationRequested(); + return await Repository.GetPagingAsync(searchRequest.Predicate, searchRequest.PagingData, cancellationToken); + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.ServerError, ex); + } } public virtual PagingResponseModel ParseSearchResult(SearchRequestDto req, PagingResponseModel result, CancellationToken cancellationToken = default) diff --git a/src/platform/mix.library/Startup/AuthServiceCollectionExtensions.cs b/src/platform/mix.library/Startup/AuthServiceCollectionExtensions.cs index d8fb26ed5..f39129673 100644 --- a/src/platform/mix.library/Startup/AuthServiceCollectionExtensions.cs +++ b/src/platform/mix.library/Startup/AuthServiceCollectionExtensions.cs @@ -17,6 +17,7 @@ using Mix.Identity.Services; using Mix.Lib.Services; using Mix.Shared.Models.Configurations; +using System.Reflection; using System.Text; namespace Microsoft.Extensions.DependencyInjection { @@ -103,18 +104,17 @@ public static IServiceCollection AddMixAuthorize(this IServiceCollec .AddMicrosoftIdentityWebApiIf( !string.IsNullOrEmpty(authConfigurations.AzureAd?.ClientId), configuration); - - services.ConfigureApplicationCookie(options => - { - options.Cookie.HttpOnly = true; - options.Cookie.MaxAge = TimeSpan.FromMinutes(authConfigurations.AccessTokenExpiration); - options.ExpireTimeSpan = TimeSpan.FromMinutes(authConfigurations.AccessTokenExpiration); - options.LoginPath = accessDeniedPath; - options.LogoutPath = "/"; - options.AccessDeniedPath = accessDeniedPath; - options.SlidingExpiration = true; - }); - + //services.ConfigureApplicationCookie(options => + //{ + // options.Cookie.Name = authConfigurations.Issuer; + // options.Cookie.HttpOnly = true; + // options.Cookie.MaxAge = TimeSpan.FromMinutes(authConfigurations.AccessTokenExpiration); + // options.ExpireTimeSpan = TimeSpan.FromMinutes(authConfigurations.AccessTokenExpiration); + // options.LoginPath = accessDeniedPath; + // options.LogoutPath = "/"; + // options.AccessDeniedPath = accessDeniedPath; + // options.SlidingExpiration = true; + //}); // Firebase service must be singleton (only one firebase default instance) services.TryAddSingleton(); services.TryAddScoped(); diff --git a/src/platform/mix.library/Startup/Cors.cs b/src/platform/mix.library/Startup/Cors.cs index 7d29ef524..115ec342c 100644 --- a/src/platform/mix.library/Startup/Cors.cs +++ b/src/platform/mix.library/Startup/Cors.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Microsoft.Extensions.DependencyInjection { @@ -8,7 +9,7 @@ public static partial class ServiceCollectionExtensions public static IServiceCollection AddMixCors(this IServiceCollection services) { - + services.TryAddSingleton(); var mixEndpointService = services.GetService(); origins = mixEndpointService.Endpoints .Where(e => !string.IsNullOrEmpty(e)) diff --git a/src/platform/mix.library/Startup/GenerateRestApi.cs b/src/platform/mix.library/Startup/GenerateRestApi.cs index 3abe50453..061d4c022 100644 --- a/src/platform/mix.library/Startup/GenerateRestApi.cs +++ b/src/platform/mix.library/Startup/GenerateRestApi.cs @@ -1,15 +1,16 @@ using Mix.Lib.Conventions; using Mix.Lib.Providers; +using System.Reflection; using System.Text.Json.Serialization; namespace Microsoft.Extensions.DependencyInjection { public static partial class ServiceCollectionExtensions { - private static IServiceCollection AddGeneratedRestApi(this IServiceCollection services) + public static IServiceCollection AddGeneratedRestApi(this IServiceCollection services, List assemblies) { List restCandidates = GetCandidatesByAttributeType( - MixAssemblies, typeof(GenerateRestApiControllerAttribute)); + assemblies, typeof(GenerateRestApiControllerAttribute)); services. AddControllers(o => o.Conventions.Add( new GenericControllerRouteConvention() diff --git a/src/platform/mix.library/Startup/Migration.cs b/src/platform/mix.library/Startup/Migration.cs index 0a8f01095..9eb2f6d06 100644 --- a/src/platform/mix.library/Startup/Migration.cs +++ b/src/platform/mix.library/Startup/Migration.cs @@ -10,7 +10,7 @@ namespace Microsoft.Extensions.DependencyInjection public static partial class ServiceCollectionExtensions { - private static void ApplyMigrations(this IServiceCollection services, GlobalSettingsModel options) + public static void ApplyMigrations(this IServiceCollection services, GlobalSettingsModel options) { if (!options.IsInit) { diff --git a/src/platform/mix.library/Startup/MixCommonService.cs b/src/platform/mix.library/Startup/MixCommonService.cs index cbd03e4f2..b7aeabd2c 100644 --- a/src/platform/mix.library/Startup/MixCommonService.cs +++ b/src/platform/mix.library/Startup/MixCommonService.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; using Mix.Communicator.Services; using Mix.Database.Services; @@ -13,8 +14,9 @@ namespace Microsoft.Extensions.DependencyInjection { public static partial class ServiceCollectionExtensions { - private static IServiceCollection AddMixCommonServices(this IServiceCollection services, Assembly executingAssembly, IConfiguration configuration) + public static IServiceCollection AddMixCommonServices(this IServiceCollection services, IConfiguration configuration) { + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); @@ -25,13 +27,10 @@ private static IServiceCollection AddMixCommonServices(this IServiceCollection s services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); - - services.TryAddScoped(); + services.TryAddSingleton(); - services.TryAddScoped(); - services.TryAddScoped(); services.TryAddScoped(); - + services.TryAddScoped(); services.TryAddScoped(); diff --git a/src/platform/mix.library/Startup/MixTenant.cs b/src/platform/mix.library/Startup/MixTenant.cs index 97162a5d3..77802e0d8 100644 --- a/src/platform/mix.library/Startup/MixTenant.cs +++ b/src/platform/mix.library/Startup/MixTenant.cs @@ -1,15 +1,33 @@ using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; using Mix.Lib.Interfaces; using Mix.Lib.Middlewares; using Mix.Lib.Services; +using Mix.Shared.Models.Configurations; +using RepoDb; +using RepoDb.Interfaces; namespace Microsoft.Extensions.DependencyInjection { public static partial class ServiceCollectionExtensions { - public static IServiceCollection AddMixTenant(this IServiceCollection services) + public static IServiceCollection AddMixTenant(this IServiceCollection services, IConfiguration configuration) { + var authConfig = configuration.GetSection(MixAppSettingsSection.Authentication).Get(); + services.AddMixCache(configuration); + services.AddSession( + options => + { + options.IdleTimeout = TimeSpan.FromMinutes(authConfig.AccessTokenExpiration); + options.Cookie.SecurePolicy = CookieSecurePolicy.Always; + options.Cookie.SameSite = SameSiteMode.Strict; + options.Cookie.HttpOnly = true; + options.Cookie.Name = authConfig.Issuer; + } + ); + services.TryAddSingleton(); return services; } diff --git a/src/platform/mix.library/Startup/Queue.cs b/src/platform/mix.library/Startup/Queue.cs index 3a724f366..d48cbd6f3 100644 --- a/src/platform/mix.library/Startup/Queue.cs +++ b/src/platform/mix.library/Startup/Queue.cs @@ -14,7 +14,7 @@ private static IServiceCollection AddQueues(this IServiceCollection services, As // Message Queue // Need singleton instance to store all message from mix publishers - services.TryAddSingleton, QueueService>(); + services.TryAddSingleton, MemoryQueueService>(); return services; } } diff --git a/src/platform/mix.library/Startup/_ServiceCollectionExtensions.cs b/src/platform/mix.library/Startup/_ServiceCollectionExtensions.cs index a62341afe..a4d206a9c 100644 --- a/src/platform/mix.library/Startup/_ServiceCollectionExtensions.cs +++ b/src/platform/mix.library/Startup/_ServiceCollectionExtensions.cs @@ -1,20 +1,25 @@ using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Azure.Amqp.Framing; +using Microsoft.Build.Framework; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Options; +using Mix.Lib.Interfaces; using Mix.Lib.Middlewares; +using Mix.Lib.Services; using Mix.Mixdb.Event.Services; using Mix.Service.Interfaces; using Mix.Shared; using Mix.Shared.Interfaces; using Mix.Shared.Models.Configurations; using Mix.SignalR.Interfaces; +using StackExchange.Redis; using System.Reflection; namespace Microsoft.Extensions.DependencyInjection @@ -23,7 +28,7 @@ public static partial class ServiceCollectionExtensions { public static List MixAssemblies { - get => MixAssemblyFinder.GetMixAssemblies(); + get => MixAssemblyFinder.GetAssembliesByPrefix("mix"); } #region Services @@ -32,42 +37,62 @@ public static IServiceCollection AddMixServices(this IServiceCollection services { var globalConfig = configuration.GetSection(MixAppSettingsSection.GlobalSettings) .Get(); + + var authConfig = configuration.GetSection(MixAppSettingsSection.Authentication) + .Get(); + + var redisCnn = configuration.GetSection("Redis").GetValue("ConnectionString"); + services.AddOptions() .Bind(configuration.GetSection(MixAppSettingsSection.GlobalSettings)) .ValidateDataAnnotations(); - services.AddMvc().AddSessionStateTempDataProvider(); - services.TryAddSingleton(); - services.AddSession(options => + + if (!string.IsNullOrEmpty(redisCnn)) { - options.IdleTimeout = TimeSpan.FromHours(4); - options.Cookie.SecurePolicy = CookieSecurePolicy.None; - options.Cookie.SameSite = SameSiteMode.Strict; - options.Cookie.HttpOnly = true; - // Make the session cookie essential if you wish - //options.Cookie.IsEssential = true; - }); - services.AddMixCommonServices(executingAssembly, configuration); + var redis = ConnectionMultiplexer.Connect(configuration.GetSection("Redis").GetValue("ConnectionString")); + services.AddDataProtection() + .SetApplicationName(authConfig.Issuer) + .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys"); + + var sp = services.BuildServiceProvider(); + + // perform a protect operation to force the system to put at least + // one key in the key ring + sp.GetDataProtector("Sample.KeyManager.v1").Protect("payload"); + Console.WriteLine("Performed a protect operation."); + Thread.Sleep(2000); + } + else + { + services.AddDataProtection() + .UnprotectKeysWithAnyCertificate() + .SetApplicationName(authConfig.Issuer); + } + + + services.AddMixCommonServices(configuration); + services.TryAddScoped(); + services.TryAddScoped(); + services.AddMixDbContexts(); services.AddUoWs(); - services.AddMixCache(configuration); services.CustomValidationResponse(); services.AddHttpClient(); services.AddHttpLogging(opt => opt.CombineLogs = true); - services.ApplyMigrations(globalConfig); services.AddQueues(executingAssembly, configuration); // Don't need to inject all entity repository by default //services.AddEntityRepositories(); - services.AddMixTenant(); + services.AddMixTenant(configuration); services.AddGeneratedPublisher(); services.AddMixModuleServices(configuration); - services.AddGeneratedRestApi(); + services.AddGeneratedRestApi(MixAssemblies); services.AddMixSwaggerServices(executingAssembly); services.AddSSL(); @@ -90,13 +115,17 @@ public static IServiceCollection AddMixTestServices(this IServiceCollection serv { // Clone Settings from shared folder var globalConfig = configuration.GetSection(MixAppSettingsSection.GlobalSettings).Get()!; - + var authConfig = configuration.GetSection(MixAppSettingsSection.Authentication) + .Get(); services.AddMvc().AddSessionStateTempDataProvider(); - services.AddSession(); - services.AddMixCommonServices(executingAssembly, configuration); + + + services.AddMixCommonServices(configuration); + services.TryAddScoped(); + services.TryAddScoped(); + services.AddMixDbContexts(); services.AddUoWs(); - services.AddMixCache(configuration); services.CustomValidationResponse(); services.AddHttpClient(); services.AddLogging(); @@ -105,13 +134,13 @@ public static IServiceCollection AddMixTestServices(this IServiceCollection serv services.AddQueues(executingAssembly, configuration); - services.AddMixTenant(); + services.AddMixTenant(configuration); services.AddGeneratedPublisher(); services.AddMixModuleServices(configuration); - services.AddGeneratedRestApi(); + services.AddGeneratedRestApi(MixAssemblies); services.AddMixSwaggerServices(executingAssembly); services.AddSSL(); diff --git a/src/platform/mix.library/Subscribers/MixBackgroundTaskSubscriber.cs b/src/platform/mix.library/Subscribers/MixBackgroundTaskSubscriber.cs index 8b1e77e8f..999a96edf 100644 --- a/src/platform/mix.library/Subscribers/MixBackgroundTaskSubscriber.cs +++ b/src/platform/mix.library/Subscribers/MixBackgroundTaskSubscriber.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Mix.Communicator.Models; using Mix.Communicator.Services; using Mix.Database.Entities.Account; @@ -33,8 +34,9 @@ public MixBackgroundTaskSubscriber( IConfiguration configuration, IPortalHubClientService portalHub, MixDbEventService mixDbEventService, - IQueueService queueService) - : base(TopicId, nameof(MixBackgroundTaskSubscriber), 20, serviceProvider, configuration, queueService) + IMemoryQueueService queueService, + ILogger logger) + : base(TopicId, nameof(MixBackgroundTaskSubscriber), 20, serviceProvider, configuration, queueService, logger) { PortalHub = portalHub; MixDbEventService = mixDbEventService; @@ -42,15 +44,23 @@ public MixBackgroundTaskSubscriber( public override Task StartAsync(CancellationToken cancellationToken = default) { - Task.Run(async () => + base.StartAsync(cancellationToken); + + return Task.Run(async () => { while (PortalHub.Connection == null || PortalHub.Connection.State != Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected) { - await Task.Delay(5000); - await PortalHub.StartConnection(); + try + { + await Task.Delay(5000); + await PortalHub.StartConnection(); + } + catch (Exception ex) + { + _logger.LogError(GetType().Name, ex); + } } }); - return base.StartAsync(cancellationToken); } public override async Task Handler(MessageQueueModel model) { diff --git a/src/platform/mix.library/Subscribers/MixDbCommandSubscriber.cs b/src/platform/mix.library/Subscribers/MixDbCommandSubscriber.cs index d5068aede..65a400b92 100644 --- a/src/platform/mix.library/Subscribers/MixDbCommandSubscriber.cs +++ b/src/platform/mix.library/Subscribers/MixDbCommandSubscriber.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Mix.Communicator.Models; using Mix.Communicator.Services; using Mix.Database.Entities.MixDb; @@ -24,8 +25,9 @@ public class MixDbCommandSubscriber : SubscriberBase public MixDbCommandSubscriber( IServiceProvider serviceProvider, IConfiguration configuration, - IQueueService queueService) - : base(TopicId, nameof(MixDbCommandSubscriber), 20, serviceProvider, configuration, queueService) + IMemoryQueueService queueService, + ILogger logger) + : base(TopicId, nameof(MixDbCommandSubscriber), 20, serviceProvider, configuration, queueService, logger) { } diff --git a/src/platform/mix.library/Subscribers/MixViewModelChangedSubscriber.cs b/src/platform/mix.library/Subscribers/MixViewModelChangedSubscriber.cs index 274d34e69..3507fdf4f 100644 --- a/src/platform/mix.library/Subscribers/MixViewModelChangedSubscriber.cs +++ b/src/platform/mix.library/Subscribers/MixViewModelChangedSubscriber.cs @@ -19,14 +19,16 @@ public MixViewModelChangedSubscriber( IServiceProvider serviceProvider, IConfiguration configuration, IMixTenantService mixTenantService, - IQueueService queueService) - : base(TopicId, nameof(MixDbCommandSubscriber), 20, serviceProvider, configuration, queueService) + IMemoryQueueService queueService, + ILogger logger) + : base(TopicId, nameof(MixDbCommandSubscriber), 20, serviceProvider, configuration, queueService, logger) { _mixTenantService = mixTenantService; } public override async Task Handler(MessageQueueModel data) { + CacheService ??= GetRequiredService(); await UpdateCacheHandler(data); switch (data.DataTypeFullName) { @@ -71,6 +73,7 @@ private async Task UpdateCacheHandler(MessageQueueModel data) default: break; } + serviceScope.Dispose(); } } } diff --git a/src/platform/mix.library/ViewModels/MixDatabaseContextViewModel.cs b/src/platform/mix.library/ViewModels/MixDatabaseContextViewModel.cs index 74538ae39..1d85c4c1e 100644 --- a/src/platform/mix.library/ViewModels/MixDatabaseContextViewModel.cs +++ b/src/platform/mix.library/ViewModels/MixDatabaseContextViewModel.cs @@ -5,6 +5,7 @@ public sealed class MixDatabaseContextViewModel { #region Properties public MixDatabaseProvider DatabaseProvider { get; set; } + public MixDatabaseNamingConvention NamingConvention { get; set; } public string ConnectionString { get; set; } public string Schema { get; set; } public string SystemName { get; set; } diff --git a/src/platform/mix.library/ViewModels/MixDatabaseViewModel.cs b/src/platform/mix.library/ViewModels/MixDatabaseViewModel.cs index a06bad331..830ed0afd 100644 --- a/src/platform/mix.library/ViewModels/MixDatabaseViewModel.cs +++ b/src/platform/mix.library/ViewModels/MixDatabaseViewModel.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Mix.Lib.ViewModels.ReadOnly; using System.ComponentModel.DataAnnotations; +using System.Threading; namespace Mix.Lib.ViewModels { @@ -10,7 +11,6 @@ public sealed class MixDatabaseViewModel : TenantDataViewModelBase ReadPermissions { get; set; } public List CreatePermissions { get; set; } @@ -113,11 +113,47 @@ protected override async Task SaveEntityRelationshipAsync(MixDatabase parentEnti item.ParentId = parentEntity.Id; item.SourceDatabaseName = parentEntity.SystemName; await item.SaveAsync(cancellationToken); + + await CreateRefColumn(item); + ModifiedEntities.AddRange(item.ModifiedEntities); } } } + private async Task CreateRefColumn(MixDatabaseRelationshipViewModel item, CancellationToken cancellationToken = default) + { + if (item.Type == MixDatabaseRelationshipType.OneToMany) + { + var referenceColumnName = $"{item.SourceDatabaseName}Id"; + var fieldNameService = new FieldNameService(MixDatabaseNamingConvention.TitleCase); + if (MixDatabaseContextId.HasValue) + { + var dbContext = Context.MixDatabaseContext.First(m => m.Id == MixDatabaseContextId); + fieldNameService = new FieldNameService(dbContext.NamingConvention); + referenceColumnName = $"{item.SourceDatabaseName}_id"; + } + + if (!Context.MixDatabaseColumn.Any(m => m.MixDatabaseName == item.DestinateDatabaseName && m.SystemName == referenceColumnName)) + { + var srcDb = Context.MixDatabase.FirstOrDefault(m => m.SystemName == item.SourceDatabaseName); + var destDb = Context.MixDatabase.FirstOrDefault(m => m.SystemName == item.DestinateDatabaseName); + var refCol = new MixDatabaseColumnViewModel(UowInfo) + { + MixDatabaseName = item.DestinateDatabaseName, + MixDatabaseId = destDb.Id, + DataType = MixDataType.Reference, + CreatedBy = CreatedBy, + DisplayName = item.ReferenceColumnName.ToTitleCase(), + SystemName = referenceColumnName + }; + + await refCol.SaveAsync(cancellationToken); + ModifiedEntities.AddRange(refCol.ModifiedEntities); + } + } + } + protected override async Task DeleteHandlerAsync(CancellationToken cancellationToken = default) { // Exception: This MySqlConnection is already in use. See https://fl.vu/mysql-conn-reuse when delete nested entity using Repository diff --git a/src/platform/mix.library/mix.library.csproj b/src/platform/mix.library/mix.library.csproj index a644836ae..70eb2f7be 100644 --- a/src/platform/mix.library/mix.library.csproj +++ b/src/platform/mix.library/mix.library.csproj @@ -81,6 +81,7 @@ + diff --git a/src/platform/mix.log/Publishers/MixLogPublisher.cs b/src/platform/mix.log/Publishers/MixLogPublisher.cs index 2ee496b83..1eba25360 100644 --- a/src/platform/mix.log/Publishers/MixLogPublisher.cs +++ b/src/platform/mix.log/Publishers/MixLogPublisher.cs @@ -14,7 +14,7 @@ public class MixLogPublisher : PublisherBase private const string TopicId = MixQueueTopics.MixLog; public MixLogPublisher( - IQueueService queueService, + IMemoryQueueService queueService, IConfiguration configuration, MixEndpointService mixEndpointService, ILogger logger) diff --git a/src/platform/mix.log/ServiceCollectionExtension.cs b/src/platform/mix.log/ServiceCollectionExtension.cs index 5d4b90291..88945be88 100644 --- a/src/platform/mix.log/ServiceCollectionExtension.cs +++ b/src/platform/mix.log/ServiceCollectionExtension.cs @@ -1,15 +1,21 @@ using Google.Api; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Mix.Constant.Constants; using Mix.Database.Entities.AuditLog; using Mix.Database.Entities.Queue; +using Mix.Database.Services; +using Mix.Lib.Interfaces; using Mix.Log.Lib.Interfaces; using Mix.Log.Lib.Models; using Mix.Log.Lib.Publishers; using Mix.Log.Lib.Services; using Mix.Log.Lib.Subscribers; +using Mix.Mq.Lib.Models; +using Mix.Queue.Interfaces; +using Mix.Queue.Services; using Mix.Service.Services; using Mix.Shared.Interfaces; using Mix.Shared.Models.Configurations; @@ -30,6 +36,15 @@ public static IServiceCollection AddMixLog(this IServiceCollection services, ICo { var globalConfigs = configuration.GetSection(MixAppSettingsSection.GlobalSettings).Get()!; + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton, MemoryQueueService>(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + + services.AddDbContext(); services.AddDbContext(); services.TryAddScoped(); diff --git a/src/platform/mix.log/Services/AuditLogService.cs b/src/platform/mix.log/Services/AuditLogService.cs index d38db55b4..1f74fcd4c 100644 --- a/src/platform/mix.log/Services/AuditLogService.cs +++ b/src/platform/mix.log/Services/AuditLogService.cs @@ -18,10 +18,10 @@ namespace Mix.Log.Lib.Services public class AuditLogService : IAuditLogService { private readonly ILogStreamHubClientService _logStreamHub; - private readonly IQueueService _queueService; + private readonly IMemoryQueueService _queueService; private AuditLogDbContext _dbContext; public int TenantId { get; set; } - public AuditLogService(IQueueService queueService, ILogStreamHubClientService logStreamHub) + public AuditLogService(IMemoryQueueService queueService, ILogStreamHubClientService logStreamHub) { _queueService = queueService; _logStreamHub = logStreamHub; @@ -60,7 +60,7 @@ public async Task SaveRequestAsync(AuditLogDataModel request) public void QueueRequest(AuditLogDataModel request) { var cmd = new LogAuditLogCommand(request); - _queueService.PushQueue(TenantId, MixQueueTopics.MixLog, MixQueueActions.AuditLog, cmd); + _queueService.PushMemoryQueue(TenantId, MixQueueTopics.MixLog, MixQueueActions.AuditLog, cmd); } #region Helpers diff --git a/src/platform/mix.log/Services/MixQueueLogService.cs b/src/platform/mix.log/Services/MixQueueLogService.cs index 2a20ea560..b10c6e20d 100644 --- a/src/platform/mix.log/Services/MixQueueLogService.cs +++ b/src/platform/mix.log/Services/MixQueueLogService.cs @@ -39,7 +39,7 @@ public async Task EnqueueMessageAsync(MessageQueueModel queueMessage) Action = queueMessage.Action, TopicId = queueMessage.TopicId, DataTypeFullName = queueMessage.DataTypeFullName, - Subscriptions = ReflectionHelper.ParseArray(_mixQueueService.GetTopic(queueMessage.TopicId).Subscriptions), + Subscriptions = ReflectionHelper.ParseArray(_mixQueueService.GetTopic(queueMessage.TopicId).Subscriptions.Select(m => m.Value).ToList()), State = MixQueueMessageLogState.NACK, Status = MixContentStatus.Published }; @@ -74,7 +74,7 @@ public async Task AckQueueMessage(MessageQueueModel ackQueueMessage) var rootLog = await _dbContext.MixQueueMessage.FirstOrDefaultAsync(m => m.Id == ackQueueMessage.Id); if (rootLog != null) { - var subs = rootLog.Subscriptions.FirstOrDefault(m => + var subs = rootLog.Subscriptions.FirstOrDefault(m => m.Value("id") == ackQueueMessage.Sender) as JObject; if (subs != null) { @@ -104,7 +104,7 @@ public async Task FailedQueueMessage(MessageQueueModel log) using (_dbContext = new()) { InitDbContext(); - + var rootLog = await _dbContext.MixQueueMessage.FirstOrDefaultAsync(m => m.Id == log.Id); if (rootLog != null) { diff --git a/src/platform/mix.log/Services/MixTenantService.cs b/src/platform/mix.log/Services/MixTenantService.cs new file mode 100644 index 000000000..8653c82de --- /dev/null +++ b/src/platform/mix.log/Services/MixTenantService.cs @@ -0,0 +1,77 @@ +using Microsoft.EntityFrameworkCore; +using Mix.Constant.Enums; +using Mix.Database.Entities.Cms; +using Mix.Database.Services; +using Mix.Lib.Interfaces; +using Mix.Service.Models; +using Mix.Service.Services; +using Mix.Shared.Services; + +namespace Mix.Log.Lib.Services +{ + public sealed class MixTenantService : IMixTenantService + { + private readonly DatabaseService _databaseService; + + public List AllTenants { get; set; } + + public List AllCultures { get; set; } + public List AllThemes { get; set; } + + public MixTenantService(DatabaseService databaseService) + { + _databaseService = databaseService; + } + + public async Task Reload(CancellationToken cancellationToken = default) + { + if (GlobalConfigService.Instance.InitStatus != InitStep.Blank) + { + using (var dbContext = _databaseService.GetDbContext()) + { + var mixTenants = await dbContext.MixTenant.ToListAsync(cancellationToken); + + var tenantIds = mixTenants.Select(p => p.Id).ToList(); + + var domains = await dbContext.MixDomain.Where(p => tenantIds.Contains(p.MixTenantId)).ToListAsync(cancellationToken); + AllCultures = await dbContext.MixCulture.ToListAsync(cancellationToken); + AllThemes = await dbContext.MixTheme.ToListAsync(cancellationToken); + + var tenants = mixTenants + .Select(p => new MixTenantSystemModel + { + Id = p.Id, + SystemName = p.SystemName, + Description = p.Description, + PrimaryDomain = p.PrimaryDomain, + DisplayName = p.DisplayName, + Configurations = new TenantConfigService(p.SystemName).AppSettings, + Domains = domains.Where(d => d.MixTenantId == p.Id).ToList(), + Cultures = AllCultures.Where(c => c.MixTenantId == p.Id).ToList(), + Themes = AllThemes.Where(c => c.MixTenantId == p.Id).ToList(), + }) + .ToList(); + + AllTenants = tenants; + } + } + } + + public MixTenantSystemModel GetTenant(string host) + { + return AllTenants.FirstOrDefault(m => m.Domains.Any(d => d.Host == host)) ?? AllTenants.First(); + } + + public async Task GetDefaultTenant() + { + if (AllTenants == null) + { + await Reload(); + } + return AllTenants?.FirstOrDefault() ?? new MixTenantSystemModel() + { + Id = 1 + }; + } + } +} diff --git a/src/platform/mix.log/Subscribers/MixLogSubscriber.cs b/src/platform/mix.log/Subscribers/MixLogSubscriber.cs index 1320b2dea..0051a7be7 100644 --- a/src/platform/mix.log/Subscribers/MixLogSubscriber.cs +++ b/src/platform/mix.log/Subscribers/MixLogSubscriber.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using Mix.Constant.Constants; using Mix.Constant.Enums; using Mix.Database.Entities.Queue; @@ -38,10 +39,11 @@ public MixLogSubscriber( IServiceProvider serviceProvider, IConfiguration configuration, IPortalHubClientService portalHub, - IQueueService queueService, + IMemoryQueueService queueService, IMixQueueLog queueMessageLogService, - IAuditLogService auditLogService) - : base(TopicId, nameof(MixLogSubscriber), 20, serviceProvider, configuration, queueService) + IAuditLogService auditLogService, + ILogger logger) + : base(TopicId, nameof(MixLogSubscriber), 20, serviceProvider, configuration, queueService, logger) { _queueMessageLogService = queueMessageLogService; _portalHub = portalHub; @@ -50,15 +52,23 @@ public MixLogSubscriber( public override Task StartAsync(CancellationToken cancellationToken = default) { - Task.Run(async () => + base.StartAsync(cancellationToken); + + return Task.Run(async () => { while (_portalHub.Connection == null || _portalHub.Connection.State != Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected) { - await Task.Delay(5000); - await _portalHub.StartConnection(); + try + { + await Task.Delay(5000); + await _portalHub.StartConnection(); + } + catch(Exception ex) + { + _logger.LogError(GetType().Name, ex); + } } }); - return base.StartAsync(cancellationToken); } public override async Task Handler(MessageQueueModel model) { @@ -70,10 +80,10 @@ public override async Task Handler(MessageQueueModel model) switch (model.Action) { case MixQueueActions.AuditLog: - var aditLogCmd = model.ParseData(); - if (aditLogCmd != null) + var auditLogCmd = model.ParseData(); + if (auditLogCmd != null) { - await _auditLogService.SaveRequestAsync(aditLogCmd.Request); + await _auditLogService.SaveRequestAsync(auditLogCmd.Request); } break; diff --git a/src/platform/mix.quartz/Extensions/ServiceCollectionExtensions.cs b/src/platform/mix.quartz/Extensions/ServiceCollectionExtensions.cs index 7c4d86b8c..f6456380f 100644 --- a/src/platform/mix.quartz/Extensions/ServiceCollectionExtensions.cs +++ b/src/platform/mix.quartz/Extensions/ServiceCollectionExtensions.cs @@ -20,7 +20,7 @@ public static IServiceCollection AddMixQuartzServices(this IServiceCollection se private static void AddSchedulerJobs(this IServiceCollection services) { - var assemblies = MixAssemblyFinder.GetMixAssemblies(); + var assemblies = MixAssemblyFinder.GetAssembliesByPrefix("mix"); foreach (var assembly in assemblies) { diff --git a/src/platform/mix.quartz/Jobs/MixJobBase.cs b/src/platform/mix.quartz/Jobs/MixJobBase.cs index b38386654..33fcd9f22 100644 --- a/src/platform/mix.quartz/Jobs/MixJobBase.cs +++ b/src/platform/mix.quartz/Jobs/MixJobBase.cs @@ -8,10 +8,10 @@ namespace Mix.Quartz.Jobs public abstract class MixJobBase : IJob { protected readonly IServiceProvider ServiceProvider; - protected readonly IQueueService QueueService; + protected readonly IMemoryQueueService QueueService; protected MixJobBase( IServiceProvider serviceProvider, - IQueueService queueService) + IMemoryQueueService queueService) { ServiceProvider = serviceProvider; JobType = GetType(); diff --git a/src/platform/mix.quartz/Services/QuartzService.cs b/src/platform/mix.quartz/Services/QuartzService.cs index 60cba7deb..eb0e23a2c 100644 --- a/src/platform/mix.quartz/Services/QuartzService.cs +++ b/src/platform/mix.quartz/Services/QuartzService.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Mix.Database.Services; using Mix.Heart.Enums; +using Mix.Heart.Exceptions; using Mix.Quartz.Constants; using Mix.Quartz.Extensions; using Mix.Quartz.Interfaces; @@ -23,9 +25,9 @@ public class QuartzService : IQuartzService private readonly DatabaseService _databaseService; public IScheduler Scheduler; - public QuartzService(IJobFactory jobFactory, IHttpContextAccessor httpContextAccessor) + public QuartzService(IJobFactory jobFactory, IHttpContextAccessor httpContextAccessor, IConfiguration configuration) { - _databaseService = new DatabaseService(httpContextAccessor); + _databaseService = new DatabaseService(httpContextAccessor, configuration); LoadScheduler().GetAwaiter().GetResult(); Scheduler.JobFactory = jobFactory; } @@ -177,7 +179,7 @@ public async Task ScheduleJob(JobSchedule schedule, CancellationToken cancellati } catch (Exception ex) { - LogException(ex); + throw new MixException(MixErrorStatus.Badrequest, ex); } } @@ -215,7 +217,7 @@ private ITrigger CreateTrigger(JobSchedule schedule, IJobDetail job = null) .Create() .ForJobIf(job != null, job) .WithIdentity(schedule.Name) - .WithDescription(schedule.CronExpression) + .WithDescription(schedule.Description) .UsingJobDataIf(schedule.JobData != null, schedule.JobData) .WithCronScheduleIf(!string.IsNullOrEmpty(schedule.CronExpression), schedule.CronExpression) .StartNowIf(schedule.IsStartNow) @@ -227,7 +229,7 @@ private ITrigger CreateTrigger(JobSchedule schedule, IJobDetail job = null) private Type FindJobType(string jobName) { - var assemblies = MixAssemblyFinder.GetMixAssemblies(); + var assemblies = MixAssemblyFinder.GetAssembliesByPrefix("mix"); Type jobType = null; foreach (var assembly in assemblies) { diff --git a/src/platform/mix.queue/Engines/Mix/MixQueuePublisher.cs b/src/platform/mix.queue/Engines/Mix/MixQueuePublisher.cs index 5d087880d..1ddadcbfb 100644 --- a/src/platform/mix.queue/Engines/Mix/MixQueuePublisher.cs +++ b/src/platform/mix.queue/Engines/Mix/MixQueuePublisher.cs @@ -17,13 +17,13 @@ public class MixQueuePublisher : IQueuePublisher { private string _topicId; private readonly MixEndpointService _mixEndpointService; - private GrpcChannelModel _mixMqSubscriber; + private GrpcChannelModel _mixMqPublisher; public MixQueuePublisher(QueueSetting queueSetting, string topicName, MixEndpointService mixEndpointService) { _topicId = topicName; _mixEndpointService = mixEndpointService; - _mixMqSubscriber = new GrpcChannelModel(_mixEndpointService.MixMq); + _mixMqPublisher = new GrpcChannelModel(_mixEndpointService.MixMq); } public Task SendMessage(T message) @@ -35,7 +35,7 @@ public Task SendMessage(T message) message.Id = Guid.NewGuid(); } message.CreatedDate = DateTime.UtcNow; - _mixMqSubscriber.Client.Publish(new PublishMessageRequest + _mixMqPublisher.Client.Publish(new PublishMessageRequest { TopicId = _topicId, Message = JObject.FromObject(message).ToString(Newtonsoft.Json.Formatting.None) diff --git a/src/platform/mix.queue/Engines/Mix/MixQueueSubscriber.cs b/src/platform/mix.queue/Engines/Mix/MixQueueSubscriber.cs index 6372b2676..6efdcc4d7 100644 --- a/src/platform/mix.queue/Engines/Mix/MixQueueSubscriber.cs +++ b/src/platform/mix.queue/Engines/Mix/MixQueueSubscriber.cs @@ -23,16 +23,18 @@ public class MixQueueSubscriber : BackgroundService, IQueueSubscriber private MixTopicModel _topic; private readonly MixQueueSetting _queueSetting; private readonly Func _messageHandler; - private readonly IQueueService _memQueues; + private readonly IMemoryQueueService _memQueues; private readonly MixEndpointService _mixEndpointService; private GrpcChannelModel _mixMqSubscriber; private SubscribeRequest _subscribeRequest; + private AsyncServerStreamingCall _call; + private CancellationToken _startCancellationToken; public MixQueueSubscriber( QueueSetting queueSetting, string topicId, string subscriptionId, Func messageHandler, - IQueueService memQueues, + IMemoryQueueService memQueues, MixEndpointService mixEndpointService) { _queueSetting = queueSetting as MixQueueSetting; @@ -54,40 +56,61 @@ public MixQueueSubscriber( /// public async Task ProcessQueue(CancellationToken cancellationToken = default) { - using var call = _mixMqSubscriber.Client.Subscribe(_subscribeRequest); - - while (await call.ResponseStream.MoveNext()) + try { - if (!IsProcessing) + _call = _mixMqSubscriber.Client.Subscribe(_subscribeRequest); + while (await _call.ResponseStream.MoveNext()) { - IsProcessing = true; - - - if (call.ResponseStream.Current.Messages.Count > 0) + if (!IsProcessing) { - foreach (var msg in call.ResponseStream.Current.Messages) + IsProcessing = true; + + if (_call.ResponseStream.Current.Messages.Count > 0) { - var obj = JObject.Parse(msg).ToObject(); - AckQueueMessage(obj); - await _messageHandler.Invoke(obj); + foreach (var msg in _call.ResponseStream.Current.Messages) + { + var obj = JObject.Parse(msg).ToObject(); + AckQueueMessage(obj); + await _messageHandler.Invoke(obj); + } } + IsProcessing = false; } - IsProcessing = false; - await Task.Delay(1000, cancellationToken); } } + catch + { + throw; + } + } + + public async Task Disconnect(CancellationToken cancellationToken = default) + { + try + { + cancellationToken.ThrowIfCancellationRequested(); + await _mixMqSubscriber.Client.DisconnectAsync(_subscribeRequest); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex); + } } protected override Task ExecuteAsync(CancellationToken stoppingToken) { - return ProcessQueue(stoppingToken); + while (!stoppingToken.IsCancellationRequested) + { + return ProcessQueue(stoppingToken); + } + return Task.CompletedTask; } private void AckQueueMessage(T model) { if (model.TopicId != MixQueueTopics.MixLog) { - var logQueue = _memQueues.GetQueue(MixQueueTopics.MixLog); + var logQueue = _memQueues.GetMemoryQueue(MixQueueTopics.MixLog); if (logQueue != null) { logQueue.Enqueue(new MessageQueueModel() @@ -102,5 +125,6 @@ private void AckQueueMessage(T model) } } } + } } diff --git a/src/platform/mix.queue/Engines/PublisherBase.cs b/src/platform/mix.queue/Engines/PublisherBase.cs index 310739a4d..c215cf210 100644 --- a/src/platform/mix.queue/Engines/PublisherBase.cs +++ b/src/platform/mix.queue/Engines/PublisherBase.cs @@ -17,7 +17,7 @@ namespace Mix.Queue.Engines { public abstract class PublisherBase : BackgroundService { - private readonly IQueueService _queueService; + private readonly IMemoryQueueService _queueService; private List> _publishers; private readonly IConfiguration _configuration; private readonly MixEndpointService _mixEndpointService; @@ -27,7 +27,7 @@ public abstract class PublisherBase : BackgroundService protected ILogger _logger; protected PublisherBase( string topicId, - IQueueService queueService, + IMemoryQueueService queueService, IConfiguration configuration, MixEndpointService mixEndpointService, ILogger logger) @@ -105,7 +105,7 @@ private Task StartMixQueueEngine(CancellationToken cancellationToken = default) { isProcessing = true; // Get messages from IQueueService - var inQueueItems = _queueService.ConsumeQueue(MaxConsumeLength, _topicId); + var inQueueItems = _queueService.ConsumeMemoryQueue(MaxConsumeLength, _topicId); if (inQueueItems.Any() && _publishers != null) { diff --git a/src/platform/mix.queue/Engines/QueueEngineFactory.cs b/src/platform/mix.queue/Engines/QueueEngineFactory.cs index 2cbd179c2..17e4d63f9 100644 --- a/src/platform/mix.queue/Engines/QueueEngineFactory.cs +++ b/src/platform/mix.queue/Engines/QueueEngineFactory.cs @@ -40,7 +40,7 @@ public static IQueueSubscriber CreateSubscriber( string topicId, string subscriptionId, Func handler, - IQueueService memQueues, + IMemoryQueueService memQueues, MixEndpointService mixEndpointService) where T : MessageQueueModel { diff --git a/src/platform/mix.queue/Engines/SubscriberBase.cs b/src/platform/mix.queue/Engines/SubscriberBase.cs index c1a5c76d4..f655853a6 100644 --- a/src/platform/mix.queue/Engines/SubscriberBase.cs +++ b/src/platform/mix.queue/Engines/SubscriberBase.cs @@ -1,9 +1,11 @@ using Azure.Core; using Google.Api; +using Google.Apis.Logging; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Mix.Heart.Enums; using Mix.Heart.Exceptions; using Mix.Heart.Helpers; @@ -21,16 +23,18 @@ namespace Mix.Queue.Engines { - public abstract class SubscriberBase : IHostedService + public abstract class SubscriberBase : BackgroundService { - protected IQueueService _memQueueService; - protected readonly IQueueSubscriber _subscriber; + protected IMemoryQueueService _memQueueService; + protected IQueueSubscriber _subscriber; protected readonly IConfiguration _configuration; protected readonly string _topicId; + protected readonly string _moduleName; protected readonly int _timeout; protected MixCacheService CacheService; protected readonly IServiceProvider ServicesProvider; protected IServiceScope ServiceScope { get; set; } + protected ILogger _logger { get; set; } protected SubscriberBase( @@ -39,39 +43,67 @@ protected SubscriberBase( int timeout, IServiceProvider servicesProvider, IConfiguration configuration, - IQueueService queueService) + IMemoryQueueService queueService, + ILogger logger) { _timeout = timeout; _configuration = configuration; _topicId = topicId; + _moduleName = moduleName; _memQueueService = queueService; ServicesProvider = servicesProvider; - _subscriber = CreateSubscriber(_topicId, $"{_topicId}_{moduleName}"); + _logger = logger; + } + protected async override Task ExecuteAsync(CancellationToken cancellationToken) + { + _subscriber = CreateSubscriber(_topicId, $"{_topicId}_{_moduleName}"); + await StartProcessQueue(cancellationToken); } - public virtual Task StartAsync(CancellationToken cancellationToken = default) + public virtual async Task StopAsync(CancellationToken cancellationToken) { - try + Console.Error.WriteLine($"{_subscriber.SubscriptionId} stopped at {DateTime.UtcNow}"); + if (_subscriber is MixQueueSubscriber) { - Task.Run(async () => + await (_subscriber as MixQueueSubscriber).Disconnect(); + } + } + + #region Privates + private async Task StartProcessQueue(CancellationToken cancellationToken) + { + _logger.LogInformation($"StartProcessQueue: {_subscriber.SubscriptionId} started at {DateTime.UtcNow.AddHours(7)}"); + while (!cancellationToken.IsCancellationRequested) + { + try { + if (_subscriber != null) { + await _subscriber.ProcessQueue(cancellationToken); } - }, cancellationToken); - return Task.CompletedTask; - } - catch (Exception ex) - { - throw new MixException(MixErrorStatus.ServerError, _subscriber.SubscriptionId, ex); - } - } + await Task.Delay(1000, cancellationToken); + if (_subscriber is MixQueueSubscriber) + { + await (_subscriber as MixQueueSubscriber).Disconnect(); + } + } + catch (Exception ex) + { + if (_subscriber is MixQueueSubscriber) + { + await (_subscriber as MixQueueSubscriber).Disconnect(); + } - public virtual Task StopAsync(CancellationToken cancellationToken = default) - { - Console.Error.WriteLine($"{_subscriber.SubscriptionId} stopped at {DateTime.UtcNow}"); - return Task.CompletedTask; + _logger.LogError($"StartProcessQueue: {_subscriber.SubscriptionId} is broken at {DateTime.UtcNow.AddHours(7)}, Trying to reconnect from client: {ex.Message}", ex); + + await Task.Delay(2000, cancellationToken); + _subscriber = CreateSubscriber(_topicId, $"{_topicId}_{_moduleName}"); + await StartProcessQueue(cancellationToken); + } + } + _logger.LogInformation($"StartProcessQueue: {_subscriber.SubscriptionId} stopped at {DateTime.UtcNow.AddHours(7)}"); } private IQueueSubscriber CreateSubscriber(string topicId, string subscriptionId) @@ -122,10 +154,10 @@ private IQueueSubscriber CreateSubscriber(string topicId, string subscriptionId) return default; } - protected T GetRequiredService() + protected T? GetRequiredService() { ServiceScope ??= ServicesProvider.CreateScope(); - return ServiceScope.ServiceProvider.GetRequiredService(); + return ServiceScope.ServiceProvider.GetRequiredService(); } public async Task MessageHandler(MessageQueueModel data) @@ -137,7 +169,6 @@ public async Task MessageHandler(MessageQueueModel data) return; } - CacheService ??= GetRequiredService(); if (Handler(data).Wait(TimeSpan.FromSeconds(_timeout))) { return; @@ -149,11 +180,16 @@ public async Task MessageHandler(MessageQueueModel data) { await HandleException(data, ex); } + finally + { + ServiceScope?.Dispose(); + ServiceScope = null; + } } public virtual Task HandleDeadLetter(MessageQueueModel message) { - _memQueueService.PushQueue(new MessageQueueModel(1) + _memQueueService.PushMemoryQueue(new MessageQueueModel(1) { Action = MixQueueActions.DeadLetter, TopicId = MixQueueTopics.MixLog, @@ -165,7 +201,7 @@ public virtual Task HandleDeadLetter(MessageQueueModel message) public virtual Task HandleException(MessageQueueModel data, Exception ex) { - _memQueueService.PushQueue(new MessageQueueModel(1) + _memQueueService.PushMemoryQueue(new MessageQueueModel(1) { Action = MixQueueActions.QueueFailed, TopicId = MixQueueTopics.MixLog, @@ -179,5 +215,6 @@ public virtual Task HandleException(MessageQueueModel data, Exception ex) } public abstract Task Handler(MessageQueueModel model); + #endregion } } diff --git a/src/platform/mix.queue/Interfaces/IMemoryQueueService.cs b/src/platform/mix.queue/Interfaces/IMemoryQueueService.cs new file mode 100644 index 000000000..fdef868db --- /dev/null +++ b/src/platform/mix.queue/Interfaces/IMemoryQueueService.cs @@ -0,0 +1,20 @@ +using Mix.Mq.Lib.Models; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace Mix.Queue.Interfaces +{ + public interface IMemoryQueueService + { + void PushMemoryQueue(T model); + void PushMemoryQueue(int tenantId, string topicId, string action, object data); + + IList ConsumeMemoryQueue(int length, string topicId); + IList ConsumeAllMemoryQueue(int length); + + bool Any(string topicId); + + void PushMessageToMemoryQueue(int tenantId, TModel data, string action, bool status); + ConcurrentQueue GetMemoryQueue(string topicId); + } +} diff --git a/src/platform/mix.queue/Interfaces/IQueueService.cs b/src/platform/mix.queue/Interfaces/IQueueService.cs deleted file mode 100644 index 8f67c580e..000000000 --- a/src/platform/mix.queue/Interfaces/IQueueService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Mix.Mq.Lib.Models; -using System.Collections.Concurrent; -using System.Collections.Generic; - -namespace Mix.Queue.Interfaces -{ - public interface IQueueService - { - void PushQueue(T model); - void PushQueue(int tenantId, string topicId, string action, object data); - - IList ConsumeQueue(int length, string topicId); - - bool Any(string topicId); - - void PushMessage(int tenantId, TModel data, string action, bool status); - ConcurrentQueue GetQueue(string topicId); - } -} diff --git a/src/platform/mix.queue/Models/MixTopicModel.cs b/src/platform/mix.queue/Models/MixTopicModel.cs index 98eac753a..cc9649a67 100644 --- a/src/platform/mix.queue/Models/MixTopicModel.cs +++ b/src/platform/mix.queue/Models/MixTopicModel.cs @@ -10,12 +10,11 @@ public class MixTopicModel { public string Id { get; set; } public bool IsProcessing { get; set; } - public List Subscriptions { get; set; } = new(); + public ConcurrentDictionary Subscriptions { get; set; } = new(); public ConcurrentQueue Messages { get; private set; } = new(); public MixSubscriptionModel CreateSubscription(string subscriptionId) { - var subscription = Subscriptions.Find(m => m.Id == subscriptionId); - if (subscription == null) + if (!Subscriptions.TryGetValue(subscriptionId, out var subscription)) { subscription = new MixSubscriptionModel() { @@ -23,14 +22,19 @@ public MixSubscriptionModel CreateSubscription(string subscriptionId) Status = MixQueueMessageLogState.NACK, TopicId = Id }; - Subscriptions.Add(subscription); + Subscriptions.TryAdd(subscriptionId, subscription); } return subscription; } public MixSubscriptionModel GetSubscription(string subscriptionId) { - return Subscriptions.Find(m => m.Id == subscriptionId); + return Subscriptions.GetValueOrDefault(subscriptionId); + } + + public bool RemoveSubscription(string subscriptionId) + { + return Subscriptions.TryRemove(subscriptionId, out _); } public bool Any() @@ -41,9 +45,8 @@ public bool Any() public IList ConsumeQueue(string subscriptionId, int length) { var result = new List(); - var subscription = Subscriptions.Find(m => m.Id == subscriptionId); - if (subscription == null) + if (!Subscriptions.TryGetValue(subscriptionId, out var subscription)) { return result; } diff --git a/src/platform/mix.queue/Protos/mixmq.proto b/src/platform/mix.queue/Protos/mixmq.proto index 3ead5efc1..359260311 100644 --- a/src/platform/mix.queue/Protos/mixmq.proto +++ b/src/platform/mix.queue/Protos/mixmq.proto @@ -9,6 +9,7 @@ package mixmq; service MixMq { // Sends a greeting rpc Subscribe (SubscribeRequest) returns (stream SubscribeReply); + rpc Disconnect (SubscribeRequest) returns (google.protobuf.Empty); rpc Publish (PublishMessageRequest) returns (google.protobuf.Empty); } diff --git a/src/platform/mix.queue/Services/QueueService.cs b/src/platform/mix.queue/Services/MemoryQueueService.cs similarity index 69% rename from src/platform/mix.queue/Services/QueueService.cs rename to src/platform/mix.queue/Services/MemoryQueueService.cs index ed6da96b8..95a5e5300 100644 --- a/src/platform/mix.queue/Services/QueueService.cs +++ b/src/platform/mix.queue/Services/MemoryQueueService.cs @@ -8,24 +8,24 @@ namespace Mix.Queue.Services { - public class QueueService : IQueueService + public class MemoryQueueService : IMemoryQueueService { // Memory queue store message to local memory before push to MQ engine private readonly ConcurrentDictionary> _queues; - public QueueService() + public MemoryQueueService() { _queues = new ConcurrentDictionary>(); } public bool Any(string topicId) { - var queue = GetQueue(topicId); + var queue = GetMemoryQueue(topicId); return queue.Any(); } - public IList ConsumeQueue(int length, string topicId) + public IList ConsumeMemoryQueue(int length, string topicId) { - var queue = GetQueue(topicId); + var queue = GetMemoryQueue(topicId); List result = new(); if (queue.All(m => m.TopicId != topicId)) { @@ -45,7 +45,16 @@ public IList ConsumeQueue(int length, string topicId) return result; } - public ConcurrentQueue GetQueue(string topicId) + public IList ConsumeAllMemoryQueue(int length) + { + List result = new(); + foreach (var topic in _queues) + { + result.AddRange(ConsumeMemoryQueue(length, topic.Key)); + } + return result; + } + public ConcurrentQueue GetMemoryQueue(string topicId) { if (string.IsNullOrEmpty(topicId)) { @@ -59,9 +68,9 @@ public ConcurrentQueue GetQueue(string topicId) return _queues[topicId]; } - public void PushQueue(MessageQueueModel model) + public void PushMemoryQueue(MessageQueueModel model) { - var queue = GetQueue(model.TopicId); + var queue = GetMemoryQueue(model.TopicId); if (queue != null) { model.Id = Guid.NewGuid(); @@ -71,14 +80,14 @@ public void PushQueue(MessageQueueModel model) } - public void PushQueue(int tenantId, string topicId, string action, object data) + public void PushMemoryQueue(int tenantId, string topicId, string action, object data) { var msg = new MessageQueueModel(tenantId, topicId, action, data); - PushQueue(msg); + PushMemoryQueue(msg); } // Push message to MQ Engine - public void PushMessage(int tenantId, T data, string action, bool success) + public void PushMessageToMemoryQueue(int tenantId, T data, string action, bool success) { var msg = new MessageQueueModel(tenantId) { @@ -86,7 +95,7 @@ public void PushMessage(int tenantId, T data, string action, bool success) Success = success, }; msg.Package(data); - PushQueue(msg); + PushMemoryQueue(msg); } @@ -94,7 +103,7 @@ private void EnqueueLog(MessageQueueModel model) { if (model.TopicId != MixQueueTopics.MixLog) { - var logQueue = GetQueue(MixQueueTopics.MixLog); + var logQueue = GetMemoryQueue(MixQueueTopics.MixLog); if (logQueue != null) { logQueue.Enqueue(new MessageQueueModel() diff --git a/src/platform/mix.repodb/Helpers/MixDbHelper.cs b/src/platform/mix.repodb/Helpers/MixDbHelper.cs index 60c8b3b34..ed1709882 100644 --- a/src/platform/mix.repodb/Helpers/MixDbHelper.cs +++ b/src/platform/mix.repodb/Helpers/MixDbHelper.cs @@ -4,6 +4,7 @@ using Mix.Heart.Extensions; using Mix.Heart.Helpers; using Mix.RepoDb.ViewModels; +using Mix.Service.Services; using Mix.Shared.Services; using MySqlX.XDevAPI.Common; using Newtonsoft.Json; @@ -13,19 +14,7 @@ namespace Mix.RepoDb.Helpers { public class MixDbHelper { - public const string CreatedByFieldName = "CreatedBy"; - public const string ModifiedByFieldName = "ModifiedBy"; - public const string LastModifiedFieldName = "LastModified"; - public const string CreatedDateFieldName = "CreatedDateTime"; - public const string PriorityFieldName = "Priority"; - public const string IdFieldName = "Id"; - public const string ParentIdFieldName = "ParentId"; - public const string ChildIdFieldName = "ChildId"; - public const string TenantIdFieldName = "MixTenantId"; - public const string StatusFieldName = "Status"; - public const string IsDeletedFieldName = "IsDeleted"; - - public static Task ParseDtoToEntityAsync(JObject dto, List columns, int? tenantId = null, string? username = null) + public static Task ParseDtoToEntityAsync(JObject dto, List columns, FieldNameService fieldNameService, int? tenantId = null, string? username = null) { try { @@ -42,61 +31,61 @@ public static Task ParseDtoToEntityAsync(JObject dto, List ParseDtoToEntityAsync(JObject dto, List ParseImportDtoToEntityAsync(JObject dto, List columns, int? tenantId = null, string? username = null) + public static Task ParseImportDtoToEntityAsync(JObject dto, List columns, + FieldNameService fieldNameService, + int? tenantId = null, string? username = null) { try { @@ -123,7 +114,7 @@ public static Task ParseImportDtoToEntityAsync(JObject dto, List ParseImportDtoToEntityAsync(JObject dto, List ParseImportDtoToEntityAsync(JObject dto, List GetById(string tableName, int id, bool loadNestedData); - public Task MigrateDatabase(string name); - - public Task RestoreFromLocal(string name); - - public Task BackupDatabase(string databaseName, CancellationToken cancellationToken = default); Task GetByParentIdAsync(string tableName, MixContentType parentType, int parentId, bool loadNestedData); Task ParseDataAsync(string tableName, dynamic obj); + public Task MigrateDatabase(RepoDbMixDatabaseViewModel database); + + public Task BackupDatabase(RepoDbMixDatabaseViewModel database, CancellationToken cancellationToken = default); + public Task RestoreFromLocal(RepoDbMixDatabaseViewModel database); Task MigrateSystemDatabases(CancellationToken cancellationToken = default); Task MigrateInitNewDbContextDatabases(MixDatabaseContext dbContext, CancellationToken cancellationToken = default); } diff --git a/src/platform/mix.repodb/Publishers/MixRepoDbPublisher.cs b/src/platform/mix.repodb/Publishers/MixRepoDbPublisher.cs index 1fd0b87bf..da57eefe0 100644 --- a/src/platform/mix.repodb/Publishers/MixRepoDbPublisher.cs +++ b/src/platform/mix.repodb/Publishers/MixRepoDbPublisher.cs @@ -12,7 +12,7 @@ namespace Mix.RepoDb.Publishers public class MixRepoDbPublisher : PublisherBase { public MixRepoDbPublisher( - IQueueService queueService, + IMemoryQueueService queueService, IConfiguration configuration, MixEndpointService mixEndpointService, ILogger logger) diff --git a/src/platform/mix.repodb/Repositories/MixRepoDbRepository.cs b/src/platform/mix.repodb/Repositories/MixRepoDbRepository.cs index 8e7256f73..309997804 100644 --- a/src/platform/mix.repodb/Repositories/MixRepoDbRepository.cs +++ b/src/platform/mix.repodb/Repositories/MixRepoDbRepository.cs @@ -320,17 +320,14 @@ private Operation ParseMixOperator(SearchQueryField field) // Get - public async Task GetSingleAsync(long id) + public async Task GetSingleAsync(QueryField idQuery) { try { BeginTransaction(); return (await _connection.QueryAsync( _tableName, - new - { - Id = id - }, + idQuery, commandTimeout: _settings.CommandTimeout, transaction: _dbTransaction, trace: _trace))?.SingleOrDefault(); diff --git a/src/platform/mix.repodb/ServiceCollectionExtensions.cs b/src/platform/mix.repodb/ServiceCollectionExtensions.cs index ff811fbc2..6d2a327c4 100644 --- a/src/platform/mix.repodb/ServiceCollectionExtensions.cs +++ b/src/platform/mix.repodb/ServiceCollectionExtensions.cs @@ -16,8 +16,9 @@ public static class ServiceCollectionExtensions public static IServiceCollection AddMixRepoDb(this IServiceCollection services, GlobalSettingsModel globalConfig) { services.TryAddScoped(); - services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddScoped(); services.TryAddScoped(); return services; diff --git a/src/platform/mix.repodb/Services/MixDbDataService.cs b/src/platform/mix.repodb/Services/MixDbDataService.cs index a3d64a06d..6b1ce26fe 100644 --- a/src/platform/mix.repodb/Services/MixDbDataService.cs +++ b/src/platform/mix.repodb/Services/MixDbDataService.cs @@ -35,6 +35,7 @@ public class MixDbDataService : TenantServiceBase, IMixDbDataService private readonly MixRepoDbRepository _repository; private readonly IMixMemoryCacheService _memoryCache; private RepoDbMixDatabaseViewModel? _mixDb; + private FieldNameService _fieldNameService; #region Properties private readonly UnitOfWorkInfo _cmsUow; @@ -162,7 +163,7 @@ public async Task> GetMyData(string tableName, Sear public async Task GetById(string tableName, int id, bool loadNestedData) { await InitRepository(tableName); - var obj = await _repository.GetSingleAsync(id); + var obj = await _repository.GetSingleAsync(new QueryField(_fieldNameService.Id, id)); if (obj != null) { var data = ReflectionHelper.ParseObject(obj); @@ -479,6 +480,7 @@ private Operation ParseSearchOperation(MixCompareOperator? searchMethod) private async Task InitRepository(string tableName) { _mixDb = await GetMixDatabase(tableName); + _fieldNameService = new FieldNameService(_mixDb.NamingConvention); if (_mixDb == null) { throw new MixException(MixErrorStatus.Badrequest, $"Invalid Mix Db {tableName}"); diff --git a/src/platform/mix.repodb/Services/MixDbService.cs b/src/platform/mix.repodb/Services/MixDbService.cs index cbe9f404c..65bb55752 100644 --- a/src/platform/mix.repodb/Services/MixDbService.cs +++ b/src/platform/mix.repodb/Services/MixDbService.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Azure.Amqp.Framing; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Mix.Constant.Constants; using Mix.Constant.Enums; using Mix.Database.Base; @@ -22,7 +24,6 @@ using Mix.Service.Services; using Mix.Shared.Dtos; using Mix.Shared.Models; -using Mix.Shared.Services; using Newtonsoft.Json.Linq; using RepoDb; using RepoDb.Enumerations; @@ -32,43 +33,20 @@ namespace Mix.RepoDb.Services { - public class MixDbService : TenantServiceBase, IMixDbService + public class MixDbService : TenantServiceBase, IMixDbService, IDisposable { + #region Properties private IDatabaseConstants _databaseConstant; private MixDatabaseProvider _databaseProvider; private readonly ICache _cache; private MixRepoDbRepository _repository; private MixRepoDbRepository _backupRepository; - private MixRepoDbRepository _associationRepository; private IMixMemoryCacheService _memoryCache; - #region Properties private readonly UnitOfWorkInfo _cmsUow; private readonly DatabaseService _databaseService; - private const string CreatedDateFieldName = "CreatedDateTime"; - private const string CreatedByFieldName = "CreatedBy"; - private const string PriorityFieldName = "Priority"; - private const string IdFieldName = "Id"; - private const string ParentIdFieldName = "ParentId"; - private const string ChildIdFieldName = "ChildId"; - private const string TenantIdFieldName = "MixTenantId"; - private const string StatusFieldName = "Status"; - private const string IsDeletedFieldName = "IsDeleted"; - - private static readonly string[] DefaultProperties = - { - "Id", - "CreatedDateTime", - "LastModified", - "MixTenantId", - "CreatedBy", - "ModifiedBy", - "Priority", - "Status", - "IsDeleted" - }; #endregion public MixDbService( @@ -86,8 +64,6 @@ public MixDbService( _cmsUow = uow; _databaseService = databaseService; _repository = repository; - _associationRepository = new MixRepoDbRepository(cache, databaseService, uow); - _associationRepository.InitTableName(nameof(MixDatabaseAssociation)); _backupRepository = new MixRepoDbRepository(cache, databaseService, uow); _databaseProvider = _databaseService.DatabaseProvider; _databaseConstant = _databaseProvider switch @@ -103,7 +79,7 @@ public MixDbService( #region Methods - #region CRUD + #region Implements public async Task> GetMyData(string tableName, SearchMixDbRequestDto req, string username) { var paging = new PagingRequestModel() @@ -113,19 +89,24 @@ public async Task> GetMyData(string tableName, Sear SortBy = req.OrderBy, SortDirection = req.Direction }; - var queries = await BuildSearchQueryAsync(tableName, req); - queries.Add(new(CreatedByFieldName, Operation.Equal, username)); + var mixDb = await GetMixDatabase(tableName); + + var fieldNameService = new FieldNameService(mixDb.NamingConvention); + var queries = await BuildSearchQueryAsync(tableName, req, fieldNameService); + queries.Add(new(fieldNameService.CreatedBy, Operation.Equal, username)); return await GetResult(tableName, queries, paging, req.LoadNestedData); } public async Task GetMyDataById(string tableName, string username, int id, bool loadNestedData) { + var mixDb = await GetMixDatabase(tableName); + var fieldNameService = new FieldNameService(mixDb.NamingConvention); _repository.InitTableName(tableName); var queries = new List() { - new QueryField(TenantIdFieldName, CurrentTenant.Id), - new QueryField(IdFieldName, id), - new QueryField(CreatedByFieldName, username) + new QueryField(fieldNameService.TenantId, CurrentTenant.Id), + new QueryField(fieldNameService.Id, id), + new QueryField(fieldNameService.CreatedBy, username) }; var obj = await _repository.GetSingleByAsync(queries); @@ -134,7 +115,7 @@ public async Task> GetMyData(string tableName, Sear var data = ReflectionHelper.ParseObject(obj); if (loadNestedData) { - await LoadNestedData(id, data, tableName); + await LoadNestedData(id, data, mixDb, fieldNameService); } return data; } @@ -145,9 +126,12 @@ public async Task> GetMyData(string tableName, Sear { try { + var mixDb = await GetMixDatabase(tableName); + var fieldNameService = new FieldNameService(mixDb.NamingConvention); + _repository.InitTableName(tableName); - var obj = await _repository.GetSingleAsync(id); + var obj = await _repository.GetSingleAsync(new QueryField(fieldNameService.Id, id)); if (obj != null) { var data = await ParseDataAsync(tableName, obj); @@ -155,12 +139,16 @@ public async Task> GetMyData(string tableName, Sear if (loadNestedData) { - await LoadNestedData(id, data, tableName); + await LoadNestedData(id, data, mixDb, fieldNameService); } return data; } return default; } + catch (MixException) + { + throw; + } catch (Exception ex) { throw new MixException(MixErrorStatus.ServerError, ex); @@ -169,20 +157,33 @@ public async Task> GetMyData(string tableName, Sear public async Task GetByParentIdAsync(string tableName, MixContentType parentType, int parentId, bool loadNestedData) { - _repository.InitTableName(tableName); - - var obj = await _repository.GetSingleByParentAsync(parentType, parentId); - if (obj != null) + try { - var data = await ParseDataAsync(tableName, obj); + var mixDb = await GetMixDatabase(tableName); + var fieldNameService = new FieldNameService(mixDb.NamingConvention); + _repository.InitTableName(tableName); - if (loadNestedData) + var obj = await _repository.GetSingleByParentAsync(parentType, parentId); + if (obj != null) { - await LoadNestedData(data.Value("id"), data, tableName); + var data = await ParseDataAsync(tableName, obj); + + if (loadNestedData) + { + await LoadNestedData(data.Value("id"), data, mixDb, fieldNameService); + } + return data; } - return data; + return default; + } + catch (MixException) + { + throw; + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.ServerError, ex); } - return default; } public async Task ParseDataAsync(string tableName, dynamic obj) @@ -220,6 +221,190 @@ public async Task ParseDataAsync(string tableName, dynamic obj) } + // TODO: check why need to restart application to load new database schema for Repo Db Context !important + public async Task MigrateDatabase(RepoDbMixDatabaseViewModel database) + { + if (database.MixDatabaseContextId.HasValue) + { + await SwitchDbContext(database.MixDatabaseContext); + } + + if (database is { Columns.Count: > 0 }) + { + await Migrate(database, _databaseProvider, _repository); + _repository.CompleteTransaction(); + return true; + } + return false; + } + public async Task BackupDatabase(RepoDbMixDatabaseViewModel database, CancellationToken cancellationToken = default) + { + if (database != null) + { + var data = await GetCurrentData(database, cancellationToken); + var fieldNameService = new FieldNameService(database.NamingConvention); + if (data is { Count: > 0 }) + { + InitBackupRepository(database.SystemName); + await Migrate(database, _backupRepository.DatabaseProvider, _backupRepository); + foreach (var item in data) + { + GetMembers(item, database.Columns.Select(c => c.SystemName).ToList(), fieldNameService); + } + var result = await _backupRepository.InsertManyAsync(data); + return result > 0; + } + return true; + } + return false; + } + + public async Task RestoreFromLocal(RepoDbMixDatabaseViewModel database, FieldNameService fieldNameService) + { + try + { + if (File.Exists($"{MixFolders.BackupFolder}/backup_{database.SystemName}.sqlite")) + { + InitBackupRepository(database.SystemName); + var data = await _backupRepository.GetAllAsync(); + if (data is { Count: > 0 }) + { + var dbColumns = database.Columns.Select(c => c.SystemName).Union(fieldNameService.GetAllFieldName()).ToList(); + string insertQuery = $"INSERT INTO {_databaseConstant.BacktickOpen}{database.SystemName}{_databaseConstant.BacktickClose} ({string.Join(',', dbColumns.Select(m => $"{_databaseConstant.BacktickOpen}{m}{_databaseConstant.BacktickClose}"))}) VALUES "; + List queries = new(); + foreach (var item in data) + { + queries.Add(GetInsertQuery(item, dbColumns)); + } + insertQuery += string.Join(',', queries); + if (database.MixDatabaseContextId.HasValue) + { + _repository.Init(database.SystemName, database.MixDatabaseContext.DatabaseProvider, database.MixDatabaseContext.ConnectionString); + } + else + { + _repository.InitTableName(database.SystemName); + } + var result = await _repository.ExecuteCommand(insertQuery); + return result >= 0; + } + } + return true; + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.ServerError, ex); + } + } + public async Task MigrateSystemDatabases(CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + var strMixDbs = MixFileHelper.GetFile( + "system-databases", MixFileExtensions.Json, MixFolders.JsonDataFolder); + var obj = JObject.Parse(strMixDbs.Content); + var databases = obj.Value("databases")?.ToObject>(); + var columns = obj.Value("columns")?.ToObject>(); + if (databases != null) + { + foreach (var database in databases) + { + if (!_cmsUow.DbContext.MixDatabase.Any(m => m.SystemName == database.SystemName)) + { + + RepoDbMixDatabaseViewModel currentDb = new(database, _cmsUow); + currentDb.Id = 0; + currentDb.MixTenantId = CurrentTenant?.Id ?? 1; + currentDb.CreatedDateTime = DateTime.UtcNow; + currentDb.Columns = new(); + + if (columns is not null) + { + var cols = columns.Where(c => c.MixDatabaseName == database.SystemName).ToList(); + foreach (var col in cols) + { + col.Id = 0; + currentDb.Columns.Add(new(col, _cmsUow)); + } + } + + await currentDb.SaveAsync(cancellationToken); + + if (currentDb is { Columns.Count: > 0 }) + { + await Migrate(currentDb, _databaseService.DatabaseProvider, _repository); + + } + } + } + return true; + + } + return false; + } + + public async Task MigrateInitNewDbContextDatabases(MixDatabaseContext dbContext, CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + try + { + var strMixDbs = MixFileHelper.GetFile( + "init-new-dbcontext-databases", MixFileExtensions.Json, MixFolders.JsonDataFolder); + var obj = JObject.Parse(strMixDbs.Content); + var databases = obj.Value("databases")?.ToObject>(); + var columns = obj.Value("columns")?.ToObject>(); + if (databases != null) + { + + foreach (var database in databases) + { + string newDbName = $"{dbContext.SystemName}_{database.SystemName}"; + _repository.Init(newDbName, dbContext.DatabaseProvider, dbContext.ConnectionString); + var currentDb = await RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService) + .GetSingleAsync(m => m.SystemName == newDbName); + if (currentDb == null) + { + + currentDb = new(database, _cmsUow); + currentDb.Id = 0; + currentDb.SystemName = newDbName; + currentDb.MixTenantId = CurrentTenant?.Id ?? 1; + currentDb.MixDatabaseContextId = dbContext.Id; + currentDb.CreatedDateTime = DateTime.UtcNow; + currentDb.Columns = new(); + + if (columns is not null) + { + var cols = columns.Where(c => c.MixDatabaseName == database.SystemName).ToList(); + foreach (var col in cols) + { + col.Id = 0; + col.MixDatabaseName = newDbName; + currentDb.Columns.Add(new(col, _cmsUow)); + } + } + + await currentDb.SaveAsync(cancellationToken); + + } + if (currentDb is { Columns.Count: > 0 }) + { + await Migrate(currentDb, _databaseService.DatabaseProvider, _repository); + + } + } + return true; + + } + return false; + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.Badrequest, ex); + } + } + //public Task CreateData(string tableName, JObject data) //{ // _repository.InitTableName(tableName); @@ -258,123 +443,115 @@ public async Task ParseDataAsync(string tableName, dynamic obj) #region Helper - private async Task LoadNestedData(int id, JObject data, string tableName) + + + private async Task> GetResult(string tableName, + IEnumerable queries, PagingRequestModel paging, bool loadNestedData) { + var result = await _repository.GetPagingAsync(queries, paging); + var mixDb = await GetMixDatabase(tableName); + var fieldNameService = new FieldNameService(mixDb.NamingConvention); + var items = new List(); var database = await GetMixDatabase(tableName); if (database is null) { - return; + return new PagingResponseModel(); } - _repository.InitTableName(tableName); + foreach (var item in result.Items) + { + var data = ReflectionHelper.ParseObject(item); + if (loadNestedData) + { + var id = data.Value("id"); + LoadNestedData(id, data, mixDb, fieldNameService); + } + items.Add(data); + } + return new PagingResponseModel { Items = items, PagingData = result.PagingData }; + } + private async Task LoadNestedData(int id, JObject data, RepoDbMixDatabaseViewModel database, FieldNameService fieldNameService) + { + foreach (var item in database.Relationships) { - string pIdName = $"{item.SourceDatabaseName.ToTitleCase()}Id"; - _repository.InitTableName(item.DestinateDatabaseName); - List query = new() { new(pIdName, Operation.Equal, id) }; - var nestedData = await _repository.GetListByAsync(query); - if (nestedData is null) + // Many to many + if (item.Type == MixDatabaseRelationshipType.ManyToMany) { - continue; + var relDb = await GetMixDatabase(GetRelationshipDbName(database)); + var relFieldName = new FieldNameService(relDb.NamingConvention); + _repository.InitTableName(relDb.SystemName); + data = await LoadManyToManyData(relFieldName, item, id, fieldNameService); } - - JArray result = new(); - foreach (var nd in nestedData) + else if(item.Type == MixDatabaseRelationshipType.OneToMany) { - result.Add(await ParseDataAsync(item.DestinateDatabaseName, nd)); + data = await LoadOneToManyData(item, id, fieldNameService); } - data.Add(new JProperty(item.DisplayName, result)); - - //List associationQueries = GetAssociationQueries(item.SourceDatabaseName, item.DestinateDatabaseName, id); - //var associations = await _associationRepository.GetListByAsync(associationQueries); - //if (associations != null && associations.Count > 0) - //{ - // var nestedIds = JArray.FromObject(associations).Select(m => m.Value(ChildIdFieldName)).ToList(); - // _repository.InitTableName(item.DestinateDatabaseName); - // List query = new() { new(IdFieldName, Operation.In, nestedIds) }; - // var nestedData = await _repository.GetListByAsync(query); - // if (nestedData is null) - // { - // continue; - // } - - // JArray result = new(); - // foreach (var nd in nestedData) - // { - // result.Add(await ParseDataAsync(item.DestinateDatabaseName, nd)); - // } - // data.Add(new JProperty(item.DisplayName, result)); - //} - //else - //{ - // data.Add(new JProperty(item.DisplayName, new JArray())); - //} } } - private async Task> GetResult(string tableName, - IEnumerable queries, PagingRequestModel paging, bool loadNestedData) + private async Task LoadOneToManyData(MixDatabaseRelationshipViewModel item, int id, FieldNameService fieldNameService) { - var result = await _repository.GetPagingAsync(queries, paging); + JObject data = new JObject(); + string pIdName = fieldNameService.GetParentId(item.SourceDatabaseName); + _repository.InitTableName(item.DestinateDatabaseName); + List query = new() { new(pIdName, Operation.Equal, id) }; + var nestedData = await _repository.GetListByAsync(query); - var items = new List(); - var database = await GetMixDatabase(tableName); - if (database is null) + JArray result = new(); + foreach (var nd in nestedData) { - return new PagingResponseModel(); + result.Add(await ParseDataAsync(item.DestinateDatabaseName, nd)); } + data.Add(new JProperty(item.DisplayName, result)); + return data; + } - foreach (var item in result.Items) + private async Task LoadManyToManyData(FieldNameService relFieldName, MixDatabaseRelationshipViewModel item, int id, FieldNameService fieldNameService) + { + JObject data = new JObject(); + List queries = GetAssociationQueries(relFieldName, item.SourceDatabaseName, item.DestinateDatabaseName, id); + var associations = await _repository.GetListByAsync(queries); + if (associations is { Count: > 0 }) { - var data = ReflectionHelper.ParseObject(item); - if (loadNestedData) + var nestedIds = JArray.FromObject(associations).Select(m => m.Value(fieldNameService.ChildId)).ToList(); + _repository.InitTableName(item.DestinateDatabaseName); + List query = new() { new(fieldNameService.Id, Operation.In, nestedIds) }; + var nestedData = await _repository.GetListByAsync(query); + if (nestedData != null) { - foreach (var rel in database.Relationships) - { - var id = data.Value("id"); - - List nestedQueries = GetAssociationQueries(rel.SourceDatabaseName, rel.DestinateDatabaseName, id); - var associations = await _associationRepository.GetListByAsync(nestedQueries); - if (associations is { Count: > 0 }) - { - var nestedIds = JArray.FromObject(associations).Select(m => m.Value(ChildIdFieldName)).ToList(); - _repository.InitTableName(rel.DestinateDatabaseName); - List query = new() { new(IdFieldName, Operation.In, nestedIds) }; - var nestedData = await _repository.GetListByAsync(query); - data.Add(new JProperty(rel.DisplayName, ReflectionHelper.ParseArray(nestedData))); - } - } + data.Add(new JProperty(item.DisplayName, JArray.FromObject(nestedData))); } - items.Add(data); } - return new PagingResponseModel { Items = items, PagingData = result.PagingData }; + + return data; } - private List GetAssociationQueries(string? parentDatabaseName = null, string? childDatabaseName = null, int? parentId = null, int? childId = null) + private List GetAssociationQueries(FieldNameService fieldNameService, string? parentDatabaseName = null, string? childDatabaseName = null, int? parentId = null, int? childId = null) { var queries = new List(); if (!string.IsNullOrEmpty(parentDatabaseName)) { - queries.Add(new QueryField("ParentDatabaseName", parentDatabaseName)); + queries.Add(new QueryField(fieldNameService.ParentDatabaseName, parentDatabaseName)); } if (!string.IsNullOrEmpty(childDatabaseName)) { - queries.Add(new QueryField("ChildDatabaseName", childDatabaseName)); + queries.Add(new QueryField(fieldNameService.ChildDatabaseName, childDatabaseName)); } if (parentId.HasValue) { - queries.Add(new QueryField(ParentIdFieldName, parentId)); + queries.Add(new QueryField(fieldNameService.ParentId, parentId)); } if (childId.HasValue) { - queries.Add(new QueryField(ChildIdFieldName, parentId)); + queries.Add(new QueryField(fieldNameService.Id, parentId)); } return queries; } - private async Task GetMixDatabase(string tableName) + private async Task GetMixDatabase(string tableName) { - return await _memoryCache.TryGetValueAsync( + var result = await _memoryCache.TryGetValueAsync( tableName, cache => { @@ -382,11 +559,21 @@ private List GetAssociationQueries(string? parentDatabaseName = null return RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == tableName); } ); + if (result == null) + { + throw new MixException(MixErrorStatus.Badrequest, "Invalid table name"); + } + return result; } - - private async Task> BuildSearchQueryAsync(string tableName, SearchMixDbRequestDto request) + private string GetRelationshipDbName(RepoDbMixDatabaseViewModel mixDb) { - var queries = BuildSearchPredicate(request); + return mixDb.MixDatabaseContextId.HasValue + ? $"{mixDb.MixDatabaseContext.SystemName}_{MixDatabaseNames.DATA_RELATIONSHIP}" + : MixDatabaseNames.DATA_RELATIONSHIP; + } + private async Task> BuildSearchQueryAsync(string tableName, SearchMixDbRequestDto request, FieldNameService fieldNameService) + { + var queries = BuildSearchPredicate(request, fieldNameService); if (request.ParentId.HasValue) { var database = await GetMixDatabase(tableName); @@ -397,14 +584,14 @@ private async Task> BuildSearchQueryAsync(string tableName, Sea if (database.Type == MixDatabaseType.AdditionalData || database.Type == MixDatabaseType.GuidAdditionalData) { - queries.Add(new(ParentIdFieldName, request.ParentId)); + queries.Add(new(fieldNameService.ParentId, request.ParentId)); } else { var allowsIds = _cmsUow.DbContext.MixDatabaseAssociation .Where(m => m.ParentDatabaseName == request.ParentName && m.ParentId == request.ParentId.Value && m.ChildDatabaseName == tableName) .Select(m => m.ChildId).ToList(); - queries.Add(new(IdFieldName, Operation.In, allowsIds)); + queries.Add(new(fieldNameService.Id, Operation.In, allowsIds)); } } @@ -419,11 +606,11 @@ private async Task> BuildSearchQueryAsync(string tableName, Sea return queries; } - private List BuildSearchPredicate(SearchMixDbRequestDto req) + private List BuildSearchPredicate(SearchMixDbRequestDto req, FieldNameService fieldNameService) { var queries = new List() { - new QueryField(TenantIdFieldName, CurrentTenant.Id) + new QueryField(fieldNameService.TenantId, CurrentTenant.Id) }; if (!string.IsNullOrEmpty(req.SearchColumns) && !string.IsNullOrEmpty(req.Keyword)) { @@ -499,34 +686,11 @@ private Operation ParseSearchOperation(MixCompareOperator? searchMethod) #endregion - // TODO: check why need to restart application to load new database schema for Repo Db Context !important - public async Task MigrateDatabase(string name) - { - RepoDbMixDatabaseViewModel database = await RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == name); - - if (database.MixDatabaseContextId.HasValue) - { - await SwitchDbContext(database.MixDatabaseContextId.Value); - } - - if (database is { Columns.Count: > 0 }) - { - //await BackupDatabase(database.SystemName); - await Migrate(database, _databaseProvider, _repository); - _repository.CompleteTransaction(); - //await RestoreFromLocal(database); - return true; - } - return false; - } - - private async Task SwitchDbContext(int dbContextId) + private async Task SwitchDbContext(MixDatabaseContextReadViewModel dbContext) { - var dbContext = await _cmsUow.DbContext.MixDatabaseContext.FirstOrDefaultAsync(m => m.Id == dbContextId); - if (dbContext == null) { - throw new MixException(MixErrorStatus.Badrequest, $"Invalid MixDatabaseContext Id {dbContextId}"); + throw new MixException(MixErrorStatus.Badrequest, $"Invalid MixDatabaseContext"); } _databaseProvider = dbContext.DatabaseProvider; _databaseConstant = _databaseProvider switch @@ -543,168 +707,17 @@ private async Task SwitchDbContext(int dbContextId) // Only run after init CMS success // TODO: Add version to systemDatabases and update if have newer version - public async Task MigrateSystemDatabases(CancellationToken cancellationToken = default) - { - cancellationToken.ThrowIfCancellationRequested(); - - var strMixDbs = MixFileHelper.GetFile( - "system-databases", MixFileExtensions.Json, MixFolders.JsonDataFolder); - var obj = JObject.Parse(strMixDbs.Content); - var databases = obj.Value("databases")?.ToObject>(); - var columns = obj.Value("columns")?.ToObject>(); - if (databases != null) - { - foreach (var database in databases) - { - if (!_cmsUow.DbContext.MixDatabase.Any(m => m.SystemName == database.SystemName)) - { - - RepoDbMixDatabaseViewModel currentDb = new(database, _cmsUow); - currentDb.Id = 0; - currentDb.MixTenantId = CurrentTenant?.Id ?? 1; - currentDb.CreatedDateTime = DateTime.UtcNow; - currentDb.Columns = new(); - - if (columns is not null) - { - var cols = columns.Where(c => c.MixDatabaseName == database.SystemName).ToList(); - foreach (var col in cols) - { - col.Id = 0; - currentDb.Columns.Add(new(col, _cmsUow)); - } - } - await currentDb.SaveAsync(cancellationToken); - if (currentDb is { Columns.Count: > 0 }) - { - await Migrate(currentDb, _databaseService.DatabaseProvider, _repository); - - } - } - } - return true; - - } - return false; - } - - public async Task MigrateInitNewDbContextDatabases(MixDatabaseContext dbContext, CancellationToken cancellationToken = default) - { - cancellationToken.ThrowIfCancellationRequested(); - - try - { - var strMixDbs = MixFileHelper.GetFile( - "init-new-dbcontext-databases", MixFileExtensions.Json, MixFolders.JsonDataFolder); - var obj = JObject.Parse(strMixDbs.Content); - var databases = obj.Value("databases")?.ToObject>(); - var columns = obj.Value("columns")?.ToObject>(); - if (databases != null) - { - - foreach (var database in databases) - { - string newDbName = $"{dbContext.SystemName}_{database.SystemName}"; - _repository.Init(newDbName, dbContext.DatabaseProvider, dbContext.ConnectionString); - - if (!_cmsUow.DbContext.MixDatabase.Any(m => m.SystemName == newDbName)) - { - - RepoDbMixDatabaseViewModel currentDb = new(database, _cmsUow); - currentDb.Id = 0; - currentDb.SystemName = newDbName; - currentDb.MixTenantId = CurrentTenant?.Id ?? 1; - currentDb.MixDatabaseContextId = dbContext.Id; - currentDb.CreatedDateTime = DateTime.UtcNow; - currentDb.Columns = new(); - - if (columns is not null) - { - var cols = columns.Where(c => c.MixDatabaseName == database.SystemName).ToList(); - foreach (var col in cols) - { - col.Id = 0; - col.MixDatabaseName = newDbName; - currentDb.Columns.Add(new(col, _cmsUow)); - } - } - - await currentDb.SaveAsync(cancellationToken); - if (currentDb is { Columns.Count: > 0 }) - { - await Migrate(currentDb, _databaseService.DatabaseProvider, _repository); - - } - } - } - return true; - - } - return false; - } - catch (Exception ex) - { - throw new MixException(MixErrorStatus.Badrequest, ex); - } - } - - // TODO: check why need to restart application to load new database schema for Repo Db Context !important - public async Task RestoreFromLocal(string name) - { - try - { - RepoDbMixDatabaseViewModel database = await RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == name); - if (database is { Columns.Count: > 0 }) - { - return await RestoreFromLocal(database); - } - return false; - } - catch (MixException) - { - throw; - } - catch (Exception ex) - { - throw new MixException(MixErrorStatus.ServerError, ex); - } - } - - public async Task BackupDatabase(string databaseName, CancellationToken cancellationToken = default) - { - var database = await RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == databaseName, cancellationToken); - if (database != null) - { - return await BackupToLocal(database, cancellationToken); - } - return false; - } #endregion #region Private - private async Task BackupToLocal(RepoDbMixDatabaseViewModel database, CancellationToken cancellationToken = default) - { - var data = await GetCurrentData(database.SystemName, cancellationToken); - if (data is { Count: > 0 }) - { - InitBackupRepository(database.SystemName); - await Migrate(database, _backupRepository.DatabaseProvider, _backupRepository); - foreach (var item in data) - { - GetMembers(item, database.Columns.Select(c => c.SystemName.ToTitleCase()).ToList()); - } - var result = await _backupRepository.InsertManyAsync(data); - return result > 0; - } - return true; - } private void InitBackupRepository(string databaseName) { - string cnn = $"Data Source=MixContent/Backup/backup_{databaseName}.sqlite"; + MixFileHelper.CreateFolderIfNotExist(MixFolders.BackupFolder); + string cnn = $"Data Source={MixFolders.BackupFolder}/backup_{databaseName}.sqlite"; using var ctx = new BackupDbContext(cnn); ctx.Database.EnsureCreated(); ctx.Dispose(); @@ -712,36 +725,13 @@ private void InitBackupRepository(string databaseName) } - private async Task RestoreFromLocal(RepoDbMixDatabaseViewModel database) - { - if (File.Exists($"MixContent/Backup/backup_{database.SystemName}.sqlite")) - { - InitBackupRepository(database.SystemName); - var data = await _backupRepository.GetAllAsync(); - if (data is { Count: > 0 }) - { - var dbColumns = database.Columns.Select(c => c.SystemName.ToTitleCase()).Union(DefaultProperties).ToList(); - string insertQuery = $"INSERT INTO {database.SystemName} ({string.Join(',', dbColumns.Select(m => $"{_databaseConstant.BacktickOpen}{m}{_databaseConstant.BacktickClose}"))}) VALUES "; - List queries = new(); - foreach (var item in data) - { - queries.Add(GetInsertQuery(item, dbColumns)); - } - insertQuery += string.Join(',', queries); - _repository.InitTableName(database.SystemName); - var result = await _repository.ExecuteCommand(insertQuery); - return result >= 0; - } - } - return true; - } - private void GetMembers(ExpandoObject obj, List selectMembers) + private void GetMembers(ExpandoObject obj, List selectMembers, FieldNameService fieldNameService) { var result = obj.ToList(); foreach (KeyValuePair kvp in result) { - if (DefaultProperties.All(m => m != kvp.Key) && selectMembers.All(m => m != kvp.Key)) + if (fieldNameService.GetAllFieldName().All(m => m != kvp.Key) && selectMembers.All(m => m != kvp.Key)) { obj!.Remove(kvp.Key, out _); } @@ -774,10 +764,17 @@ private string GetInsertQuery(ExpandoObject obj, List selectMembers) return $"({string.Join(',', values)})"; } - private async Task?> GetCurrentData(string databaseName, CancellationToken cancellationToken = default) + private async Task?> GetCurrentData(RepoDbMixDatabaseViewModel database, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - _repository.InitTableName(databaseName); + if (database.MixDatabaseContextId.HasValue) + { + _repository.Init(database.SystemName, database.MixDatabaseContext.DatabaseProvider, database.MixDatabaseContext.ConnectionString); + } + else + { + _repository.InitTableName(database.SystemName); + } return await _repository.GetAllAsync(cancellationToken); } @@ -785,6 +782,7 @@ private async Task Migrate(RepoDbMixDatabaseViewModel database, MixDatabaseProvider databaseProvider, MixRepoDbRepository repo) { + var fieldNameService = new FieldNameService(database.NamingConvention); var colsSql = new List(); var tableName = database.SystemName; @@ -793,7 +791,7 @@ private async Task Migrate(RepoDbMixDatabaseViewModel database, colsSql.Add(GenerateColumnSql(col)); } - var commandText = GetMigrateTableSql(tableName, databaseProvider, colsSql); + var commandText = GetMigrateTableSql(tableName, databaseProvider, colsSql, fieldNameService); if (!string.IsNullOrEmpty(commandText)) { await repo.ExecuteCommand($"DROP TABLE IF EXISTS {_databaseConstant.BacktickOpen}{tableName}{_databaseConstant.BacktickClose};"); @@ -804,18 +802,18 @@ private async Task Migrate(RepoDbMixDatabaseViewModel database, return false; } - private string GetMigrateTableSql(string tableName, MixDatabaseProvider databaseProvider, List colsSql) + private string GetMigrateTableSql(string tableName, MixDatabaseProvider databaseProvider, List colsSql, FieldNameService fieldNameService) { return $"CREATE TABLE {_databaseConstant.BacktickOpen}{tableName}{_databaseConstant.BacktickClose} " + - $"({_databaseConstant.BacktickOpen}Id{_databaseConstant.BacktickClose} {GetAutoIncreaseIdSyntax(databaseProvider)}, " + - $"{_databaseConstant.BacktickOpen}CreatedDateTime{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.DateTime)}, " + - $"{_databaseConstant.BacktickOpen}LastModified{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.DateTime)} NULL, " + - $"{_databaseConstant.BacktickOpen}MixTenantId{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Integer)} NULL, " + - $"{_databaseConstant.BacktickOpen}CreatedBy{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Text)} NULL, " + - $"{_databaseConstant.BacktickOpen}ModifiedBy{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Text)} NULL, " + - $"{_databaseConstant.BacktickOpen}Priority{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Integer)} NOT NULL, " + - $"{_databaseConstant.BacktickOpen}Status{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Text)} NOT NULL, " + - $"{_databaseConstant.BacktickOpen}IsDeleted{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Boolean)} NOT NULL, " + + $"({_databaseConstant.BacktickOpen}{fieldNameService.Id}{_databaseConstant.BacktickClose} {GetAutoIncreaseIdSyntax(databaseProvider)}, " + + $"{_databaseConstant.BacktickOpen}{fieldNameService.CreatedDateTime}{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.DateTime)}, " + + $"{_databaseConstant.BacktickOpen}{fieldNameService.LastModified}{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.DateTime)} NULL, " + + $"{_databaseConstant.BacktickOpen}{fieldNameService.TenantId}{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Integer)} NULL, " + + $"{_databaseConstant.BacktickOpen}{fieldNameService.CreatedBy}{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Text)} NULL, " + + $"{_databaseConstant.BacktickOpen}{fieldNameService.ModifiedBy}{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Text)} NULL, " + + $"{_databaseConstant.BacktickOpen}{fieldNameService.Priority}{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Integer)} NOT NULL, " + + $"{_databaseConstant.BacktickOpen}{fieldNameService.Status}{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Text)} NOT NULL, " + + $"{_databaseConstant.BacktickOpen}{fieldNameService.IsDeleted}{_databaseConstant.BacktickClose} {GetColumnType(MixDataType.Boolean)} NOT NULL, " + $" {string.Join(",", colsSql.ToArray())})"; } @@ -838,7 +836,7 @@ private string GenerateColumnSql(MixDatabaseColumnViewModel col) string unique = col.ColumnConfigurations.IsUnique ? "Unique" : ""; string defaultValue = !IsLongTextColumn(col) && !string.IsNullOrEmpty(col.DefaultValue) ? $"DEFAULT '{@col.DefaultValue}'" : string.Empty; - return $"{_databaseConstant.BacktickOpen}{col.SystemName.ToTitleCase()}{_databaseConstant.BacktickClose} {colType} {nullable} {unique} {defaultValue}"; + return $"{_databaseConstant.BacktickOpen}{col.SystemName}{_databaseConstant.BacktickClose} {colType} {nullable} {unique} {defaultValue}"; } private bool IsLongTextColumn(MixDatabaseColumnViewModel col) @@ -907,6 +905,11 @@ public void Dispose() _backupRepository.Dispose(); _cmsUow.Dispose(); } + + public Task RestoreFromLocal(RepoDbMixDatabaseViewModel database) + { + throw new NotImplementedException(); + } #endregion } } diff --git a/src/platform/mix.repodb/Subscribers/MixRepoDbSubscriber.cs b/src/platform/mix.repodb/Subscribers/MixRepoDbSubscriber.cs index fa4e22179..89cbd4696 100644 --- a/src/platform/mix.repodb/Subscribers/MixRepoDbSubscriber.cs +++ b/src/platform/mix.repodb/Subscribers/MixRepoDbSubscriber.cs @@ -1,30 +1,36 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Mix.Constant.Constants; using Mix.Database.Entities.Cms; +using Mix.Heart.Services; using Mix.Heart.UnitOfWork; using Mix.Mq.Lib.Models; using Mix.Queue.Engines; using Mix.Queue.Engines.MixQueue; using Mix.Queue.Interfaces; using Mix.RepoDb.Interfaces; +using Mix.RepoDb.ViewModels; using Mix.SignalR.Enums; using Mix.SignalR.Interfaces; using Mix.SignalR.Models; +using System.Threading; namespace Mix.RepoDb.Subscribers { public class MixRepoDbSubscriber : SubscriberBase { protected IPortalHubClientService PortalHub; - + protected UnitOfWorkInfo _cmsUow; + protected RepoDbMixDatabaseViewModel _database; private IMixDbService _mixDbService; public MixRepoDbSubscriber( IConfiguration configuration, IServiceProvider serviceProvider, IPortalHubClientService portalHub, - IQueueService queueService) - : base(MixQueueTopics.MixRepoDb, nameof(MixRepoDbSubscriber), 20, serviceProvider, configuration, queueService) + IMemoryQueueService queueService, + ILogger logger) + : base(MixQueueTopics.MixRepoDb, nameof(MixRepoDbSubscriber), 20, serviceProvider, configuration, queueService, logger) { PortalHub = portalHub; } @@ -33,29 +39,31 @@ public override async Task Handler(MessageQueueModel model) { try { - using (ServiceScope = ServicesProvider.CreateScope()) + + _mixDbService = GetRequiredService(); + var cacheService = GetRequiredService(); + _cmsUow = GetRequiredService>(); + _database = await RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, cacheService) + .GetSingleAsync(m => m.SystemName == model.Data); + switch (model.Action) { - _mixDbService = GetRequiredService(); - var cmsUow = GetRequiredService>(); - switch (model.Action) - { - case MixRepoDbQueueAction.Backup: - await BackupDatabase(model); - break; - case MixRepoDbQueueAction.Restore: - await RestoreDatabase(model); - break; - case MixRepoDbQueueAction.Migrate: - await MigrateDatabase(model); - break; - case MixRepoDbQueueAction.Update: - await UpdateDatabase(model); - break; - default: - break; - } - await cmsUow.CompleteAsync(); + case MixRepoDbQueueAction.Backup: + await BackupDatabase(model); + break; + case MixRepoDbQueueAction.Restore: + await RestoreDatabase(model); + break; + case MixRepoDbQueueAction.Migrate: + await MigrateDatabase(model); + break; + case MixRepoDbQueueAction.Update: + await UpdateDatabase(model); + break; + default: + break; } + await _cmsUow.CompleteAsync(); + _cmsUow.Dispose(); } catch (Exception ex) { @@ -65,28 +73,28 @@ public override async Task Handler(MessageQueueModel model) private async Task BackupDatabase(MessageQueueModel model) { - await _mixDbService.BackupDatabase(model.Data); + await _mixDbService.BackupDatabase(_database); await SendMessage($"{MixRepoDbQueueAction.Backup} {model.Data} Successfully", true); } private async Task RestoreDatabase(MessageQueueModel model) { - await _mixDbService.RestoreFromLocal(model.Data); + await _mixDbService.RestoreFromLocal(_database); await SendMessage($"{MixRepoDbQueueAction.Restore} {model.Data} Successfully", true); } private async Task MigrateDatabase(MessageQueueModel model) { - await _mixDbService.MigrateDatabase(model.Data); + await _mixDbService.MigrateDatabase(_database); string msg = $"{MixRepoDbQueueAction.Migrate} {model.Data} Successfully"; await SendMessage(msg, true); } - + private async Task UpdateDatabase(MessageQueueModel model) { - await _mixDbService.BackupDatabase(model.Data); - await _mixDbService.MigrateDatabase(model.Data); - await _mixDbService.RestoreFromLocal(model.Data); + await _mixDbService.BackupDatabase(_database); + await _mixDbService.MigrateDatabase(_database); + await _mixDbService.RestoreFromLocal(_database); string msg = $"{MixRepoDbQueueAction.Update} {model.Data} Successfully"; await SendMessage(msg, true); } diff --git a/src/platform/mix.repodb/ViewModels/MixDatabaseContextReadViewModel.cs b/src/platform/mix.repodb/ViewModels/MixDatabaseContextReadViewModel.cs index dcd3c5528..5b7b9cad8 100644 --- a/src/platform/mix.repodb/ViewModels/MixDatabaseContextReadViewModel.cs +++ b/src/platform/mix.repodb/ViewModels/MixDatabaseContextReadViewModel.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Mix.Constant.Enums; using Mix.Database.Entities.Cms; using Mix.Heart.Enums; using Mix.Heart.UnitOfWork; @@ -11,6 +12,7 @@ public sealed class MixDatabaseContextReadViewModel : TenantDataViewModelBase { #region Properties + public MixDatabaseNamingConvention NamingConvention { get; set; } public MixDatabaseProvider DatabaseProvider { get; set; } public string ConnectionString { get; set; } public string Schema { get; set; } diff --git a/src/platform/mix.repodb/ViewModels/RepoDbMixDatabaseViewModel.cs b/src/platform/mix.repodb/ViewModels/RepoDbMixDatabaseViewModel.cs index d36cd1c5d..5b4d19fd8 100644 --- a/src/platform/mix.repodb/ViewModels/RepoDbMixDatabaseViewModel.cs +++ b/src/platform/mix.repodb/ViewModels/RepoDbMixDatabaseViewModel.cs @@ -13,7 +13,7 @@ public sealed class RepoDbMixDatabaseViewModel public int? MixDatabaseContextId { get; set; } [Required] public string SystemName { get; set; } - + public MixDatabaseNamingConvention NamingConvention { get; set; } = MixDatabaseNamingConvention.TitleCase; public MixDatabaseType Type { get; set; } = MixDatabaseType.Service; public List ReadPermissions { get; set; } public List CreatePermissions { get; set; } @@ -52,6 +52,7 @@ public override async Task ExpandView(CancellationToken cancellationToken = defa if (MixDatabaseContextId.HasValue) { MixDatabaseContext = await MixDatabaseContextReadViewModel.GetRepository(UowInfo, CacheService).GetSingleAsync(m => m.Id == MixDatabaseContextId.Value); + NamingConvention = MixDatabaseContext.NamingConvention; } } diff --git a/src/platform/mix.service/Services/BaseHubClientService.cs b/src/platform/mix.service/Services/BaseHubClientService.cs index 192b6e123..01c2d9faf 100644 --- a/src/platform/mix.service/Services/BaseHubClientService.cs +++ b/src/platform/mix.service/Services/BaseHubClientService.cs @@ -108,8 +108,9 @@ public async Task StartConnection() } catch (Exception ex) - { + { IsStarting = false; + await Task.Delay(2000); Console.WriteLine(ex); } } diff --git a/src/platform/mix.service/Services/FieldNameService.cs b/src/platform/mix.service/Services/FieldNameService.cs new file mode 100644 index 000000000..435018833 --- /dev/null +++ b/src/platform/mix.service/Services/FieldNameService.cs @@ -0,0 +1,91 @@ +using Microsoft.Azure.Amqp; +using Mix.Constant.Enums; +using Mix.Heart.Helpers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mix.Service.Services +{ + public sealed class FieldNameService + { + private MixDatabaseNamingConvention _namingConvention; + #region Properties + public string Id { get; set; } + public string ParentId { get; set; } + public string ParentDatabaseName { get; set; } + public string ChildId { get; set; } + public string ChildDatabaseName { get; set; } + public string CreatedDateTime { get; set; } + public string LastModified { get; set; } + public string TenantId { get; set; } + public string CreatedBy { get; set; } + public string ModifiedBy { get; set; } + public string Priority { get; set; } + public string Status { get; set; } + public string IsDeleted { get; set; } + #endregion + public FieldNameService(MixDatabaseNamingConvention namingConvention) + { + _namingConvention = namingConvention; + switch (namingConvention) + { + case MixDatabaseNamingConvention.TitleCase: + Id = "Id"; + ParentId = "ParentId"; + ParentDatabaseName = "ParentDatabaseName"; + ChildId = "ChildId"; + ChildDatabaseName = "ChildDatabaseName"; + CreatedDateTime = "CreatedDateTime"; + LastModified = "LastModified"; + TenantId = "MixTenantId"; + CreatedBy = "CreatedBy"; + ModifiedBy = "ModifiedBy"; + Priority = "Priority"; + Status = "Status"; + IsDeleted = "IsDeleted"; + break; + case MixDatabaseNamingConvention.SnakeCase: + Id = "id"; + ParentId = "parent_id"; + ParentDatabaseName = "parent_database_name"; + ChildId = "child_id"; + ChildDatabaseName = "child_database_name"; + CreatedDateTime = "created_date_time"; + LastModified = "last_modified"; + TenantId = "mix_tenant_id"; + CreatedBy = "created_by"; + ModifiedBy = "modified_by"; + Priority = "priority"; + Status = "status"; + IsDeleted = "is_deleted"; + break; + } + } + + public string GetParentId(string parentName) + { + switch (_namingConvention) + { + case MixDatabaseNamingConvention.SnakeCase: + return $"{parentName}_id"; + case MixDatabaseNamingConvention.TitleCase: + default: + return $"{parentName}Id"; + } + } + + public List GetAllFieldName() + { + List result = new(); + var props = GetType().GetProperties(); + foreach (var item in props) + { + result.Append(item.GetValue(this)?.ToString()); + } + return result; + } + } +} diff --git a/src/platform/mix.library/Services/TenantConfigService.cs b/src/platform/mix.service/Services/TenantConfigService.cs similarity index 89% rename from src/platform/mix.library/Services/TenantConfigService.cs rename to src/platform/mix.service/Services/TenantConfigService.cs index a1a0f3ad9..e137f1d83 100644 --- a/src/platform/mix.library/Services/TenantConfigService.cs +++ b/src/platform/mix.service/Services/TenantConfigService.cs @@ -1,4 +1,8 @@ -namespace Mix.Lib.Services +using Mix.Constant.Constants; +using Mix.Heart.Services; +using Mix.Service.Models; + +namespace Mix.Service.Services { public class TenantConfigService : ConfigurationServiceBase { diff --git a/src/platform/mix.shared/MixAssemblyFinder.cs b/src/platform/mix.shared/MixAssemblyFinder.cs index 61bb3b9e5..0b77ff13c 100644 --- a/src/platform/mix.shared/MixAssemblyFinder.cs +++ b/src/platform/mix.shared/MixAssemblyFinder.cs @@ -4,14 +4,14 @@ namespace Mix.Shared { public class MixAssemblyFinder { - public static List GetMixAssemblies() + public static List GetAssembliesByPrefix(string prefix) { - return AppDomain.CurrentDomain.GetAssemblies().Where(IsMixModule()).ToList(); + return AppDomain.CurrentDomain.GetAssemblies().Where(IsSelectedModule(prefix)).ToList(); } - private static Func IsMixModule() + private static Func IsSelectedModule(string prefix) { - return p => p.FullName.StartsWith("mix"); + return p => p.FullName.StartsWith(prefix); } } } diff --git a/src/platform/mix.shared/mix.shared.csproj b/src/platform/mix.shared/mix.shared.csproj index 9c0b93e75..a52af86af 100644 --- a/src/platform/mix.shared/mix.shared.csproj +++ b/src/platform/mix.shared/mix.shared.csproj @@ -13,13 +13,12 @@ - - + diff --git a/src/platform/mix.signalr.hub/Hubs/MixDbCommandHub.cs b/src/platform/mix.signalr.hub/Hubs/MixDbCommandHub.cs index 3f2653b9f..8cdf1302e 100644 --- a/src/platform/mix.signalr.hub/Hubs/MixDbCommandHub.cs +++ b/src/platform/mix.signalr.hub/Hubs/MixDbCommandHub.cs @@ -15,8 +15,8 @@ namespace Mix.SignalR.Hubs { public class MixDbCommandHub : BaseSignalRHub { - private readonly IQueueService _queueService; - public MixDbCommandHub(IAuditLogService auditLogService, IMixTenantService mixTenantService, IQueueService queueService) : base(auditLogService, mixTenantService) + private readonly IMemoryQueueService _queueService; + public MixDbCommandHub(IAuditLogService auditLogService, IMixTenantService mixTenantService, IMemoryQueueService queueService) : base(auditLogService, mixTenantService) { _queueService = queueService; } @@ -27,7 +27,7 @@ public virtual void CreateData(string message) obj.MixTenantId = CurrentUser?.TenantId ?? 1; obj.RequestedBy = Context.User?.Identity?.Name; obj.ConnectionId = Context.ConnectionId; - _queueService.PushQueue(obj.MixTenantId, MixQueueTopics.MixDbCommand, MixDbCommandQueueActions.Create, obj); + _queueService.PushMemoryQueue(obj.MixTenantId, MixQueueTopics.MixDbCommand, MixDbCommandQueueActions.Create, obj); } public virtual void UpdateData(string message) @@ -35,7 +35,7 @@ public virtual void UpdateData(string message) var obj = ReflectionHelper.ParseStringToObject(message); obj.RequestedBy = Context.User?.Identity?.Name; obj.ConnectionId = Context.ConnectionId; - _queueService.PushQueue(obj.MixTenantId, MixQueueTopics.MixDbCommand, MixDbCommandQueueActions.Update, obj); + _queueService.PushMemoryQueue(obj.MixTenantId, MixQueueTopics.MixDbCommand, MixDbCommandQueueActions.Update, obj); } } } \ No newline at end of file diff --git a/src/platform/mix.storage.lib/Engines/Mix/MixUploader.cs b/src/platform/mix.storage.lib/Engines/Mix/MixUploader.cs index 61a48cc08..4b45a9d24 100644 --- a/src/platform/mix.storage.lib/Engines/Mix/MixUploader.cs +++ b/src/platform/mix.storage.lib/Engines/Mix/MixUploader.cs @@ -13,13 +13,13 @@ namespace Mix.Storage.Lib.Engines.Mix { public class MixUploader : UploaderBase { - protected readonly IQueueService _queueService; + protected readonly IMemoryQueueService _queueService; public StorageSettingsModel Settings { get; set; } = new(); public MixUploader( IHttpContextAccessor httpContextAccessor, IConfiguration configuration, UnitOfWorkInfo cmsUow, - IQueueService queueService) + IMemoryQueueService queueService) : base(httpContextAccessor, configuration, cmsUow) { Configuration.Bind("StorageSetting", Settings); @@ -49,7 +49,7 @@ public MixUploader( if (Settings.IsAutoScaleImage && ImageHelper.IsImageResizeable(fileModel.Extension)) { - _queueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.ScaleImage, fileModel.FullPath); + _queueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.ScaleImage, fileModel.FullPath); } if (saveResult) diff --git a/src/platform/mix.storage.lib/Services/MixStorageService.cs b/src/platform/mix.storage.lib/Services/MixStorageService.cs index f551cff71..d66cc1fb4 100644 --- a/src/platform/mix.storage.lib/Services/MixStorageService.cs +++ b/src/platform/mix.storage.lib/Services/MixStorageService.cs @@ -17,7 +17,7 @@ namespace Mix.Storage.Lib.Services { public class MixStorageService { - protected readonly IQueueService _queueService; + protected readonly IMemoryQueueService _queueService; private readonly IMixUploader _uploader; private readonly IConfiguration _configuration; private readonly HttpService _httpService; @@ -26,7 +26,7 @@ public MixStorageService( IHttpContextAccessor httpContext, UnitOfWorkInfo cmsUow, IConfiguration configuration, - HttpService httpService, IQueueService queueService) + HttpService httpService, IMemoryQueueService queueService) { _configuration = configuration; _httpService = httpService; diff --git a/src/platform/mix.storage.lib/Subscribers/StorageBackgroundTaskSubscriber.cs b/src/platform/mix.storage.lib/Subscribers/StorageBackgroundTaskSubscriber.cs index 28b248e9d..324efed31 100644 --- a/src/platform/mix.storage.lib/Subscribers/StorageBackgroundTaskSubscriber.cs +++ b/src/platform/mix.storage.lib/Subscribers/StorageBackgroundTaskSubscriber.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Mix.Communicator.Models; using Mix.Communicator.Services; using Mix.Lib.Subscribers; @@ -32,8 +33,9 @@ public StorageBackgroundTaskSubscriber( IConfiguration configuration, IAuditLogService auditLogService, IPortalHubClientService portalHub, - IQueueService queueService) - : base(TopicId, nameof(StorageBackgroundTaskSubscriber), 20, serviceProvider, configuration, queueService) + IMemoryQueueService queueService, + ILogger logger) + : base(TopicId, nameof(StorageBackgroundTaskSubscriber), 20, serviceProvider, configuration, queueService, logger) { AuditLogService = auditLogService; PortalHub = portalHub; diff --git a/src/services/core/ecommerces/mix.services.ecommerce.lib/Extensions/EcommerceServiceProviderExtensions.cs b/src/services/core/ecommerces/mix.services.ecommerce.lib/Extensions/EcommerceServiceProviderExtensions.cs index 6d04a4a46..116ce5983 100644 --- a/src/services/core/ecommerces/mix.services.ecommerce.lib/Extensions/EcommerceServiceProviderExtensions.cs +++ b/src/services/core/ecommerces/mix.services.ecommerce.lib/Extensions/EcommerceServiceProviderExtensions.cs @@ -60,6 +60,7 @@ public static void AddMixOnepay(this IServiceCollection services) { context.Database.Migrate(); } + context.Dispose(); } } services.TryAddScoped(); @@ -79,6 +80,7 @@ public static void AddMixPaypal(this IServiceCollection services) { context.Database.Migrate(); } + context.Dispose(); } } services.TryAddScoped(); diff --git a/src/services/core/ecommerces/mix.services.ecommerce/Controllers/ApiEcommerceController.cs b/src/services/core/ecommerces/mix.services.ecommerce/Controllers/ApiEcommerceController.cs index aa6e1abc4..5c33ce475 100644 --- a/src/services/core/ecommerces/mix.services.ecommerce/Controllers/ApiEcommerceController.cs +++ b/src/services/core/ecommerces/mix.services.ecommerce/Controllers/ApiEcommerceController.cs @@ -9,7 +9,6 @@ using Mix.Lib.Services; using Mix.Mq.Lib.Models; using Mix.Queue.Interfaces; -using Mix.Queue.Models; using Mix.Service.Services; using Mix.Services.Ecommerce.Lib.Dtos; using Mix.Services.Ecommerce.Lib.Enums; @@ -39,7 +38,7 @@ public ApiEcommerceController( MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, - IQueueService queueService, + IMemoryQueueService queueService, IEcommerceService ecommerceService, UnitOfWorkInfo cmsUow, IOrderService orderService, @@ -150,7 +149,7 @@ public async Task> CheckoutGuest(PaymentGateway? gateway, return BadRequest(); } var url = await _ecommerceService.CheckoutGuest(gateway.Value, cart, cancellationToken); - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.PlacedOrder, cart); + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.PlacedOrder, cart); return !string.IsNullOrEmpty(url) ? Ok(new JObject(new JProperty("url", url))) : BadRequest(); } @@ -181,7 +180,7 @@ public async Task PaymentResponse([FromQuery] int? orderId, Cancel ? $"{_paymentConfiguration.Urls.PaymentSuccessUrl}?id={orderId}" : $"{_paymentConfiguration.Urls.PaymentFailUrl}?id={orderId}"; - QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.PaymentResponse, result); + QueueService.PushMemoryQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.PaymentResponse, result); return Redirect(url); } diff --git a/src/services/core/ecommerces/mix.services.ecommerce/Controllers/ApiOrderDetailController.cs b/src/services/core/ecommerces/mix.services.ecommerce/Controllers/ApiOrderDetailController.cs index 517472018..6ce47d0b3 100644 --- a/src/services/core/ecommerces/mix.services.ecommerce/Controllers/ApiOrderDetailController.cs +++ b/src/services/core/ecommerces/mix.services.ecommerce/Controllers/ApiOrderDetailController.cs @@ -7,7 +7,6 @@ using Mix.Lib.Services; using Mix.Mq.Lib.Models; using Mix.Queue.Interfaces; -using Mix.Queue.Models; using Mix.Services.Ecommerce.Lib.Dtos; using Mix.Services.Ecommerce.Lib.Entities.Mix; using Mix.Services.Ecommerce.Lib.Interfaces; @@ -31,7 +30,7 @@ public OrderDetailController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/services/core/ecommerces/mix.services.ecommerce/Program.cs b/src/services/core/ecommerces/mix.services.ecommerce/Program.cs index 48863a6d6..632a615f1 100644 --- a/src/services/core/ecommerces/mix.services.ecommerce/Program.cs +++ b/src/services/core/ecommerces/mix.services.ecommerce/Program.cs @@ -16,7 +16,7 @@ app.UseSwaggerUI(); } -app.UseHttpsRedirection(); +//app.UseHttpsRedirection(); app.UseAuthorization(); diff --git a/src/services/core/ecommerces/mix.services.ecommerce/StartupService.cs b/src/services/core/ecommerces/mix.services.ecommerce/StartupService.cs index c5f80a7cd..25e0cd0c0 100644 --- a/src/services/core/ecommerces/mix.services.ecommerce/StartupService.cs +++ b/src/services/core/ecommerces/mix.services.ecommerce/StartupService.cs @@ -1,11 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.DependencyInjection.Extensions; using Mix.Constant.Constants; using Mix.Services.Databases.Lib.Interfaces; using Mix.Services.Databases.Lib.Services; -using Mix.Services.Ecommerce.Lib.Interfaces; -using Mix.Services.Ecommerce.Lib.Models; -using Mix.Services.Ecommerce.Lib.Services; using Mix.Shared.Interfaces; using Mix.Shared.Models.Configurations; diff --git a/src/services/core/graphql/mix.services.graphql/Program.cs b/src/services/core/graphql/mix.services.graphql/Program.cs index 48863a6d6..632a615f1 100644 --- a/src/services/core/graphql/mix.services.graphql/Program.cs +++ b/src/services/core/graphql/mix.services.graphql/Program.cs @@ -16,7 +16,7 @@ app.UseSwaggerUI(); } -app.UseHttpsRedirection(); +//app.UseHttpsRedirection(); app.UseAuthorization(); diff --git a/src/services/core/mix-databases/mix.services.databases.lib/StartupService.cs b/src/services/core/mix-databases/mix.services.databases.lib/StartupService.cs index d1f3767a4..79c4d75d7 100644 --- a/src/services/core/mix-databases/mix.services.databases.lib/StartupService.cs +++ b/src/services/core/mix-databases/mix.services.databases.lib/StartupService.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Mix.Database.Entities.MixDb; using Mix.Heart.UnitOfWork; using Mix.Lib.Middlewares; using Mix.Services.Databases.Lib.Interfaces; diff --git a/src/services/core/mix-databases/mix.servives.databases/Controllers/MixMetadataController.cs b/src/services/core/mix-databases/mix.servives.databases/Controllers/MixMetadataController.cs index 3b946dd5d..cb0880a43 100644 --- a/src/services/core/mix-databases/mix.servives.databases/Controllers/MixMetadataController.cs +++ b/src/services/core/mix-databases/mix.servives.databases/Controllers/MixMetadataController.cs @@ -4,7 +4,6 @@ using Mix.Lib.Models.Common; using Mix.Lib.Services; using Mix.Queue.Interfaces; -using Mix.Queue.Models; using Mix.Service.Services; using Mix.Services.Databases.Lib.Dtos; using Mix.Shared.Dtos; @@ -33,7 +32,7 @@ public MixMetadataController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/services/core/mix-databases/mix.servives.databases/Controllers/MixPermissionController.cs b/src/services/core/mix-databases/mix.servives.databases/Controllers/MixPermissionController.cs index 420c3a5d2..cba8a9421 100644 --- a/src/services/core/mix-databases/mix.servives.databases/Controllers/MixPermissionController.cs +++ b/src/services/core/mix-databases/mix.servives.databases/Controllers/MixPermissionController.cs @@ -4,7 +4,6 @@ using Mix.Lib.Base; using Mix.Lib.Services; using Mix.Queue.Interfaces; -using Mix.Queue.Models; using Mix.Service.Services; using Mix.Services.Databases.Lib.Dtos; using Mix.Mixdb.ViewModels; @@ -32,7 +31,7 @@ public MixPermissionController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/services/core/mix-databases/mix.servives.databases/Controllers/MixUserDataController.cs b/src/services/core/mix-databases/mix.servives.databases/Controllers/MixUserDataController.cs index 2a56ef898..d03c42afe 100644 --- a/src/services/core/mix-databases/mix.servives.databases/Controllers/MixUserDataController.cs +++ b/src/services/core/mix-databases/mix.servives.databases/Controllers/MixUserDataController.cs @@ -5,7 +5,6 @@ using Mix.Lib.Base; using Mix.Lib.Services; using Mix.Queue.Interfaces; -using Mix.Queue.Models; using Mix.Service.Services; using Mix.Services.Databases.Lib.Dtos; using Mix.Services.Databases.Lib.Interfaces; @@ -34,7 +33,7 @@ public MixUserDataController( TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, - IQueueService queueService, + IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService) : base(httpContextAccessor, configuration, diff --git a/src/services/core/mix-databases/mix.servives.databases/mix.services.databases.csproj b/src/services/core/mix-databases/mix.servives.databases/mix.services.databases.csproj index 298752a36..63e0babdf 100644 --- a/src/services/core/mix-databases/mix.servives.databases/mix.services.databases.csproj +++ b/src/services/core/mix-databases/mix.servives.databases/mix.services.databases.csproj @@ -7,143 +7,9 @@ Mix.Services.Databases - - <_ContentIncludedByDefault Remove="MixContent\Shared\AppConfigs\authentication.json" /> - <_ContentIncludedByDefault Remove="MixContent\Shared\AppConfigs\azure.json" /> - <_ContentIncludedByDefault Remove="MixContent\Shared\AppConfigs\configuration.json" /> - - - - - - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - PreserveNewest - true - PreserveNewest - - - - - diff --git a/src/services/mix-auth-service/mix.auth.service/Controllers/MixAccountController.cs b/src/services/mix-auth-service/mix.auth.api/Controllers/MixAccountController.cs similarity index 99% rename from src/services/mix-auth-service/mix.auth.service/Controllers/MixAccountController.cs rename to src/services/mix-auth-service/mix.auth.api/Controllers/MixAccountController.cs index 14d0a5db3..ad700018e 100644 --- a/src/services/mix-auth-service/mix.auth.service/Controllers/MixAccountController.cs +++ b/src/services/mix-auth-service/mix.auth.api/Controllers/MixAccountController.cs @@ -57,7 +57,7 @@ public MixAccountController( MixCacheService mixService, TranslatorService translator, MixIdentityService mixIdentityService, - IQueueService queueService, + IMemoryQueueService queueService, AuthConfigService authConfigService, IMixEdmService edmService, IMixTenantService mixTenantService, diff --git a/src/services/mix-auth-service/mix.auth.service/Controllers/MixRoleController.cs b/src/services/mix-auth-service/mix.auth.api/Controllers/MixRoleController.cs similarity index 73% rename from src/services/mix-auth-service/mix.auth.service/Controllers/MixRoleController.cs rename to src/services/mix-auth-service/mix.auth.api/Controllers/MixRoleController.cs index ef3d11e96..0b91a79ce 100644 --- a/src/services/mix-auth-service/mix.auth.service/Controllers/MixRoleController.cs +++ b/src/services/mix-auth-service/mix.auth.api/Controllers/MixRoleController.cs @@ -15,6 +15,7 @@ namespace mix.auth.service.Controllers [ApiController] public class MixRoleController : MixRestEntityApiControllerBase { + private readonly TenantRoleManager _roleManager; public MixRoleController( IHttpContextAccessor httpContextAccessor, IConfiguration configuration, @@ -23,13 +24,18 @@ public MixRoleController( MixIdentityService mixIdentityService, MixCacheDbContext cacheDbContext, MixCmsAccountContext context, - IQueueService queueService, - IMixTenantService mixTenantService) + IMemoryQueueService queueService, + IMixTenantService mixTenantService, + TenantRoleManager roleManager) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, cacheDbContext, context, queueService, mixTenantService) { - + _roleManager = roleManager; + } + protected override async Task DeleteHandler(MixRole data) + { + await _roleManager.DeleteAsync(data); + await base.DeleteHandler(data); } - } } diff --git a/src/services/mix-auth-service/mix.auth.service/Controllers/OAuthClientController.cs b/src/services/mix-auth-service/mix.auth.api/Controllers/OAuthClientController.cs similarity index 83% rename from src/services/mix-auth-service/mix.auth.service/Controllers/OAuthClientController.cs rename to src/services/mix-auth-service/mix.auth.api/Controllers/OAuthClientController.cs index 291681555..2d4a56efe 100644 --- a/src/services/mix-auth-service/mix.auth.service/Controllers/OAuthClientController.cs +++ b/src/services/mix-auth-service/mix.auth.api/Controllers/OAuthClientController.cs @@ -17,7 +17,7 @@ namespace mix.auth.service.Controllers public class OAuthClientController : MixRestfulApiControllerBase { private readonly IOAuthClientService _oauthClientService; - public OAuthClientController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService, IOAuthClientService oauthClientService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) + public OAuthClientController(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, MixCacheService cacheService, TranslatorService translator, MixIdentityService mixIdentityService, UnitOfWorkInfo uow, IMemoryQueueService queueService, IPortalHubClientService portalHub, IMixTenantService mixTenantService, IOAuthClientService oauthClientService) : base(httpContextAccessor, configuration, cacheService, translator, mixIdentityService, uow, queueService, portalHub, mixTenantService) { _oauthClientService = oauthClientService; } diff --git a/src/services/mix-auth-service/mix.auth.api/Dockerfile b/src/services/mix-auth-service/mix.auth.api/Dockerfile new file mode 100644 index 000000000..94a1286c9 --- /dev/null +++ b/src/services/mix-auth-service/mix.auth.api/Dockerfile @@ -0,0 +1,47 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["platform/core/mix-heart/nuget.config", "platform/core/mix-heart/"] +COPY ["services/mix-auth-service/mix.auth.service/mix.auth.api.csproj", "services/mix-auth-service/mix.auth.service/"] +COPY ["applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj", "applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/"] +COPY ["modules/mix.grpc/mix.grpc.csproj", "modules/mix.grpc/"] +COPY ["platform/mix.library/mix.library.csproj", "platform/mix.library/"] +COPY ["platform/core/mix.mixdb.event/mix.mixdb.event.csproj", "platform/core/mix.mixdb.event/"] +COPY ["platform/mix.mixdb/mix.mixdb.csproj", "platform/mix.mixdb/"] +COPY ["platform/mix.database/mix.database.csproj", "platform/mix.database/"] +COPY ["platform/mix.shared/mix.shared.csproj", "platform/mix.shared/"] +COPY ["platform/core/mix-heart/src/mix.heart/mix.heart.csproj", "platform/core/mix-heart/src/mix.heart/"] +COPY ["platform/mix.constant/mix.constant.csproj", "platform/mix.constant/"] +COPY ["platform/mix.service/mix.service.csproj", "platform/mix.service/"] +COPY ["platform/mix.identity/mix.identity.csproj", "platform/mix.identity/"] +COPY ["platform/mix.auth/mix.auth.csproj", "platform/mix.auth/"] +COPY ["platform/mix.quartz/mix.quartz.csproj", "platform/mix.quartz/"] +COPY ["platform/mix.queue/mix.queue.csproj", "platform/mix.queue/"] +COPY ["services/mix-message-queue/mix.mq.server/mix.mq.server.csproj", "services/mix-message-queue/mix.mq/"] +COPY ["services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj", "services/mix-message-queue/mix.mq.lib/"] +COPY ["platform/mix.signalr/mix.signalr.csproj", "platform/mix.signalr/"] +COPY ["platform/mix.repodb/mix.repodb.csproj", "platform/mix.repodb/"] +COPY ["platform/mix.communicator/mix.communicator.csproj", "platform/mix.communicator/"] +COPY ["platform/mix.signalr.hub/mix.signalr.hub.csproj", "platform/mix.signalr.hub/"] +COPY ["platform/mix.log/mix.log.lib.csproj", "platform/mix.log/"] +RUN dotnet restore "./services/mix-auth-service/mix.auth.service/mix.auth.api.csproj" +COPY . . +WORKDIR "/src/services/mix-auth-service/mix.auth.service" +RUN dotnet build "./mix.auth.api.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./mix.auth.api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "mix.auth.api.dll"] \ No newline at end of file diff --git a/src/services/mix-auth-service/mix.auth.service/Dockerfile b/src/services/mix-auth-service/mix.auth.api/Dockerfile_linux similarity index 84% rename from src/services/mix-auth-service/mix.auth.service/Dockerfile rename to src/services/mix-auth-service/mix.auth.api/Dockerfile_linux index ecaa48c20..f36bf250b 100644 --- a/src/services/mix-auth-service/mix.auth.service/Dockerfile +++ b/src/services/mix-auth-service/mix.auth.api/Dockerfile_linux @@ -8,7 +8,7 @@ EXPOSE 8081 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release COPY ["src/platform/core/mix-heart/nuget.config", "src/platform/core/mix-heart/"] -COPY ["src/services/mix-auth-service/mix.auth.service/mix.auth.service.csproj", "src/services/mix-auth-service/mix.auth.service/"] +COPY ["src/services/mix-auth-service/mix.auth.service/mix.auth.api.csproj", "src/services/mix-auth-service/mix.auth.service/"] COPY ["src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj", "src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/"] COPY ["src/modules/mix.grpc/mix.grpc.csproj", "src/modules/mix.grpc/"] COPY ["src/platform/mix.library/mix.library.csproj", "src/platform/mix.library/"] @@ -23,21 +23,21 @@ COPY ["src/platform/mix.identity/mix.identity.csproj", "src/platform/mix.identit COPY ["src/platform/mix.auth/mix.auth.csproj", "src/platform/mix.auth/"] COPY ["src/platform/mix.quartz/mix.quartz.csproj", "src/platform/mix.quartz/"] COPY ["src/platform/mix.queue/mix.queue.csproj", "src/platform/mix.queue/"] -COPY ["src/services/mix-message-queue/mix.mq/mix.mq.csproj", "src/services/mix-message-queue/mix.mq/"] +COPY ["src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj", "src/services/mix-message-queue/mix.mq/"] COPY ["src/services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj", "src/services/mix-message-queue/mix.mq.lib/"] COPY ["src/platform/mix.signalr/mix.signalr.csproj", "src/platform/mix.signalr/"] COPY ["src/platform/mix.repodb/mix.repodb.csproj", "src/platform/mix.repodb/"] COPY ["src/platform/mix.communicator/mix.communicator.csproj", "src/platform/mix.communicator/"] COPY ["src/platform/mix.signalr.hub/mix.signalr.hub.csproj", "src/platform/mix.signalr.hub/"] COPY ["src/platform/mix.log/mix.log.lib.csproj", "src/platform/mix.log/"] -RUN dotnet restore "src/services/mix-auth-service/mix.auth.service/mix.auth.service.csproj" +RUN dotnet restore "src/services/mix-auth-service/mix.auth.service/mix.auth.api.csproj" COPY . . -RUN dotnet build "src/services/mix-auth-service/mix.auth.service/mix.auth.service.csproj" -c $BUILD_CONFIGURATION -o /app/build +RUN dotnet build "src/services/mix-auth-service/mix.auth.service/mix.auth.api.csproj" -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Release -RUN dotnet publish "src/services/mix-auth-service/mix.auth.service/mix.auth.service.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false +RUN dotnet publish "src/services/mix-auth-service/mix.auth.service/mix.auth.api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "mix.auth.service.dll"] \ No newline at end of file +ENTRYPOINT ["dotnet", "mix.auth.api.dll"] \ No newline at end of file diff --git a/src/services/mix-auth-service/mix.auth.service/Domain/Protos/mixmq.proto b/src/services/mix-auth-service/mix.auth.api/Domain/Protos/mixmq.proto similarity index 100% rename from src/services/mix-auth-service/mix.auth.service/Domain/Protos/mixmq.proto rename to src/services/mix-auth-service/mix.auth.api/Domain/Protos/mixmq.proto diff --git a/src/services/mix-auth-service/mix.auth.service/Domain/StartupService.cs b/src/services/mix-auth-service/mix.auth.api/Domain/StartupService.cs similarity index 100% rename from src/services/mix-auth-service/mix.auth.service/Domain/StartupService.cs rename to src/services/mix-auth-service/mix.auth.api/Domain/StartupService.cs diff --git a/src/services/mix-auth-service/mix.auth.service/Domain/ViewModels/MixRoleViewModel.cs b/src/services/mix-auth-service/mix.auth.api/Domain/ViewModels/MixRoleViewModel.cs similarity index 100% rename from src/services/mix-auth-service/mix.auth.service/Domain/ViewModels/MixRoleViewModel.cs rename to src/services/mix-auth-service/mix.auth.api/Domain/ViewModels/MixRoleViewModel.cs diff --git a/src/services/mix-auth-service/mix.auth.service/Program.cs b/src/services/mix-auth-service/mix.auth.api/Program.cs similarity index 81% rename from src/services/mix-auth-service/mix.auth.service/Program.cs rename to src/services/mix-auth-service/mix.auth.api/Program.cs index 604106bfd..d674c9de9 100644 --- a/src/services/mix-auth-service/mix.auth.service/Program.cs +++ b/src/services/mix-auth-service/mix.auth.api/Program.cs @@ -7,20 +7,23 @@ using Microsoft.Azure.Amqp.Framing; using Mix.Lib.Middlewares; -if (Directory.Exists("../../../applications/mixcore/mixcontent")) +if (Directory.Exists($"../{MixFolders.MixCoreConfigurationFolder}")) { - MixFileHelper.CopyFolder("../../../applications/mixcore/mixcontent", MixFolders.MixContentFolder); + MixFileHelper.CopyFolder($"../{MixFolders.MixCoreConfigurationFolder}", MixFolders.MixContentSharedFolder); } + var builder = MixCmsHelper.CreateWebApplicationBuilder(args); -builder.AddServiceDefaults(); +if (builder.Environment.IsDevelopment()) +{ + builder.AddServiceDefaults(); +} // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); builder.Services.AddMixServices(Assembly.GetExecutingAssembly(), builder.Configuration); builder.Services.AddMixCors(); @@ -31,13 +34,11 @@ var app = builder.Build(); -app.MapDefaultEndpoints(); - app.UseMixTenant(); app.UseMiddleware(); -app.UseMixAuth(); app.UseMixCors(); app.UseRouting(); +app.UseMixAuth(); app.UseMixCors(); app.UseMixApps(Assembly.GetExecutingAssembly(), builder.Configuration, builder.Environment.ContentRootPath, builder.Environment.IsDevelopment()); diff --git a/src/services/mix-auth-service/mix.auth.service/Properties/launchSettings.json b/src/services/mix-auth-service/mix.auth.api/Properties/launchSettings.json similarity index 94% rename from src/services/mix-auth-service/mix.auth.service/Properties/launchSettings.json rename to src/services/mix-auth-service/mix.auth.api/Properties/launchSettings.json index cfa24d85b..55993c1c3 100644 --- a/src/services/mix-auth-service/mix.auth.service/Properties/launchSettings.json +++ b/src/services/mix-auth-service/mix.auth.api/Properties/launchSettings.json @@ -8,7 +8,7 @@ "ASPNETCORE_ENVIRONMENT": "Development" }, "dotnetRunMessages": true, - "applicationUrl": "https://localhost:7016;http://localhost:5238" + "applicationUrl": "https://localhost:7116;http://localhost:5238" }, "IIS Express": { "commandName": "IISExpress", diff --git a/src/services/mix-auth-service/mix.auth.service/appsettings.Development.json b/src/services/mix-auth-service/mix.auth.api/appsettings.Development.json similarity index 100% rename from src/services/mix-auth-service/mix.auth.service/appsettings.Development.json rename to src/services/mix-auth-service/mix.auth.api/appsettings.Development.json diff --git a/src/services/mix-auth-service/mix.auth.service/mix.auth.service.csproj b/src/services/mix-auth-service/mix.auth.api/mix.auth.api.csproj similarity index 85% rename from src/services/mix-auth-service/mix.auth.service/mix.auth.service.csproj rename to src/services/mix-auth-service/mix.auth.api/mix.auth.api.csproj index 0c07d9c3f..84d076925 100644 --- a/src/services/mix-auth-service/mix.auth.service/mix.auth.service.csproj +++ b/src/services/mix-auth-service/mix.auth.api/mix.auth.api.csproj @@ -2,22 +2,23 @@ net8.0 + false + false + en enable enable - false true e7c022bb-c2da-4d62-b3ed-5a0574c52280 Linux ..\..\.. + Mix.Auth.Api - - - - - + + + + - diff --git a/src/services/mix-auth-service/mix.auth.service/mix.auth.service.http b/src/services/mix-auth-service/mix.auth.api/mix.auth.api.http similarity index 100% rename from src/services/mix-auth-service/mix.auth.service/mix.auth.service.http rename to src/services/mix-auth-service/mix.auth.api/mix.auth.api.http diff --git a/src/services/mix-auth-service/mix.auth.api/runtimeconfig.template.json b/src/services/mix-auth-service/mix.auth.api/runtimeconfig.template.json new file mode 100644 index 000000000..c1ba87344 --- /dev/null +++ b/src/services/mix-auth-service/mix.auth.api/runtimeconfig.template.json @@ -0,0 +1,8 @@ +{ + "configProperties":{ + "System.GC.Concurrent": true, + "System.GC.HeapCount": 8, + "System.GC.NoAffinitize": true, + "System.Threading.Thread.EnableAutoreleasePool": true + } +} \ No newline at end of file diff --git a/src/services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj b/src/services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj new file mode 100644 index 000000000..123195ceb --- /dev/null +++ b/src/services/mix-message-queue/mix.mq.lib/mix.mq.lib.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + enable + Mix.Mq.Lib + + + + + + + + + + + + + + diff --git a/src/services/mix-message-queue/mix.mq.server/Controllers/MqController.cs b/src/services/mix-message-queue/mix.mq.server/Controllers/MqController.cs new file mode 100644 index 000000000..6dccb563a --- /dev/null +++ b/src/services/mix-message-queue/mix.mq.server/Controllers/MqController.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Mix.Mq.Lib.Models; +using Mix.Mq.Server.Domain.Services; +using Newtonsoft.Json.Linq; +using System.Text.Json; + +namespace Mix.Mq.Server.Controllers +{ + + [Route("api/mq")] + [ApiController] + public class MqController : ControllerBase + { + private readonly MixQueueMessages _queue; + private readonly GrpcStreamingService _grpcStreamingService; + + public MqController(MixQueueMessages queue, GrpcStreamingService grpcStreamingService) + { + _queue = queue; + _grpcStreamingService = grpcStreamingService; + } + + [HttpGet("topics")] + public ActionResult GetQueueMessages() + { + var topics = _queue.GetAllTopic(); + return new JsonResult(topics); + } + + [HttpGet("streams")] + public ActionResult GetStreams() + { + List arr = new(); + foreach (var item in _grpcStreamingService.MessageSubscriptions) + { + arr.Add(new + { + subscription_id = item.Key.SubsctiptionId, + stream_id = item.Value.GetHashCode() + }); + } + return new JsonResult(arr); + } + + [HttpGet("pending-messages")] + public ActionResult GetPendingMessages() + { + List arr = new(); + foreach (var item in _grpcStreamingService.PendingMessages) + { + arr.Add(new + { + subscription_id = item.Key, + messages = item.Value + }); + } + return new JsonResult(arr); + } + } +} diff --git a/src/services/mix-message-queue/mix.mq.server/Dockerfile b/src/services/mix-message-queue/mix.mq.server/Dockerfile new file mode 100644 index 000000000..ed931e7e6 --- /dev/null +++ b/src/services/mix-message-queue/mix.mq.server/Dockerfile @@ -0,0 +1,45 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["platform/core/mix-heart/nuget.config", "platform/core/mix-heart/"] +COPY ["services/mix-message-queue/mix.mq.server/mix.mq.server.csproj", "services/mix-message-queue/mix.mq.server/"] +COPY ["applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj", "applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/"] +COPY ["modules/mix.messenger/mix.messenger.csproj", "modules/mix.messenger/"] +COPY ["platform/mix.signalr.hub/mix.signalr.hub.csproj", "platform/mix.signalr.hub/"] +COPY ["platform/core/mix-heart/src/mix.heart/mix.heart.csproj", "platform/core/mix-heart/src/mix.heart/"] +COPY ["platform/mix.log/mix.log.lib.csproj", "platform/mix.log/"] +COPY ["platform/mix.service/mix.service.csproj", "platform/mix.service/"] +COPY ["platform/mix.identity/mix.identity.csproj", "platform/mix.identity/"] +COPY ["platform/mix.auth/mix.auth.csproj", "platform/mix.auth/"] +COPY ["platform/mix.database/mix.database.csproj", "platform/mix.database/"] +COPY ["platform/mix.shared/mix.shared.csproj", "platform/mix.shared/"] +COPY ["platform/mix.constant/mix.constant.csproj", "platform/mix.constant/"] +COPY ["platform/mix.quartz/mix.quartz.csproj", "platform/mix.quartz/"] +COPY ["platform/mix.queue/mix.queue.csproj", "platform/mix.queue/"] +COPY ["platform/mix.signalr/mix.signalr.csproj", "platform/mix.signalr/"] +COPY ["platform/mix.communicator/mix.communicator.csproj", "platform/mix.communicator/"] +COPY ["platform/mix.library/mix.library.csproj", "platform/mix.library/"] +COPY ["platform/core/mix.mixdb.event/mix.mixdb.event.csproj", "platform/core/mix.mixdb.event/"] +COPY ["platform/mix.mixdb/mix.mixdb.csproj", "platform/mix.mixdb/"] +COPY ["platform/mix.repodb/mix.repodb.csproj", "platform/mix.repodb/"] +RUN dotnet restore "./services/mix-message-queue/mix.mq.server/mix.mq.server.csproj" +COPY . . +WORKDIR "/src/services/mix-message-queue/mix.mq.server" +RUN dotnet build "./mix.mq.server.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./mix.mq.server.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "mix.mq.server.dll"] \ No newline at end of file diff --git a/src/services/mix-message-queue/mix.mq.server/Dockerfile_linux b/src/services/mix-message-queue/mix.mq.server/Dockerfile_linux new file mode 100644 index 000000000..73c82910b --- /dev/null +++ b/src/services/mix-message-queue/mix.mq.server/Dockerfile_linux @@ -0,0 +1,41 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +COPY ["src/platform/core/mix-heart/nuget.config", "src/platform/core/mix-heart/"] +COPY ["src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj", "src/services/mix-message-queue/mix.mq.server/"] +COPY ["src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/mixcore.host.aspire.ServiceDefaults.csproj", "src/applications/mixcore.host.aspire/mixcore.host.aspire.ServiceDefaults/"] +COPY ["src/modules/mix.messenger/mix.messenger.csproj", "src/modules/mix.messenger/"] +COPY ["src/platform/mix.signalr.hub/mix.signalr.hub.csproj", "src/platform/mix.signalr.hub/"] +COPY ["src/platform/core/mix-heart/src/mix.heart/mix.heart.csproj", "src/platform/core/mix-heart/src/mix.heart/"] +COPY ["src/platform/mix.log/mix.log.lib.csproj", "src/platform/mix.log/"] +COPY ["src/platform/mix.service/mix.service.csproj", "src/platform/mix.service/"] +COPY ["src/platform/mix.identity/mix.identity.csproj", "src/platform/mix.identity/"] +COPY ["src/platform/mix.auth/mix.auth.csproj", "src/platform/mix.auth/"] +COPY ["src/platform/mix.database/mix.database.csproj", "src/platform/mix.database/"] +COPY ["src/platform/mix.shared/mix.shared.csproj", "src/platform/mix.shared/"] +COPY ["src/platform/mix.constant/mix.constant.csproj", "src/platform/mix.constant/"] +COPY ["src/platform/mix.quartz/mix.quartz.csproj", "src/platform/mix.quartz/"] +COPY ["src/platform/mix.queue/mix.queue.csproj", "src/platform/mix.queue/"] +COPY ["src/platform/mix.signalr/mix.signalr.csproj", "src/platform/mix.signalr/"] +COPY ["src/platform/mix.communicator/mix.communicator.csproj", "src/platform/mix.communicator/"] +COPY ["src/platform/mix.library/mix.library.csproj", "src/platform/mix.library/"] +COPY ["src/platform/core/mix.mixdb.event/mix.mixdb.event.csproj", "src/platform/core/mix.mixdb.event/"] +COPY ["src/platform/mix.mixdb/mix.mixdb.csproj", "src/platform/mix.mixdb/"] +COPY ["src/platform/mix.repodb/mix.repodb.csproj", "src/platform/mix.repodb/"] +RUN dotnet restore "src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj" +COPY . . +RUN dotnet build "/src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "/src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "mix.mq.server.dll"] \ No newline at end of file diff --git a/src/services/mix-message-queue/mix.mq.server/Domain/Protos/mixmq.proto b/src/services/mix-message-queue/mix.mq.server/Domain/Protos/mixmq.proto index 3ead5efc1..359260311 100644 --- a/src/services/mix-message-queue/mix.mq.server/Domain/Protos/mixmq.proto +++ b/src/services/mix-message-queue/mix.mq.server/Domain/Protos/mixmq.proto @@ -9,6 +9,7 @@ package mixmq; service MixMq { // Sends a greeting rpc Subscribe (SubscribeRequest) returns (stream SubscribeReply); + rpc Disconnect (SubscribeRequest) returns (google.protobuf.Empty); rpc Publish (PublishMessageRequest) returns (google.protobuf.Empty); } diff --git a/src/services/mix-message-queue/mix.mq.server/Domain/Services/GrpcStreamingService.cs b/src/services/mix-message-queue/mix.mq.server/Domain/Services/GrpcStreamingService.cs new file mode 100644 index 000000000..a8c25245f --- /dev/null +++ b/src/services/mix-message-queue/mix.mq.server/Domain/Services/GrpcStreamingService.cs @@ -0,0 +1,153 @@ +using Grpc.Core; +using Mix.Mq.Lib.Models; +using Newtonsoft.Json.Linq; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace Mix.Mq.Server.Domain.Services +{ + public class GrpcStreamingService + { + public ConcurrentDictionary> MessageSubscriptions { get; set; } + public ConcurrentQueue Tasks; + private readonly MixQueueMessages _queue; + private CancellationToken _cancellationToken; + private ILogger _logger; + public ConcurrentDictionary> PendingMessages; + + public GrpcStreamingService(MixQueueMessages queue, ILogger logger) + { + MessageSubscriptions = new(); + _queue = queue; + Tasks = new(); + PendingMessages = new(); + _logger = logger; + } + + public Task LoadAllSubscriptions(CancellationToken cancellationToken) + { + _cancellationToken = cancellationToken; + return Task.WhenAll(Tasks); + } + + + public Task AddSubscription(SubscribeRequest request, IServerStreamWriter responseStream) + { + MessageSubscriptions.TryRemove(request, out _); + if (MessageSubscriptions.TryAdd(request, responseStream)) + { + return CreateSubscription(request, responseStream); + } + return Task.CompletedTask; + } + public Task RemoveSubscription(SubscribeRequest request) + { + var _topic = _queue.GetTopic(request.TopicId); + _topic.RemoveSubscription(request.SubsctiptionId); + MessageSubscriptions.TryRemove(request, out _); + return Task.CompletedTask; + } + + private async Task CreateSubscription(SubscribeRequest request, IServerStreamWriter responseStream) + { + var _topic = _queue.GetTopic(request.TopicId); + Initialize(_topic, request.SubsctiptionId); + + while (!_cancellationToken.IsCancellationRequested) + { + var inQueueItems = _topic.ConsumeQueue(request.SubsctiptionId, 10); + try + { + await SendPendingMessages(request, responseStream); + + var result = new SubscribeReply + { + Messages = { } + }; + if (inQueueItems.Count > 0) + { + foreach (var item in inQueueItems) + { + result.Messages.Add(JObject.FromObject(item).ToString(Newtonsoft.Json.Formatting.None)); + } + } + + await responseStream.WriteAsync(result).ConfigureAwait(false); + } + catch (RpcException ex) + { + _logger.LogError($"RpcException at{DateTime.UtcNow.AddHours(7)} - {GetType().Name} Cannot write stream message to {request.SubsctiptionId}: {ex.Message}", ex); + AddToPendingMessages(request.SubsctiptionId, inQueueItems.ToList()); + await RemoveSubscription(request); + break; + } + catch (Exception ex) + { + _logger.LogError($"Exception at{DateTime.UtcNow.AddHours(7)} - {GetType().Name} Cannot write stream message to {request.SubsctiptionId}: {ex.Message}", ex); + AddToPendingMessages(request.SubsctiptionId, inQueueItems.ToList()); + await RemoveSubscription(request); + break; + } + + await Task.Delay(1000, _cancellationToken); + } + } + + private async Task SendPendingMessages(SubscribeRequest request, IServerStreamWriter responseStream) + { + PendingMessages.TryGetValue(request.SubsctiptionId, out var messages); + if (messages != null && messages.Count > 0) + { + try + { + + var result = new SubscribeReply + { + Messages = { } + }; + foreach (var item in messages) + { + result.Messages.Add(JObject.FromObject(item).ToString(Newtonsoft.Json.Formatting.None)); + } + await responseStream.WriteAsync(result).ConfigureAwait(false); ; + PendingMessages.TryRemove(request.SubsctiptionId, out _); + } + catch (RpcException ex) + { + _logger.LogError($"RpcException - {GetType().Name} Cannot write pending stream message to {request.SubsctiptionId}: {ex.Message}", ex); + AddToPendingMessages(request.SubsctiptionId, messages); + await RemoveSubscription(request); + } + catch (Exception ex) + { + _logger.LogError($"Exception - {GetType().Name} Cannot write pending stream message to {request.SubsctiptionId}: {ex.Message}", ex); + AddToPendingMessages(request.SubsctiptionId, messages); + await RemoveSubscription(request); + } + } + } + + private void AddToPendingMessages(string subscriptionId, List inQueueItems) + { + PendingMessages.TryGetValue(subscriptionId, out var messages); + if (messages == null) + { + PendingMessages.TryAdd(subscriptionId, inQueueItems); + } + else + { + PendingMessages[subscriptionId].AddRange(inQueueItems); + } + } + + private void Initialize(MixTopicModel topic, string subscriptionId) + { + while (topic == null) + { + Thread.Sleep(1000); + } + topic.CreateSubscription(subscriptionId); + } + } +} diff --git a/src/services/mix-message-queue/mix.mq.server/Domain/Services/MixMqService.cs b/src/services/mix-message-queue/mix.mq.server/Domain/Services/MixMqService.cs index bd864637e..ce9075e6d 100644 --- a/src/services/mix-message-queue/mix.mq.server/Domain/Services/MixMqService.cs +++ b/src/services/mix-message-queue/mix.mq.server/Domain/Services/MixMqService.cs @@ -4,7 +4,10 @@ using Grpc.Core; using Mix.Heart.Extensions; using Mix.Mq.Lib.Models; +using Mix.Signalr.Hub.Models; using Newtonsoft.Json.Linq; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Threading; namespace Mix.Mq.Server.Domain.Services; @@ -13,43 +16,34 @@ public class MixMqService : MixMq.MixMqBase { private readonly ILogger _logger; private readonly MixQueueMessages _queue; - public MixMqService(ILogger logger, MixQueueMessages queue) + private readonly GrpcStreamingService _subscriptionService; + public MixMqService(ILogger logger, MixQueueMessages queue, GrpcStreamingService subscriptionService) { _logger = logger; _queue = queue; + _subscriptionService = subscriptionService; } public override async Task Subscribe(SubscribeRequest request, IServerStreamWriter responseStream, ServerCallContext context) { - var _topic = _queue.GetTopic(request.TopicId); - Initialize(_topic, request.SubsctiptionId); - - while (!context.CancellationToken.IsCancellationRequested) + try + { + _logger.LogInformation($"{request.SubsctiptionId} started at {DateTime.UtcNow.AddHours(7)}"); + await _subscriptionService.AddSubscription(request, responseStream); + await Task.Delay(100, context.CancellationToken); + } + catch (Exception e) { - try - { - var inQueueItems = _queue.GetTopic(request.TopicId).ConsumeQueue(request.SubsctiptionId, 10); - if (inQueueItems.Count > 0) - { - var result = new SubscribeReply - { - Messages = { } - }; - foreach (var item in inQueueItems) - { - result.Messages.Add(JObject.FromObject(item).ToString(Newtonsoft.Json.Formatting.None)); - } - await responseStream.WriteAsync(result); - } - Thread.Sleep(1000); - } - catch (Exception ex) - { - _logger.LogError(ex, "Cannot consume queue"); - } + _logger.LogError($"{request.SubsctiptionId} broken at {DateTime.UtcNow.AddHours(7)}: {e.Message}", e); + await _subscriptionService.RemoveSubscription(request); } + } - _logger.LogInformation($"Request {request.TopicId} - {request.SubsctiptionId} canceled"); + public override async Task Disconnect(SubscribeRequest request, ServerCallContext context) + { + await _subscriptionService.RemoveSubscription(request); + _logger.LogInformation($"{request.SubsctiptionId} disconnected at {DateTime.UtcNow.AddHours(7)}"); + return new(); } public override Task Publish(PublishMessageRequest request, ServerCallContext context) @@ -68,15 +62,6 @@ public override Task Publish(PublishMessageRequest request, ServerCallCon return Task.FromResult(new()); } - private void Initialize(MixTopicModel topic, string subscriptionId) - { - while (topic == null) - { - Thread.Sleep(1000); - } - topic.CreateSubscription(subscriptionId); - } - private MessageQueueModel? TryParseMessage(string message) { try diff --git a/src/services/mix-message-queue/mix.mq.server/Domain/Services/MixMqSubscriptionService.cs b/src/services/mix-message-queue/mix.mq.server/Domain/Services/MixMqSubscriptionService.cs new file mode 100644 index 000000000..0385c67a9 --- /dev/null +++ b/src/services/mix-message-queue/mix.mq.server/Domain/Services/MixMqSubscriptionService.cs @@ -0,0 +1,33 @@ +using Azure.Messaging.ServiceBus.Administration; +using Grpc.Core; +using Mix.Mq.Lib.Models; +using Newtonsoft.Json.Linq; +using System.Collections.Concurrent; +using System.Threading; + +namespace Mix.Mq.Server.Domain.Services +{ + public sealed class MixMqSubscriptionService : IHostedService + { + private readonly ILogger _logger; + private CancellationToken _cancellationToken; + private GrpcStreamingService _grpcStreamingService { get; set; } + public MixMqSubscriptionService(ILogger logger, GrpcStreamingService grpcStreamingService) + { + _logger = logger; + _grpcStreamingService = grpcStreamingService; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + return _grpcStreamingService.LoadAllSubscriptions(cancellationToken); + } + public Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogInformation($"{GetType().FullName} stopped"); + return Task.CompletedTask; + } + + + } +} diff --git a/src/services/mix-message-queue/mix.mq.server/Domain/StartupService.cs b/src/services/mix-message-queue/mix.mq.server/Domain/StartupService.cs index 3a0ea7181..7c657d773 100644 --- a/src/services/mix-message-queue/mix.mq.server/Domain/StartupService.cs +++ b/src/services/mix-message-queue/mix.mq.server/Domain/StartupService.cs @@ -13,6 +13,7 @@ public class StartupService : IStartupService { public void AddServices(IServiceCollection services, IConfiguration configuration) { + services.TryAddSingleton(); services.TryAddSingleton>(); services.AddGrpc(); services.AddCors(o => o.AddPolicy("AllowAllGrpc", builder => diff --git a/src/services/mix-message-queue/mix.mq.server/Program.cs b/src/services/mix-message-queue/mix.mq.server/Program.cs index ad75b704e..58745f03b 100644 --- a/src/services/mix-message-queue/mix.mq.server/Program.cs +++ b/src/services/mix-message-queue/mix.mq.server/Program.cs @@ -1,10 +1,25 @@ using Microsoft.Extensions.DependencyInjection.Extensions; +using Mix.Constant.Constants; +using Mix.Heart.Services; +using Mix.Lib.Helpers; +using Mix.Log.Lib; using Mix.Mq.Lib.Models; using Mix.Mq.Server.Domain.Services; +using OpenTelemetry; +using System.Configuration; +using System.Reflection; + +if (Directory.Exists($"../{MixFolders.MixCoreConfigurationFolder}")) +{ + MixFileHelper.CopyFolder($"../{MixFolders.MixCoreConfigurationFolder}", MixFolders.MixContentSharedFolder); +} -var builder = WebApplication.CreateBuilder(args); -builder.AddServiceDefaults(); +var builder = MixCmsHelper.CreateWebApplicationBuilder(args); +if (builder.Environment.IsDevelopment()) +{ + builder.AddServiceDefaults(); +} // Add services to the container. @@ -13,11 +28,14 @@ builder.Services.AddEndpointsApiExplorer(); +builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton>(); +builder.Services.AddHostedService(); // Add services to the container. builder.Services.AddGrpc(); -builder.Services.AddCors(o => o.AddPolicy("AllowAll", builder => +builder.Services.AddMixCors(); +builder.Services.AddCors(o => o.AddPolicy("AllowAllGrpc", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() @@ -25,21 +43,31 @@ .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding"); })); +builder.Services.AddMixLog(builder.Configuration); +builder.Services.AddMixSignalR(builder.Configuration); +builder.Services.AddMixCommunicators(); +builder.Services.AddSwaggerGen(); + var app = builder.Build(); -app.MapDefaultEndpoints(); +if (app.Environment.IsDevelopment()) +{ + app.MapDefaultEndpoints(); +} // Configure the HTTP request pipeline. app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true }); app.UseRouting(); -app.UseCors(); +app.UseMixCors(); app.UseEndpoints(endpoints => { endpoints.MapGrpcService().EnableGrpcWeb() - .RequireCors("AllowAll"); ; + .RequireCors("AllowAllGrpc"); + endpoints.UseMixSignalRApp(); }); - -app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); - -app.Run(); +app.UseSwagger(); +app.UseSwaggerUI(); +app.UseMixSwaggerApps(app.Environment.IsDevelopment(), Assembly.GetExecutingAssembly()); +app.MapControllers(); +app.Run(); \ No newline at end of file diff --git a/src/services/mix-message-queue/mix.mq.server/Properties/launchSettings.json b/src/services/mix-message-queue/mix.mq.server/Properties/launchSettings.json index 49eaaa003..dfa0391c9 100644 --- a/src/services/mix-message-queue/mix.mq.server/Properties/launchSettings.json +++ b/src/services/mix-message-queue/mix.mq.server/Properties/launchSettings.json @@ -1,33 +1,14 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:39272", - "sslPort": 44361 - } - }, +{ "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "http://localhost:5062", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, "https": { "commandName": "Project", - "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7105;http://localhost:5062", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7275;http://localhost:5062" }, "IIS Express": { "commandName": "IISExpress", @@ -36,6 +17,26 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_HTTPS_PORTS": "8081", + "ASPNETCORE_HTTP_PORTS": "8080" + }, + "publishAllPorts": true, + "useSSL": true + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:39272", + "sslPort": 44361 } } -} +} \ No newline at end of file diff --git a/src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj b/src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj index 2287a2148..01562f667 100644 --- a/src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj +++ b/src/services/mix-message-queue/mix.mq.server/mix.mq.server.csproj @@ -2,11 +2,15 @@ net8.0 + false false enable enable true Mix.Mq.Server + 8bd31145-2a3f-4051-9229-af754f13c778 + Linux + ..\..\.. @@ -18,19 +22,16 @@ + - + - - - - diff --git a/src/services/mix-message-queue/mix.mq.server/runtimeconfig.template.json b/src/services/mix-message-queue/mix.mq.server/runtimeconfig.template.json new file mode 100644 index 000000000..cbbea1422 --- /dev/null +++ b/src/services/mix-message-queue/mix.mq.server/runtimeconfig.template.json @@ -0,0 +1,12 @@ +{ + "configProperties": { + "System.GC.RetainVM": false, + "System.GC.NoAffinitize": false, + "System.GC.ConserveMemory": 5, + "System.GC.Server": false, + "System.GC.Concurrent": true, + "System.GC.HeapCount": 12, + "System.Threading.Thread.EnableAutoreleasePool": true + } + } + \ No newline at end of file diff --git a/src/test/locustfile.py b/src/test/locustfile.py index e958af2af..6da4fa3a8 100644 --- a/src/test/locustfile.py +++ b/src/test/locustfile.py @@ -6,15 +6,15 @@ class QuickstartUser(HttpUser): # self.headers = {'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiT3duZXItMSIsIlN1cGVyQWRtaW4iXSwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiI1NWFmNjA4OC04MjllLTQ0YWEtODUyYS01YjdiY2NjOGFlM2IiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGlua3UiLCJSZWZyZXNoVG9rZW4iOiIyYzdkODljMi1hNzVlLTRmOGItODMyNC0xZmQyN2JmYjY5Y2MiLCJBdmF0YXIiOiIvbWl4LWFwcC9hc3NldHMvaW1nL3VzZXIucG5nIiwiQUVTS2V5IjoiTkVsVWVtcE9TbXg0UVZsWFJGUm1TeXM1WjBscFp6MDlMRVJCU0VOVFVVbFpXRVZOWVZSSlJsRXJjMjU2YkU5SWJtbzFaMHd3Y201UFJtOWlNRGxYU0VKU00wVTkiLCJSU0FQdWJsaWNLZXkiOiI8P3htbCB2ZXJzaW9uPVwiMS4wXCIgZW5jb2Rpbmc9XCJ1dGYtMTZcIj8-XHJcbjxSU0FQYXJhbWV0ZXJzIHhtbG5zOnhzaT1cImh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlXCIgeG1sbnM6eHNkPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWFcIj5cclxuICA8RXhwb25lbnQ-QVFBQjwvRXhwb25lbnQ-XHJcbiAgPE1vZHVsdXM-b1hIN09ISUVQdXFRRXVHRk8wRm81dXgyT0NyQTBoclAyeWpBK0FCUUlvV3JTdmMvVkM0T2pZdEpvODhQY2VaR2ZWc0dUaXhkdDlMZ1YrZzZTTVpGMWxIME1BUVRWTzhndGU0YzBvbkdZL09FOFAySDVSZFVQL0E0eVA1Sldjd1VuQ21mSG8ydUJuempPSXF4MnRjaFB4cnR6UmlQZnJkZGp1MHVUcXJJNUwwSVVERTFZSk1rbzFaUDVLY2oyQzBPcnVqd0FCVzBsTitxZXhFTnpidDBZZFoyVzd2UXBrZ0xFcXlVdWJ1RUo0MllieDQzSVBEWWxnY1JNaHZ2YnYxTGl2U3liLzBRZkJSNVhXSFRQYzduMGJZRWpBQkI1RkgrT29YdnlHZXpHSU1qR1FMMnoxVnpiT0lqMzFpS2lCclhrcjBrR2ZJSzRsQzdSNElqdkh1K0FRPT08L01vZHVsdXM-XHJcbjwvUlNBUGFyYW1ldGVycz4iLCJFeHBpcmVBdCI6IjIwMjMtMDUtMTRUMDU6MDA6MzMuNzk0WiIsIm5iZiI6MTY4NDAzOTIzMywiZXhwIjoxNjg0MDQwNDMzLCJpc3MiOiJtaXgtY29yZSIsImF1ZCI6Im1peC1jb3JlIn0.3IARED63s03ZOlCa0olj4sN9V3XFoAej0xS9sJfLL54'} @task def hello_world(self): - # self.client.get("/") + self.client.get("/") # self.client.get("/post/3/the-future-of-cms-from-mixcore") - self.client.post( - url="/api/v2/rest/mix-portal/mix-db/Metadata/hub", - json={"type":"testuser", "content":"secret", "seoContent": "asdfa"}, - auth=None, - # headers={"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiT3duZXItMSIsIlN1cGVyQWRtaW4iXSwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiI1NWFmNjA4OC04MjllLTQ0YWEtODUyYS01YjdiY2NjOGFlM2IiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGlua3UiLCJSZWZyZXNoVG9rZW4iOiIyYzdkODljMi1hNzVlLTRmOGItODMyNC0xZmQyN2JmYjY5Y2MiLCJBdmF0YXIiOiIvbWl4LWFwcC9hc3NldHMvaW1nL3VzZXIucG5nIiwiQUVTS2V5IjoiTkVsVWVtcE9TbXg0UVZsWFJGUm1TeXM1WjBscFp6MDlMRVJCU0VOVFVVbFpXRVZOWVZSSlJsRXJjMjU2YkU5SWJtbzFaMHd3Y201UFJtOWlNRGxYU0VKU00wVTkiLCJSU0FQdWJsaWNLZXkiOiI8P3htbCB2ZXJzaW9uPVwiMS4wXCIgZW5jb2Rpbmc9XCJ1dGYtMTZcIj8-XHJcbjxSU0FQYXJhbWV0ZXJzIHhtbG5zOnhzaT1cImh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlXCIgeG1sbnM6eHNkPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWFcIj5cclxuICA8RXhwb25lbnQ-QVFBQjwvRXhwb25lbnQ-XHJcbiAgPE1vZHVsdXM-b1hIN09ISUVQdXFRRXVHRk8wRm81dXgyT0NyQTBoclAyeWpBK0FCUUlvV3JTdmMvVkM0T2pZdEpvODhQY2VaR2ZWc0dUaXhkdDlMZ1YrZzZTTVpGMWxIME1BUVRWTzhndGU0YzBvbkdZL09FOFAySDVSZFVQL0E0eVA1Sldjd1VuQ21mSG8ydUJuempPSXF4MnRjaFB4cnR6UmlQZnJkZGp1MHVUcXJJNUwwSVVERTFZSk1rbzFaUDVLY2oyQzBPcnVqd0FCVzBsTitxZXhFTnpidDBZZFoyVzd2UXBrZ0xFcXlVdWJ1RUo0MllieDQzSVBEWWxnY1JNaHZ2YnYxTGl2U3liLzBRZkJSNVhXSFRQYzduMGJZRWpBQkI1RkgrT29YdnlHZXpHSU1qR1FMMnoxVnpiT0lqMzFpS2lCclhrcjBrR2ZJSzRsQzdSNElqdkh1K0FRPT08L01vZHVsdXM-XHJcbjwvUlNBUGFyYW1ldGVycz4iLCJFeHBpcmVBdCI6IjIwMjMtMDUtMTRUMDU6MDA6MzMuNzk0WiIsIm5iZiI6MTY4NDAzOTIzMywiZXhwIjoxNjg0MDQwNDMzLCJpc3MiOiJtaXgtY29yZSIsImF1ZCI6Im1peC1jb3JlIn0.3IARED63s03ZOlCa0olj4sN9V3XFoAej0xS9sJfLL54"}, - name="Metadata/hub", - ) + # self.client.post( + # url="/api/v2/rest/mix-portal/mix-db/Metadata/hub", + # json={"type":"testuser", "content":"secret", "seoContent": "asdfa"}, + # auth=None, + # # headers={"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiT3duZXItMSIsIlN1cGVyQWRtaW4iXSwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiI1NWFmNjA4OC04MjllLTQ0YWEtODUyYS01YjdiY2NjOGFlM2IiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGlua3UiLCJSZWZyZXNoVG9rZW4iOiIyYzdkODljMi1hNzVlLTRmOGItODMyNC0xZmQyN2JmYjY5Y2MiLCJBdmF0YXIiOiIvbWl4LWFwcC9hc3NldHMvaW1nL3VzZXIucG5nIiwiQUVTS2V5IjoiTkVsVWVtcE9TbXg0UVZsWFJGUm1TeXM1WjBscFp6MDlMRVJCU0VOVFVVbFpXRVZOWVZSSlJsRXJjMjU2YkU5SWJtbzFaMHd3Y201UFJtOWlNRGxYU0VKU00wVTkiLCJSU0FQdWJsaWNLZXkiOiI8P3htbCB2ZXJzaW9uPVwiMS4wXCIgZW5jb2Rpbmc9XCJ1dGYtMTZcIj8-XHJcbjxSU0FQYXJhbWV0ZXJzIHhtbG5zOnhzaT1cImh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlXCIgeG1sbnM6eHNkPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWFcIj5cclxuICA8RXhwb25lbnQ-QVFBQjwvRXhwb25lbnQ-XHJcbiAgPE1vZHVsdXM-b1hIN09ISUVQdXFRRXVHRk8wRm81dXgyT0NyQTBoclAyeWpBK0FCUUlvV3JTdmMvVkM0T2pZdEpvODhQY2VaR2ZWc0dUaXhkdDlMZ1YrZzZTTVpGMWxIME1BUVRWTzhndGU0YzBvbkdZL09FOFAySDVSZFVQL0E0eVA1Sldjd1VuQ21mSG8ydUJuempPSXF4MnRjaFB4cnR6UmlQZnJkZGp1MHVUcXJJNUwwSVVERTFZSk1rbzFaUDVLY2oyQzBPcnVqd0FCVzBsTitxZXhFTnpidDBZZFoyVzd2UXBrZ0xFcXlVdWJ1RUo0MllieDQzSVBEWWxnY1JNaHZ2YnYxTGl2U3liLzBRZkJSNVhXSFRQYzduMGJZRWpBQkI1RkgrT29YdnlHZXpHSU1qR1FMMnoxVnpiT0lqMzFpS2lCclhrcjBrR2ZJSzRsQzdSNElqdkh1K0FRPT08L01vZHVsdXM-XHJcbjwvUlNBUGFyYW1ldGVycz4iLCJFeHBpcmVBdCI6IjIwMjMtMDUtMTRUMDU6MDA6MzMuNzk0WiIsIm5iZiI6MTY4NDAzOTIzMywiZXhwIjoxNjg0MDQwNDMzLCJpc3MiOiJtaXgtY29yZSIsImF1ZCI6Im1peC1jb3JlIn0.3IARED63s03ZOlCa0olj4sN9V3XFoAej0xS9sJfLL54"}, + # name="Metadata/hub", + # ) # self.client.post("/api/v2/rest/mix-portal/mix-db/Metadata/hub", {"type":"testuser", "content":"secret", "seoContent": "asdfa"}) # @task(3) From fbde64732ef484f3b5b9d2dfe08599e957d88616 Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Sat, 20 Jan 2024 14:28:04 +0700 Subject: [PATCH 2/2] fix concurrent --- src/applications/mixcore/mixcore.csproj | 4 +++- .../Startup/_ServiceCollectionExtensions.cs | 7 ++++++- src/platform/mix.queue/Engines/SubscriberBase.cs | 10 +++++++--- .../mix.mq.server/Domain/StartupService.cs | 1 + .../mix-message-queue/mix.mq.server/Program.cs | 5 +++++ 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/applications/mixcore/mixcore.csproj b/src/applications/mixcore/mixcore.csproj index b38c61430..7e22d630f 100644 --- a/src/applications/mixcore/mixcore.csproj +++ b/src/applications/mixcore/mixcore.csproj @@ -14,6 +14,8 @@ + + @@ -67,7 +69,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/platform/mix.library/Startup/_ServiceCollectionExtensions.cs b/src/platform/mix.library/Startup/_ServiceCollectionExtensions.cs index a4d206a9c..3105ff721 100644 --- a/src/platform/mix.library/Startup/_ServiceCollectionExtensions.cs +++ b/src/platform/mix.library/Startup/_ServiceCollectionExtensions.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using Mix.Lib.Interfaces; using Mix.Lib.Middlewares; @@ -42,7 +43,11 @@ public static IServiceCollection AddMixServices(this IServiceCollection services .Get(); var redisCnn = configuration.GetSection("Redis").GetValue("ConnectionString"); - + services.Configure(options => + { + options.ServicesStartConcurrently = true; + options.ServicesStopConcurrently = false; + }); services.AddOptions() .Bind(configuration.GetSection(MixAppSettingsSection.GlobalSettings)) .ValidateDataAnnotations(); diff --git a/src/platform/mix.queue/Engines/SubscriberBase.cs b/src/platform/mix.queue/Engines/SubscriberBase.cs index f655853a6..205e77939 100644 --- a/src/platform/mix.queue/Engines/SubscriberBase.cs +++ b/src/platform/mix.queue/Engines/SubscriberBase.cs @@ -54,10 +54,14 @@ protected SubscriberBase( ServicesProvider = servicesProvider; _logger = logger; } - protected async override Task ExecuteAsync(CancellationToken cancellationToken) + protected override Task ExecuteAsync(CancellationToken cancellationToken) { - _subscriber = CreateSubscriber(_topicId, $"{_topicId}_{_moduleName}"); - await StartProcessQueue(cancellationToken); + Task.Run(() => + { + _subscriber = CreateSubscriber(_topicId, $"{_topicId}_{_moduleName}"); + StartProcessQueue(cancellationToken); + }); + return Task.CompletedTask; } public virtual async Task StopAsync(CancellationToken cancellationToken) diff --git a/src/services/mix-message-queue/mix.mq.server/Domain/StartupService.cs b/src/services/mix-message-queue/mix.mq.server/Domain/StartupService.cs index 7c657d773..45c8862c5 100644 --- a/src/services/mix-message-queue/mix.mq.server/Domain/StartupService.cs +++ b/src/services/mix-message-queue/mix.mq.server/Domain/StartupService.cs @@ -13,6 +13,7 @@ public class StartupService : IStartupService { public void AddServices(IServiceCollection services, IConfiguration configuration) { + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton>(); services.AddGrpc(); diff --git a/src/services/mix-message-queue/mix.mq.server/Program.cs b/src/services/mix-message-queue/mix.mq.server/Program.cs index 58745f03b..519f4a700 100644 --- a/src/services/mix-message-queue/mix.mq.server/Program.cs +++ b/src/services/mix-message-queue/mix.mq.server/Program.cs @@ -27,6 +27,11 @@ // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); +builder.Services.Configure(options => +{ + options.ServicesStartConcurrently = true; + options.ServicesStopConcurrently = false; +}); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton>();