diff --git a/README.md b/README.md index 27d403ae..2e357580 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,13 @@ You can either run in Visual Studio, or using [Microsoft Tye](https://github.com - Wait until all applications are up! - - You can check running application from tye dashboard ([localhost:8000](http://127.0.0.1:8000/)) + - You can check running application from tye dashboard ([localhost:8000](http://127.0.0.1:8000/)) + - **Note**: If you see all of your applications keep restarting on tye dashboard or tye console, you may be facing ssl certificate issues. To diagnose the problems better, check any application logs. If it is related with SSL, developer certificate creation may have failed because of powershell issues regarding authorization. Check the powershell script running configuration and set policy for your local machine as: + ```bash + Get-ExecutionPolicy list + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine + ``` + See [Microsoft Powershell documentation](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/get-executionpolicy?view=powershell-7.2) for more information. - After all your backend services are up, start the angular application: @@ -39,6 +45,19 @@ You can either run in Visual Studio, or using [Microsoft Tye](https://github.com yarn start ``` +### Certificate Expiration +If the cerficiate is expired you'll see following error: + + + + +Generating a new certificate will fix that issue. To generate new one, + +- Remove `etc/dev-cert/localhost.pfx` + +- Manually execute `create-certificate.ps1` **or** re-run solution with `run-tye.ps1` + + ## Roadmap - [x] New blank micro-service solution ✔️ diff --git a/docs/images/ssl-error.png b/docs/images/ssl-error.png new file mode 100644 index 00000000..f16403f9 Binary files /dev/null and b/docs/images/ssl-error.png differ diff --git a/docs/roadmap/Phase_1.png b/docs/roadmap/Phase_1.png index 17015e8e..14bf3594 100644 Binary files a/docs/roadmap/Phase_1.png and b/docs/roadmap/Phase_1.png differ diff --git a/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/AdministrationServiceHttpApiHostModule.cs b/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/AdministrationServiceHttpApiHostModule.cs index beafc3f7..cb17f630 100644 --- a/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/AdministrationServiceHttpApiHostModule.cs +++ b/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/AdministrationServiceHttpApiHostModule.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using EShopOnAbp.AdministrationService.DbMigrations; using EShopOnAbp.AdministrationService.EntityFrameworkCore; using EShopOnAbp.Shared.Hosting.AspNetCore; @@ -11,12 +7,15 @@ using Microsoft.AspNetCore.Cors; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; using Volo.Abp.Http.Client.IdentityModel.Web; using Volo.Abp.Identity; using Volo.Abp.Modularity; -using Volo.Abp.Threading; namespace EShopOnAbp.AdministrationService; diff --git a/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/Controllers/HomeController.cs b/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/Controllers/HomeController.cs index aad4dea1..40ae5bd5 100644 --- a/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/Controllers/HomeController.cs +++ b/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/Controllers/HomeController.cs @@ -1,13 +1,12 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; -namespace EShopOnAbp.AdministrationService.Controllers +namespace EShopOnAbp.AdministrationService.Controllers; + +public class HomeController : AbpController { - public class HomeController : AbpController + public ActionResult Index() { - public ActionResult Index() - { - return Redirect("~/swagger"); - } + return Redirect("~/swagger"); } -} +} \ No newline at end of file diff --git a/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationChecker.cs b/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationChecker.cs index c99ac38b..a683e8eb 100644 --- a/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationChecker.cs +++ b/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationChecker.cs @@ -5,23 +5,22 @@ using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.AdministrationService.DbMigrations +namespace EShopOnAbp.AdministrationService.DbMigrations; + +public class AdministrationServiceDatabaseMigrationChecker + : PendingEfCoreMigrationsChecker { - public class AdministrationServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker + public AdministrationServiceDatabaseMigrationChecker( + IUnitOfWorkManager unitOfWorkManager, + IServiceProvider serviceProvider, + ICurrentTenant currentTenant, + IDistributedEventBus distributedEventBus) + : base( + unitOfWorkManager, + serviceProvider, + currentTenant, + distributedEventBus, + AdministrationServiceDbProperties.ConnectionStringName) { - public AdministrationServiceDatabaseMigrationChecker( - IUnitOfWorkManager unitOfWorkManager, - IServiceProvider serviceProvider, - ICurrentTenant currentTenant, - IDistributedEventBus distributedEventBus) - : base( - unitOfWorkManager, - serviceProvider, - currentTenant, - distributedEventBus, - AdministrationServiceDbProperties.ConnectionStringName) - { - - } } -} +} \ No newline at end of file diff --git a/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationEventHandler.cs b/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationEventHandler.cs index 4640dfcf..a90f68de 100644 --- a/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationEventHandler.cs +++ b/services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationEventHandler.cs @@ -1,101 +1,94 @@ using EShopOnAbp.AdministrationService.EntityFrameworkCore; +using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; +using Serilog; using System; using System.Linq; using System.Threading.Tasks; -using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; +using Volo.Abp.DistributedLocking; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.PermissionManagement; using Volo.Abp.Uow; -namespace EShopOnAbp.AdministrationService.DbMigrations -{ - public class AdministrationServiceDatabaseMigrationEventHandler +namespace EShopOnAbp.AdministrationService.DbMigrations; + +public class AdministrationServiceDatabaseMigrationEventHandler : DatabaseEfCoreMigrationEventHandler, - IDistributedEventHandler, - IDistributedEventHandler + IDistributedEventHandler +{ + private readonly IPermissionDefinitionManager _permissionDefinitionManager; + private readonly IPermissionDataSeeder _permissionDataSeeder; + + public AdministrationServiceDatabaseMigrationEventHandler( + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + ITenantStore tenantStore, + IPermissionDefinitionManager permissionDefinitionManager, + IPermissionDataSeeder permissionDataSeeder, + IDistributedEventBus distributedEventBus, + IAbpDistributedLock distributedLockProvider + ) : base( + currentTenant, + unitOfWorkManager, + tenantStore, + distributedEventBus, + AdministrationServiceDbProperties.ConnectionStringName, + distributedLockProvider + ) { - private readonly IPermissionDefinitionManager _permissionDefinitionManager; - private readonly IPermissionDataSeeder _permissionDataSeeder; + _permissionDefinitionManager = permissionDefinitionManager; + _permissionDataSeeder = permissionDataSeeder; + } - public AdministrationServiceDatabaseMigrationEventHandler( - ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager, - ITenantStore tenantStore, - IPermissionDefinitionManager permissionDefinitionManager, - IPermissionDataSeeder permissionDataSeeder, - IDistributedEventBus distributedEventBus - ) : base( - currentTenant, - unitOfWorkManager, - tenantStore, - distributedEventBus, - AdministrationServiceDbProperties.ConnectionStringName) + public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + { + if (eventData.DatabaseName != DatabaseName) { - _permissionDefinitionManager = permissionDefinitionManager; - _permissionDataSeeder = permissionDataSeeder; + return; } - public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + try { - if (eventData.DatabaseName != DatabaseName) + await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName)) { - return; - } + Log.Information("AdministrationService acquired lock for db migration and seeding..."); - try - { - var schemaMigrated = await MigrateDatabaseSchemaAsync(eventData.TenantId); - await SeedDataAsync(eventData.TenantId); - } - catch (Exception ex) - { - await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); + if (handle != null) + { + await MigrateDatabaseSchemaAsync(); + await SeedDataAsync(); + } } } - - public async Task HandleEventAsync(TenantCreatedEto eventData) + catch (Exception ex) { - try - { - await MigrateDatabaseSchemaAsync(eventData.Id); - await SeedDataAsync(eventData.Id); - } - catch (Exception ex) - { - await HandleErrorTenantCreatedAsync(eventData, ex); - } + await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); } + } - private async Task SeedDataAsync(Guid? tenantId) + private async Task SeedDataAsync() + { + using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true)) { - using (CurrentTenant.Change(tenantId)) - { - using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true)) - { - var multiTenancySide = tenantId == null - ? MultiTenancySides.Host - : MultiTenancySides.Tenant; + var multiTenancySide = MultiTenancySides.Host; - var permissionNames = _permissionDefinitionManager - .GetPermissions() - .Where(p => p.MultiTenancySide.HasFlag(multiTenancySide)) - .Where(p => !p.Providers.Any() || p.Providers.Contains(RolePermissionValueProvider.ProviderName)) - .Select(p => p.Name) - .ToArray(); + var permissionNames = _permissionDefinitionManager + .GetPermissions() + .Where(p => p.MultiTenancySide.HasFlag(multiTenancySide)) + .Where(p => !p.Providers.Any() || + p.Providers.Contains(RolePermissionValueProvider.ProviderName)) + .Select(p => p.Name) + .ToArray(); - await _permissionDataSeeder.SeedAsync( - RolePermissionValueProvider.ProviderName, - "admin", - permissionNames, - tenantId - ); + await _permissionDataSeeder.SeedAsync( + RolePermissionValueProvider.ProviderName, + "admin", + permissionNames + ); - await uow.CompleteAsync(); - } - } + await uow.CompleteAsync(); } } -} +} \ No newline at end of file diff --git a/services/basket/src/EShopOnAbp.BasketService/BasketServiceModule.cs b/services/basket/src/EShopOnAbp.BasketService/BasketServiceModule.cs index 3f952db3..97bef87e 100644 --- a/services/basket/src/EShopOnAbp.BasketService/BasketServiceModule.cs +++ b/services/basket/src/EShopOnAbp.BasketService/BasketServiceModule.cs @@ -16,175 +16,174 @@ using Volo.Abp.Http.Client; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; -namespace EShopOnAbp.BasketService +namespace EShopOnAbp.BasketService; + +[DependsOn( + typeof(AbpAspNetCoreMvcModule), + typeof(AbpHttpClientModule), + typeof(AbpAutoMapperModule), + typeof(AbpCachingModule), + typeof(AbpDddApplicationModule), + typeof(AbpDddDomainModule), + typeof(BasketServiceContractsModule), + typeof(EShopOnAbpSharedHostingMicroservicesModule) +)] +public class BasketServiceModule : AbpModule { - [DependsOn( - typeof(AbpAspNetCoreMvcModule), - typeof(AbpHttpClientModule), - typeof(AbpAutoMapperModule), - typeof(AbpCachingModule), - typeof(AbpDddApplicationModule), - typeof(AbpDddDomainModule), - typeof(BasketServiceContractsModule), - typeof(EShopOnAbpSharedHostingMicroservicesModule) - )] - public class BasketServiceModule : AbpModule + public override void ConfigureServices(ServiceConfigurationContext context) { - public override void ConfigureServices(ServiceConfigurationContext context) - { - var hostingEnvironment = context.Services.GetHostingEnvironment(); + var hostingEnvironment = context.Services.GetHostingEnvironment(); - Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = hostingEnvironment.IsDevelopment(); + Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = hostingEnvironment.IsDevelopment(); - var configuration = context.Services.GetConfiguration(); + var configuration = context.Services.GetConfiguration(); - ConfigureAutoMapper(); - ConfigureAspNetCoreRouting(context); - ConfigureGrpc(context); - ConfigureDistributedCache(); - ConfigureVirtualFileSystem(); - ConfigureAuthentication(context, configuration); - ConfigureSwagger(context, configuration); - ConfigureAutoApiControllers(); - } + ConfigureAutoMapper(); + ConfigureAspNetCoreRouting(context); + ConfigureGrpc(context); + ConfigureDistributedCache(); + ConfigureVirtualFileSystem(); + ConfigureAuthentication(context, configuration); + ConfigureSwagger(context, configuration); + ConfigureAutoApiControllers(); + } - private void ConfigureAspNetCoreRouting(ServiceConfigurationContext context) + private void ConfigureAspNetCoreRouting(ServiceConfigurationContext context) + { + Configure(options => { - Configure(options => + options.ConventionalControllers.Create(typeof(BasketServiceModule).Assembly, opts => { - options.ConventionalControllers.Create(typeof(BasketServiceModule).Assembly, opts => - { - opts.RootPath = "basket"; - opts.RemoteServiceName = BasketServiceConstants.RemoteServiceName; - }); + opts.RootPath = "basket"; + opts.RemoteServiceName = BasketServiceConstants.RemoteServiceName; }); - } - - public override void OnApplicationInitialization(ApplicationInitializationContext context) - { - var app = context.GetApplicationBuilder(); - var env = context.GetEnvironment(); + }); + } - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + var env = context.GetEnvironment(); - app.UseCorrelationId(); - app.UseCors(); - app.UseAbpRequestLocalization(); - app.UseStaticFiles(); - app.UseRouting(); - app.UseAuthentication(); - app.UseAbpClaimsMap(); - app.UseAuthorization(); - app.UseSwagger(); - app.UseSwaggerUI(options => - { - var configuration = context.ServiceProvider.GetRequiredService(); - options.SwaggerEndpoint("/swagger/v1/swagger.json", "Basket Service API"); - options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); - options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); - }); - app.UseAbpSerilogEnrichers(); - app.UseAuditing(); - app.UseUnitOfWork(); - app.UseConfiguredEndpoints(); - } - - private void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration) + if (env.IsDevelopment()) { - SwaggerConfigurationHelper.ConfigureWithAuth( - context: context, - authority: configuration["AuthServer:Authority"], - scopes: new - Dictionary /* Requested scopes for authorization code request and descriptions for swagger UI only */ - { - {"BasketService", "Basket Service API"} - }, - apiTitle: "Basket Service API" - ); + app.UseDeveloperExceptionPage(); } - - private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) + + app.UseCorrelationId(); + app.UseCors(); + app.UseAbpRequestLocalization(); + app.UseStaticFiles(); + app.UseRouting(); + app.UseAuthentication(); + app.UseAbpClaimsMap(); + app.UseAuthorization(); + app.UseSwagger(); + app.UseSwaggerUI(options => { - JwtBearerConfigurationHelper.Configure(context, "BasketService"); + var configuration = context.ServiceProvider.GetRequiredService(); + options.SwaggerEndpoint("/swagger/v1/swagger.json", "Basket Service API"); + options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); + options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); + }); + app.UseAbpSerilogEnrichers(); + app.UseAuditing(); + app.UseUnitOfWork(); + app.UseConfiguredEndpoints(); + } + + private void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration) + { + SwaggerConfigurationHelper.ConfigureWithAuth( + context: context, + authority: configuration["AuthServer:Authority"], + scopes: new + Dictionary /* Requested scopes for authorization code request and descriptions for swagger UI only */ + { + {"BasketService", "Basket Service API"} + }, + apiTitle: "Basket Service API" + ); + } + + private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) + { + JwtBearerConfigurationHelper.Configure(context, "BasketService"); - context.Services.AddCors(options => + context.Services.AddCors(options => + { + options.AddDefaultPolicy(builder => { - options.AddDefaultPolicy(builder => - { - builder - .WithOrigins( - configuration["App:CorsOrigins"] - .Split(",", StringSplitOptions.RemoveEmptyEntries) - .Select(o => o.Trim().RemovePostFix("/")) - .ToArray() - ) - .WithAbpExposedHeaders() - .SetIsOriginAllowedToAllowWildcardSubdomains() - .AllowAnyHeader() - .AllowAnyMethod() - .AllowCredentials(); - }); + builder + .WithOrigins( + configuration["App:CorsOrigins"] + .Split(",", StringSplitOptions.RemoveEmptyEntries) + .Select(o => o.Trim().RemovePostFix("/")) + .ToArray() + ) + .WithAbpExposedHeaders() + .SetIsOriginAllowedToAllowWildcardSubdomains() + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials(); }); + }); - Configure(options => { options.AutoValidate = false; }); - } + Configure(options => { options.AutoValidate = false; }); + } - private void ConfigureAutoApiControllers() + private void ConfigureAutoApiControllers() + { + Configure(options => { - Configure(options => - { - options.ConventionalControllers.Create(typeof(BasketServiceModule).Assembly); - }); - } + options.ConventionalControllers.Create(typeof(BasketServiceModule).Assembly); + }); + } - private void ConfigureGrpc(ServiceConfigurationContext context) + private void ConfigureGrpc(ServiceConfigurationContext context) + { + context.Services.AddGrpcClient((services, options) => { - context.Services.AddGrpcClient((services, options) => - { - var remoteServiceOptions = services.GetRequiredService>().CurrentValue; - var catalogServiceConfiguration = remoteServiceOptions.RemoteServices.GetConfigurationOrDefault("Catalog"); - var catalogGrpcUrl = catalogServiceConfiguration.GetOrDefault("GrpcUrl"); + var remoteServiceOptions = services.GetRequiredService>().CurrentValue; + var catalogServiceConfiguration = remoteServiceOptions.RemoteServices.GetConfigurationOrDefault("Catalog"); + var catalogGrpcUrl = catalogServiceConfiguration.GetOrDefault("GrpcUrl"); - options.Address = new Uri(catalogGrpcUrl); - }); - } + options.Address = new Uri(catalogGrpcUrl); + }); + } - private void ConfigureAutoMapper() + private void ConfigureAutoMapper() + { + Configure(options => { - Configure(options => - { - options.AddMaps(); - }); - } + options.AddMaps(); + }); + } - private void ConfigureDistributedCache() + private void ConfigureDistributedCache() + { + Configure(options => { - Configure(options => + options.CacheConfigurators.Add(cacheName => { - options.CacheConfigurators.Add(cacheName => + if (cacheName == CacheNameAttribute.GetCacheName(typeof(Basket))) { - if (cacheName == CacheNameAttribute.GetCacheName(typeof(Basket))) + return new DistributedCacheEntryOptions { - return new DistributedCacheEntryOptions - { - SlidingExpiration = TimeSpan.FromDays(7) - }; - } + SlidingExpiration = TimeSpan.FromDays(7) + }; + } - return null; - }); + return null; }); - } + }); + } - private void ConfigureVirtualFileSystem() + private void ConfigureVirtualFileSystem() + { + Configure(options => { - Configure(options => - { - options.FileSets.AddEmbedded(); - }); - } + options.FileSets.AddEmbedded(); + }); } -} +} \ No newline at end of file diff --git a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/CatalogServiceHttpApiHostModule.cs b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/CatalogServiceHttpApiHostModule.cs index b8a4881d..72c8cf92 100644 --- a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/CatalogServiceHttpApiHostModule.cs +++ b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/CatalogServiceHttpApiHostModule.cs @@ -1,24 +1,21 @@ using EShopOnAbp.CatalogService.DbMigrations; +using EShopOnAbp.CatalogService.Grpc; +using EShopOnAbp.CatalogService.MongoDB; using EShopOnAbp.Shared.Hosting.AspNetCore; using EShopOnAbp.Shared.Hosting.Microservices; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; -using EShopOnAbp.CatalogService.Grpc; -using EShopOnAbp.CatalogService.MongoDB; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.AntiForgery; using Volo.Abp.Modularity; -using Volo.Abp.Threading; using Volo.Abp.Uow; namespace EShopOnAbp.CatalogService; diff --git a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/Controllers/HomeController.cs b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/Controllers/HomeController.cs index 4a2836a2..f00f870a 100644 --- a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/Controllers/HomeController.cs +++ b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/Controllers/HomeController.cs @@ -1,13 +1,12 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; -namespace EShopOnAbp.CatalogService.Controllers +namespace EShopOnAbp.CatalogService.Controllers; + +public class HomeController : AbpController { - public class HomeController : AbpController + public ActionResult Index() { - public ActionResult Index() - { - return Redirect("~/swagger"); - } + return Redirect("~/swagger"); } -} +} \ No newline at end of file diff --git a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationChecker.cs b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationChecker.cs index 36d5ee5f..62551ec9 100644 --- a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationChecker.cs +++ b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationChecker.cs @@ -6,32 +6,31 @@ using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.CatalogService.DbMigrations +namespace EShopOnAbp.CatalogService.DbMigrations; + +public class CatalogServiceDatabaseMigrationChecker : PendingMongoDbMigrationsChecker { - public class CatalogServiceDatabaseMigrationChecker : PendingMongoDbMigrationsChecker - { - private readonly ProductServiceDataSeeder _productServiceDataSeeder; + private readonly ProductServiceDataSeeder _productServiceDataSeeder; - public CatalogServiceDatabaseMigrationChecker( - IUnitOfWorkManager unitOfWorkManager, - IServiceProvider serviceProvider, - ICurrentTenant currentTenant, - IDistributedEventBus distributedEventBus, - ProductServiceDataSeeder productServiceDataSeeder) - : base( - unitOfWorkManager, - serviceProvider, - currentTenant, - distributedEventBus, - CatalogServiceDbProperties.ConnectionStringName) - { - _productServiceDataSeeder = productServiceDataSeeder; - } + public CatalogServiceDatabaseMigrationChecker( + IUnitOfWorkManager unitOfWorkManager, + IServiceProvider serviceProvider, + ICurrentTenant currentTenant, + IDistributedEventBus distributedEventBus, + ProductServiceDataSeeder productServiceDataSeeder) + : base( + unitOfWorkManager, + serviceProvider, + currentTenant, + distributedEventBus, + CatalogServiceDbProperties.ConnectionStringName) + { + _productServiceDataSeeder = productServiceDataSeeder; + } - public override async Task CheckAsync() - { - await base.CheckAsync(); - await _productServiceDataSeeder.SeedAsync(); - } + public override async Task CheckAsync() + { + await base.CheckAsync(); + await _productServiceDataSeeder.SeedAsync(); } -} +} \ No newline at end of file diff --git a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationEventHandler.cs b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationEventHandler.cs index 9fb54311..adff87a9 100644 --- a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationEventHandler.cs +++ b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationEventHandler.cs @@ -1,53 +1,66 @@ -using System; -using System.Threading.Tasks; -using EShopOnAbp.CatalogService.MongoDB; +using EShopOnAbp.CatalogService.MongoDB; using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.MongoDb; +using System; +using System.Threading.Tasks; +using Serilog; using Volo.Abp.Data; +using Volo.Abp.DistributedLocking; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.CatalogService.DbMigrations -{ - public class CatalogServiceDatabaseMigrationEventHandler - : DatabaseMongoDbMigrationEventHandler, +namespace EShopOnAbp.CatalogService.DbMigrations; + +public class CatalogServiceDatabaseMigrationEventHandler + : DatabaseMongoDbMigrationEventHandler, IDistributedEventHandler +{ + public CatalogServiceDatabaseMigrationEventHandler( + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + ITenantStore tenantStore, + IDistributedEventBus distributedEventBus, + IServiceProvider serviceProvider, + IAbpDistributedLock distributedLockProvider + ) : base( + currentTenant, + unitOfWorkManager, + tenantStore, + distributedEventBus, + CatalogServiceDbProperties.ConnectionStringName, + serviceProvider, + distributedLockProvider) { - public CatalogServiceDatabaseMigrationEventHandler( - ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager, - ITenantStore tenantStore, - IDistributedEventBus distributedEventBus, - IServiceProvider serviceProvider - ) : base( - currentTenant, - unitOfWorkManager, - tenantStore, - distributedEventBus, - CatalogServiceDbProperties.ConnectionStringName,serviceProvider) + } + + public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + { + if (eventData.DatabaseName != DatabaseName) { + return; } - public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + if (eventData.TenantId != null) { - if (eventData.DatabaseName != DatabaseName) - { - return; - } + return; + } - if (eventData.TenantId != null) - { - return; - } + try + { + Log.Information("CatalogService has acquired lock for db migration..."); - try + await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName)) { - await MigrateDatabaseSchemaAsync(null); - } - catch (Exception ex) - { - await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); + if (handle != null) + { + Log.Information("CatalogService is migrating database..."); + await MigrateDatabaseSchemaAsync(); + } } } + catch (Exception ex) + { + await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); + } } -} +} \ No newline at end of file diff --git a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/ProductServiceDataSeeder.cs b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/ProductServiceDataSeeder.cs index bb26bf7b..ae74bef7 100644 --- a/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/ProductServiceDataSeeder.cs +++ b/services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/ProductServiceDataSeeder.cs @@ -1,110 +1,108 @@ using System; using System.Threading.Tasks; using EShopOnAbp.CatalogService.Products; -using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.Uow; -namespace EShopOnAbp.CatalogService.DbMigrations +namespace EShopOnAbp.CatalogService.DbMigrations; + +public class ProductServiceDataSeeder : ITransientDependency { - public class ProductServiceDataSeeder : ITransientDependency + private readonly ProductManager _productManager; + private readonly IRepository _productRepository; + + public ProductServiceDataSeeder( + IRepository productRepository, + ProductManager productManager) { - private readonly ProductManager _productManager; - private readonly IRepository _productRepository; + _productRepository = productRepository; + _productManager = productManager; + } - public ProductServiceDataSeeder( - IRepository productRepository, - ProductManager productManager) - { - _productRepository = productRepository; - _productManager = productManager; - } + [UnitOfWork] + public virtual async Task SeedAsync() + { + await AddProductsAsync(); + } - [UnitOfWork] - public virtual async Task SeedAsync() + private async Task AddProductsAsync() + { + if (await _productRepository.GetCountAsync() > 0) { - await AddProductsAsync(); + return; } - private async Task AddProductsAsync() - { - if (await _productRepository.GetCountAsync() > 0) - { - return; - } - - await _productManager.CreateAsync( - "ABP04918", - "Lego Star Wars - 75059 Sandcrawler UCS", - 999, - 42, - "lego.jpg" - ); + await _productManager.CreateAsync( + "ABP04918", + "Lego Star Wars - 75059 Sandcrawler UCS", + 999, + 42, + "lego.jpg" + ); - await _productManager.CreateAsync( - "ABP23849", - "Nikon AF-S 50mm f/1.8 G Lens", - 1499, - 56, - "nikon.jpg" - ); + await _productManager.CreateAsync( + "ABP23849", + "Nikon AF-S 50mm f/1.8 G Lens", + 1499, + 56, + "nikon.jpg" + ); - await _productManager.CreateAsync( - "ABP82731", - "Beats Solo3 Wireless On-Ear Headphone", - 97, - 20, - "beats.jpg" - ); + await _productManager.CreateAsync( + "ABP82731", + "Beats Solo3 Wireless On-Ear Headphone", + 97, + 20, + "beats.jpg" + ); - await _productManager.CreateAsync( - "ABP12322", - "Rampage Sn-Rw2 Gamer Headphone", - 654, - 42, - "rampage.jpg" - ); + await _productManager.CreateAsync( + "ABP12322", + "Rampage Sn-Rw2 Gamer Headphone", + 654, + 42, + "rampage.jpg" + ); - await _productManager.CreateAsync( - "ABP00291", - "Asus Transformer Book T300CHI-FH011H", - 1249, - 3, - "asus.jpg" - ); + await _productManager.CreateAsync( + "ABP00291", + "Asus Transformer Book T300CHI-FH011H", + 1249, + 3, + "asus.jpg" + ); - await _productManager.CreateAsync( - "ABP02918", - "OKI C332DN Dublex + Network A4 Laser Printer", - 215, - 6, - "oki.jpg" - ); + await _productManager.CreateAsync( + "ABP02918", + "OKI C332DN Dublex + Network A4 Laser Printer", + 215, + 6, + "oki.jpg" + ); - await _productManager.CreateAsync( - "ABP11121", - "Bluecat Rd810 Mini Led", - 449, - 13, - "bluecat.jpg" - ); + await _productManager.CreateAsync( + "ABP11121", + "Bluecat Rd810 Mini Led", + 449, + 13, + "bluecat.jpg" + ); - await _productManager.CreateAsync( - "ABP44432", - "Sunny 55\" TV 4K Ultra HD Curved Smart Led TV", - 2249, - 1, - "sunny.jpg" - ); + await _productManager.CreateAsync( + "ABP44432", + "Sunny 55\" TV 4K Ultra HD Curved Smart Led TV", + 2249, + 1, + "sunny.jpg" + ); - await _productManager.CreateAsync( - "ABP37182", - "Sony Playstation 4 Slim 500 GB (PAL)", - 699, - 120, - "playstation.jpg" - ); - } + await _productManager.CreateAsync( + "ABP37182", + "Sony Playstation 4 Slim 500 GB (PAL)", + 699, + 120, + "playstation.jpg" + ); } -} +} \ No newline at end of file diff --git a/services/catalog/src/EShopOnAbp.CatalogService.MongoDB/MongoDB/CatalogServiceMongoDbContext.cs b/services/catalog/src/EShopOnAbp.CatalogService.MongoDB/MongoDB/CatalogServiceMongoDbContext.cs index 3e7570b4..c82af0c6 100644 --- a/services/catalog/src/EShopOnAbp.CatalogService.MongoDB/MongoDB/CatalogServiceMongoDbContext.cs +++ b/services/catalog/src/EShopOnAbp.CatalogService.MongoDB/MongoDB/CatalogServiceMongoDbContext.cs @@ -8,7 +8,7 @@ namespace EShopOnAbp.CatalogService.MongoDB [ConnectionStringName(CatalogServiceDbProperties.ConnectionStringName)] public class CatalogServiceMongoDbContext : AbpMongoDbContext, ICatalogServiceMongoDbContext { - public IMongoCollection Questions => Collection(); + public IMongoCollection Products => Collection(); protected override void CreateModel(IMongoModelBuilder modelBuilder) { diff --git a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/Controllers/HomeController.cs b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/Controllers/HomeController.cs index 897474e3..67742d40 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/Controllers/HomeController.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/Controllers/HomeController.cs @@ -1,13 +1,12 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; -namespace EShopOnAbp.IdentityService.Controllers +namespace EShopOnAbp.IdentityService.Controllers; + +public class HomeController : AbpController { - public class HomeController : AbpController + public ActionResult Index() { - public ActionResult Index() - { - return Redirect("~/swagger"); - } + return Redirect("~/swagger"); } -} +} \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/ApplyDatabaseSeedsEto.cs b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/ApplyDatabaseSeedsEto.cs index b32fde33..7dccb6a5 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/ApplyDatabaseSeedsEto.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/ApplyDatabaseSeedsEto.cs @@ -1,10 +1,9 @@ using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus; -namespace EShopOnAbp.IdentityService.DbMigrations +namespace EShopOnAbp.IdentityService.DbMigrations; + +[EventName("abp.identity.apply_database_seeds")] +public class ApplyDatabaseSeedsEto : EtoBase { - [EventName("abp.identity.apply_database_seeds")] - public class ApplyDatabaseSeedsEto : EtoBase - { - } -} +} \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/DataSeederEventHandler.cs b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/DataSeederEventHandler.cs index 3bf1d3f4..8160d222 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/DataSeederEventHandler.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/DataSeederEventHandler.cs @@ -1,23 +1,21 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus; -namespace EShopOnAbp.IdentityService.DbMigrations +namespace EShopOnAbp.IdentityService.DbMigrations; + +public class DataSeederEventHandler : ILocalEventHandler, ITransientDependency { - public class DataSeederEventHandler : ILocalEventHandler, ITransientDependency - { - protected IDataSeeder DataSeeder { get; } + protected IDataSeeder DataSeeder { get; } - public DataSeederEventHandler(IDataSeeder dataSeeder) - { - DataSeeder = dataSeeder; - } + public DataSeederEventHandler(IDataSeeder dataSeeder) + { + DataSeeder = dataSeeder; + } - public async Task HandleEventAsync(ApplyDatabaseSeedsEto eventData) - { - await DataSeeder.SeedAsync(); - } + public async Task HandleEventAsync(ApplyDatabaseSeedsEto eventData) + { + await DataSeeder.SeedAsync(); } -} +} \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs index 112f72d0..a77a7bd9 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs @@ -20,381 +20,381 @@ using ApiResource = Volo.Abp.IdentityServer.ApiResources.ApiResource; using ApiScope = Volo.Abp.IdentityServer.ApiScopes.ApiScope; using Client = Volo.Abp.IdentityServer.Clients.Client; -namespace EShopOnAbp.IdentityService.DbMigrations +namespace EShopOnAbp.IdentityService.DbMigrations; + +public class IdentityServerDataSeeder : IDataSeedContributor, ITransientDependency { - public class IdentityServerDataSeeder : IDataSeedContributor, ITransientDependency + private readonly IApiResourceRepository _apiResourceRepository; + private readonly IApiScopeRepository _apiScopeRepository; + private readonly IClientRepository _clientRepository; + private readonly IIdentityResourceDataSeeder _identityResourceDataSeeder; + private readonly IGuidGenerator _guidGenerator; + private readonly IPermissionDataSeeder _permissionDataSeeder; + private readonly IConfiguration _configuration; + private readonly ICurrentTenant _currentTenant; + + public IdentityServerDataSeeder( + IClientRepository clientRepository, + IApiResourceRepository apiResourceRepository, + IApiScopeRepository apiScopeRepository, + IIdentityResourceDataSeeder identityResourceDataSeeder, + IGuidGenerator guidGenerator, + IPermissionDataSeeder permissionDataSeeder, + IConfiguration configuration, + ICurrentTenant currentTenant) { - private readonly IApiResourceRepository _apiResourceRepository; - private readonly IApiScopeRepository _apiScopeRepository; - private readonly IClientRepository _clientRepository; - private readonly IIdentityResourceDataSeeder _identityResourceDataSeeder; - private readonly IGuidGenerator _guidGenerator; - private readonly IPermissionDataSeeder _permissionDataSeeder; - private readonly IConfiguration _configuration; - private readonly ICurrentTenant _currentTenant; + _clientRepository = clientRepository; + _apiResourceRepository = apiResourceRepository; + _apiScopeRepository = apiScopeRepository; + _identityResourceDataSeeder = identityResourceDataSeeder; + _guidGenerator = guidGenerator; + _permissionDataSeeder = permissionDataSeeder; + _configuration = configuration; + _currentTenant = currentTenant; + } - public IdentityServerDataSeeder( - IClientRepository clientRepository, - IApiResourceRepository apiResourceRepository, - IApiScopeRepository apiScopeRepository, - IIdentityResourceDataSeeder identityResourceDataSeeder, - IGuidGenerator guidGenerator, - IPermissionDataSeeder permissionDataSeeder, - IConfiguration configuration, - ICurrentTenant currentTenant) - { - _clientRepository = clientRepository; - _apiResourceRepository = apiResourceRepository; - _apiScopeRepository = apiScopeRepository; - _identityResourceDataSeeder = identityResourceDataSeeder; - _guidGenerator = guidGenerator; - _permissionDataSeeder = permissionDataSeeder; - _configuration = configuration; - _currentTenant = currentTenant; - } + public virtual Task SeedAsync(DataSeedContext context) + { + return SeedAsync(); + } - public virtual Task SeedAsync(DataSeedContext context) + [UnitOfWork] + public virtual async Task SeedAsync() + { + using (_currentTenant.Change(null)) { - return SeedAsync(); + await _identityResourceDataSeeder.CreateStandardResourcesAsync(); + await CreateApiResourcesAsync(); + await CreateApiScopesAsync(); + await CreateSwaggerClientsAsync(); + await CreateClientsAsync(); } + } - [UnitOfWork] - public virtual async Task SeedAsync() + private async Task CreateApiResourcesAsync() + { + var commonApiUserClaims = new[] { - using (_currentTenant.Change(null)) - { - await _identityResourceDataSeeder.CreateStandardResourcesAsync(); - await CreateApiResourcesAsync(); - await CreateApiScopesAsync(); - await CreateSwaggerClientsAsync(); - await CreateClientsAsync(); - } - } + "email", + "email_verified", + "name", + "phone_number", + "phone_number_verified", + "role" + }; - private async Task CreateApiResourcesAsync() - { - var commonApiUserClaims = new[] - { - "email", - "email_verified", - "name", - "phone_number", - "phone_number_verified", - "role" - }; + await CreateApiResourceAsync("AccountService", commonApiUserClaims); + await CreateApiResourceAsync("IdentityService", commonApiUserClaims); + await CreateApiResourceAsync("AdministrationService", commonApiUserClaims); + await CreateApiResourceAsync("CatalogService", commonApiUserClaims); + await CreateApiResourceAsync("BasketService", commonApiUserClaims); + await CreateApiResourceAsync("OrderingService", commonApiUserClaims); + await CreateApiResourceAsync("PaymentService", commonApiUserClaims); + } - await CreateApiResourceAsync("AccountService", commonApiUserClaims); - await CreateApiResourceAsync("IdentityService", commonApiUserClaims); - await CreateApiResourceAsync("AdministrationService", commonApiUserClaims); - await CreateApiResourceAsync("CatalogService", commonApiUserClaims); - await CreateApiResourceAsync("BasketService", commonApiUserClaims); - await CreateApiResourceAsync("OrderingService", commonApiUserClaims); - await CreateApiResourceAsync("PaymentService", commonApiUserClaims); - } + private async Task CreateApiScopesAsync() + { + await CreateApiScopeAsync("AccountService"); + await CreateApiScopeAsync("IdentityService"); + await CreateApiScopeAsync("AdministrationService"); + await CreateApiScopeAsync("CatalogService"); + await CreateApiScopeAsync("BasketService"); + await CreateApiScopeAsync("OrderingService"); + await CreateApiScopeAsync("PaymentService"); + } + + private async Task CreateSwaggerClientsAsync() + { + await CreateWebGatewaySwaggerClientAsync("WebGateway", + new[] + { + "AccountService", "IdentityService", "AdministrationService", + "CatalogService", "BasketService", + "PaymentService", "OrderingService" + }); + } - private async Task CreateApiScopesAsync() + private async Task CreateWebGatewaySwaggerClientAsync(string name, string[] scopes = null) + { + var commonScopes = new[] { - await CreateApiScopeAsync("AccountService"); - await CreateApiScopeAsync("IdentityService"); - await CreateApiScopeAsync("AdministrationService"); - await CreateApiScopeAsync("CatalogService"); - await CreateApiScopeAsync("BasketService"); - await CreateApiScopeAsync("OrderingService"); - await CreateApiScopeAsync("PaymentService"); - } + "email", + "openid", + "profile", + "role", + "phone", + "address" + }; + scopes ??= new[] {name}; - private async Task CreateSwaggerClientsAsync() + // Swagger Client + var swaggerClientId = $"{name}_Swagger"; + if (!swaggerClientId.IsNullOrWhiteSpace()) { - await CreateWebGatewaySwaggerClientAsync("WebGateway", - new[] + var webGatewaySwaggerRootUrl = _configuration[$"IdentityServerClients:{name}:RootUrl"].TrimEnd('/'); + var publicWebGatewayRootUrl = _configuration[$"IdentityServerClients:PublicWebGateway:RootUrl"].TrimEnd('/'); + var accountServiceRootUrl = _configuration[$"IdentityServerClients:AccountService:RootUrl"].TrimEnd('/'); + var identityServiceRootUrl = _configuration[$"IdentityServerClients:IdentityService:RootUrl"].TrimEnd('/'); + var administrationServiceRootUrl = _configuration[$"IdentityServerClients:AdministrationService:RootUrl"].TrimEnd('/'); + var catalogServiceRootUrl = _configuration[$"IdentityServerClients:CatalogService:RootUrl"].TrimEnd('/'); + var basketServiceRootUrl = _configuration[$"IdentityServerClients:BasketService:RootUrl"].TrimEnd('/'); + var orderingServiceRootUrl = _configuration[$"IdentityServerClients:OrderingService:RootUrl"].TrimEnd('/'); + var paymentServiceRootUrl = _configuration[$"IdentityServerClients:PaymentService:RootUrl"].TrimEnd('/'); + + await CreateClientAsync( + name: swaggerClientId, + scopes: commonScopes.Union(scopes), + grantTypes: new[] {"authorization_code"}, + secret: "1q2w3e*".Sha256(), + requireClientSecret: false, + redirectUris: new List + { + $"{webGatewaySwaggerRootUrl}/swagger/oauth2-redirect.html", // WebGateway redirect uri + $"{publicWebGatewayRootUrl}/swagger/oauth2-redirect.html", // PublicWebGateway redirect uri + $"{accountServiceRootUrl}/swagger/oauth2-redirect.html", // AccountService redirect uri + $"{identityServiceRootUrl}/swagger/oauth2-redirect.html", // IdentityService redirect uri + $"{administrationServiceRootUrl}/swagger/oauth2-redirect.html", // AdministrationService redirect uri + $"{catalogServiceRootUrl}/swagger/oauth2-redirect.html", // CatalogService redirect uri + $"{basketServiceRootUrl}/swagger/oauth2-redirect.html", // BasketService redirect uri + $"{orderingServiceRootUrl}/swagger/oauth2-redirect.html", // OrderingService redirect uri + $"{paymentServiceRootUrl}/swagger/oauth2-redirect.html" // PaymentService redirect uri + }, + corsOrigins: new[] { - "AccountService", "IdentityService", "AdministrationService", - "CatalogService", "BasketService", - "PaymentService", "OrderingService" - }); + webGatewaySwaggerRootUrl.RemovePostFix("/"), + publicWebGatewayRootUrl.RemovePostFix("/"), + accountServiceRootUrl.RemovePostFix("/"), + identityServiceRootUrl.RemovePostFix("/"), + administrationServiceRootUrl.RemovePostFix("/"), + catalogServiceRootUrl.RemovePostFix("/"), + basketServiceRootUrl.RemovePostFix("/"), + orderingServiceRootUrl.RemovePostFix("/"), + paymentServiceRootUrl.RemovePostFix("/") + } + ); } + } - private async Task CreateWebGatewaySwaggerClientAsync(string name, string[] scopes = null) + private async Task CreateApiResourceAsync(string name, IEnumerable claims) + { + var apiResource = await _apiResourceRepository.FindByNameAsync(name); + if (apiResource == null) { - var commonScopes = new[] - { - "email", - "openid", - "profile", - "role", - "phone", - "address" - }; - scopes ??= new[] {name}; - - // Swagger Client - var swaggerClientId = $"{name}_Swagger"; - if (!swaggerClientId.IsNullOrWhiteSpace()) - { - var webGatewaySwaggerRootUrl = _configuration[$"IdentityServerClients:{name}:RootUrl"].TrimEnd('/'); - var publicWebGatewayRootUrl = _configuration[$"IdentityServerClients:PublicWebGateway:RootUrl"].TrimEnd('/'); - var accountServiceRootUrl = _configuration[$"IdentityServerClients:AccountService:RootUrl"].TrimEnd('/'); - var identityServiceRootUrl = _configuration[$"IdentityServerClients:IdentityService:RootUrl"].TrimEnd('/'); - var administrationServiceRootUrl = _configuration[$"IdentityServerClients:AdministrationService:RootUrl"].TrimEnd('/'); - var catalogServiceRootUrl = _configuration[$"IdentityServerClients:CatalogService:RootUrl"].TrimEnd('/'); - var basketServiceRootUrl = _configuration[$"IdentityServerClients:BasketService:RootUrl"].TrimEnd('/'); - var orderingServiceRootUrl = _configuration[$"IdentityServerClients:OrderingService:RootUrl"].TrimEnd('/'); - var paymentServiceRootUrl = _configuration[$"IdentityServerClients:PaymentService:RootUrl"].TrimEnd('/'); - - await CreateClientAsync( - name: swaggerClientId, - scopes: commonScopes.Union(scopes), - grantTypes: new[] {"authorization_code"}, - secret: "1q2w3e*".Sha256(), - requireClientSecret: false, - redirectUris: new List - { - $"{webGatewaySwaggerRootUrl}/swagger/oauth2-redirect.html", // WebGateway redirect uri - $"{publicWebGatewayRootUrl}/swagger/oauth2-redirect.html", // PublicWebGateway redirect uri - $"{accountServiceRootUrl}/swagger/oauth2-redirect.html", // AccountService redirect uri - $"{identityServiceRootUrl}/swagger/oauth2-redirect.html", // IdentityService redirect uri - $"{administrationServiceRootUrl}/swagger/oauth2-redirect.html", // AdministrationService redirect uri - $"{catalogServiceRootUrl}/swagger/oauth2-redirect.html", // CatalogService redirect uri - $"{basketServiceRootUrl}/swagger/oauth2-redirect.html", // BasketService redirect uri - $"{orderingServiceRootUrl}/swagger/oauth2-redirect.html", // OrderingService redirect uri - $"{paymentServiceRootUrl}/swagger/oauth2-redirect.html" // PaymentService redirect uri - }, - corsOrigins: new[] - { - webGatewaySwaggerRootUrl.RemovePostFix("/"), - publicWebGatewayRootUrl.RemovePostFix("/"), - accountServiceRootUrl.RemovePostFix("/"), - identityServiceRootUrl.RemovePostFix("/"), - administrationServiceRootUrl.RemovePostFix("/"), - catalogServiceRootUrl.RemovePostFix("/"), - basketServiceRootUrl.RemovePostFix("/"), - orderingServiceRootUrl.RemovePostFix("/"), - paymentServiceRootUrl.RemovePostFix("/") - } - ); - } + apiResource = await _apiResourceRepository.InsertAsync( + new ApiResource( + _guidGenerator.Create(), + name, + name + " API" + ), + autoSave: true + ); } - private async Task CreateApiResourceAsync(string name, IEnumerable claims) + foreach (var claim in claims) { - var apiResource = await _apiResourceRepository.FindByNameAsync(name); - if (apiResource == null) + if (apiResource.FindClaim(claim) == null) { - apiResource = await _apiResourceRepository.InsertAsync( - new ApiResource( - _guidGenerator.Create(), - name, - name + " API" - ), - autoSave: true - ); - } - - foreach (var claim in claims) - { - if (apiResource.FindClaim(claim) == null) - { - apiResource.AddUserClaim(claim); - } + apiResource.AddUserClaim(claim); } - - return await _apiResourceRepository.UpdateAsync(apiResource); } - private async Task CreateApiScopeAsync(string name) - { - var apiScope = await _apiScopeRepository.FindByNameAsync(name); - if (apiScope == null) - { - apiScope = await _apiScopeRepository.InsertAsync( - new ApiScope( - _guidGenerator.Create(), - name, - name + " API" - ), - autoSave: true - ); - } + return await _apiResourceRepository.UpdateAsync(apiResource); + } - return apiScope; + private async Task CreateApiScopeAsync(string name) + { + var apiScope = await _apiScopeRepository.FindByNameAsync(name); + if (apiScope == null) + { + apiScope = await _apiScopeRepository.InsertAsync( + new ApiScope( + _guidGenerator.Create(), + name, + name + " API" + ), + autoSave: true + ); } - private async Task CreateClientsAsync() + return apiScope; + } + + private async Task CreateClientsAsync() + { + var commonScopes = new[] { - var commonScopes = new[] + "email", + "openid", + "profile", + "role", + "phone", + "address" + }; + + //Public Web Client + var publicWebClientRootUrl = _configuration["IdentityServerClients:PublicWeb:RootUrl"] + .EnsureEndsWith('/'); + await CreateClientAsync( + name: "PublicWeb", + scopes: commonScopes.Union(new[] { - "email", - "openid", - "profile", - "role", - "phone", - "address" - }; + "AccountService", + "AdministrationService", + "CatalogService", + "BasketService", + "PaymentService", + "OrderingService" + }), + grantTypes: new[] {"hybrid"}, + secret: "1q2w3e*".Sha256(), + redirectUris: new List{ $"{publicWebClientRootUrl}signin-oidc" }, + postLogoutRedirectUri: $"{publicWebClientRootUrl}signout-callback-oidc", + frontChannelLogoutUri: $"{publicWebClientRootUrl}Account/FrontChannelLogout", + corsOrigins: new[] {publicWebClientRootUrl.RemovePostFix("/")} + ); - //Public Web Client - var publicWebClientRootUrl = _configuration["IdentityServerClients:PublicWeb:RootUrl"] - .EnsureEndsWith('/'); - await CreateClientAsync( - name: "PublicWeb", - scopes: commonScopes.Union(new[] - { - "AccountService", - "AdministrationService", - "CatalogService", - "BasketService", - "PaymentService", - "OrderingService" - }), - grantTypes: new[] {"hybrid"}, - secret: "1q2w3e*".Sha256(), - redirectUris: new List{ $"{publicWebClientRootUrl}signin-oidc" }, - postLogoutRedirectUri: $"{publicWebClientRootUrl}signout-callback-oidc", - frontChannelLogoutUri: $"{publicWebClientRootUrl}Account/FrontChannelLogout", - corsOrigins: new[] {publicWebClientRootUrl.RemovePostFix("/")} - ); + //Angular Client + var angularClientRootUrl = + _configuration["IdentityServerClients:Web:RootUrl"].TrimEnd('/'); + await CreateClientAsync( + name: "Web", + scopes: commonScopes.Union(new[] + { + "AccountService", + "IdentityService", + "AdministrationService", + "CatalogService", + "OrderingService" + }), + grantTypes: new[] {"authorization_code", "LinkLogin", "password"}, + secret: "1q2w3e*".Sha256(), + requirePkce: true, + requireClientSecret: false, + redirectUris: new List{ $"{angularClientRootUrl}" }, + postLogoutRedirectUri: $"{angularClientRootUrl}", + corsOrigins: new[] {angularClientRootUrl} + ); - //Angular Client - var angularClientRootUrl = - _configuration["IdentityServerClients:Web:RootUrl"].TrimEnd('/'); - await CreateClientAsync( - name: "Web", - scopes: commonScopes.Union(new[] - { - "AccountService", - "IdentityService", - "AdministrationService", - "CatalogService" - }), - grantTypes: new[] {"authorization_code", "LinkLogin", "password"}, - secret: "1q2w3e*".Sha256(), - requirePkce: true, - requireClientSecret: false, - redirectUris: new List{ $"{angularClientRootUrl}" }, - postLogoutRedirectUri: $"{angularClientRootUrl}", - corsOrigins: new[] {angularClientRootUrl} - ); + //Administration Service Client + await CreateClientAsync( + name: "EShopOnAbp_AdministrationService", + scopes: commonScopes.Union(new[] + { + "IdentityService" + }), + grantTypes: new[] {"client_credentials"}, + secret: "1q2w3e*".Sha256(), + permissions: new[] {IdentityPermissions.Users.Default} + ); + } - //Administration Service Client - await CreateClientAsync( - name: "EShopOnAbp_AdministrationService", - scopes: commonScopes.Union(new[] + private async Task CreateClientAsync( + string name, + IEnumerable scopes, + IEnumerable grantTypes, + string secret = null, + List redirectUris = null, + string postLogoutRedirectUri = null, + string frontChannelLogoutUri = null, + bool requireClientSecret = true, + bool requirePkce = false, + IEnumerable permissions = null, + IEnumerable corsOrigins = null) + { + var client = await _clientRepository.FindByClientIdAsync(name); + if (client == null) + { + client = await _clientRepository.InsertAsync( + new Client( + _guidGenerator.Create(), + name + ) { - "IdentityService" - }), - grantTypes: new[] {"client_credentials"}, - secret: "1q2w3e*".Sha256(), - permissions: new[] {IdentityPermissions.Users.Default} + ClientName = name, + ProtocolType = "oidc", + Description = name, + AlwaysIncludeUserClaimsInIdToken = true, + AllowOfflineAccess = true, + AbsoluteRefreshTokenLifetime = 31536000, //365 days + AccessTokenLifetime = 31536000, //365 days + AuthorizationCodeLifetime = 300, + IdentityTokenLifetime = 300, + RequireConsent = false, + FrontChannelLogoutUri = frontChannelLogoutUri, + RequireClientSecret = requireClientSecret, + RequirePkce = requirePkce + }, + autoSave: true ); } - private async Task CreateClientAsync( - string name, - IEnumerable scopes, - IEnumerable grantTypes, - string secret = null, - List redirectUris = null, - string postLogoutRedirectUri = null, - string frontChannelLogoutUri = null, - bool requireClientSecret = true, - bool requirePkce = false, - IEnumerable permissions = null, - IEnumerable corsOrigins = null) + foreach (var scope in scopes) { - var client = await _clientRepository.FindByClientIdAsync(name); - if (client == null) + if (client.FindScope(scope) == null) { - client = await _clientRepository.InsertAsync( - new Client( - _guidGenerator.Create(), - name - ) - { - ClientName = name, - ProtocolType = "oidc", - Description = name, - AlwaysIncludeUserClaimsInIdToken = true, - AllowOfflineAccess = true, - AbsoluteRefreshTokenLifetime = 31536000, //365 days - AccessTokenLifetime = 31536000, //365 days - AuthorizationCodeLifetime = 300, - IdentityTokenLifetime = 300, - RequireConsent = false, - FrontChannelLogoutUri = frontChannelLogoutUri, - RequireClientSecret = requireClientSecret, - RequirePkce = requirePkce - }, - autoSave: true - ); - } - - foreach (var scope in scopes) - { - if (client.FindScope(scope) == null) - { - client.AddScope(scope); - } + client.AddScope(scope); } + } - foreach (var grantType in grantTypes) + foreach (var grantType in grantTypes) + { + if (client.FindGrantType(grantType) == null) { - if (client.FindGrantType(grantType) == null) - { - client.AddGrantType(grantType); - } + client.AddGrantType(grantType); } + } - if (!secret.IsNullOrEmpty()) + if (!secret.IsNullOrEmpty()) + { + if (client.FindSecret(secret) == null) { - if (client.FindSecret(secret) == null) - { - client.AddSecret(secret); - } + client.AddSecret(secret); } + } - if (redirectUris != null) + if (redirectUris != null) + { + foreach (var redirectUri in redirectUris) { - foreach (var redirectUri in redirectUris) + if (redirectUri != null) { - if (redirectUri != null) + if (client.FindRedirectUri(redirectUri) == null) { - if (client.FindRedirectUri(redirectUri) == null) - { - client.AddRedirectUri(redirectUri); - } + client.AddRedirectUri(redirectUri); } } } + } - if (postLogoutRedirectUri != null) + if (postLogoutRedirectUri != null) + { + if (client.FindPostLogoutRedirectUri(postLogoutRedirectUri) == null) { - if (client.FindPostLogoutRedirectUri(postLogoutRedirectUri) == null) - { - client.AddPostLogoutRedirectUri(postLogoutRedirectUri); - } + client.AddPostLogoutRedirectUri(postLogoutRedirectUri); } + } - if (permissions != null) - { - await _permissionDataSeeder.SeedAsync( - ClientPermissionValueProvider.ProviderName, - name, - permissions, - null - ); - } + if (permissions != null) + { + await _permissionDataSeeder.SeedAsync( + ClientPermissionValueProvider.ProviderName, + name, + permissions, + null + ); + } - if (corsOrigins != null) + if (corsOrigins != null) + { + foreach (var origin in corsOrigins) { - foreach (var origin in corsOrigins) + if (!origin.IsNullOrWhiteSpace() && client.FindCorsOrigin(origin) == null) { - if (!origin.IsNullOrWhiteSpace() && client.FindCorsOrigin(origin) == null) - { - client.AddCorsOrigin(origin); - } + client.AddCorsOrigin(origin); } } - - return await _clientRepository.UpdateAsync(client); } + + return await _clientRepository.UpdateAsync(client); } } \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationChecker.cs b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationChecker.cs index 75c16423..29bdd116 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationChecker.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationChecker.cs @@ -7,38 +7,37 @@ using Volo.Abp.EventBus.Local; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.IdentityService.DbMigrations +namespace EShopOnAbp.IdentityService.DbMigrations; + +public class IdentityServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker { - public class IdentityServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker + protected ILocalEventBus LocalEventBus { get; } + + public IdentityServiceDatabaseMigrationChecker( + IUnitOfWorkManager unitOfWorkManager, + IServiceProvider serviceProvider, + ICurrentTenant currentTenant, + IDistributedEventBus distributedEventBus, + ILocalEventBus localEventBus) + : base( + unitOfWorkManager, + serviceProvider, + currentTenant, + distributedEventBus, + IdentityServiceDbProperties.ConnectionStringName) { - protected ILocalEventBus LocalEventBus { get; } + LocalEventBus = localEventBus; + } - public IdentityServiceDatabaseMigrationChecker( - IUnitOfWorkManager unitOfWorkManager, - IServiceProvider serviceProvider, - ICurrentTenant currentTenant, - IDistributedEventBus distributedEventBus, - ILocalEventBus localEventBus) - : base( - unitOfWorkManager, - serviceProvider, - currentTenant, - distributedEventBus, - IdentityServiceDbProperties.ConnectionStringName) - { - LocalEventBus = localEventBus; - } + public override async Task CheckAsync() + { + var isMigrationRequired = await base.CheckAsync(); - public override async Task CheckAsync() + if (!isMigrationRequired) { - var isMigrationRequired = await base.CheckAsync(); - - if (!isMigrationRequired) - { - await LocalEventBus.PublishAsync(new ApplyDatabaseSeedsEto()); - } - - return isMigrationRequired; + await LocalEventBus.PublishAsync(new ApplyDatabaseSeedsEto()); } + + return isMigrationRequired; } } \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationEventHandler.cs b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationEventHandler.cs index 17d8dd98..e879ea3a 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationEventHandler.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationEventHandler.cs @@ -1,104 +1,90 @@ using EShopOnAbp.IdentityService.EntityFrameworkCore; +using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; using Serilog; using System; -using System.Collections.Generic; using System.Threading.Tasks; -using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; using Volo.Abp.Data; +using Volo.Abp.DistributedLocking; using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Local; using Volo.Abp.Identity; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.IdentityService.DbMigrations +namespace EShopOnAbp.IdentityService.DbMigrations; + +public class IdentityServiceDatabaseMigrationEventHandler + : DatabaseEfCoreMigrationEventHandler, + IDistributedEventHandler { - public class IdentityServiceDatabaseMigrationEventHandler - : DatabaseEfCoreMigrationEventHandler, - IDistributedEventHandler, - IDistributedEventHandler + private readonly IIdentityDataSeeder _identityDataSeeder; + private readonly IdentityServerDataSeeder _identityServerDataSeeder; + private readonly ILocalEventBus _localEventBus; + + public IdentityServiceDatabaseMigrationEventHandler( + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + ITenantStore tenantStore, + IIdentityDataSeeder identityDataSeeder, + IdentityServerDataSeeder identityServerDataSeeder, + IDistributedEventBus distributedEventBus, + ILocalEventBus localEventBus, + IAbpDistributedLock distributedLockProvider + ) : base( + currentTenant, + unitOfWorkManager, + tenantStore, + distributedEventBus, + IdentityServiceDbProperties.ConnectionStringName, + distributedLockProvider) { - private readonly IIdentityDataSeeder _identityDataSeeder; - private readonly IdentityServerDataSeeder _identityServerDataSeeder; - private readonly ILocalEventBus _localEventBus; + _identityDataSeeder = identityDataSeeder; + _identityServerDataSeeder = identityServerDataSeeder; + _localEventBus = localEventBus; + } - public IdentityServiceDatabaseMigrationEventHandler( - ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager, - ITenantStore tenantStore, - IIdentityDataSeeder identityDataSeeder, - IdentityServerDataSeeder identityServerDataSeeder, - IDistributedEventBus distributedEventBus, - ILocalEventBus localEventBus - ) : base( - currentTenant, - unitOfWorkManager, - tenantStore, - distributedEventBus, - IdentityServiceDbProperties.ConnectionStringName) + public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + { + if (eventData.DatabaseName != DatabaseName) { - _identityDataSeeder = identityDataSeeder; - _identityServerDataSeeder = identityServerDataSeeder; - _localEventBus = localEventBus; + return; } - public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + try { - if (eventData.DatabaseName != DatabaseName) - { - return; - } - - try + await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName)) { - var schemaMigrated = await MigrateDatabaseSchemaAsync(eventData.TenantId); - await SeedDataAsync( - tenantId: eventData.TenantId, - adminEmail: IdentityServiceDbProperties.DefaultAdminEmailAddress, - adminPassword: IdentityServiceDbProperties.DefaultAdminPassword - ); + Log.Information("IdentityService has acquired lock for db migration..."); - await _localEventBus.PublishAsync(new ApplyDatabaseSeedsEto()); - } - catch (Exception ex) - { - await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); + if (handle != null) + { + Log.Information("IdentityService is migrating database..."); + await MigrateDatabaseSchemaAsync(); + Log.Information("IdentityService is seeding data..."); + await SeedDataAsync( + adminEmail: IdentityServiceDbProperties.DefaultAdminEmailAddress, + adminPassword: IdentityServiceDbProperties.DefaultAdminPassword + ); + } } + await _localEventBus.PublishAsync(new ApplyDatabaseSeedsEto()); } - - public async Task HandleEventAsync(TenantCreatedEto eventData) - { - try - { - await MigrateDatabaseSchemaAsync(eventData.Id); - await SeedDataAsync( - tenantId: eventData.Id, - adminEmail: eventData.Properties.GetOrDefault(IdentityDataSeedContributor.AdminEmailPropertyName) ?? IdentityServiceDbProperties.DefaultAdminEmailAddress, - adminPassword: eventData.Properties.GetOrDefault(IdentityDataSeedContributor.AdminPasswordPropertyName) ?? IdentityServiceDbProperties.DefaultAdminPassword - ); - } - catch (Exception ex) - { - await HandleErrorTenantCreatedAsync(eventData, ex); - } - } - private async Task SeedDataAsync(Guid? tenantId, string adminEmail, string adminPassword) + catch (Exception ex) { - using (CurrentTenant.Change(tenantId)) - { - if (tenantId == null) - { - Log.Information($"Seeding IdentityServer data..."); - await _identityServerDataSeeder.SeedAsync(); - } - Log.Information($"Seeding user data..."); - await _identityDataSeeder.SeedAsync( - adminEmail, - adminPassword, - tenantId - ); - } + await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); } } -} + + private async Task SeedDataAsync(string adminEmail, string adminPassword) + { + Log.Information($"Seeding IdentityServer data..."); + await _identityServerDataSeeder.SeedAsync(); + + Log.Information($"Seeding user data..."); + await _identityDataSeeder.SeedAsync( + adminEmail, + adminPassword + ); + } +} \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/IdentityServiceHttpApiHostModule.cs b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/IdentityServiceHttpApiHostModule.cs index 5fbed800..ddffb7a5 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/IdentityServiceHttpApiHostModule.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/IdentityServiceHttpApiHostModule.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using EShopOnAbp.IdentityService.DbMigrations; using EShopOnAbp.IdentityService.EntityFrameworkCore; using EShopOnAbp.Shared.Hosting.AspNetCore; @@ -12,9 +8,12 @@ using Microsoft.AspNetCore.Cors; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Modularity; -using Volo.Abp.Threading; namespace EShopOnAbp.IdentityService; diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs b/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs index 29ca1943..8c0bdadd 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs @@ -6,10 +6,9 @@ namespace EShopOnAbp.OrderingService.Orders; public class OrderDto : EntityDto { - public DateTime OrderDate { get; set; } - public int OrderNo {get;set;} - public int OrderStatusId { get; set; } - public string OrderStatus { get; set; } + public DateTime OrderDate { get; set; } + public int OrderNo { get; set; } + public OrderStatus OrderStatus { get; set; } public string PaymentMethod { get; set; } public BuyerDto Buyer { get; set; } public OrderAddressDto Address { get; set; } = new(); diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs b/services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs index 19c0701a..d39b0a15 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using EShopOnAbp.OrderingService.Localization; +using EShopOnAbp.OrderingService.Localization; using EShopOnAbp.OrderingService.Orders.Specifications; using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp.Application.Services; using Volo.Abp.Specifications; using Volo.Abp.Users; @@ -34,9 +34,9 @@ public class OrderAppService : ApplicationService, IOrderAppService public async Task> GetMyOrdersAsync(GetMyOrdersInput input) { ISpecification specification = SpecificationFactory.Create(input.Filter); - + var orders = await _orderRepository.GetOrdersByUserId(CurrentUser.GetId(), specification, true); - + return CreateOrderDtoMapping(orders); } @@ -106,8 +106,7 @@ public class OrderAppService : ApplicationService, IOrderAppService Id = order.Id, OrderNo = order.OrderNo, OrderDate = order.OrderDate, - OrderStatus = order.OrderStatus.Name, - OrderStatusId = order.OrderStatus.Id, + OrderStatus = order.OrderStatus, PaymentMethod = order.PaymentMethod }; } diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderStatus.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderStatus.cs new file mode 100644 index 00000000..b3f464d2 --- /dev/null +++ b/services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderStatus.cs @@ -0,0 +1,9 @@ +namespace EShopOnAbp.OrderingService.Orders; + +public enum OrderStatus +{ + Placed, + Paid, + Shipped, + Cancelled +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs index 989208a0..8e159007 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs @@ -1,8 +1,8 @@ -using System; +using EShopOnAbp.PaymentService.PaymentRequests; +using JetBrains.Annotations; +using System; using System.Collections.Generic; using System.Linq; -using EShopOnAbp.PaymentService.PaymentRequests; -using JetBrains.Annotations; using Volo.Abp; using Volo.Abp.Domain.Entities; @@ -10,7 +10,6 @@ namespace EShopOnAbp.OrderingService.Orders; public class Order : AggregateRoot { - private int _orderStatusId; public DateTime OrderDate { get; private set; } public int OrderNo { get; private set; } public string PaymentMethod { get; private set; } @@ -25,15 +24,14 @@ public class Order : AggregateRoot { } - internal Order(Guid id, Buyer buyer, Address address, [NotNull]string paymentMethod, Guid? paymentRequestId = null) : base(id) + internal Order(Guid id, Buyer buyer, Address address, [NotNull] string paymentMethod, Guid? paymentRequestId = null) : base(id) { - _orderStatusId = OrderStatus.Placed.Id; OrderDate = DateTime.UtcNow; OrderNo = GenerateOrderNo(id); Buyer = buyer; Address = address; PaymentRequestId = paymentRequestId; - PaymentMethod = Check.NotNullOrEmpty(paymentMethod,nameof(paymentMethod),maxLength:OrderConstants.OrderPaymentMethodNameMaxLength); + PaymentMethod = Check.NotNullOrEmpty(paymentMethod, nameof(paymentMethod), maxLength: OrderConstants.OrderPaymentMethodNameMaxLength); PaymentStatus = PaymentRequestState.Waiting.ToString(); // From PaymentService.Domain.Shared OrderItems = new List(); } diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderStatus.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderStatus.cs deleted file mode 100644 index dcd06c06..00000000 --- a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderStatus.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Volo.Abp; - -namespace EShopOnAbp.OrderingService.Orders; - -public class OrderStatus : Enumeration -{ - public static OrderStatus Placed = new OrderStatus(1, nameof(Placed).ToLowerInvariant()); - public static OrderStatus Paid = new OrderStatus(2, nameof(Paid).ToLowerInvariant()); - public static OrderStatus Shipped = new OrderStatus(3, nameof(Shipped).ToLowerInvariant()); - public static OrderStatus Cancelled = new OrderStatus(4, nameof(Cancelled).ToLowerInvariant()); - - public OrderStatus(int id, string name) : base(id, name) - { - } - - public static IEnumerable List() => - new[] {Placed, Paid, Shipped, Cancelled}; - - public static OrderStatus FromName(string name) - { - var state = List() - .SingleOrDefault(s => String.Equals(s.Name, name, StringComparison.CurrentCultureIgnoreCase)); - - if (state == null) - { - throw new BusinessException(OrderingServiceErrorCodes.OrderingStatusNotFound) - .WithData("OrderStatus", String.Join(",", List().Select(s => s.Name))); - } - - return state; - } - - public static OrderStatus From(int id) - { - var state = List().SingleOrDefault(s => s.Id == id); - - if (state == null) - { - throw new BusinessException(OrderingServiceErrorCodes.OrderingStatusNotFound) - .WithData("OrderStatus", String.Join(",", List().Select(s => s.Name))); - } - - return state; - } -} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs deleted file mode 100644 index 2ebd3abd..00000000 --- a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using EShopOnAbp.OrderingService.Orders; -using Microsoft.EntityFrameworkCore; -using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; - -namespace EShopOnAbp.OrderingService.EntityFrameworkCore; - -/// -/// DataSeedContributor for seeding pre-exist order status data. -/// This is a sample for seeding data without DbSet (non-aggregate data), without using repository. -/// -public class OrderServiceDataSeedContributor : IDataSeedContributor, ITransientDependency -{ - private readonly IOrderingServiceDbContext _dbContext; - - public OrderServiceDataSeedContributor(IOrderingServiceDbContext dbContext) - { - _dbContext = dbContext; - } - - public async Task SeedAsync(DataSeedContext context) - { - await SeedOrderStatusAsync(); - } - - private async Task SeedOrderStatusAsync() - { - if (!await _dbContext.Set().AnyAsync()) - { - await _dbContext.Set().AddRangeAsync(OrderStatus.List()); - await _dbContext.SaveChangesAsync(); - } - } -} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs index d4b2d864..146bfd8e 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs @@ -1,6 +1,7 @@ -using System; -using EShopOnAbp.OrderingService.Orders; +using EShopOnAbp.OrderingService.Orders; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using System; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.Modeling; @@ -17,17 +18,17 @@ public class OrderingServiceDbContext : AbpDbContext, { } - protected override void OnModelCreating(ModelBuilder builder) + protected override void OnModelCreating(ModelBuilder modelBuilder) { - base.OnModelCreating(builder); + base.OnModelCreating(modelBuilder); /* Include modules to your migration db context */ - builder.ConfigureOrderingService(); + modelBuilder.ConfigureOrderingService(); /* Configure your own tables/entities inside here */ - builder.Entity(b => + modelBuilder.Entity(b => { b.ToTable(OrderingServiceDbProperties.DbTablePrefix + "Orders", OrderingServiceDbProperties.DbSchema); b.ConfigureByConvention(); //auto configure for the base class props @@ -38,16 +39,12 @@ public class OrderingServiceDbContext : AbpDbContext, b.OwnsOne(o => o.Address, a => { a.WithOwner(); }); b.OwnsOne(o => o.Buyer, a => { a.WithOwner(); }); - b.Property("_orderStatusId").UsePropertyAccessMode(PropertyAccessMode.Field) - .HasColumnName("OrderStatusId") - .IsRequired(); - - b.HasOne(q => q.OrderStatus).WithMany().HasForeignKey("_orderStatusId"); - b.Navigation(q => q.OrderItems).UsePropertyAccessMode(PropertyAccessMode.Property); + + b.Property(q => q.OrderStatus).HasConversion(new EnumToStringConverter()); }); - builder.Entity(b => + modelBuilder.Entity(b => { b.ToTable(OrderingServiceDbProperties.DbTablePrefix + "OrderItems", OrderingServiceDbProperties.DbSchema); @@ -62,23 +59,5 @@ public class OrderingServiceDbContext : AbpDbContext, b.Property(q => q.Units).IsRequired(); b.Property(q => q.PictureUrl).IsRequired(false); }); - - builder.Entity(b => - { - b.ToTable(OrderingServiceDbProperties.DbTablePrefix + "OrderStatus", - OrderingServiceDbProperties.DbSchema); - b.ConfigureByConvention(); //auto configure for the base class props - - b.HasKey(q => q.Id); - - b.Property(q => q.Id) - .HasDefaultValue(1) - .ValueGeneratedNever() - .IsRequired(); - - b.Property(o => o.Name) - .HasMaxLength(OrderConstants.OrderStatusNameMaxLength) - .IsRequired(); - }); } } diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/20220317123922_RemovedOrderStatusTable.Designer.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/20220317123922_RemovedOrderStatusTable.Designer.cs new file mode 100644 index 00000000..a0089c22 --- /dev/null +++ b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/20220317123922_RemovedOrderStatusTable.Designer.cs @@ -0,0 +1,182 @@ +// +using System; +using EShopOnAbp.OrderingService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace EShopOnAbp.OrderingService.Migrations +{ + [DbContext(typeof(OrderingServiceDbContext))] + [Migration("20220317123922_RemovedOrderStatusTable")] + partial class RemovedOrderStatusTable + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "6.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("EShopOnAbp.OrderingService.Orders.Order", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("OrderDate") + .HasColumnType("timestamp without time zone"); + + b.Property("OrderNo") + .HasColumnType("integer"); + + b.Property("OrderStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentMethod") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("PaymentStatus") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.ToTable("Orders", (string)null); + }); + + modelBuilder.Entity("EShopOnAbp.OrderingService.Orders.OrderItem", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Discount") + .HasColumnType("numeric"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("PictureUrl") + .HasColumnType("text"); + + b.Property("ProductCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("ProductName") + .IsRequired() + .HasColumnType("text"); + + b.Property("UnitPrice") + .HasColumnType("numeric"); + + b.Property("Units") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("OrderItems", (string)null); + }); + + modelBuilder.Entity("EShopOnAbp.OrderingService.Orders.Order", b => + { + b.OwnsOne("EShopOnAbp.OrderingService.Orders.Address", "Address", b1 => + { + b1.Property("OrderId") + .HasColumnType("uuid"); + + b1.Property("City") + .HasColumnType("text"); + + b1.Property("Country") + .HasColumnType("text"); + + b1.Property("Description") + .HasColumnType("text"); + + b1.Property("Street") + .HasColumnType("text"); + + b1.Property("ZipCode") + .HasColumnType("text"); + + b1.HasKey("OrderId"); + + b1.ToTable("Orders"); + + b1.WithOwner() + .HasForeignKey("OrderId"); + }); + + b.OwnsOne("EShopOnAbp.OrderingService.Orders.Buyer", "Buyer", b1 => + { + b1.Property("OrderId") + .HasColumnType("uuid"); + + b1.Property("Email") + .HasColumnType("text"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Name") + .HasColumnType("text"); + + b1.HasKey("OrderId"); + + b1.ToTable("Orders"); + + b1.WithOwner() + .HasForeignKey("OrderId"); + }); + + b.Navigation("Address"); + + b.Navigation("Buyer"); + }); + + modelBuilder.Entity("EShopOnAbp.OrderingService.Orders.OrderItem", b => + { + b.HasOne("EShopOnAbp.OrderingService.Orders.Order", null) + .WithMany("OrderItems") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("EShopOnAbp.OrderingService.Orders.Order", b => + { + b.Navigation("OrderItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/20220317123922_RemovedOrderStatusTable.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/20220317123922_RemovedOrderStatusTable.cs new file mode 100644 index 00000000..f856edbc --- /dev/null +++ b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/20220317123922_RemovedOrderStatusTable.cs @@ -0,0 +1,73 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace EShopOnAbp.OrderingService.Migrations +{ + public partial class RemovedOrderStatusTable : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Orders_OrderStatus_OrderStatusId", + table: "Orders"); + + migrationBuilder.DropTable( + name: "OrderStatus"); + + migrationBuilder.DropIndex( + name: "IX_Orders_OrderStatusId", + table: "Orders"); + + migrationBuilder.DropColumn( + name: "OrderStatusId", + table: "Orders"); + + migrationBuilder.AddColumn( + name: "OrderStatus", + table: "Orders", + type: "text", + nullable: false, + defaultValue: ""); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "OrderStatus", + table: "Orders"); + + migrationBuilder.AddColumn( + name: "OrderStatusId", + table: "Orders", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "OrderStatus", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false, defaultValue: 1), + Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrderStatus", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Orders_OrderStatusId", + table: "Orders", + column: "OrderStatusId"); + + migrationBuilder.AddForeignKey( + name: "FK_Orders_OrderStatus_OrderStatusId", + table: "Orders", + column: "OrderStatusId", + principalTable: "OrderStatus", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/OrderingServiceDbContextModelSnapshot.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/OrderingServiceDbContextModelSnapshot.cs index d1a7946a..1652602c 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/OrderingServiceDbContextModelSnapshot.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Migrations/OrderingServiceDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace EShopOnAbp.OrderingService.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) - .HasAnnotation("ProductVersion", "6.0.0") + .HasAnnotation("ProductVersion", "6.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -45,6 +45,10 @@ namespace EShopOnAbp.OrderingService.Migrations b.Property("OrderNo") .HasColumnType("integer"); + b.Property("OrderStatus") + .IsRequired() + .HasColumnType("text"); + b.Property("PaymentMethod") .IsRequired() .HasMaxLength(128) @@ -57,14 +61,8 @@ namespace EShopOnAbp.OrderingService.Migrations .HasMaxLength(256) .HasColumnType("character varying(256)"); - b.Property("_orderStatusId") - .HasColumnType("integer") - .HasColumnName("OrderStatusId"); - b.HasKey("Id"); - b.HasIndex("_orderStatusId"); - b.ToTable("Orders", (string)null); }); @@ -106,30 +104,8 @@ namespace EShopOnAbp.OrderingService.Migrations b.ToTable("OrderItems", (string)null); }); - modelBuilder.Entity("EShopOnAbp.OrderingService.Orders.OrderStatus", b => - { - b.Property("Id") - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.ToTable("OrderStatus", (string)null); - }); - modelBuilder.Entity("EShopOnAbp.OrderingService.Orders.Order", b => { - b.HasOne("EShopOnAbp.OrderingService.Orders.OrderStatus", "OrderStatus") - .WithMany() - .HasForeignKey("_orderStatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - b.OwnsOne("EShopOnAbp.OrderingService.Orders.Address", "Address", b1 => { b1.Property("OrderId") @@ -183,8 +159,6 @@ namespace EShopOnAbp.OrderingService.Migrations b.Navigation("Address"); b.Navigation("Buyer"); - - b.Navigation("OrderStatus"); }); modelBuilder.Entity("EShopOnAbp.OrderingService.Orders.OrderItem", b => diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs index 45ef6948..74bde613 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs @@ -1,11 +1,11 @@ -using System; +using EShopOnAbp.OrderingService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using System; using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; -using EShopOnAbp.OrderingService.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -20,14 +20,6 @@ public class EfCoreOrderRepository : EfCoreRepository InsertAsync(Order entity, bool autoSave = false, - CancellationToken cancellationToken = default) - { - var newEntity = await base.InsertAsync(entity, autoSave, GetCancellationToken(cancellationToken)); - await EnsurePropertyLoadedAsync(newEntity, o => o.OrderStatus, GetCancellationToken(cancellationToken)); - return newEntity; - } - public async Task> GetOrdersByUserId( Guid userId, ISpecification spec, diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs index cecca583..fef4878c 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs @@ -15,7 +15,6 @@ public static class OrderEfCoreQueryableExtensions return queryable .Include(x => x.Address) .Include(x => x.Buyer) - .Include(x => x.OrderItems) - .Include(x => x.OrderStatus); + .Include(x => x.OrderItems); } } \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/Controllers/HomeController.cs b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/Controllers/HomeController.cs index c7b2bbe3..c494a523 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/Controllers/HomeController.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/Controllers/HomeController.cs @@ -1,13 +1,12 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; -namespace EShopOnAbp.OrderingService.Controllers +namespace EShopOnAbp.OrderingService.Controllers; + +public class HomeController : AbpController { - public class HomeController : AbpController + public ActionResult Index() { - public ActionResult Index() - { - return Redirect("~/swagger"); - } + return Redirect("~/swagger"); } -} +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationChecker.cs b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationChecker.cs index ef8b92b9..889464b0 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationChecker.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationChecker.cs @@ -5,23 +5,22 @@ using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.OrderingService.DbMigrations +namespace EShopOnAbp.OrderingService.DbMigrations; + +public class OrderingServiceDatabaseMigrationChecker + : PendingEfCoreMigrationsChecker { - public class OrderingServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker + public OrderingServiceDatabaseMigrationChecker( + IUnitOfWorkManager unitOfWorkManager, + IServiceProvider serviceProvider, + ICurrentTenant currentTenant, + IDistributedEventBus distributedEventBus) + : base( + unitOfWorkManager, + serviceProvider, + currentTenant, + distributedEventBus, + OrderingServiceDbProperties.ConnectionStringName) { - public OrderingServiceDatabaseMigrationChecker( - IUnitOfWorkManager unitOfWorkManager, - IServiceProvider serviceProvider, - ICurrentTenant currentTenant, - IDistributedEventBus distributedEventBus) - : base( - unitOfWorkManager, - serviceProvider, - currentTenant, - distributedEventBus, - OrderingServiceDbProperties.ConnectionStringName) - { - - } } -} +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationEventHandler.cs b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationEventHandler.cs index 98f77546..a5b6672f 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationEventHandler.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationEventHandler.cs @@ -1,58 +1,70 @@ using EShopOnAbp.OrderingService.EntityFrameworkCore; +using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; using System; using System.Threading.Tasks; -using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; -using Microsoft.Extensions.Logging; +using Serilog; using Volo.Abp.Data; +using Volo.Abp.DistributedLocking; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.OrderingService.DbMigrations -{ - public class OrderingServiceDatabaseMigrationEventHandler - : DatabaseEfCoreMigrationEventHandler, +namespace EShopOnAbp.OrderingService.DbMigrations; + +public class OrderingServiceDatabaseMigrationEventHandler + : DatabaseEfCoreMigrationEventHandler, IDistributedEventHandler +{ + private readonly IDataSeeder _dataSeeder; + + public OrderingServiceDatabaseMigrationEventHandler( + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + ITenantStore tenantStore, + IDistributedEventBus distributedEventBus, + IDataSeeder dataSeeder, + IAbpDistributedLock distributedLockProvider) + : base( + currentTenant, + unitOfWorkManager, + tenantStore, + distributedEventBus, + OrderingServiceDbProperties.ConnectionStringName, + distributedLockProvider) { - private readonly IDataSeeder _dataSeeder; - public OrderingServiceDatabaseMigrationEventHandler( - ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager, - ITenantStore tenantStore, - IDistributedEventBus distributedEventBus, - IDataSeeder dataSeeder) - : base( - currentTenant, - unitOfWorkManager, - tenantStore, - distributedEventBus, - OrderingServiceDbProperties.ConnectionStringName) + _dataSeeder = dataSeeder; + } + + public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + { + if (eventData.DatabaseName != DatabaseName) { - _dataSeeder = dataSeeder; + return; } - public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + if (eventData.TenantId != null) { - if (eventData.DatabaseName != DatabaseName) - { - return; - } + return; + } - if (eventData.TenantId != null) + try + { + await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName)) { - return; - } + Log.Information("OrderingService has acquired lock for db migration..."); - try - { - await MigrateDatabaseSchemaAsync(null); - Logger.LogInformation("Starting OrderingService DataSeeder..."); - await _dataSeeder.SeedAsync(); - } - catch (Exception ex) - { - await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); + if (handle != null) + { + Log.Information("OrderingService is migrating database..."); + await MigrateDatabaseSchemaAsync(); + Log.Information("OrderingService is seeding data..."); + await _dataSeeder.SeedAsync(); + } } } + catch (Exception ex) + { + await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); + } } -} +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/OrderingServiceHttpApiHostModule.cs b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/OrderingServiceHttpApiHostModule.cs index d5a9a9eb..29782aa7 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/OrderingServiceHttpApiHostModule.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/OrderingServiceHttpApiHostModule.cs @@ -4,17 +4,16 @@ using EShopOnAbp.Shared.Hosting.AspNetCore; using EShopOnAbp.Shared.Hosting.Microservices; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Modularity; -using Volo.Abp.Threading; namespace EShopOnAbp.OrderingService; diff --git a/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs b/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs index 580b80e4..902cf2a7 100644 --- a/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs +++ b/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs @@ -1,12 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using EShopOnAbp.OrderingService.Orders; +using EShopOnAbp.OrderingService.Orders; using EShopOnAbp.OrderingService.Orders.Specifications; using EShopOnAbp.OrderingService.Samples; -using Microsoft.EntityFrameworkCore; using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Xunit; namespace EShopOnAbp.OrderingService.EntityFrameworkCore.Orders; @@ -26,14 +25,6 @@ public class OrderRepository_Tests : SampleRepository_Tests(); } - [Fact] - public async Task Should_Get_OrderStatus() - { - var dbSet = _dbContext.Set(); - var statusList = await dbSet.ToListAsync(); - statusList.Count.ShouldNotBe(0); - } - [Fact] public async Task Should_Get_User_Orders() { diff --git a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/Controllers/HomeController.cs b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/Controllers/HomeController.cs index 23718617..74162a92 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/Controllers/HomeController.cs +++ b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/Controllers/HomeController.cs @@ -1,13 +1,12 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; -namespace EShopOnAbp.PaymentService.Controllers +namespace EShopOnAbp.PaymentService.Controllers; + +public class HomeController : AbpController { - public class HomeController : AbpController + public ActionResult Index() { - public ActionResult Index() - { - return Redirect("~/swagger"); - } + return Redirect("~/swagger"); } -} +} \ No newline at end of file diff --git a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationChecker.cs b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationChecker.cs index 85c2a026..e5b9a962 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationChecker.cs +++ b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationChecker.cs @@ -5,23 +5,22 @@ using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.PaymentService.DbMigrations +namespace EShopOnAbp.PaymentService.DbMigrations; + +public class PaymentServiceDatabaseMigrationChecker + : PendingEfCoreMigrationsChecker { - public class PaymentServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker + public PaymentServiceDatabaseMigrationChecker( + IUnitOfWorkManager unitOfWorkManager, + IServiceProvider serviceProvider, + ICurrentTenant currentTenant, + IDistributedEventBus distributedEventBus) + : base( + unitOfWorkManager, + serviceProvider, + currentTenant, + distributedEventBus, + PaymentServiceDbProperties.ConnectionStringName) { - public PaymentServiceDatabaseMigrationChecker( - IUnitOfWorkManager unitOfWorkManager, - IServiceProvider serviceProvider, - ICurrentTenant currentTenant, - IDistributedEventBus distributedEventBus) - : base( - unitOfWorkManager, - serviceProvider, - currentTenant, - distributedEventBus, - PaymentServiceDbProperties.ConnectionStringName) - { - - } } -} +} \ No newline at end of file diff --git a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationEventHandler.cs b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationEventHandler.cs index 7fd87b4f..5b59bd4d 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationEventHandler.cs +++ b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationEventHandler.cs @@ -1,52 +1,64 @@ using EShopOnAbp.PaymentService.EntityFrameworkCore; +using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; using System; using System.Threading.Tasks; -using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; +using Serilog; using Volo.Abp.Data; +using Volo.Abp.DistributedLocking; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace EShopOnAbp.PaymentService.DbMigrations -{ - public class PaymentServiceDatabaseMigrationEventHandler - : DatabaseEfCoreMigrationEventHandler, +namespace EShopOnAbp.PaymentService.DbMigrations; + +public class PaymentServiceDatabaseMigrationEventHandler + : DatabaseEfCoreMigrationEventHandler, IDistributedEventHandler +{ + public PaymentServiceDatabaseMigrationEventHandler( + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + ITenantStore tenantStore, + IDistributedEventBus distributedEventBus, + IAbpDistributedLock distributedLockProvider) + : base( + currentTenant, + unitOfWorkManager, + tenantStore, + distributedEventBus, + PaymentServiceDbProperties.ConnectionStringName, + distributedLockProvider) { - public PaymentServiceDatabaseMigrationEventHandler( - ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager, - ITenantStore tenantStore, - IDistributedEventBus distributedEventBus) - : base( - currentTenant, - unitOfWorkManager, - tenantStore, - distributedEventBus, - PaymentServiceDbProperties.ConnectionStringName) + } + + public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + { + if (eventData.DatabaseName != DatabaseName) { + return; } - public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) + if (eventData.TenantId != null) { - if (eventData.DatabaseName != DatabaseName) - { - return; - } + return; + } - if (eventData.TenantId != null) - { - return; - } + try + { + Log.Information("PaymentService has acquired lock for db migration..."); - try + await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName)) { - await MigrateDatabaseSchemaAsync(null); - } - catch (Exception ex) - { - await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); + if (handle != null) + { + Log.Information("PaymentService is migrating database..."); + await MigrateDatabaseSchemaAsync(); + } } } + catch (Exception ex) + { + await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); + } } -} +} \ No newline at end of file diff --git a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs index e267e8d3..d51fbba3 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs +++ b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs @@ -4,16 +4,15 @@ using EShopOnAbp.Shared.Hosting.AspNetCore; using EShopOnAbp.Shared.Hosting.Microservices; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; using Volo.Abp; using Volo.Abp.Modularity; -using Volo.Abp.Threading; namespace EShopOnAbp.PaymentService; diff --git a/shared/EShopOnAbp.Shared.Hosting.AspNetCore/EShopOnAbpSharedHostingAspNetCoreModule.cs b/shared/EShopOnAbp.Shared.Hosting.AspNetCore/EShopOnAbpSharedHostingAspNetCoreModule.cs index d641b79d..9fef08f5 100644 --- a/shared/EShopOnAbp.Shared.Hosting.AspNetCore/EShopOnAbpSharedHostingAspNetCoreModule.cs +++ b/shared/EShopOnAbp.Shared.Hosting.AspNetCore/EShopOnAbpSharedHostingAspNetCoreModule.cs @@ -2,17 +2,16 @@ using Volo.Abp.Modularity; using Volo.Abp.Swashbuckle; -namespace EShopOnAbp.Shared.Hosting.AspNetCore +namespace EShopOnAbp.Shared.Hosting.AspNetCore; + +[DependsOn( + typeof(EShopOnAbpSharedHostingModule), + typeof(AbpSwashbuckleModule), + typeof(AbpAspNetCoreSerilogModule) +)] +public class EShopOnAbpSharedHostingAspNetCoreModule : AbpModule { - [DependsOn( - typeof(EShopOnAbpSharedHostingModule), - typeof(AbpSwashbuckleModule), - typeof(AbpAspNetCoreSerilogModule) - )] - public class EShopOnAbpSharedHostingAspNetCoreModule : AbpModule + public override void ConfigureServices(ServiceConfigurationContext context) { - public override void ConfigureServices(ServiceConfigurationContext context) - { - } } } \ No newline at end of file diff --git a/shared/EShopOnAbp.Shared.Hosting.AspNetCore/SerilogConfigurationHelper.cs b/shared/EShopOnAbp.Shared.Hosting.AspNetCore/SerilogConfigurationHelper.cs index 0c0b922c..9b1ec2f0 100644 --- a/shared/EShopOnAbp.Shared.Hosting.AspNetCore/SerilogConfigurationHelper.cs +++ b/shared/EShopOnAbp.Shared.Hosting.AspNetCore/SerilogConfigurationHelper.cs @@ -1,40 +1,39 @@ using Serilog; using Serilog.Events; -namespace EShopOnAbp.Shared.Hosting.AspNetCore +namespace EShopOnAbp.Shared.Hosting.AspNetCore; + +public static class SerilogConfigurationHelper { - public static class SerilogConfigurationHelper + public static void Configure(string applicationName) { - public static void Configure(string applicationName) - { - // TODO: Uncomment following lines for ElasticSearch configuration - // var configuration = new ConfigurationBuilder() - // .SetBasePath(Directory.GetCurrentDirectory()) - // .AddJsonFile("appsettings.json") - // .AddEnvironmentVariables() - // .Build(); + // TODO: Uncomment following lines for ElasticSearch configuration + // var configuration = new ConfigurationBuilder() + // .SetBasePath(Directory.GetCurrentDirectory()) + // .AddJsonFile("appsettings.json") + // .AddEnvironmentVariables() + // .Build(); - Log.Logger = new LoggerConfiguration() + Log.Logger = new LoggerConfiguration() #if DEBUG - .MinimumLevel.Debug() + .MinimumLevel.Debug() #else .MinimumLevel.Information() #endif - .MinimumLevel.Override("Microsoft", LogEventLevel.Information) - .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) - .Enrich.FromLogContext() - .Enrich.WithProperty("Application", $"{applicationName}") - .WriteTo.Async(c => c.File("Logs/logs.txt")) - // TODO: Uncomment following lines for ElasticSearch configuration - // .WriteTo.Elasticsearch( - // new ElasticsearchSinkOptions(new Uri(configuration["ElasticSearch:Url"])) - // { - // AutoRegisterTemplate = true, - // AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6, - // IndexFormat = "MyProjectName-log-{0:yyyy.MM}" - // }) - .WriteTo.Async(c => c.Console()) - .CreateLogger(); - } + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) + .Enrich.FromLogContext() + .Enrich.WithProperty("Application", $"{applicationName}") + .WriteTo.Async(c => c.File("Logs/logs.txt")) + // TODO: Uncomment following lines for ElasticSearch configuration + // .WriteTo.Elasticsearch( + // new ElasticsearchSinkOptions(new Uri(configuration["ElasticSearch:Url"])) + // { + // AutoRegisterTemplate = true, + // AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6, + // IndexFormat = "MyProjectName-log-{0:yyyy.MM}" + // }) + .WriteTo.Async(c => c.Console()) + .CreateLogger(); } } \ No newline at end of file diff --git a/shared/EShopOnAbp.Shared.Hosting.AspNetCore/SwaggerConfigurationHelper.cs b/shared/EShopOnAbp.Shared.Hosting.AspNetCore/SwaggerConfigurationHelper.cs index 3990971c..6e79b550 100644 --- a/shared/EShopOnAbp.Shared.Hosting.AspNetCore/SwaggerConfigurationHelper.cs +++ b/shared/EShopOnAbp.Shared.Hosting.AspNetCore/SwaggerConfigurationHelper.cs @@ -3,40 +3,39 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using Volo.Abp.Modularity; -namespace EShopOnAbp.Shared.Hosting.AspNetCore +namespace EShopOnAbp.Shared.Hosting.AspNetCore; + +public static class SwaggerConfigurationHelper { - public static class SwaggerConfigurationHelper + public static void Configure( + ServiceConfigurationContext context, + string apiTitle + ) { - public static void Configure( - ServiceConfigurationContext context, - string apiTitle - ) + context.Services.AddSwaggerGen(options => { - context.Services.AddSwaggerGen(options => + options.SwaggerDoc("v1", new OpenApiInfo {Title = apiTitle, Version = "v1"}); + options.DocInclusionPredicate((docName, description) => true); + options.CustomSchemaIds(type => type.FullName); + }); + } + public static void ConfigureWithAuth( + ServiceConfigurationContext context, + string authority, + Dictionary scopes, + string apiTitle, + string apiVersion = "v1", + string apiName = "v1" + ) + { + context.Services.AddAbpSwaggerGenWithOAuth( + authority: authority, + scopes: scopes, + options => { - options.SwaggerDoc("v1", new OpenApiInfo {Title = apiTitle, Version = "v1"}); + options.SwaggerDoc(apiName, new OpenApiInfo { Title = apiTitle, Version = apiVersion }); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); }); - } - public static void ConfigureWithAuth( - ServiceConfigurationContext context, - string authority, - Dictionary scopes, - string apiTitle, - string apiVersion = "v1", - string apiName = "v1" - ) - { - context.Services.AddAbpSwaggerGenWithOAuth( - authority: authority, - scopes: scopes, - options => - { - options.SwaggerDoc(apiName, new OpenApiInfo { Title = apiTitle, Version = apiVersion }); - options.DocInclusionPredicate((docName, description) => true); - options.CustomSchemaIds(type => type.FullName); - }); - } } } \ No newline at end of file diff --git a/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/EfCore/DatabaseEfCoreMigrationEventHandler.cs b/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/EfCore/DatabaseEfCoreMigrationEventHandler.cs index 298102b5..02719e9a 100644 --- a/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/EfCore/DatabaseEfCoreMigrationEventHandler.cs +++ b/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/EfCore/DatabaseEfCoreMigrationEventHandler.cs @@ -1,14 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Serilog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Data; +using Volo.Abp.DistributedLocking; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EventBus.Distributed; @@ -22,26 +23,29 @@ public abstract class DatabaseEfCoreMigrationEventHandler : Database { protected const string TryCountPropertyName = "TryCount"; protected const int MaxEventTryCount = 3; - protected ICurrentTenant CurrentTenant { get; } protected IUnitOfWorkManager UnitOfWorkManager { get; } protected ITenantStore TenantStore { get; } protected IDistributedEventBus DistributedEventBus { get; } protected ILogger> Logger { get; set; } protected string DatabaseName { get; } + protected IAbpDistributedLock DistributedLockProvider { get; } protected DatabaseEfCoreMigrationEventHandler( ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, ITenantStore tenantStore, IDistributedEventBus distributedEventBus, - string databaseName) + string databaseName, + IAbpDistributedLock distributedLockProvider + ) { CurrentTenant = currentTenant; UnitOfWorkManager = unitOfWorkManager; TenantStore = tenantStore; DatabaseName = databaseName; DistributedEventBus = distributedEventBus; + DistributedLockProvider = distributedLockProvider; Logger = NullLogger>.Instance; } @@ -50,47 +54,32 @@ public abstract class DatabaseEfCoreMigrationEventHandler : Database /// Apply pending EF Core schema migrations to the database. /// Returns true if any migration has applied. /// - protected virtual async Task MigrateDatabaseSchemaAsync(Guid? tenantId) + protected virtual async Task MigrateDatabaseSchemaAsync() { var result = false; - using (CurrentTenant.Change(tenantId)) + using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false)) { - using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false)) + async Task MigrateDatabaseSchemaWithDbContextAsync() { - async Task MigrateDatabaseSchemaWithDbContextAsync() - { - var dbContext = await uow.ServiceProvider - .GetRequiredService>() - .GetDbContextAsync(); - - if ((await dbContext.Database.GetPendingMigrationsAsync()).Any()) - { - await dbContext.Database.MigrateAsync(); - return true; - } - - return false; - } + var dbContext = await uow.ServiceProvider + .GetRequiredService>() + .GetDbContextAsync(); - if (tenantId == null) + if ((await dbContext.Database.GetPendingMigrationsAsync()).Any()) { - //Migrating the host database - result = await MigrateDatabaseSchemaWithDbContextAsync(); - } - else - { - var tenantConfiguration = await TenantStore.FindAsync(tenantId.Value); - if (!tenantConfiguration.ConnectionStrings.Default.IsNullOrWhiteSpace() || - !tenantConfiguration.ConnectionStrings.GetOrDefault(DatabaseName).IsNullOrWhiteSpace()) - { - //Migrating the tenant database (only if tenant has a separate database) - result = await MigrateDatabaseSchemaWithDbContextAsync(); - } + await dbContext.Database.MigrateAsync(); + return true; } - await uow.CompleteAsync(); + return false; } + + //Migrating the host database + Log.Information($"There is no tenant. Migrating {DatabaseName}..."); + result = await MigrateDatabaseSchemaWithDbContextAsync(); + + await uow.CompleteAsync(); } return result; @@ -113,56 +102,12 @@ public abstract class DatabaseEfCoreMigrationEventHandler : Database } else { - Log.Error( + Log.Warning( $"Could not apply database migrations. Canceling the operation. TenantId = {eventData.TenantId}, DatabaseName = {eventData.DatabaseName}."); Log.Error(exception.ToString()); } } - protected virtual async Task HandleErrorTenantCreatedAsync( - TenantCreatedEto eventData, - Exception exception) - { - var tryCount = IncrementEventTryCount(eventData); - if (tryCount <= MaxEventTryCount) - { - Logger.LogWarning( - $"Could not perform tenant created event. Re-queueing the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}."); - Logger.LogException(exception, LogLevel.Warning); - - await Task.Delay(RandomHelper.GetRandom(5000, 15000)); - await DistributedEventBus.PublishAsync(eventData); - } - else - { - Logger.LogError( - $"Could not perform tenant created event. Canceling the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}."); - Logger.LogException(exception); - } - } - - protected virtual async Task HandleErrorTenantConnectionStringUpdatedAsync( - TenantConnectionStringUpdatedEto eventData, - Exception exception) - { - var tryCount = IncrementEventTryCount(eventData); - if (tryCount <= MaxEventTryCount) - { - Logger.LogWarning( - $"Could not perform tenant connection string updated event. Re-queueing the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}."); - Logger.LogException(exception, LogLevel.Warning); - - await Task.Delay(RandomHelper.GetRandom(5000, 15000)); - await DistributedEventBus.PublishAsync(eventData); - } - else - { - Logger.LogError( - $"Could not perform tenant connection string updated event. Canceling the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}."); - Logger.LogException(exception); - } - } - private static int GetEventTryCount(EtoBase eventData) { var tryCountAsString = eventData.Properties.GetOrDefault(TryCountPropertyName); diff --git a/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/MongoDb/DatabaseMongoDbMigrationEventHandler.cs b/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/MongoDb/DatabaseMongoDbMigrationEventHandler.cs index 452cd7de..79784821 100644 --- a/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/MongoDb/DatabaseMongoDbMigrationEventHandler.cs +++ b/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/MongoDb/DatabaseMongoDbMigrationEventHandler.cs @@ -1,13 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Data; +using Volo.Abp.DistributedLocking; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MongoDB; @@ -27,16 +27,20 @@ public abstract class DatabaseMongoDbMigrationEventHandler : Databas protected ITenantStore TenantStore { get; } protected IDistributedEventBus DistributedEventBus { get; } protected ILogger> Logger { get; set; } - protected IServiceProvider ServiceProvider { get; } protected string DatabaseName { get; } + protected IAbpDistributedLock DistributedLockProvider { get; } + protected DatabaseMongoDbMigrationEventHandler( ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, ITenantStore tenantStore, IDistributedEventBus distributedEventBus, - string databaseName, IServiceProvider serviceProvider) + string databaseName, + IServiceProvider serviceProvider, + IAbpDistributedLock distributedLockProvider + ) { CurrentTenant = currentTenant; UnitOfWorkManager = unitOfWorkManager; @@ -44,6 +48,7 @@ public abstract class DatabaseMongoDbMigrationEventHandler : Databas DatabaseName = databaseName; ServiceProvider = serviceProvider; DistributedEventBus = distributedEventBus; + DistributedLockProvider = distributedLockProvider; Logger = NullLogger>.Instance; } @@ -52,62 +57,46 @@ public abstract class DatabaseMongoDbMigrationEventHandler : Databas /// Apply pending EF Core schema migrations to the database. /// Returns true if any migration has applied. /// - protected virtual async Task MigrateDatabaseSchemaAsync(Guid? tenantId) + protected virtual async Task MigrateDatabaseSchemaAsync() { var result = false; - using (CurrentTenant.Change(tenantId)) + using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false)) { - using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false)) + async Task MigrateDatabaseSchemaWithDbContextAsync() { - async Task MigrateDatabaseSchemaWithDbContextAsync() - { - var dbContexts = ServiceProvider.GetServices(); - var connectionStringResolver = ServiceProvider.GetRequiredService(); + var dbContexts = ServiceProvider.GetServices(); + var connectionStringResolver = ServiceProvider.GetRequiredService(); - foreach (var dbContext in dbContexts) + foreach (var dbContext in dbContexts) + { + var connectionString = + await connectionStringResolver.ResolveAsync( + ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType())); + if (connectionString.IsNullOrWhiteSpace()) { - var connectionString = - await connectionStringResolver.ResolveAsync( - ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType())); - if (connectionString.IsNullOrWhiteSpace()) - { - continue; - } - - var mongoUrl = new MongoUrl(connectionString); - var databaseName = mongoUrl.DatabaseName; - var client = new MongoClient(mongoUrl); - - if (databaseName.IsNullOrWhiteSpace()) - { - databaseName = ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType()); - } - - (dbContext as AbpMongoDbContext)?.InitializeCollections(client.GetDatabase(databaseName)); + continue; } - return true; - } + var mongoUrl = new MongoUrl(connectionString); + var databaseName = mongoUrl.DatabaseName; + var client = new MongoClient(mongoUrl); - if (tenantId == null) - { - //Migrating the host database - result = await MigrateDatabaseSchemaWithDbContextAsync(); - } - else - { - var tenantConfiguration = await TenantStore.FindAsync(tenantId.Value); - if (!tenantConfiguration.ConnectionStrings.Default.IsNullOrWhiteSpace() || - !tenantConfiguration.ConnectionStrings.GetOrDefault(DatabaseName).IsNullOrWhiteSpace()) + if (databaseName.IsNullOrWhiteSpace()) { - //Migrating the tenant database (only if tenant has a separate database) - result = await MigrateDatabaseSchemaWithDbContextAsync(); + databaseName = ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType()); } + + (dbContext as AbpMongoDbContext)?.InitializeCollections(client.GetDatabase(databaseName)); } - await uow.CompleteAsync(); + return true; } + + //Migrating the host database + result = await MigrateDatabaseSchemaWithDbContextAsync(); + + await uow.CompleteAsync(); } return result; @@ -135,50 +124,6 @@ public abstract class DatabaseMongoDbMigrationEventHandler : Databas } } - protected virtual async Task HandleErrorTenantCreatedAsync( - TenantCreatedEto eventData, - Exception exception) - { - var tryCount = IncrementEventTryCount(eventData); - if (tryCount <= MaxEventTryCount) - { - Logger.LogWarning( - $"Could not perform tenant created event. Re-queueing the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}."); - Logger.LogException(exception, LogLevel.Warning); - - await Task.Delay(RandomHelper.GetRandom(5000, 15000)); - await DistributedEventBus.PublishAsync(eventData); - } - else - { - Logger.LogError( - $"Could not perform tenant created event. Canceling the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}."); - Logger.LogException(exception); - } - } - - protected virtual async Task HandleErrorTenantConnectionStringUpdatedAsync( - TenantConnectionStringUpdatedEto eventData, - Exception exception) - { - var tryCount = IncrementEventTryCount(eventData); - if (tryCount <= MaxEventTryCount) - { - Logger.LogWarning( - $"Could not perform tenant connection string updated event. Re-queueing the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}."); - Logger.LogException(exception, LogLevel.Warning); - - await Task.Delay(RandomHelper.GetRandom(5000, 15000)); - await DistributedEventBus.PublishAsync(eventData); - } - else - { - Logger.LogError( - $"Could not perform tenant connection string updated event. Canceling the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}."); - Logger.LogException(exception); - } - } - private static int GetEventTryCount(EtoBase eventData) { var tryCountAsString = eventData.Properties.GetOrDefault(TryCountPropertyName); diff --git a/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/PendingMigrationsCheckerBase.cs b/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/PendingMigrationsCheckerBase.cs index 492db8f1..22d69b2d 100644 --- a/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/PendingMigrationsCheckerBase.cs +++ b/shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/PendingMigrationsCheckerBase.cs @@ -1,8 +1,7 @@ using Volo.Abp.DependencyInjection; -namespace EShopOnAbp.Shared.Hosting.Microservices.DbMigrations +namespace EShopOnAbp.Shared.Hosting.Microservices.DbMigrations; + +public abstract class PendingMigrationsCheckerBase : ITransientDependency { - public abstract class PendingMigrationsCheckerBase : ITransientDependency - { - } } \ No newline at end of file diff --git a/shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbp.Shared.Hosting.Microservices.csproj b/shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbp.Shared.Hosting.Microservices.csproj index b4bd451f..948da22e 100644 --- a/shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbp.Shared.Hosting.Microservices.csproj +++ b/shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbp.Shared.Hosting.Microservices.csproj @@ -9,6 +9,7 @@ + diff --git a/shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbpSharedHostingMicroservicesModule.cs b/shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbpSharedHostingMicroservicesModule.cs index 1e9fcfe6..ad58eef3 100644 --- a/shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbpSharedHostingMicroservicesModule.cs +++ b/shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbpSharedHostingMicroservicesModule.cs @@ -1,5 +1,7 @@ using EShopOnAbp.AdministrationService.EntityFrameworkCore; using EShopOnAbp.Shared.Hosting.AspNetCore; +using Medallion.Threading; +using Medallion.Threading.Redis; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; using StackExchange.Redis; @@ -11,37 +13,42 @@ using Volo.Abp.EventBus.RabbitMq; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; -namespace EShopOnAbp.Shared.Hosting.Microservices +namespace EShopOnAbp.Shared.Hosting.Microservices; + +[DependsOn( + typeof(EShopOnAbpSharedHostingAspNetCoreModule), + typeof(AbpBackgroundJobsRabbitMqModule), + typeof(AbpAspNetCoreMultiTenancyModule), + typeof(AbpEventBusRabbitMqModule), + typeof(AbpCachingStackExchangeRedisModule), + typeof(AdministrationServiceEntityFrameworkCoreModule) +)] +public class EShopOnAbpSharedHostingMicroservicesModule : AbpModule { - [DependsOn( - typeof(EShopOnAbpSharedHostingAspNetCoreModule), - typeof(AbpBackgroundJobsRabbitMqModule), - typeof(AbpAspNetCoreMultiTenancyModule), - typeof(AbpEventBusRabbitMqModule), - typeof(AbpCachingStackExchangeRedisModule), - typeof(AdministrationServiceEntityFrameworkCoreModule) - )] - public class EShopOnAbpSharedHostingMicroservicesModule : AbpModule + public override void ConfigureServices(ServiceConfigurationContext context) { - public override void ConfigureServices(ServiceConfigurationContext context) + var configuration = context.Services.GetConfiguration(); + + Configure(options => { - var configuration = context.Services.GetConfiguration(); - var hostingEnvironment = context.Services.GetHostingEnvironment(); + options.IsEnabled = true; + }); - Configure(options => - { - options.IsEnabled = true; - }); + Configure(options => + { + options.KeyPrefix = "EShopOnAbp:"; + }); - Configure(options => - { - options.KeyPrefix = "EShopOnAbp:"; - }); + var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); + context.Services + .AddDataProtection() + .PersistKeysToStackExchangeRedis(redis, "EShopOnAbp-Protection-Keys"); - var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); - context.Services - .AddDataProtection() - .PersistKeysToStackExchangeRedis(redis, "EShopOnAbp-Protection-Keys"); - } + + context.Services.AddSingleton(sp => + { + var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); + return new RedisDistributedSynchronizationProvider(connection.GetDatabase()); + }); } } \ No newline at end of file diff --git a/shared/EShopOnAbp.Shared.Hosting.Microservices/JwtBearerConfigurationHelper.cs b/shared/EShopOnAbp.Shared.Hosting.Microservices/JwtBearerConfigurationHelper.cs index 720f5517..b00229f1 100644 --- a/shared/EShopOnAbp.Shared.Hosting.Microservices/JwtBearerConfigurationHelper.cs +++ b/shared/EShopOnAbp.Shared.Hosting.Microservices/JwtBearerConfigurationHelper.cs @@ -3,23 +3,22 @@ using Microsoft.Extensions.DependencyInjection; using System; using Volo.Abp.Modularity; -namespace EShopOnAbp.Shared.Hosting.Microservices +namespace EShopOnAbp.Shared.Hosting.Microservices; + +public static class JwtBearerConfigurationHelper { - public static class JwtBearerConfigurationHelper + public static void Configure( + ServiceConfigurationContext context, + string audience) { - public static void Configure( - ServiceConfigurationContext context, - string audience) - { - var configuration = context.Services.GetConfiguration(); + var configuration = context.Services.GetConfiguration(); - context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddJwtBearer(options => - { - options.Authority = configuration["AuthServer:Authority"]; - options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); - options.Audience = audience; - }); - } + context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.Authority = configuration["AuthServer:Authority"]; + options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); + options.Audience = audience; + }); } } \ No newline at end of file diff --git a/shared/EShopOnAbp.Shared.Localization/EShopOnAbpSharedLocalizationModule.cs b/shared/EShopOnAbp.Shared.Localization/EShopOnAbpSharedLocalizationModule.cs index 56e1743b..b7ea984c 100644 --- a/shared/EShopOnAbp.Shared.Localization/EShopOnAbpSharedLocalizationModule.cs +++ b/shared/EShopOnAbp.Shared.Localization/EShopOnAbpSharedLocalizationModule.cs @@ -5,30 +5,29 @@ using Volo.Abp.Validation; using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; -namespace EShopOnAbp +namespace EShopOnAbp; + +[DependsOn( + typeof(AbpValidationModule) +)] +public class EShopOnAbpSharedLocalizationModule : AbpModule { - [DependsOn( - typeof(AbpValidationModule) - )] - public class EShopOnAbpSharedLocalizationModule : AbpModule + public override void ConfigureServices(ServiceConfigurationContext context) { - public override void ConfigureServices(ServiceConfigurationContext context) + Configure(options => { - Configure(options => - { - options.FileSets.AddEmbedded(); - }); + options.FileSets.AddEmbedded(); + }); - Configure(options => - { - options.Resources - .Add("en") - .AddBaseTypes( - typeof(AbpValidationResource) - ).AddVirtualJson("/Localization/EShopOnAbp"); + Configure(options => + { + options.Resources + .Add("en") + .AddBaseTypes( + typeof(AbpValidationResource) + ).AddVirtualJson("/Localization/EShopOnAbp"); - options.DefaultResourceType = typeof(EShopOnAbpResource); - }); - } + options.DefaultResourceType = typeof(EShopOnAbpResource); + }); } } \ No newline at end of file