Browse Source

Merge branch 'main' into 11427-Order-Managment

pull/92/head
malik masis 5 years ago
parent
commit
fb45d64f04
  1. 3
      services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/AdministrationServiceHttpApiHostModule.cs
  2. 13
      services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/Controllers/HomeController.cs
  3. 33
      services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationChecker.cs
  4. 139
      services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationEventHandler.cs
  5. 273
      services/basket/src/EShopOnAbp.BasketService/BasketServiceModule.cs
  6. 13
      services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/Controllers/HomeController.cs
  7. 49
      services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationChecker.cs
  8. 83
      services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationEventHandler.cs
  9. 172
      services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/ProductServiceDataSeeder.cs
  10. 13
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/Controllers/HomeController.cs
  11. 11
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/ApplyDatabaseSeedsEto.cs
  12. 28
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/DataSeederEventHandler.cs
  13. 625
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs
  14. 53
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationChecker.cs
  15. 150
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationEventHandler.cs
  16. 13
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/Controllers/HomeController.cs
  17. 33
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationChecker.cs
  18. 89
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationEventHandler.cs
  19. 1
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/OrderingServiceHttpApiHostModule.cs
  20. 13
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/Controllers/HomeController.cs
  21. 33
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationChecker.cs
  22. 79
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationEventHandler.cs
  23. 19
      shared/EShopOnAbp.Shared.Hosting.AspNetCore/EShopOnAbpSharedHostingAspNetCoreModule.cs
  24. 55
      shared/EShopOnAbp.Shared.Hosting.AspNetCore/SerilogConfigurationHelper.cs
  25. 55
      shared/EShopOnAbp.Shared.Hosting.AspNetCore/SwaggerConfigurationHelper.cs
  26. 109
      shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/EfCore/DatabaseEfCoreMigrationEventHandler.cs
  27. 112
      shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/MongoDb/DatabaseMongoDbMigrationEventHandler.cs
  28. 7
      shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/PendingMigrationsCheckerBase.cs
  29. 61
      shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbpSharedHostingMicroservicesModule.cs
  30. 29
      shared/EShopOnAbp.Shared.Hosting.Microservices/JwtBearerConfigurationHelper.cs
  31. 39
      shared/EShopOnAbp.Shared.Localization/EShopOnAbpSharedLocalizationModule.cs

3
services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/AdministrationServiceHttpApiHostModule.cs

@ -2,14 +2,11 @@ using EShopOnAbp.AdministrationService.DbMigrations;
using EShopOnAbp.AdministrationService.EntityFrameworkCore; using EShopOnAbp.AdministrationService.EntityFrameworkCore;
using EShopOnAbp.Shared.Hosting.AspNetCore; using EShopOnAbp.Shared.Hosting.AspNetCore;
using EShopOnAbp.Shared.Hosting.Microservices; using EShopOnAbp.Shared.Hosting.Microservices;
using Medallion.Threading;
using Medallion.Threading.Redis;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using StackExchange.Redis;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;

13
services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/Controllers/HomeController.cs

@ -1,13 +1,12 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.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");
}
} }
} }

33
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.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.AdministrationService.DbMigrations namespace EShopOnAbp.AdministrationService.DbMigrations;
public class AdministrationServiceDatabaseMigrationChecker
: PendingEfCoreMigrationsChecker<AdministrationServiceDbContext>
{ {
public class AdministrationServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker<AdministrationServiceDbContext> 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)
{
}
} }
} }

139
services/administration/src/EShopOnAbp.AdministrationService.HttpApi.Host/DbMigrations/AdministrationServiceDatabaseMigrationEventHandler.cs

@ -1,10 +1,9 @@
using EShopOnAbp.AdministrationService.EntityFrameworkCore; using EShopOnAbp.AdministrationService.EntityFrameworkCore;
using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore; using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore;
using Microsoft.Extensions.Logging; using Serilog;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Serilog;
using Volo.Abp.Authorization.Permissions; using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DistributedLocking; using Volo.Abp.DistributedLocking;
@ -13,105 +12,83 @@ using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.AdministrationService.DbMigrations namespace EShopOnAbp.AdministrationService.DbMigrations;
public class AdministrationServiceDatabaseMigrationEventHandler
: DatabaseEfCoreMigrationEventHandler<AdministrationServiceDbContext>,
IDistributedEventHandler<ApplyDatabaseMigrationsEto>
{ {
public class AdministrationServiceDatabaseMigrationEventHandler private readonly IPermissionDefinitionManager _permissionDefinitionManager;
: DatabaseEfCoreMigrationEventHandler<AdministrationServiceDbContext>, private readonly IPermissionDataSeeder _permissionDataSeeder;
IDistributedEventHandler<TenantCreatedEto>,
IDistributedEventHandler<ApplyDatabaseMigrationsEto> 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; _permissionDefinitionManager = permissionDefinitionManager;
private readonly IPermissionDataSeeder _permissionDataSeeder; _permissionDataSeeder = permissionDataSeeder;
}
public AdministrationServiceDatabaseMigrationEventHandler( public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData)
ICurrentTenant currentTenant, {
IUnitOfWorkManager unitOfWorkManager, if (eventData.DatabaseName != DatabaseName)
ITenantStore tenantStore,
IPermissionDefinitionManager permissionDefinitionManager,
IPermissionDataSeeder permissionDataSeeder,
IDistributedEventBus distributedEventBus,
IAbpDistributedLock distributedLockProvider
) : base(
currentTenant,
unitOfWorkManager,
tenantStore,
distributedEventBus,
AdministrationServiceDbProperties.ConnectionStringName,
distributedLockProvider
)
{ {
_permissionDefinitionManager = permissionDefinitionManager; return;
_permissionDataSeeder = permissionDataSeeder;
} }
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 if (handle != null)
{
await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName))
{ {
Log.Information("AdministrationService acquired lock for db migration and seeding..."); await MigrateDatabaseSchemaAsync();
await SeedDataAsync();
if (handle != null)
{
await MigrateDatabaseSchemaAsync(eventData.TenantId);
await SeedDataAsync(eventData.TenantId);
}
} }
} }
catch (Exception ex)
{
await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
}
} }
catch (Exception ex)
public async Task HandleEventAsync(TenantCreatedEto eventData)
{ {
try await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
{
await MigrateDatabaseSchemaAsync(eventData.Id);
Logger.LogInformation("Starting AdministrationService DataSeeder...");
await SeedDataAsync(eventData.Id);
}
catch (Exception ex)
{
await HandleErrorTenantCreatedAsync(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)) var multiTenancySide = MultiTenancySides.Host;
{
using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true))
{
var multiTenancySide = tenantId == null
? MultiTenancySides.Host
: MultiTenancySides.Tenant;
var permissionNames = _permissionDefinitionManager var permissionNames = _permissionDefinitionManager
.GetPermissions() .GetPermissions()
.Where(p => p.MultiTenancySide.HasFlag(multiTenancySide)) .Where(p => p.MultiTenancySide.HasFlag(multiTenancySide))
.Where(p => !p.Providers.Any() || .Where(p => !p.Providers.Any() ||
p.Providers.Contains(RolePermissionValueProvider.ProviderName)) p.Providers.Contains(RolePermissionValueProvider.ProviderName))
.Select(p => p.Name) .Select(p => p.Name)
.ToArray(); .ToArray();
await _permissionDataSeeder.SeedAsync( await _permissionDataSeeder.SeedAsync(
RolePermissionValueProvider.ProviderName, RolePermissionValueProvider.ProviderName,
"admin", "admin",
permissionNames, permissionNames
tenantId );
);
await uow.CompleteAsync(); await uow.CompleteAsync();
}
}
} }
} }
} }

