Activities of "rogercprops"

  • ABP Framework version: v7.2 commercial
  • UI Type: MVC
  • Database System: EF Core (SQL Server)
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes
  • Exception message and full stack trace: [17:25:49 INF] Request starting HTTP/1.1 POST http://authserver.mydomain.dev/Account/Register application/x-www-form-urlencoded 272 [17:25:58 ERR] Padding is invalid and cannot be removed. System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed. at System.Security.Cryptography.SymmetricPadding.GetPaddingLength(ReadOnlySpan1 block, PaddingMode paddingMode, Int32 blockSize) at System.Security.Cryptography.UniversalCryptoDecryptor.UncheckedTransformFinalBlock(ReadOnlySpan1 inputBuffer, Span1 outputBuffer) at System.Security.Cryptography.UniversalCryptoDecryptor.UncheckedTransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) at System.Security.Cryptography.UniversalCryptoTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) at System.Security.Cryptography.CryptoStream.ReadAsyncCore(Memory1 buffer, CancellationToken cancellationToken, Boolean useAsync) at System.Security.Cryptography.CryptoStream.Read(Byte[] buffer, Int32 offset, Int32 count) at Volo.Abp.Security.Encryption.StringEncryptionService.Decrypt(String cipherText, String passPhrase, Byte[] salt) at Volo.Abp.Settings.SettingEncryptionService.Decrypt(SettingDefinition settingDefinition, String encryptedValue) [17:25:58 ERR] ---------- RemoteServiceErrorInfo ---------- { "code": null, "message": "An internal error occurred during your request!", "details": null, "data": {}, "validationErrors": null } [17:25:58 ERR] Setting value for 'Abp.Mailing.Smtp.Password' is null or empty! Volo.Abp.AbpException: Setting value for 'Abp.Mailing.Smtp.Password' is null or empty! at Volo.Abp.Emailing.EmailSenderConfiguration.GetNotEmptySettingValueAsync(String name) at Volo.Abp.Emailing.Smtp.SmtpEmailSender.BuildClientAsync() at Volo.Abp.Emailing.Smtp.SmtpEmailSender.SendEmailAsync(MailMessage mail) at Volo.Abp.Emailing.EmailSenderBase.SendAsync(MailMessage mail, Boolean normalize) at Volo.Abp.Emailing.EmailSenderBase.SendAsync(String to, String subject, String body, Boolean isBodyHtml) at Volo.Abp.Account.Emailing.AccountEmailer.SendEmailConfirmationLinkAsync(IdentityUser user, String confirmationToken, String appName, String returnUrl, String returnUrlHash) at Volo.Abp.Account.AccountAppService.SendEmailConfirmationTokenAsync(IdentityUser user, String applicationName, String returnUrl, String returnUrlHash) at Volo.Abp.Account.AccountAppService.RegisterAsync(RegisterDto input) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope) at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Volo.Abp.Account.Public.Web.Pages.Account.RegisterModel.RegisterLocalUserAsync() at Volo.Abp.Account.Public.Web.Pages.Account.RegisterModel.OnPostAsync() at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Convert[T](Object taskAsObject) at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments) at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync() at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync() at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context) at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync() at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ExceptionContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) .... [17:26:11 INF] Request finished HTTP/1.1 GET http://authserver.mydomain.dev/Abp/ApplicationLocalizationScript?cultureName=en - - - 200 106364 application/javascript 10787.4888ms`
  • Steps to reproduce the issue:

We're using the Microservice template and trying to register a new user with the self registration on the login page. It works fine when running the solution on localhost with the databases on our test server. It throws the above error when registering through the app running on AKS with the same databases on our test server.

  1. Added email settings to both the host and tenant using the Web MVC application
  2. Ran the microservice solution on local host
  3. Successfully registered a new user
  4. Deployed all of the microservices and applications to our test ASK cluster
  5. Tried to register a user in both the host and a test tenant and got the above error.
  6. I reviewed all of the other posts and didn't find any with the exact same problem but most of the resolutions had to do with updating email settings in appsettings.json (which doesn't apply since we're running a SaaS application) or setting StringEncryption (which we've done in both in appsettings.json and the deployment yaml for the AKS application)

We created a new test AKS cluster with Abp version 9.0 and the registration process works. But given our project time line I don't think we can wait until we have all of our microservices upgraded to V9 so ideally we get this fixed in V7.2

