@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();
}
}
Dear guys,
I have been encrypted the connection string based on IStringEncryptionService (from external application) and updated to appsettings.json looks like this:
"ConnectionStrings": { // "Default": "Server=192.168.0.1;Database=AbpTemplate;User=sa; Password=123xxx;TrustServerCertificate=true" "Default": "ENC_5W8PezYlu1g+VaIc/XzdKRGabzhpT8aAbk7R2Irkt8AhOpODisXIK4SMQEmd4EuT91Y....." },
Then, I decrypted:
AbpTemplateDbContext.cs `public class AbpTemplateDbContextFactory : IDesignTimeDbContextFactory
AbpTemplateEfCoreEntityExtensionMappings.Configure();
// This line to decrypted the connection string in appsettings.json
var connectionString = configuration.GetConnectionString("Default").DecryptConnectionString();
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();
}
}`
I got this error while running app:
An unhandled exception occurred while processing the request. ArgumentException: Format of the initialization string does not conform to specification starting at index 0. System.Data.Common.DbConnectionOptions.GetKeyValuePair(string connectionString, int currentPosition, StringBuilder buffer, bool useOdbcRules, out string keyname, out string keyvalue).
System.ArgumentException: Format of the initialization string does not conform to specification starting at index 0.
at System.Data.Common.DbConnectionOptions.GetKeyValuePair(String connectionString, Int32 currentPosition, StringBuilder buffer, Boolean useOdbcRules, String& keyname, String& keyvalue)
at System.Data.Common.DbConnectionOptions.ParseInternal(Dictionary2 parsetable, String connectionString, Boolean buildChain, Dictionary2 synonyms, Boolean firstKey)
at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Dictionary2 synonyms, Boolean useOdbcRules) at System.Data.Common.DbConnectionStringBuilder.set_ConnectionString(String value) at Microsoft.Data.SqlClient.SqlConnectionStringBuilder..ctor(String connectionString) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.<>c.<get_IsMultipleActiveResultSetsEnabled>b__7_0(String cs) at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.get_IsMultipleActiveResultSetsEnabled() at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerCompiledQueryCacheKeyGenerator.GenerateCacheKey(Expression query, Boolean async) at Volo.Abp.EntityFrameworkCore.GlobalFilters.AbpCompiledQueryCacheKeyGenerator.GenerateCacheKey(Expression query, Boolean async) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken) at Volo.Abp.EntityFrameworkCore.AbpEntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable1.GetAsyncEnumerator() at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)
at Volo.Abp.LanguageManagement.EntityFrameworkCore.EfCoreLanguageRepository.GetListByIsEnabledAsync(Boolean isEnabled, CancellationToken cancellationToken)
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.LanguageManagement.DatabaseLanguageProvider.sCL3k4CHf() at Volo.Abp.Caching.DistributedCache2.GetOrAddAsync(TCacheKey key, Func1 factory, Func1 optionsFactory, Nullable`1 hideErrors, Boolean considerUow, CancellationToken token)
at Volo.Abp.LanguageManagement.DatabaseLanguageProvider.GetLanguagesAsync()
at Microsoft.AspNetCore.RequestLocalization.DefaultAbpRequestLocalizationOptionsProvider.GetLocalizationOptionsAsync()
at Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<
I found this code but it only allows pass connection key, how can I add the connection string encrypted value? [ReplaceDbContext(typeof(IIdentityProDbContext))] [ReplaceDbContext(typeof(ISaasDbContext))] [ConnectionStringName("Default")] public class AbpTemplateDbContext : AbpDbContext
Thank you.
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