@maliming: Thank you for your support. I was resolve my problem.
Please check your email.
I have.
public class Program { public async static Task<int> Main(string[] args) { Log.Logger = new LoggerConfiguration() .WriteTo.Async(c => c.File("Logs/logs.txt")) .WriteTo.Async(c => c.Console()) .CreateBootstrapLogger();
try
{
Log.Information("Starting web host.");
var builder = WebApplication.CreateBuilder(args);
builder.Host
.AddAppSettingsSecretsJson()
.UseAutofac()
.UseSerilog((context, services, loggerConfiguration) =>
{
loggerConfiguration
#if DEBUG
.MinimumLevel.Debug()
#else
.MinimumLevel.Information()
#endif
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Async(c => c.File("Logs/logs.txt"))
.WriteTo.Async(c => c.Console())
.WriteTo.Async(c => c.AbpStudio(services));
});
await builder.AddApplicationAsync<AbpTemplateWebModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
}
My code here, please help to check.
public class EncryptedConnectionStringResolver : ITransientDependency
{
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!;
protected IStringEncryptionService StringEncryptionService => LazyServiceProvider.LazyGetService<IStringEncryptionService>();
public EncryptedConnectionStringResolver()
{
}
public string EncryptConnectionString(string connectionString)
{
var configure = LoadEncryptionConfig();
if (configure.EnabledEncryption && !connectionString.StartsWith(configure.EncryptedPrefix))
{
var key = Environment.GetEnvironmentVariable(configure.EncryptionKey);
var iv = Environment.GetEnvironmentVariable(configure.EncryptionIv);
var keyBytes = Convert.FromBase64String(key);
var ivBytes = Convert.FromBase64String(iv);
ValidateEnvironmentVariables(configure.EncryptionKey, configure.EncryptionIv, key, iv, keyBytes, ivBytes);
var encryptedValue = StringEncryptionService.Encrypt(connectionString);
return $"{configure.EncryptedPrefix}{encryptedValue}";
}
return connectionString;
}
// Send all text of the encrypted connection string
public string DecryptConnectionString(string encryptedConnectionString)
{
var configure = LoadEncryptionConfig();
return encryptedConnectionString;
}
private SettingsDto LoadEncryptionConfig()
{
var configurationRoot = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder());
var securityConfig = configurationRoot.GetSection("App:Security");
var configure = new SettingsDto()
{
EnabledEncryption = bool.Parse(securityConfig["EnabledEncryption"]),
EncryptionKey = securityConfig["EncryptionKey"],
EncryptionIv = securityConfig["EncryptionIv"],
EncryptedPrefix = securityConfig["EncryptedPrefix"]
};
return configure;
}
private void ValidateEnvironmentVariables(string encryptionKey, string encryptionIv, string key, string iv, byte[] keyBytes, byte[] ivBytes)
{
// ...
}
}
Yeah, after check MultiTenantConnectionStringResolver, I found DefaultConnectionStringResolver need to override also. It's ok for me now.
I registered DI EncryptedConnectionStringResolver.cs public class EncryptedConnectionStringResolver { public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; protected IStringEncryptionService StringEncryptionService => LazyServiceProvider.LazyGetService<IStringEncryptionService>();
public EncryptedConnectionStringResolver()
{
}
}
LazyServiceProvider is null, what wrong maliming?
I was override MultiTenantConnectionStringResolver but when debugging, it always goes into if (_currentTenant.Id == null) condition and same error.
public class MultiTenantConnectionStringResolver : DefaultConnectionStringResolver { private readonly ICurrentTenant _currentTenant; private readonly IServiceProvider _serviceProvider;
public MultiTenantConnectionStringResolver(
IOptionsMonitor<AbpDbConnectionOptions> options,
ICurrentTenant currentTenant,
IServiceProvider serviceProvider)
: base(options)
{
_currentTenant = currentTenant;
_serviceProvider = serviceProvider;
}
public override async Task<string> ResolveAsync(string? connectionStringName = null)
{
if (_currentTenant.Id == null)
{
//No current tenant, fallback to default logic
return await base.ResolveAsync(connectionStringName);
}
// ...
}
}
Actually, my way same with your answer. Where I need to update connection string value? There is all my code:
AbpTemplateDomainModule.cs Configure<AbpStringEncryptionOptions>(opts => { var configuration = context.Services.GetConfiguration(); var securityConfig = configuration.GetSection("App:Security"); var configure = new SettingsDto() { EnabledEncryption = bool.Parse(securityConfig["EnabledEncryption"]), EncryptionKey = securityConfig["EncryptionKey"], EncryptionIv = securityConfig["EncryptionIv"], EncryptedPrefix = securityConfig["EncryptedPrefix"] };
if (configure.EnabledEncryption)
{
if (string.IsNullOrWhiteSpace(configure.EncryptionKey) || string.IsNullOrEmpty(configure.EncryptionIv))
throw new Exception("EncryptionKey or EncryptionIv is missing");
var key = Environment.GetEnvironmentVariable(configure.EncryptionKey);
var iv = Environment.GetEnvironmentVariable(configure.EncryptionIv);
if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(iv))
{
throw new Exception($"{configure.EncryptionKey} or {configure.EncryptionIv} environment variable is missing.");
}
if (key.Length != 44 || iv.Length != 24)
{
throw new Exception();
}
try
{
var keyBytes = Convert.FromBase64String(key);
var ivBytes = Convert.FromBase64String(iv);
if (keyBytes.Length != 32 || ivBytes.Length != 16)
{
throw new Exception();
}
opts.DefaultPassPhrase = key;
opts.DefaultSalt = keyBytes;
opts.InitVectorBytes = ivBytes;
}
catch (FormatException)
{
throw new Exception();
}
}
});
EncryptedConnectionStringResolver.cs public class EncryptedConnectionStringResolver { public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; protected IStringEncryptionService StringEncryptionService => LazyServiceProvider.LazyGetService<IStringEncryptionService>();
public EncryptedConnectionStringResolver()
{
}
public string EncryptConnectionString(string connectionString)
{
var configure = LoadEncryptionConfig();
if (configure.EnabledEncryption && !connectionString.StartsWith(configure.EncryptedPrefix))
{
var key = Environment.GetEnvironmentVariable(configure.EncryptionKey);
var iv = Environment.GetEnvironmentVariable(configure.EncryptionIv);
var keyBytes = Convert.FromBase64String(key);
var ivBytes = Convert.FromBase64String(iv);
ValidateEnvironmentVariables(configure.EncryptionKey, configure.EncryptionIv, key, iv, keyBytes, ivBytes);
var encryptedValue = StringEncryptionService.Encrypt(connectionString);
return $"{configure.EncryptedPrefix}{encryptedValue}";
}
return connectionString;
}
// Send all text of the encrypted connection string
public string DecryptConnectionString(string encryptedConnectionString)
{
var configure = LoadEncryptionConfig();
if (configure.EnabledEncryption && encryptedConnectionString.StartsWith(configure.EncryptedPrefix))
{
var key = Environment.GetEnvironmentVariable(configure.EncryptionKey);
var iv = Environment.GetEnvironmentVariable(configure.EncryptionIv);
var keyBytes = Convert.FromBase64String(key);
var ivBytes = Convert.FromBase64String(iv);
ValidateEnvironmentVariables(configure.EncryptionKey, configure.EncryptionIv, key, iv, keyBytes, ivBytes);
return StringEncryptionService.Decrypt(encryptedConnectionString.Substring(configure.EncryptedPrefix.Length));
}
return encryptedConnectionString;
}
private SettingsDto LoadEncryptionConfig()
{
var configurationRoot = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder());
var securityConfig = configurationRoot.GetSection("App:Security");
var configure = new SettingsDto()
{
EnabledEncryption = bool.Parse(securityConfig["EnabledEncryption"]),
EncryptionKey = securityConfig["EncryptionKey"],
EncryptionIv = securityConfig["EncryptionIv"],
EncryptedPrefix = securityConfig["EncryptedPrefix"]
};
if (!configure.EnabledEncryption)
return configure;
if (string.IsNullOrWhiteSpace(configure.EncryptionKey) || string.IsNullOrEmpty(configure.EncryptionIv))
throw new Exception();
var key = Environment.GetEnvironmentVariable(configure.EncryptionKey);
var iv = Environment.GetEnvironmentVariable(configure.EncryptionIv);
try
{
var keyBytes = Convert.FromBase64String(key);
var ivBytes = Convert.FromBase64String(iv);
if (keyBytes.Length != 32 || ivBytes.Length != 16)
{
throw new Exception();
}
}
catch (FormatException)
{
throw new Exception();
}
return configure;
}
private void ValidateEnvironmentVariables(string encryptionKey, string encryptionIv, string key, string iv, byte[] keyBytes, byte[] ivBytes)
{
if (string.IsNullOrWhiteSpace(encryptionKey) || string.IsNullOrWhiteSpace(encryptionIv))
{
throw new Exception();
}
if (key.Length != 44 || iv.Length != 24)
{
throw new Exception();
}
try
{
if (keyBytes.Length != 32 || ivBytes.Length != 16)
{
throw new Exception();
}
}
catch (FormatException)
{
throw new Exception();
}
}
}
AbpTemplateDbContextFactory.cs public class AbpTemplateDbContextFactory : IDesignTimeDbContextFactory<AbpTemplateDbContext> { public AbpTemplateDbContext CreateDbContext(string[] args) { var configuration = BuildConfiguration();
AbpTemplateEfCoreEntityExtensionMappings.Configure();
var encryptionResolver = new EncryptedConnectionStringResolver();
var connectionString = encryptionResolver.DecryptConnectionString(configuration.GetConnectionString("Default"));
var builder = new DbContextOptionsBuilder<AbpTemplateDbContext>()
.UseSqlServer(connectionString);
return new AbpTemplateDbContext(builder.Options);
}
private static IConfigurationRoot BuildConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../AbpTemplate.DbMigrator/"))
.AddJsonFile("appsettings.json", optional: false);
return builder.Build();
}
}
Finally, I found the reason.
Thank you @maliming
I have to it.
abp login-info [16:15:28 INF] You are running the second generation of the ABP CLI. If you're interested in the legacy CLI, see https://abp.io/new-cli [16:15:29 INF] Login info: Name: Surname: Username: MySecretUser (I changed real username while posting here) Email Address: MySecretUser @gmail.com Organization: Công ty TNHH phát triển công nghệ XXX