Thank you

Thanks. That was helpful

  • ABP Framework version: v9.0
  • UI Type: N/A
  • Database System: EF Core SQL Server
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes
  • Exception message and full stack trace: N/A
  • Steps to reproduce the issue: N/A

I've been exploring the ABP Studio Microservice template for Version 9.0 and watched the Youtube video Kubernetes Integrated Microservice Development with ABP Studio. Both the solution template and the video have Sql Server running as an application in Kubernetes.

In our version 7.2 environment we've been using our SQL Servers running on Azure VM's for the micro-service databases.

What's Abp's viewpoint on running in the same Kubernetes cluster as the micro-services, versus running on a VM... for performance, cost and possibly security considerations ? Do you have clients running micro-services with Sql server in Kubernetes?

Thank you.

Abp Studio Solution Configuration

  • Created ABP Studio Version: 0.9.13
  • Multi-Tenancy: Yes
  • UI Framework: mvc
  • Theme: leptonx
  • Theme Style: system
  • Database Provider: ef
  • Database Management System: sqlserver
  • Mobile Framework: none
  • Public Website: No
  • Include Tests: Yes
  • Exception message and full stack trace: I'm getting 2 errors and I'm not sure if they're related.

When I open Abp Studio I get this message: Some pre-requirements are missing. If you want the application to work as expected, you need to install the following tool(s):