273
services/basket/src/EShopOnAbp.BasketService/BasketServiceModule.cs

@ -16,175 +16,174 @@ using Volo.Abp.Http.Client;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem; 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( public override void ConfigureServices(ServiceConfigurationContext context)
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) 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(); ConfigureAutoMapper();
ConfigureAspNetCoreRouting(context); ConfigureAspNetCoreRouting(context);
ConfigureGrpc(context); ConfigureGrpc(context);
ConfigureDistributedCache(); ConfigureDistributedCache();
ConfigureVirtualFileSystem(); ConfigureVirtualFileSystem();
ConfigureAuthentication(context, configuration); ConfigureAuthentication(context, configuration);
ConfigureSwagger(context, configuration); ConfigureSwagger(context, configuration);
ConfigureAutoApiControllers(); ConfigureAutoApiControllers();
} }
private void ConfigureAspNetCoreRouting(ServiceConfigurationContext context) private void ConfigureAspNetCoreRouting(ServiceConfigurationContext context)
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{ {
Configure<AbpAspNetCoreMvcOptions>(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()) public override void OnApplicationInitialization(ApplicationInitializationContext context)
{ {
app.UseDeveloperExceptionPage(); var app = context.GetApplicationBuilder();
} var env = context.GetEnvironment();
app.UseCorrelationId(); if (env.IsDevelopment())
app.UseCors();
app.UseAbpRequestLocalization();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAbpClaimsMap();
app.UseAuthorization();
app.UseSwagger();
app.UseSwaggerUI(options =>
{
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
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( app.UseDeveloperExceptionPage();
context: context,
authority: configuration["AuthServer:Authority"],
scopes: new
Dictionary<string, string> /* 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) 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<IConfiguration>();
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<string, string> /* 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(
builder configuration["App:CorsOrigins"]
.WithOrigins( .Split(",", StringSplitOptions.RemoveEmptyEntries)
configuration["App:CorsOrigins"] .Select(o => o.Trim().RemovePostFix("/"))
.Split(",", StringSplitOptions.RemoveEmptyEntries) .ToArray()
.Select(o => o.Trim().RemovePostFix("/")) )
.ToArray() .WithAbpExposedHeaders()
) .SetIsOriginAllowedToAllowWildcardSubdomains()
.WithAbpExposedHeaders() .AllowAnyHeader()
.SetIsOriginAllowedToAllowWildcardSubdomains() .AllowAnyMethod()
.AllowAnyHeader() .AllowCredentials();
.AllowAnyMethod()
.AllowCredentials();
});
}); });
});
Configure<AbpAntiForgeryOptions>(options => { options.AutoValidate = false; }); Configure<AbpAntiForgeryOptions>(options => { options.AutoValidate = false; });
} }
private void ConfigureAutoApiControllers() private void ConfigureAutoApiControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{ {
Configure<AbpAspNetCoreMvcOptions>(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<ProductPublic.ProductPublicClient>((services, options) =>
{ {
context.Services.AddGrpcClient<ProductPublic.ProductPublicClient>((services, options) => var remoteServiceOptions = services.GetRequiredService<IOptionsMonitor<AbpRemoteServiceOptions>>().CurrentValue;
{ var catalogServiceConfiguration = remoteServiceOptions.RemoteServices.GetConfigurationOrDefault("Catalog");
var remoteServiceOptions = services.GetRequiredService<IOptionsMonitor<AbpRemoteServiceOptions>>().CurrentValue; var catalogGrpcUrl = catalogServiceConfiguration.GetOrDefault("GrpcUrl");
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<AbpAutoMapperOptions>(options =>
{ {
Configure<AbpAutoMapperOptions>(options => options.AddMaps<BasketServiceModule>();
{ });
options.AddMaps<BasketServiceModule>(); }
});
}
private void ConfigureDistributedCache() private void ConfigureDistributedCache()
{
Configure<AbpDistributedCacheOptions>(options =>
{ {
Configure<AbpDistributedCacheOptions>(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<AbpVirtualFileSystemOptions>(options =>
{ {
Configure<AbpVirtualFileSystemOptions>(options => options.FileSets.AddEmbedded<BasketServiceModule>();
{ });
options.FileSets.AddEmbedded<BasketServiceModule>();
});
}
} }
} }

13
services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/Controllers/HomeController.cs

@ -1,13 +1,12 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.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");
}
} }
} }

49
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.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.CatalogService.DbMigrations namespace EShopOnAbp.CatalogService.DbMigrations;
public class CatalogServiceDatabaseMigrationChecker : PendingMongoDbMigrationsChecker<CatalogServiceMongoDbContext>
{ {
public class CatalogServiceDatabaseMigrationChecker : PendingMongoDbMigrationsChecker<CatalogServiceMongoDbContext> private readonly ProductServiceDataSeeder _productServiceDataSeeder;
{
private readonly ProductServiceDataSeeder _productServiceDataSeeder;
public CatalogServiceDatabaseMigrationChecker( public CatalogServiceDatabaseMigrationChecker(
IUnitOfWorkManager unitOfWorkManager, IUnitOfWorkManager unitOfWorkManager,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
IDistributedEventBus distributedEventBus, IDistributedEventBus distributedEventBus,
ProductServiceDataSeeder productServiceDataSeeder) ProductServiceDataSeeder productServiceDataSeeder)
: base( : base(
unitOfWorkManager, unitOfWorkManager,
serviceProvider, serviceProvider,
currentTenant, currentTenant,
distributedEventBus, distributedEventBus,
CatalogServiceDbProperties.ConnectionStringName) CatalogServiceDbProperties.ConnectionStringName)
{ {
_productServiceDataSeeder = productServiceDataSeeder; _productServiceDataSeeder = productServiceDataSeeder;
} }
public override async Task CheckAsync() public override async Task CheckAsync()
{ {
await base.CheckAsync(); await base.CheckAsync();
await _productServiceDataSeeder.SeedAsync(); await _productServiceDataSeeder.SeedAsync();
}
} }
} }

83
services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/CatalogServiceDatabaseMigrationEventHandler.cs

@ -9,59 +9,58 @@ using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.CatalogService.DbMigrations namespace EShopOnAbp.CatalogService.DbMigrations;
{
public class CatalogServiceDatabaseMigrationEventHandler public class CatalogServiceDatabaseMigrationEventHandler
: DatabaseMongoDbMigrationEventHandler<CatalogServiceMongoDbContext>, : DatabaseMongoDbMigrationEventHandler<CatalogServiceMongoDbContext>,
IDistributedEventHandler<ApplyDatabaseMigrationsEto> IDistributedEventHandler<ApplyDatabaseMigrationsEto>
{
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, public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData)
ITenantStore tenantStore, {
IDistributedEventBus distributedEventBus, if (eventData.DatabaseName != DatabaseName)
IServiceProvider serviceProvider,
IAbpDistributedLock distributedLockProvider
) : base(
currentTenant,
unitOfWorkManager,
tenantStore,
distributedEventBus,
CatalogServiceDbProperties.ConnectionStringName,
serviceProvider,
distributedLockProvider)
{ {
return;
} }
public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) if (eventData.TenantId != null)
{ {
if (eventData.DatabaseName != DatabaseName) return;
{ }
return;
}
if (eventData.TenantId != null) try
{ {
return; Log.Information("CatalogService has acquired lock for db migration...");
}
try await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName))
{ {
Log.Information("CatalogService has acquired lock for db migration..."); if (handle != null)
await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName))
{ {
if (handle != null) Log.Information("CatalogService is migrating database...");
{ await MigrateDatabaseSchemaAsync();
Log.Information("CatalogService is migrating database...");
await MigrateDatabaseSchemaAsync(null);
}
} }
} }
catch (Exception ex) }
{ catch (Exception ex)
await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); {
} await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
} }
} }
} }

172
services/catalog/src/EShopOnAbp.CatalogService.HttpApi.Host/DbMigrations/ProductServiceDataSeeder.cs

@ -1,110 +1,108 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using EShopOnAbp.CatalogService.Products; using EShopOnAbp.CatalogService.Products;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow; 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<Product, Guid> _productRepository;
public ProductServiceDataSeeder(
IRepository<Product, Guid> productRepository,
ProductManager productManager)
{ {
private readonly ProductManager _productManager; _productRepository = productRepository;
private readonly IRepository<Product, Guid> _productRepository; _productManager = productManager;
}
public ProductServiceDataSeeder( [UnitOfWork]
IRepository<Product, Guid> productRepository, public virtual async Task SeedAsync()
ProductManager productManager) {
{ await AddProductsAsync();
_productRepository = productRepository; }
_productManager = productManager;
}
[UnitOfWork] private async Task AddProductsAsync()
public virtual async Task SeedAsync() {
if (await _productRepository.GetCountAsync() > 0)
{ {
await AddProductsAsync(); return;
} }
private async Task AddProductsAsync() await _productManager.CreateAsync(
{ "ABP04918",
if (await _productRepository.GetCountAsync() > 0) "Lego Star Wars - 75059 Sandcrawler UCS",
{ 999,
return; 42,
} "lego.jpg"
);
await _productManager.CreateAsync(
"ABP04918",
"Lego Star Wars - 75059 Sandcrawler UCS",
999,
42,
"lego.jpg"
);
await _productManager.CreateAsync( await _productManager.CreateAsync(
"ABP23849", "ABP23849",
"Nikon AF-S 50mm f/1.8 G Lens", "Nikon AF-S 50mm f/1.8 G Lens",
1499, 1499,
56, 56,
"nikon.jpg" "nikon.jpg"
); );
await _productManager.CreateAsync( await _productManager.CreateAsync(
"ABP82731", "ABP82731",
"Beats Solo3 Wireless On-Ear Headphone", "Beats Solo3 Wireless On-Ear Headphone",
97, 97,
20, 20,
"beats.jpg" "beats.jpg"
); );
await _productManager.CreateAsync( await _productManager.CreateAsync(
"ABP12322", "ABP12322",
"Rampage Sn-Rw2 Gamer Headphone", "Rampage Sn-Rw2 Gamer Headphone",
654, 654,
42, 42,
"rampage.jpg" "rampage.jpg"
); );
await _productManager.CreateAsync( await _productManager.CreateAsync(
"ABP00291", "ABP00291",
"Asus Transformer Book T300CHI-FH011H", "Asus Transformer Book T300CHI-FH011H",
1249, 1249,
3, 3,
"asus.jpg" "asus.jpg"
); );
await _productManager.CreateAsync( await _productManager.CreateAsync(
"ABP02918", "ABP02918",
"OKI C332DN Dublex + Network A4 Laser Printer", "OKI C332DN Dublex + Network A4 Laser Printer",
215, 215,
6, 6,
"oki.jpg" "oki.jpg"
); );
await _productManager.CreateAsync( await _productManager.CreateAsync(
"ABP11121", "ABP11121",
"Bluecat Rd810 Mini Led", "Bluecat Rd810 Mini Led",
449, 449,
13, 13,
"bluecat.jpg" "bluecat.jpg"
); );
await _productManager.CreateAsync( await _productManager.CreateAsync(
"ABP44432", "ABP44432",
"Sunny 55\" TV 4K Ultra HD Curved Smart Led TV", "Sunny 55\" TV 4K Ultra HD Curved Smart Led TV",
2249, 2249,
1, 1,
"sunny.jpg" "sunny.jpg"
); );
await _productManager.CreateAsync( await _productManager.CreateAsync(
"ABP37182", "ABP37182",
"Sony Playstation 4 Slim 500 GB (PAL)", "Sony Playstation 4 Slim 500 GB (PAL)",
699, 699,
120, 120,
"playstation.jpg" "playstation.jpg"
); );
}
} }
} }

13
services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/Controllers/HomeController.cs

@ -1,13 +1,12 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.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");
}
} }
} }

11
services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/ApplyDatabaseSeedsEto.cs

@ -1,10 +1,9 @@
using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus; 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
{
}
}

28
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.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus; using Volo.Abp.EventBus;
namespace EShopOnAbp.IdentityService.DbMigrations namespace EShopOnAbp.IdentityService.DbMigrations;
public class DataSeederEventHandler : ILocalEventHandler<ApplyDatabaseSeedsEto>, ITransientDependency
{ {
public class DataSeederEventHandler : ILocalEventHandler<ApplyDatabaseSeedsEto>, ITransientDependency protected IDataSeeder DataSeeder { get; }
{
protected IDataSeeder DataSeeder { get; }
public DataSeederEventHandler(IDataSeeder dataSeeder) public DataSeederEventHandler(IDataSeeder dataSeeder)
{ {
DataSeeder = dataSeeder; DataSeeder = dataSeeder;
} }
public async Task HandleEventAsync(ApplyDatabaseSeedsEto eventData) public async Task HandleEventAsync(ApplyDatabaseSeedsEto eventData)
{ {
await DataSeeder.SeedAsync(); await DataSeeder.SeedAsync();
}
} }
} }

625
services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs

@ -20,381 +20,380 @@ using ApiResource = Volo.Abp.IdentityServer.ApiResources.ApiResource;
using ApiScope = Volo.Abp.IdentityServer.ApiScopes.ApiScope; using ApiScope = Volo.Abp.IdentityServer.ApiScopes.ApiScope;
using Client = Volo.Abp.IdentityServer.Clients.Client; 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; _clientRepository = clientRepository;
private readonly IApiScopeRepository _apiScopeRepository; _apiResourceRepository = apiResourceRepository;
private readonly IClientRepository _clientRepository; _apiScopeRepository = apiScopeRepository;
private readonly IIdentityResourceDataSeeder _identityResourceDataSeeder; _identityResourceDataSeeder = identityResourceDataSeeder;
private readonly IGuidGenerator _guidGenerator; _guidGenerator = guidGenerator;
private readonly IPermissionDataSeeder _permissionDataSeeder; _permissionDataSeeder = permissionDataSeeder;
private readonly IConfiguration _configuration; _configuration = configuration;
private readonly ICurrentTenant _currentTenant; _currentTenant = currentTenant;
}
public IdentityServerDataSeeder( public virtual Task SeedAsync(DataSeedContext context)
IClientRepository clientRepository, {
IApiResourceRepository apiResourceRepository, return SeedAsync();
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) [UnitOfWork]
public virtual async Task SeedAsync()
{
using (_currentTenant.Change(null))
{ {
return SeedAsync(); await _identityResourceDataSeeder.CreateStandardResourcesAsync();
await CreateApiResourcesAsync();
await CreateApiScopesAsync();
await CreateSwaggerClientsAsync();
await CreateClientsAsync();
} }
}
[UnitOfWork] private async Task CreateApiResourcesAsync()
public virtual async Task SeedAsync() {
var commonApiUserClaims = new[]
{ {
using (_currentTenant.Change(null)) "email",
{ "email_verified",
await _identityResourceDataSeeder.CreateStandardResourcesAsync(); "name",
await CreateApiResourcesAsync(); "phone_number",
await CreateApiScopesAsync(); "phone_number_verified",
await CreateSwaggerClientsAsync(); "role"
await CreateClientsAsync(); };
}
}
private async Task CreateApiResourcesAsync() await CreateApiResourceAsync("AccountService", commonApiUserClaims);
{ await CreateApiResourceAsync("IdentityService", commonApiUserClaims);
var commonApiUserClaims = new[] await CreateApiResourceAsync("AdministrationService", commonApiUserClaims);
{ await CreateApiResourceAsync("CatalogService", commonApiUserClaims);
"email", await CreateApiResourceAsync("BasketService", commonApiUserClaims);
"email_verified", await CreateApiResourceAsync("OrderingService", commonApiUserClaims);
"name", await CreateApiResourceAsync("PaymentService", commonApiUserClaims);
"phone_number", }
"phone_number_verified",
"role"
};
await CreateApiResourceAsync("AccountService", commonApiUserClaims); private async Task CreateApiScopesAsync()
await CreateApiResourceAsync("IdentityService", commonApiUserClaims); {
await CreateApiResourceAsync("AdministrationService", commonApiUserClaims); await CreateApiScopeAsync("AccountService");
await CreateApiResourceAsync("CatalogService", commonApiUserClaims); await CreateApiScopeAsync("IdentityService");
await CreateApiResourceAsync("BasketService", commonApiUserClaims); await CreateApiScopeAsync("AdministrationService");
await CreateApiResourceAsync("OrderingService", commonApiUserClaims); await CreateApiScopeAsync("CatalogService");
await CreateApiResourceAsync("PaymentService", commonApiUserClaims); 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"); "email",
await CreateApiScopeAsync("IdentityService"); "openid",
await CreateApiScopeAsync("AdministrationService"); "profile",
await CreateApiScopeAsync("CatalogService"); "role",
await CreateApiScopeAsync("BasketService"); "phone",
await CreateApiScopeAsync("OrderingService"); "address"
await CreateApiScopeAsync("PaymentService"); };
} scopes ??= new[] {name};
private async Task CreateSwaggerClientsAsync() // Swagger Client
var swaggerClientId = $"{name}_Swagger";
if (!swaggerClientId.IsNullOrWhiteSpace())
{ {
await CreateWebGatewaySwaggerClientAsync("WebGateway", var webGatewaySwaggerRootUrl = _configuration[$"IdentityServerClients:{name}:RootUrl"].TrimEnd('/');
new[] 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<string>
{
$"{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", webGatewaySwaggerRootUrl.RemovePostFix("/"),
"CatalogService", "BasketService", publicWebGatewayRootUrl.RemovePostFix("/"),
"PaymentService", "OrderingService" 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<ApiResource> CreateApiResourceAsync(string name, IEnumerable<string> claims)
{
var apiResource = await _apiResourceRepository.FindByNameAsync(name);
if (apiResource == null)
{ {
var commonScopes = new[] apiResource = await _apiResourceRepository.InsertAsync(
{ new ApiResource(
"email", _guidGenerator.Create(),
"openid", name,
"profile", name + " API"
"role", ),
"phone", autoSave: true
"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<string>
{
$"{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("/")
}
);
}
} }
private async Task<ApiResource> CreateApiResourceAsync(string name, IEnumerable<string> claims) foreach (var claim in claims)
{ {
var apiResource = await _apiResourceRepository.FindByNameAsync(name); if (apiResource.FindClaim(claim) == null)
if (apiResource == null)
{ {
apiResource = await _apiResourceRepository.InsertAsync( apiResource.AddUserClaim(claim);
new ApiResource(
_guidGenerator.Create(),
name,
name + " API"
),
autoSave: true
);
}
foreach (var claim in claims)
{
if (apiResource.FindClaim(claim) == null)
{
apiResource.AddUserClaim(claim);
}
} }
return await _apiResourceRepository.UpdateAsync(apiResource);
} }
private async Task<ApiScope> CreateApiScopeAsync(string name) return await _apiResourceRepository.UpdateAsync(apiResource);
{ }
var apiScope = await _apiScopeRepository.FindByNameAsync(name);
if (apiScope == null)
{
apiScope = await _apiScopeRepository.InsertAsync(
new ApiScope(
_guidGenerator.Create(),
name,
name + " API"
),
autoSave: true
);
}
return apiScope; private async Task<ApiScope> 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", "AccountService",
"openid", "AdministrationService",
"profile", "CatalogService",
"role", "BasketService",
"phone", "PaymentService",
"address" "OrderingService"
}; }),
grantTypes: new[] {"hybrid"},
secret: "1q2w3e*".Sha256(),
redirectUris: new List<string>{ $"{publicWebClientRootUrl}signin-oidc" },
postLogoutRedirectUri: $"{publicWebClientRootUrl}signout-callback-oidc",
frontChannelLogoutUri: $"{publicWebClientRootUrl}Account/FrontChannelLogout",
corsOrigins: new[] {publicWebClientRootUrl.RemovePostFix("/")}
);
//Public Web Client //Angular Client
var publicWebClientRootUrl = _configuration["IdentityServerClients:PublicWeb:RootUrl"] var angularClientRootUrl =
.EnsureEndsWith('/'); _configuration["IdentityServerClients:Web:RootUrl"].TrimEnd('/');
await CreateClientAsync( await CreateClientAsync(
name: "PublicWeb", name: "Web",
scopes: commonScopes.Union(new[] scopes: commonScopes.Union(new[]
{ {
"AccountService", "AccountService",
"AdministrationService", "IdentityService",
"CatalogService", "AdministrationService",
"BasketService", "CatalogService"
"PaymentService", }),
"OrderingService" grantTypes: new[] {"authorization_code", "LinkLogin", "password"},
}), secret: "1q2w3e*".Sha256(),
grantTypes: new[] {"hybrid"}, requirePkce: true,
secret: "1q2w3e*".Sha256(), requireClientSecret: false,
redirectUris: new List<string>{ $"{publicWebClientRootUrl}signin-oidc" }, redirectUris: new List<string>{ $"{angularClientRootUrl}" },
postLogoutRedirectUri: $"{publicWebClientRootUrl}signout-callback-oidc", postLogoutRedirectUri: $"{angularClientRootUrl}",
frontChannelLogoutUri: $"{publicWebClientRootUrl}Account/FrontChannelLogout", corsOrigins: new[] {angularClientRootUrl}
corsOrigins: new[] {publicWebClientRootUrl.RemovePostFix("/")} );
);
//Angular Client //Administration Service Client
var angularClientRootUrl = await CreateClientAsync(
_configuration["IdentityServerClients:Web:RootUrl"].TrimEnd('/'); name: "EShopOnAbp_AdministrationService",
await CreateClientAsync( scopes: commonScopes.Union(new[]
name: "Web", {
scopes: commonScopes.Union(new[] "IdentityService"
{ }),
"AccountService", grantTypes: new[] {"client_credentials"},
"IdentityService", secret: "1q2w3e*".Sha256(),
"AdministrationService", permissions: new[] {IdentityPermissions.Users.Default}
"CatalogService" );
}), }
grantTypes: new[] {"authorization_code", "LinkLogin", "password"},
secret: "1q2w3e*".Sha256(),
requirePkce: true,
requireClientSecret: false,
redirectUris: new List<string>{ $"{angularClientRootUrl}" },
postLogoutRedirectUri: $"{angularClientRootUrl}",
corsOrigins: new[] {angularClientRootUrl}
);
//Administration Service Client private async Task<Client> CreateClientAsync(
await CreateClientAsync( string name,
name: "EShopOnAbp_AdministrationService", IEnumerable<string> scopes,
scopes: commonScopes.Union(new[] IEnumerable<string> grantTypes,
string secret = null,
List<string> redirectUris = null,
string postLogoutRedirectUri = null,
string frontChannelLogoutUri = null,
bool requireClientSecret = true,
bool requirePkce = false,
IEnumerable<string> permissions = null,
IEnumerable<string> corsOrigins = null)
{
var client = await _clientRepository.FindByClientIdAsync(name);
if (client == null)
{
client = await _clientRepository.InsertAsync(
new Client(
_guidGenerator.Create(),
name
)
{ {
"IdentityService" ClientName = name,
}), ProtocolType = "oidc",
grantTypes: new[] {"client_credentials"}, Description = name,
secret: "1q2w3e*".Sha256(), AlwaysIncludeUserClaimsInIdToken = true,
permissions: new[] {IdentityPermissions.Users.Default} 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<Client> CreateClientAsync( foreach (var scope in scopes)
string name,
IEnumerable<string> scopes,
IEnumerable<string> grantTypes,
string secret = null,
List<string> redirectUris = null,
string postLogoutRedirectUri = null,
string frontChannelLogoutUri = null,
bool requireClientSecret = true,
bool requirePkce = false,
IEnumerable<string> permissions = null,
IEnumerable<string> corsOrigins = null)
{ {
var client = await _clientRepository.FindByClientIdAsync(name); if (client.FindScope(scope) == null)
if (client == null)
{ {
client = await _clientRepository.InsertAsync( client.AddScope(scope);
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);
}
} }
}
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) if (permissions != null)
{ {
await _permissionDataSeeder.SeedAsync( await _permissionDataSeeder.SeedAsync(
ClientPermissionValueProvider.ProviderName, ClientPermissionValueProvider.ProviderName,
name, name,
permissions, permissions,
null 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);
} }
} }

53
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.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.IdentityService.DbMigrations namespace EShopOnAbp.IdentityService.DbMigrations;
public class IdentityServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker<IdentityServiceDbContext>
{ {
public class IdentityServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker<IdentityServiceDbContext> 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( public override async Task<bool> CheckAsync()
IUnitOfWorkManager unitOfWorkManager, {
IServiceProvider serviceProvider, var isMigrationRequired = await base.CheckAsync();
ICurrentTenant currentTenant,
IDistributedEventBus distributedEventBus,
ILocalEventBus localEventBus)
: base(
unitOfWorkManager,
serviceProvider,
currentTenant,
distributedEventBus,
IdentityServiceDbProperties.ConnectionStringName)
{
LocalEventBus = localEventBus;
}
public override async Task<bool> CheckAsync() if (!isMigrationRequired)
{ {
var isMigrationRequired = await base.CheckAsync(); await LocalEventBus.PublishAsync(new ApplyDatabaseSeedsEto());
if (!isMigrationRequired)
{
await LocalEventBus.PublishAsync(new ApplyDatabaseSeedsEto());
}
return isMigrationRequired;
} }
return isMigrationRequired;
} }
} }

150
services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServiceDatabaseMigrationEventHandler.cs

@ -1,116 +1,90 @@
using EShopOnAbp.IdentityService.EntityFrameworkCore; using EShopOnAbp.IdentityService.EntityFrameworkCore;
using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore;
using Serilog; using Serilog;
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using EShopOnAbp.Shared.Hosting.Microservices.DbMigrations.EfCore;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DistributedLocking;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local; using Volo.Abp.EventBus.Local;
using Volo.Abp.Identity; using Volo.Abp.Identity;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
using Volo.Abp.DistributedLocking;
namespace EShopOnAbp.IdentityService.DbMigrations namespace EShopOnAbp.IdentityService.DbMigrations;
public class IdentityServiceDatabaseMigrationEventHandler
: DatabaseEfCoreMigrationEventHandler<IdentityServiceDbContext>,
IDistributedEventHandler<ApplyDatabaseMigrationsEto>
{ {
public class IdentityServiceDatabaseMigrationEventHandler private readonly IIdentityDataSeeder _identityDataSeeder;
: DatabaseEfCoreMigrationEventHandler<IdentityServiceDbContext>, private readonly IdentityServerDataSeeder _identityServerDataSeeder;
IDistributedEventHandler<TenantCreatedEto>, private readonly ILocalEventBus _localEventBus;
IDistributedEventHandler<ApplyDatabaseMigrationsEto>
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; _identityDataSeeder = identityDataSeeder;
private readonly IdentityServerDataSeeder _identityServerDataSeeder; _identityServerDataSeeder = identityServerDataSeeder;
private readonly ILocalEventBus _localEventBus; _localEventBus = localEventBus;
}
public IdentityServiceDatabaseMigrationEventHandler( public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData)
ICurrentTenant currentTenant, {
IUnitOfWorkManager unitOfWorkManager, if (eventData.DatabaseName != DatabaseName)
ITenantStore tenantStore,
IIdentityDataSeeder identityDataSeeder,
IdentityServerDataSeeder identityServerDataSeeder,
IDistributedEventBus distributedEventBus,
ILocalEventBus localEventBus,
IAbpDistributedLock distributedLockProvider
) : base(
currentTenant,
unitOfWorkManager,
tenantStore,
distributedEventBus,
IdentityServiceDbProperties.ConnectionStringName,
distributedLockProvider)
{ {
_identityDataSeeder = identityDataSeeder; return;
_identityServerDataSeeder = identityServerDataSeeder;
_localEventBus = localEventBus;
} }
public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) try
{ {
if (eventData.DatabaseName != DatabaseName) await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName))
{ {
return; Log.Information("IdentityService has acquired lock for db migration...");
}
try if (handle != null)
{
await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName))
{ {
Log.Information("IdentityService has acquired lock for db migration..."); Log.Information("IdentityService is migrating database...");
await MigrateDatabaseSchemaAsync();
if (handle != null) Log.Information("IdentityService is seeding data...");
{ await SeedDataAsync(
Log.Information("IdentityService is migrating database..."); adminEmail: IdentityServiceDbProperties.DefaultAdminEmailAddress,
await MigrateDatabaseSchemaAsync(eventData.TenantId); adminPassword: IdentityServiceDbProperties.DefaultAdminPassword
Log.Information("IdentityService is seeding data..."); );
await SeedDataAsync(
tenantId: eventData.TenantId,
adminEmail: IdentityServiceDbProperties.DefaultAdminEmailAddress,
adminPassword: IdentityServiceDbProperties.DefaultAdminPassword
);
}
} }
await _localEventBus.PublishAsync(new ApplyDatabaseSeedsEto());
} }
catch (Exception ex)
{
await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
}
}
public async Task HandleEventAsync(TenantCreatedEto eventData) await _localEventBus.PublishAsync(new ApplyDatabaseSeedsEto());
{
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)) await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
{
if (tenantId == null)
{
Log.Information($"Seeding IdentityServer data...");
await _identityServerDataSeeder.SeedAsync();
}
Log.Information($"Seeding user data...");
await _identityDataSeeder.SeedAsync(
adminEmail,
adminPassword,
tenantId
);
}
} }
} }
}
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
);
}
}

13
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/Controllers/HomeController.cs

@ -1,13 +1,12 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.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");
}
} }
} }

33
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.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.OrderingService.DbMigrations namespace EShopOnAbp.OrderingService.DbMigrations;
public class OrderingServiceDatabaseMigrationChecker
: PendingEfCoreMigrationsChecker<OrderingServiceDbContext>
{ {
public class OrderingServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker<OrderingServiceDbContext> 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)
{
}
} }
} }

89
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/DbMigrations/OrderingServiceDatabaseMigrationEventHandler.cs

@ -9,63 +9,62 @@ using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.OrderingService.DbMigrations namespace EShopOnAbp.OrderingService.DbMigrations;
{
public class OrderingServiceDatabaseMigrationEventHandler public class OrderingServiceDatabaseMigrationEventHandler
: DatabaseEfCoreMigrationEventHandler<OrderingServiceDbContext>, : DatabaseEfCoreMigrationEventHandler<OrderingServiceDbContext>,
IDistributedEventHandler<ApplyDatabaseMigrationsEto> IDistributedEventHandler<ApplyDatabaseMigrationsEto>
{
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; _dataSeeder = dataSeeder;
}
public OrderingServiceDatabaseMigrationEventHandler( public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData)
ICurrentTenant currentTenant, {
IUnitOfWorkManager unitOfWorkManager, if (eventData.DatabaseName != DatabaseName)
ITenantStore tenantStore,
IDistributedEventBus distributedEventBus,
IDataSeeder dataSeeder,
IAbpDistributedLock distributedLockProvider)
: base(
currentTenant,
unitOfWorkManager,
tenantStore,
distributedEventBus,
OrderingServiceDbProperties.ConnectionStringName,
distributedLockProvider)
{ {
_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 if (handle != null)
{
await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName))
{ {
Log.Information("OrderingService has acquired lock for db migration..."); Log.Information("OrderingService is migrating database...");
await MigrateDatabaseSchemaAsync();
if (handle != null) Log.Information("OrderingService is seeding data...");
{ await _dataSeeder.SeedAsync();
Log.Information("OrderingService is migrating database...");
await MigrateDatabaseSchemaAsync(null);
Log.Information("OrderingService is seeding data...");
await _dataSeeder.SeedAsync();
}
} }
} }
catch (Exception ex) }
{ catch (Exception ex)
await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); {
} await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
} }
} }
} }

1
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Host/OrderingServiceHttpApiHostModule.cs

@ -21,7 +21,6 @@ namespace EShopOnAbp.OrderingService;
typeof(OrderingServiceHttpApiModule), typeof(OrderingServiceHttpApiModule),
typeof(OrderingServiceApplicationModule), typeof(OrderingServiceApplicationModule),
typeof(OrderingServiceEntityFrameworkCoreModule), typeof(OrderingServiceEntityFrameworkCoreModule),
//typeof(MedallionAbpDistributedLock),
typeof(EShopOnAbpSharedHostingMicroservicesModule) typeof(EShopOnAbpSharedHostingMicroservicesModule)
)] )]
public class OrderingServiceHttpApiHostModule : AbpModule public class OrderingServiceHttpApiHostModule : AbpModule

13
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/Controllers/HomeController.cs

@ -1,13 +1,12 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.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");
}
} }
} }

33
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.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.PaymentService.DbMigrations namespace EShopOnAbp.PaymentService.DbMigrations;
public class PaymentServiceDatabaseMigrationChecker
: PendingEfCoreMigrationsChecker<PaymentServiceDbContext>
{ {
public class PaymentServiceDatabaseMigrationChecker : PendingEfCoreMigrationsChecker<PaymentServiceDbContext> 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)
{
}
} }
} }

79
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/DbMigrations/PaymentServiceDatabaseMigrationEventHandler.cs

@ -9,57 +9,56 @@ using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EShopOnAbp.PaymentService.DbMigrations namespace EShopOnAbp.PaymentService.DbMigrations;
{
public class PaymentServiceDatabaseMigrationEventHandler public class PaymentServiceDatabaseMigrationEventHandler
: DatabaseEfCoreMigrationEventHandler<PaymentServiceDbContext>, : DatabaseEfCoreMigrationEventHandler<PaymentServiceDbContext>,
IDistributedEventHandler<ApplyDatabaseMigrationsEto> IDistributedEventHandler<ApplyDatabaseMigrationsEto>
{
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, public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData)
ITenantStore tenantStore, {
IDistributedEventBus distributedEventBus, if (eventData.DatabaseName != DatabaseName)
IAbpDistributedLock distributedLockProvider)
: base(
currentTenant,
unitOfWorkManager,
tenantStore,
distributedEventBus,
PaymentServiceDbProperties.ConnectionStringName,
distributedLockProvider)
{ {
return;
} }
public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData) if (eventData.TenantId != null)
{ {
if (eventData.DatabaseName != DatabaseName) return;
{ }
return;
}
if (eventData.TenantId != null) try
{ {
return; Log.Information("PaymentService has acquired lock for db migration...");
}
try await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName))
{ {
Log.Information("PaymentService has acquired lock for db migration..."); if (handle != null)
await using (var handle = await DistributedLockProvider.TryAcquireAsync(DatabaseName))
{ {
if (handle != null) Log.Information("PaymentService is migrating database...");
{ await MigrateDatabaseSchemaAsync();
Log.Information("PaymentService is migrating database...");
await MigrateDatabaseSchemaAsync(null);
}
} }
} }
catch (Exception ex) }
{ catch (Exception ex)
await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex); {
} await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
} }
} }
} }

19
shared/EShopOnAbp.Shared.Hosting.AspNetCore/EShopOnAbpSharedHostingAspNetCoreModule.cs

@ -2,17 +2,16 @@
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle; 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( public override void ConfigureServices(ServiceConfigurationContext context)
typeof(EShopOnAbpSharedHostingModule),
typeof(AbpSwashbuckleModule),
typeof(AbpAspNetCoreSerilogModule)
)]
public class EShopOnAbpSharedHostingAspNetCoreModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
} }
} }

55
shared/EShopOnAbp.Shared.Hosting.AspNetCore/SerilogConfigurationHelper.cs

@ -1,40 +1,39 @@
using Serilog; using Serilog;
using Serilog.Events; 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()
// TODO: Uncomment following lines for ElasticSearch configuration // .SetBasePath(Directory.GetCurrentDirectory())
// var configuration = new ConfigurationBuilder() // .AddJsonFile("appsettings.json")
// .SetBasePath(Directory.GetCurrentDirectory()) // .AddEnvironmentVariables()
// .AddJsonFile("appsettings.json") // .Build();
// .AddEnvironmentVariables()
// .Build();
Log.Logger = new LoggerConfiguration() Log.Logger = new LoggerConfiguration()
#if DEBUG #if DEBUG
.MinimumLevel.Debug() .MinimumLevel.Debug()
#else #else
.MinimumLevel.Information() .MinimumLevel.Information()
#endif #endif
.MinimumLevel.Override("Microsoft", LogEventLevel.Information) .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
.Enrich.FromLogContext() .Enrich.FromLogContext()
.Enrich.WithProperty("Application", $"{applicationName}") .Enrich.WithProperty("Application", $"{applicationName}")
.WriteTo.Async(c => c.File("Logs/logs.txt")) .WriteTo.Async(c => c.File("Logs/logs.txt"))
// TODO: Uncomment following lines for ElasticSearch configuration // TODO: Uncomment following lines for ElasticSearch configuration
// .WriteTo.Elasticsearch( // .WriteTo.Elasticsearch(
// new ElasticsearchSinkOptions(new Uri(configuration["ElasticSearch:Url"])) // new ElasticsearchSinkOptions(new Uri(configuration["ElasticSearch:Url"]))
// { // {
// AutoRegisterTemplate = true, // AutoRegisterTemplate = true,
// AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6, // AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6,
// IndexFormat = "MyProjectName-log-{0:yyyy.MM}" // IndexFormat = "MyProjectName-log-{0:yyyy.MM}"
// }) // })
.WriteTo.Async(c => c.Console()) .WriteTo.Async(c => c.Console())
.CreateLogger(); .CreateLogger();
}
} }
} }

55
shared/EShopOnAbp.Shared.Hosting.AspNetCore/SwaggerConfigurationHelper.cs

@ -3,40 +3,39 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Volo.Abp.Modularity; 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( context.Services.AddSwaggerGen(options =>
ServiceConfigurationContext context,
string apiTitle
)
{ {
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<string, string> 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.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName); options.CustomSchemaIds(type => type.FullName);
}); });
}
public static void ConfigureWithAuth(
ServiceConfigurationContext context,
string authority,
Dictionary<string, string> 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);
});
}
} }
} }

109
shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/EfCore/DatabaseEfCoreMigrationEventHandler.cs

@ -1,13 +1,12 @@
using System; using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Medallion.Threading;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Serilog; using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DistributedLocking; using Volo.Abp.DistributedLocking;
@ -24,7 +23,6 @@ public abstract class DatabaseEfCoreMigrationEventHandler<TDbContext> : Database
{ {
protected const string TryCountPropertyName = "TryCount"; protected const string TryCountPropertyName = "TryCount";
protected const int MaxEventTryCount = 3; protected const int MaxEventTryCount = 3;
protected ICurrentTenant CurrentTenant { get; } protected ICurrentTenant CurrentTenant { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; } protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected ITenantStore TenantStore { get; } protected ITenantStore TenantStore { get; }
@ -40,7 +38,7 @@ public abstract class DatabaseEfCoreMigrationEventHandler<TDbContext> : Database
IDistributedEventBus distributedEventBus, IDistributedEventBus distributedEventBus,
string databaseName, string databaseName,
IAbpDistributedLock distributedLockProvider IAbpDistributedLock distributedLockProvider
) )
{ {
CurrentTenant = currentTenant; CurrentTenant = currentTenant;
UnitOfWorkManager = unitOfWorkManager; UnitOfWorkManager = unitOfWorkManager;
@ -56,49 +54,32 @@ public abstract class DatabaseEfCoreMigrationEventHandler<TDbContext> : Database
/// Apply pending EF Core schema migrations to the database. /// Apply pending EF Core schema migrations to the database.
/// Returns true if any migration has applied. /// Returns true if any migration has applied.
/// </summary> /// </summary>
protected virtual async Task<bool> MigrateDatabaseSchemaAsync(Guid? tenantId) protected virtual async Task<bool> MigrateDatabaseSchemaAsync()
{ {
var result = false; 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<bool> MigrateDatabaseSchemaWithDbContextAsync()
{ {
async Task<bool> MigrateDatabaseSchemaWithDbContextAsync() var dbContext = await uow.ServiceProvider
{ .GetRequiredService<IDbContextProvider<TDbContext>>()
var dbContext = await uow.ServiceProvider .GetDbContextAsync();
.GetRequiredService<IDbContextProvider<TDbContext>>()
.GetDbContextAsync();
if ((await dbContext.Database.GetPendingMigrationsAsync()).Any())
{
await dbContext.Database.MigrateAsync();
return true;
}
return false; if ((await dbContext.Database.GetPendingMigrationsAsync()).Any())
}
if (tenantId == null)
{ {
//Migrating the host database await dbContext.Database.MigrateAsync();
Log.Information($"There is no tenant. Migrating {DatabaseName}..."); return true;
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)
Log.Information($"Migrating tenant database:{DatabaseName} with tenantId:{tenantId}...");
result = await MigrateDatabaseSchemaWithDbContextAsync();
}
} }
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; return result;
@ -121,56 +102,12 @@ public abstract class DatabaseEfCoreMigrationEventHandler<TDbContext> : Database
} }
else else
{ {
Log.Error( Log.Warning(
$"Could not apply database migrations. Canceling the operation. TenantId = {eventData.TenantId}, DatabaseName = {eventData.DatabaseName}."); $"Could not apply database migrations. Canceling the operation. TenantId = {eventData.TenantId}, DatabaseName = {eventData.DatabaseName}.");
Log.Error(exception.ToString()); Log.Error(exception.ToString());
} }
} }
protected virtual async Task HandleErrorTenantCreatedAsync(
TenantCreatedEto eventData,
Exception exception)
{
var tryCount = IncrementEventTryCount(eventData);
if (tryCount <= MaxEventTryCount)
{
Log.Warning(
$"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) private static int GetEventTryCount(EtoBase eventData)
{ {
var tryCountAsString = eventData.Properties.GetOrDefault(TryCountPropertyName); var tryCountAsString = eventData.Properties.GetOrDefault(TryCountPropertyName);

112
shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/MongoDb/DatabaseMongoDbMigrationEventHandler.cs

@ -37,7 +37,7 @@ public abstract class DatabaseMongoDbMigrationEventHandler<TDbContext> : Databas
IUnitOfWorkManager unitOfWorkManager, IUnitOfWorkManager unitOfWorkManager,
ITenantStore tenantStore, ITenantStore tenantStore,
IDistributedEventBus distributedEventBus, IDistributedEventBus distributedEventBus,
string databaseName, string databaseName,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IAbpDistributedLock distributedLockProvider IAbpDistributedLock distributedLockProvider
) )
@ -57,62 +57,46 @@ public abstract class DatabaseMongoDbMigrationEventHandler<TDbContext> : Databas
/// Apply pending EF Core schema migrations to the database. /// Apply pending EF Core schema migrations to the database.
/// Returns true if any migration has applied. /// Returns true if any migration has applied.
/// </summary> /// </summary>
protected virtual async Task<bool> MigrateDatabaseSchemaAsync(Guid? tenantId) protected virtual async Task<bool> MigrateDatabaseSchemaAsync()
{ {
var result = false; 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<bool> MigrateDatabaseSchemaWithDbContextAsync()
{ {
async Task<bool> MigrateDatabaseSchemaWithDbContextAsync() var dbContexts = ServiceProvider.GetServices<IAbpMongoDbContext>();
{ var connectionStringResolver = ServiceProvider.GetRequiredService<IConnectionStringResolver>();
var dbContexts = ServiceProvider.GetServices<IAbpMongoDbContext>();
var connectionStringResolver = ServiceProvider.GetRequiredService<IConnectionStringResolver>();
foreach (var dbContext in dbContexts) foreach (var dbContext in dbContexts)
{
var connectionString =
await connectionStringResolver.ResolveAsync(
ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType()));
if (connectionString.IsNullOrWhiteSpace())
{ {
var connectionString = continue;
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));
} }
return true; var mongoUrl = new MongoUrl(connectionString);
} var databaseName = mongoUrl.DatabaseName;
var client = new MongoClient(mongoUrl);
if (tenantId == null) if (databaseName.IsNullOrWhiteSpace())
{
//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) databaseName = ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType());
result = await MigrateDatabaseSchemaWithDbContextAsync();
} }
(dbContext as AbpMongoDbContext)?.InitializeCollections(client.GetDatabase(databaseName));
} }
await uow.CompleteAsync(); return true;
} }
//Migrating the host database
result = await MigrateDatabaseSchemaWithDbContextAsync();
await uow.CompleteAsync();
} }
return result; return result;
@ -140,50 +124,6 @@ public abstract class DatabaseMongoDbMigrationEventHandler<TDbContext> : 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) private static int GetEventTryCount(EtoBase eventData)
{ {
var tryCountAsString = eventData.Properties.GetOrDefault(TryCountPropertyName); var tryCountAsString = eventData.Properties.GetOrDefault(TryCountPropertyName);

7
shared/EShopOnAbp.Shared.Hosting.Microservices/DbMigrations/PendingMigrationsCheckerBase.cs

@ -1,8 +1,7 @@
using Volo.Abp.DependencyInjection; 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
{
}
} }

61
shared/EShopOnAbp.Shared.Hosting.Microservices/EShopOnAbpSharedHostingMicroservicesModule.cs

@ -13,43 +13,42 @@ using Volo.Abp.EventBus.RabbitMq;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy; 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( public override void ConfigureServices(ServiceConfigurationContext context)
typeof(EShopOnAbpSharedHostingAspNetCoreModule),
typeof(AbpBackgroundJobsRabbitMqModule),
typeof(AbpAspNetCoreMultiTenancyModule),
typeof(AbpEventBusRabbitMqModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AdministrationServiceEntityFrameworkCoreModule)
)]
public class EShopOnAbpSharedHostingMicroservicesModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) var configuration = context.Services.GetConfiguration();
{
var configuration = context.Services.GetConfiguration();
Configure<AbpMultiTenancyOptions>(options => Configure<AbpMultiTenancyOptions>(options =>
{ {
options.IsEnabled = true; options.IsEnabled = true;
}); });
Configure<AbpDistributedCacheOptions>(options => Configure<AbpDistributedCacheOptions>(options =>
{ {
options.KeyPrefix = "EShopOnAbp:"; options.KeyPrefix = "EShopOnAbp:";
}); });
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
context.Services context.Services
.AddDataProtection() .AddDataProtection()
.PersistKeysToStackExchangeRedis(redis, "EShopOnAbp-Protection-Keys"); .PersistKeysToStackExchangeRedis(redis, "EShopOnAbp-Protection-Keys");
context.Services.AddSingleton<IDistributedLockProvider>(sp => context.Services.AddSingleton<IDistributedLockProvider>(sp =>
{ {
var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
return new RedisDistributedSynchronizationProvider(connection.GetDatabase()); return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
}); });
}
} }
} }

29
shared/EShopOnAbp.Shared.Hosting.Microservices/JwtBearerConfigurationHelper.cs

@ -3,23 +3,22 @@ using Microsoft.Extensions.DependencyInjection;
using System; using System;
using Volo.Abp.Modularity; 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( var configuration = context.Services.GetConfiguration();
ServiceConfigurationContext context,
string audience)
{
var configuration = context.Services.GetConfiguration();
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => .AddJwtBearer(options =>
{ {
options.Authority = configuration["AuthServer:Authority"]; options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
options.Audience = audience; options.Audience = audience;
}); });
}
} }
} }

39
shared/EShopOnAbp.Shared.Localization/EShopOnAbpSharedLocalizationModule.cs

@ -5,30 +5,29 @@ using Volo.Abp.Validation;
using Volo.Abp.Validation.Localization; using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
namespace EShopOnAbp namespace EShopOnAbp;
[DependsOn(
typeof(AbpValidationModule)
)]
public class EShopOnAbpSharedLocalizationModule : AbpModule
{ {
[DependsOn( public override void ConfigureServices(ServiceConfigurationContext context)
typeof(AbpValidationModule)
)]
public class EShopOnAbpSharedLocalizationModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) Configure<AbpVirtualFileSystemOptions>(options =>
{ {
Configure<AbpVirtualFileSystemOptions>(options => options.FileSets.AddEmbedded<EShopOnAbpSharedLocalizationModule>();
{ });
options.FileSets.AddEmbedded<EShopOnAbpSharedLocalizationModule>();
});
Configure<AbpLocalizationOptions>(options => Configure<AbpLocalizationOptions>(options =>
{ {
options.Resources options.Resources
.Add<EShopOnAbpResource>("en") .Add<EShopOnAbpResource>("en")
.AddBaseTypes( .AddBaseTypes(
typeof(AbpValidationResource) typeof(AbpValidationResource)
).AddVirtualJson("/Localization/EShopOnAbp"); ).AddVirtualJson("/Localization/EShopOnAbp");
options.DefaultResourceType = typeof(EShopOnAbpResource); options.DefaultResourceType = typeof(EShopOnAbpResource);
}); });
}
} }
} }
Loading…
Cancel
Save