- PowerShell as a dotnet global tool. (Installation link: https://devblogs.microsoft.com/powershell/introducing-powershell-as-net-global-tool)

- node. (Installation link: https://nodejs.org/en)

- Volo.Abp.Studio.Cli as a dotnet global tool. (Installation link: https://abp.io/docs/latest/cli)

- dotnet-ef as a dotnet global tool. (Installation link: https://learn.microsoft.com/en-us/ef/core/cli/dotnet)

- mkcert. (Installation link: https://github.com/FiloSottile/mkcert)

If you have already installed the tool(s), please check the PATH environment variable.

Unfortunately your documentation doesn't list the prerequisites for Mac or how to install if they're missing.

The second issue shows up in the logs 4:33:44.349 Information Trying to connect to ABP Studio Backend: "http://localhost:38271"14:33:49.385 Information Trying to connect to ABP Studio Backend: "http://localhost:38271" 14:33:54.420 Information Trying to connect to ABP Studio Backend: "http://localhost:38271" 14:33:54.422 Warning Could not connect to ABP Studio Backend! Detail: "Failed to connect to StreamingHub 'IStudioBackendHub'. (Status(StatusCode="Unavailable", Detail="Error connecting to subchannel.", DebugException="System.Net.Sockets.SocketException: Connection refused"))"

  • Steps to reproduce the issue:
  1. Upgraded abp cli and .net to v9.0

  2. Installed abp Studio for Mac

  3. uninstalled abp cli dotnet tool uninstall -g Volo.Abp.Cli

  4. Installed Abp studio as a global dotnet tool install -g Volo.Abp.Studio.Cli

  5. Opened Studio

  6. Got the pre-requisites error

  7. Viewed the logs and saw the Backend connection error

  8. Verified verified that each pre-requisite installed via the terminal command line: rogerhopkins@MacBookPro ~ % node -v
    v18.19.0 rogerhopkins@MacBookPro ~ % dotnet-ef --version Entity Framework Core .NET Command-line Tools 7.0.3 rogerhopkins@MacBookPro ~ % mkcert --version v1.4.4 rogerhopkins@MacBookPro ~ % pwsh PowerShell 7.4.6 PS /Users/rogerhopkins>

To add to the conversation, this is what I'm getting just logging in with the abp cli abp login myusername -p mypassword

  1. HTTP request attempt failed to https://abp.io/api/license/check-multiple-organizations?username=rogercprops with an error: 403-Forbidden. Waiting 2 secs for the next try...
  2. HTTP request attempt failed to https://abp.io/api/license/check-multiple-organizations?username=rogercprops with an error: 403-Forbidden. Waiting 4 secs for the next try...
  3. HTTP request attempt failed to https://abp.io/api/license/check-multiple-organizations?username=rogercprops with an error: 403-Forbidden. Waiting 7 secs for the next try... ERROR: Remote server returns 'Forbidden' System.Exception: ERROR: Remote server returns 'Forbidden' at Volo.Abp.Cli.Auth.AuthService.CheckMultipleOrganizationsAsync(String username) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\Auth\AuthService.cs:line 140 at Volo.Abp.Cli.Commands.LoginCommand.HasMultipleOrganizationAndThisNotSpecified(CommandLineArgs commandLineArgs, String organization) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\Commands\LoginCommand.cs:line 107 at Volo.Abp.Cli.Commands.LoginCommand.ExecuteAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\Commands\LoginCommand.cs:line 52 at Volo.Abp.Cli.CliService.RunInternalAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 169 at Volo.Abp.Cli.CliService.RunAsync(String[] args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 77
  • ABP Framework version: v7.2 Commercial
  • UI Type: Vue
  • Database System: EF Core (SQL Server, Oracle, MySQL, PostgreSQL, etc..) / MongoDB
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes
  • Exception message and full stack trace: N/A
  • Steps to reproduce the issue: N/A

We're following the microservices architecture with the Abp Commercial microservices template.

We have a complex reporting requirement where we need to pull data from multiple domains, which means multiple databases. We tried to follow this article: https://abp.io/community/articles/how-to-use-multiple-dbcontexts-in-a-single-query-execution-488bxj4q but it didn't work.

How do we accomplish this within one microsercie without having to make service to service api calls?

Thanks

Hi again,

One more thing. This might be a kubernetes issue. I noticed our AKS cluster was at 75% memory utilization so I deleted all of the applications and then re-deployed them.

The member-config-service is running without error.

Could there be a memory leak in the application? And could a lack of available memory be causing this error and just not catching it so that it shows that error message?

Hi,

I sent you an invite to our microservices shared repository and member-config-service repositories.

The classes you requested are in the shared/CprOnAbp.Shared.Hosting.Microservices/DbMigrations/MongoDb folder.

Please let me know if you need anything else.

Thanks

Another piece of information. I applied the same docker image to our production AKS cluster and it's running fine.

So it's clearly an issue running in AKS. Could there be something in cache or some other AKS condition that's causing the microservice error?

Hi,

I looked at the GitHub issue and it doesn't seem to apply. I'm not having an issue with seeding the database and I can't find RuntimeDatabaseMigrator anywhere.

Here are the 3 classes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using MongoDB.Driver;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MongoDB;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
using Volo.Saas.Tenants;

namespace CprOnAbp.Shared.Hosting.Microservices.DbMigrations.MongoDb;

public abstract class MongoDBMigrationEventHandlerBase<TDbContext> :
        ITransientDependency
        where TDbContext : AbpMongoDbContext, IAbpMongoDbContext
{
    protected const string TryCountPropertyName = "TryCount";
    protected const int MaxEventTryCount = 3;

    protected ICurrentTenant CurrentTenant { get; }
    protected IUnitOfWorkManager UnitOfWorkManager { get; }
    protected ITenantStore TenantStore { get; }
    protected ITenantRepository TenantRepository { get; }
    protected IDistributedEventBus DistributedEventBus { get; }
    protected ILogger<MongoDBMigrationEventHandlerBase<TDbContext>> Logger { get; set; }

    protected IServiceProvider ServiceProvider { get; }
    protected string DatabaseName { get; }

    protected MongoDBMigrationEventHandlerBase(
        ICurrentTenant currentTenant,
        IUnitOfWorkManager unitOfWorkManager,
        ITenantStore tenantStore,
        ITenantRepository tenantRepository,
        IDistributedEventBus distributedEventBus,
        string databaseName, IServiceProvider serviceProvider)
    {
        CurrentTenant = currentTenant;
        UnitOfWorkManager = unitOfWorkManager;
        TenantStore = tenantStore;
        DatabaseName = databaseName;
        ServiceProvider = serviceProvider;
        DistributedEventBus = distributedEventBus;
        TenantRepository = tenantRepository;

        Logger = NullLogger<MongoDBMigrationEventHandlerBase<TDbContext>>.Instance;
    }

    /// <summary>
    /// Apply pending EF Core schema migrations to the database.
    /// Returns true if any migration has applied.
    /// </summary>
    protected virtual async Task<bool> MigrateDatabaseSchemaAsync(Guid? tenantId)
    {
        var result = false;

        using (CurrentTenant.Change(tenantId))
        {
            using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
            {
                async Task<bool> MigrateDatabaseSchemaWithDbContextAsync()
                {
                    var dbContexts = ServiceProvider.GetServices<IAbpMongoDbContext>();
                    var connectionStringResolver = ServiceProvider.GetRequiredService<IConnectionStringResolver>();

                    if (ServiceProvider.GetRequiredService<ICurrentTenant>().IsAvailable)
                    {
                        dbContexts = dbContexts.Where(x =>
                            !x.GetType().IsDefined(typeof(IgnoreMultiTenancyAttribute)));
                    }

                    foreach (var dbContext in dbContexts)
                    {
                        var connectionString =
                            await connectionStringResolver.ResolveAsync(
                                ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType()));
                        if (connectionString.IsNullOrWhiteSpace())
                        {
                            continue;
                        }
                        var mongoUrl = new MongoUrl(connectionString);
                        var databaseName = mongoUrl.DatabaseName;
                        var client = new MongoClient(mongoUrl);

                        if (databaseName.IsNullOrWhiteSpace())
                        {
                            databaseName = ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType());
                        }

                        (dbContext as AbpMongoDbContext)?.InitializeCollections(client.GetDatabase(databaseName));
                    }

                    return true;
                }

                if (tenantId == null)
                {
                    //Migrating the host database
                    result = await MigrateDatabaseSchemaWithDbContextAsync();
                }
                else
                {
                    var tenantConfiguration = await TenantStore.FindAsync(tenantId.Value);
                    if (!tenantConfiguration.ConnectionStrings.Default.IsNullOrWhiteSpace() ||
                        !tenantConfiguration.ConnectionStrings.GetOrDefault(DatabaseName).IsNullOrWhiteSpace())
                    {
                        //Migrating the tenant database (only if tenant has a separate database)
                        result = await MigrateDatabaseSchemaWithDbContextAsync();
                    }
                }

                await uow.CompleteAsync();
            }
        }

        return result;
    }

    protected virtual async Task HandleErrorOnApplyDatabaseMigrationAsync(
        ApplyDatabaseMigrationsEto eventData,
        Exception exception)
    {
        var tryCount = IncrementEventTryCount(eventData);
        if (tryCount <= MaxEventTryCount)
        {
            Logger.LogWarning(
                $"Could not apply database migrations. Re-queueing the operation. TenantId = {eventData.TenantId}, Database Name = {eventData.DatabaseName}.");
            Logger.LogException(exception, LogLevel.Warning);

            await Task.Delay(RandomHelper.GetRandom(5000, 15000));
            await DistributedEventBus.PublishAsync(eventData);
        }
        else
        {
            Logger.LogError(
                $"Could not apply database migrations. Canceling the operation. TenantId = {eventData.TenantId}, DatabaseName = {eventData.DatabaseName}.");
            Logger.LogException(exception);
        }
    }

    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);
        }
    }

    protected virtual async Task QueueTenantMigrationsAsync()
    {
        var tenants = await TenantRepository.GetListWithSeparateConnectionStringAsync();
        foreach (var tenant in tenants)
        {
            await DistributedEventBus.PublishAsync(
                new ApplyDatabaseMigrationsEto
                {
                    DatabaseName = DatabaseName,
                    TenantId = tenant.Id
                }
            );
        }
    }

    private static int GetEventTryCount(EtoBase eventData)
    {
        var tryCountAsString = eventData.Properties.GetOrDefault(TryCountPropertyName);
        if (tryCountAsString.IsNullOrEmpty())
        {
            return 0;
        }

        return int.Parse(tryCountAsString);
    }

    private static void SetEventTryCount(EtoBase eventData, int count)
    {
        eventData.Properties[TryCountPropertyName] = count.ToString();
    }

    private static int IncrementEventTryCount(EtoBase eventData)
    {
        var count = GetEventTryCount(eventData) + 1;
        SetEventTryCount(eventData, count);
        return count;
    }
}
public abstract class PendingMongoDbMigrationsChecker<TDbContext> : PendingMigrationsCheckerBase where TDbContext : AbpMongoDbContext
{
    protected IUnitOfWorkManager UnitOfWorkManager { get; }
    protected IServiceProvider ServiceProvider { get; }
    protected ICurrentTenant CurrentTenant { get; }
    protected IDistributedEventBus DistributedEventBus { get; }
    protected IAbpDistributedLock DistributedLockProvider { get; }
    protected string DatabaseName { get; }
    protected IDataSeeder DataSeeder { get; }
    
    protected PendingMongoDbMigrationsChecker(
        ILoggerFactory loggerFactory,
        IUnitOfWorkManager unitOfWorkManager,
        IServiceProvider serviceProvider,
        ICurrentTenant currentTenant,
        IDistributedEventBus distributedEventBus,
        IAbpDistributedLock abpDistributedLock,
        string databaseName, 
        IDataSeeder dataSeeder) : base(loggerFactory)
    {
        UnitOfWorkManager = unitOfWorkManager;
        ServiceProvider = serviceProvider;
        CurrentTenant = currentTenant;
        DistributedEventBus = distributedEventBus;
        DistributedLockProvider = abpDistributedLock;
        DatabaseName = databaseName;
        DataSeeder = dataSeeder;
    }
    
    public virtual async Task CheckAndApplyDatabaseMigrationsAsync()
    {
        await TryAsync(async () =>
        {
            using (CurrentTenant.Change(null))
            {
                // Create database tables if needed
                using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
                {
                    await MigrateDatabaseSchemaAsync();

                    await DataSeeder.SeedAsync();

                    await uow.CompleteAsync();
                }
            }
        });
    }
    /// <summary>
    /// Apply scheme update for MongoDB Database.
    /// </summary>
    protected virtual async Task<bool> MigrateDatabaseSchemaAsync()
    {
        var result = false;
        await using (var handle = await DistributedLockProvider.TryAcquireAsync("Migration_" + DatabaseName))
        {
            using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
            {
                Log.Information($"Lock is acquired for db migration and seeding on database named: {DatabaseName}...");

                if (handle is null)
                {
                    Log.Information($"Handle is null because of the locking for : {DatabaseName}");
                    return false;
                }

                async Task<bool> MigrateDatabaseSchemaWithDbContextAsync()
                {
                    var dbContexts = ServiceProvider.GetServices<IAbpMongoDbContext>();
                    var connectionStringResolver = ServiceProvider.GetRequiredService<IConnectionStringResolver>();

                    foreach (var dbContext in dbContexts)
                    {
                        var connectionString =
                            await connectionStringResolver.ResolveAsync(
                                ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType()));
                        if (connectionString.IsNullOrWhiteSpace())
                        {
                            continue;
                        }

                        var mongoUrl = new MongoUrl(connectionString);
                        var databaseName = mongoUrl.DatabaseName;
                        var client = new MongoClient(mongoUrl);

                        if (databaseName.IsNullOrWhiteSpace())
                        {
                            databaseName = ConnectionStringNameAttribute.GetConnStringName(dbContext.GetType());
                        }

                        (dbContext as AbpMongoDbContext)?.InitializeCollections(client.GetDatabase(databaseName));
                    }

                    return true;
                }

                //Migrating the host database
                result = await MigrateDatabaseSchemaWithDbContextAsync();

                await uow.CompleteAsync();
            }

            return result;
        }
    }
}
using System;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MongoDB;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;

namespace CprOnAbp.Shared.Hosting.Microservices.DbMigrations.MongoDb;

public class PendingMongoDBMigrationsCheckerBase<TDbContext> : ITransientDependency
        where TDbContext : AbpMongoDbContext
{
    protected IUnitOfWorkManager UnitOfWorkManager { get; }
    protected IServiceProvider ServiceProvider { get; }
    protected ICurrentTenant CurrentTenant { get; }
    protected IDistributedEventBus DistributedEventBus { get; }
    protected string DatabaseName { get; }

    protected PendingMongoDBMigrationsCheckerBase(
        IUnitOfWorkManager unitOfWorkManager,
        IServiceProvider serviceProvider,
        ICurrentTenant currentTenant,
        IDistributedEventBus distributedEventBus,
        string databaseName)
    {
        UnitOfWorkManager = unitOfWorkManager;
        ServiceProvider = serviceProvider;
        CurrentTenant = currentTenant;
        DistributedEventBus = distributedEventBus;
        DatabaseName = databaseName;
    }

    public virtual async Task CheckAsync()
    {
        using (CurrentTenant.Change(null))
        {
            // Create database tables if needed
            using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
            {
                await DistributedEventBus.PublishAsync(
                        new ApplyDatabaseMigrationsEto
                        {
                            DatabaseName = DatabaseName
                        }
                    );

                await uow.CompleteAsync();
            }
        }
    }
}
Showing 1 to 10 of 53 entries
Made with ❤️ on ABP v9.1.0-preview. Updated on December 13, 2024, 06:09