Peculiar error encountered when Creating or Updating a Database Connection in Radzen Blazor Studio

I have installed and configured Azure Key Vault in my appsettings.json and my appsettings.staging.json have the connection strings absent as these JSON files I assumed would be used when publishing my application to Azure AppService. My appsettings.development.json contains the local connection strings so that I can continue agile development on my local system. When Creating or Updating a Database Connection in Radzen Blazor Studio, I find a peculiar error. See below:

Format of the initialization string does not conform to specification starting at index 0.
at Microsoft.Data.Common.DbConnectionOptions.GetKeyValuePair(String connectionString, Int32 currentPosition, StringBuilder buffer, Boolean useOdbcRules, String& keyname, String& keyvalue)
at Microsoft.Data.Common.DbConnectionOptions.ParseInternal(Dictionary2 parsetable, String connectionString, Boolean buildChain, Dictionary2 synonyms, Boolean firstKey)
at Microsoft.Data.Common.DbConnectionOptions..ctor(String connectionString, Dictionary`2 synonyms)
at Microsoft.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at Microsoft.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at Microsoft.Data.SqlClient.SqlConnection.ConnectionString_Set(DbConnectionPoolKey key)
at Microsoft.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at Microsoft.EntityFrameworkCore.SqlServer.Scaffolding.Internal.SqlServerDatabaseModelFactory.Create(String connectionString, DatabaseModelFactoryOptions options)
at Radzen.Server.DatabaseService.Infer(InferDatabaseRequest request)
at Radzen.Server.SolutionFacade.InferDatabase(DatabaseService databaseService, InferDatabaseRequest request)
at Radzen.Server.ProgramController.InferDatabase(InferDatabaseRequest request)
at lambda_method274(Closure, Object, Object[])
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.g__Awaited|8_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task)

In my appsettings.json and my appsettings.staging.json I have listed the connection strings and azure key vault URI as follows:
{
"AzureKeyVaultUrl": "https://visionsuiteaccounting-kv.vault.azure.net/",
"ConnectionStrings": {
"ApexDbConnection": "",
"VisionDbConnection": ""
},

and in my appsettings.development.json as:
"AzureKeyVaultUrl": "",
"ConnectionStrings": {
"ApexDbConnection": "Server=FASTTRAKMOBILE;Connection Timeout=30;Persist Security Info=False;TrustServerCertificate=True;Integrated Security=True;Encrypt=True;Initial Catalog=Apex;",
"VisionDbConnection": "Server=FASTTRAKMOBILE;Connection Timeout=30;Persist Security Info=False;TrustServerCertificate=True;Integrated Security=True;Encrypt=True;Initial Catalog=Vision;"
},

I assumed that since I use debug mode in Radzen Blazor Studio predominantly, only the appsettings.development.json was important. Is this not the case? Do I need to mimic the local connection strings in all the files? Please advise.

Hi @FastTrak,

This seems to be a case Radzen Blazor Studio doesn't properly support yet. We will try to address it next week and ask you for further assistance if needed.

I tried to reproduce the problem with having empty connection string in appsettings.json however I encountered no errors. What should I do in order to reproduce the exception? When do you see it?

I ran into the problem again this afternoon. I suspect that it has something to do with the use of Azure Key Vault. When in Dev Mode I use the local configuration and when I am in release mode (i.e. deploying to Azure) I will access the application's Key Vault and pull the connection strings from there. My problem today was slightly different. I have 2 versions of the program.cs file, one which works with Radzen Blazor Studio, and one which does not, exhibiting the error which I reported earlier. The culprit can be shown simply as the difference in the following blocks of code:
(1) WORKS:
if (!builder.Environment.IsDevelopment()) // This Triggers Access to Azure Key Vault
{
var kvUrl = builder.Configuration["AzureKeyVaultUrl"];
if (!string.IsNullOrWhiteSpace(kvUrl))
{
var keyVaultEndpoint = new Uri(kvUrl);
var secretClient = new SecretClient(keyVaultEndpoint, new DefaultAzureCredential());
var apexDbConnectionSecret = secretClient.GetSecret("ApexDbConnection").Value;
var visionDbConnectionSecret = secretClient.GetSecret("VisionDbConnection").Value;

    builder.Services.AddScoped<ApexDbService>();
    builder.Services.AddDbContext<VisionSuiteAccounting.Data.ApexDbContext>(options =>
    {
        options.UseSqlServer(apexDbConnectionSecret.Value);
    });
    builder.Services.AddScoped<VisionDbService>();
    builder.Services.AddDbContext<VisionSuiteAccounting.Data.VisionDbContext>(options =>
    {
        options.UseSqlServer(visionDbConnectionSecret.Value);
    });
    builder.Services.AddHttpClient("VisionSuiteAccounting").AddHeaderPropagation(o => o.Headers.Add("Cookie"));
    builder.Services.AddHeaderPropagation(o => o.Headers.Add("Cookie"));
    builder.Services.AddAuthentication();
    builder.Services.AddAuthorization();
    builder.Services.AddScoped<SecurityService>();
    builder.Services.AddDbContext<ApplicationIdentityDbContext>(options =>
    {
        options.UseSqlServer(visionDbConnectionSecret.Value);
    });
    builder.Services.AddDbContext<VisionSuiteAccounting.Data.ApexDbContext>(options =>
    {
        options.UseSqlServer(apexDbConnectionSecret.Value);
    });
    builder.Services.AddScoped<VisionDbService>();
    builder.Services.AddDbContext<VisionSuiteAccounting.Data.VisionDbContext>(options =>
    {
        options.UseSqlServer(visionDbConnectionSecret.Value);
    });

    builder.Services.AddHttpClient("VisionSuiteAccounting").AddHeaderPropagation(o => o.Headers.Add("Cookie"));
    builder.Services.AddHeaderPropagation(o => o.Headers.Add("Cookie"));
    builder.Services.AddAuthentication();
    builder.Services.AddAuthorization();
    builder.Services.AddScoped<SecurityService>();
    builder.Services.AddDbContext<ApplicationIdentityDbContext>(options =>
    {
        options.UseSqlServer(visionDbConnectionSecret.Value);
    });
}

}
else // These are the Defaults Used for Development Only
{
builder.Services.AddScoped();
builder.Services.AddDbContext<VisionSuiteAccounting.Data.ApexDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("ApexDbConnection"));
options.EnableSensitiveDataLogging();
});
builder.Services.AddScoped();
builder.Services.AddDbContext<VisionSuiteAccounting.Data.VisionDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("VisionDbConnection"));
options.EnableSensitiveDataLogging();
});
builder.Services.AddHttpClient("VisionSuiteAccounting").AddHeaderPropagation(o => o.Headers.Add("Cookie"));
builder.Services.AddHeaderPropagation(o => o.Headers.Add("Cookie"));
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();
builder.Services.AddScoped();
builder.Services.AddDbContext(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("VisionDbConnection"));
options.EnableSensitiveDataLogging();
});
builder.Services.AddDbContext<VisionSuiteAccounting.Data.ApexDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("ApexDbConnection"));
options.EnableSensitiveDataLogging();
});
builder.Services.AddScoped();
builder.Services.AddDbContext<VisionSuiteAccounting.Data.VisionDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("VisionDbConnection"));
options.EnableSensitiveDataLogging();
});

builder.Services.AddHttpClient("VisionSuiteAccounting").AddHeaderPropagation(o => o.Headers.Add("Cookie"));
builder.Services.AddHeaderPropagation(o => o.Headers.Add("Cookie"));
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();
builder.Services.AddScoped<SecurityService>();
builder.Services.AddDbContext<ApplicationIdentityDbContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("VisionDbConnection"));
        options.EnableSensitiveDataLogging();    
});

}
(2) DOESN'T WORK: (Uses the DRY principle - Don't Repeat Yourself)
// Load the Default DB Connections
var apexDbConnection = builder.Configuration.GetConnectionString("ApexDbConnection");
var visionDbConnection = builder.Configuration.GetConnectionString("VisionDbConnection");

//************************************************************************************************************
// (WPE 20230319) - Access the KeyVault to Get the DB Configuration Settings Only in Release Mode ...
//************************************************************************************************************
if (!builder.Environment.IsDevelopment())
{
var kvUrl = builder.Configuration["AzureKeyVaultUrl"];
if (!string.IsNullOrWhiteSpace(kvUrl))
{
var keyVaultEndpoint = new Uri(kvUrl);
var secretClient = new SecretClient(keyVaultEndpoint, new DefaultAzureCredential());
var apexDbConnectionSecret = secretClient.GetSecret("ApexDbConnection").Value;
var visionDbConnectionSecret = secretClient.GetSecret("VisionDbConnection").Value;

    // If We Have Anything Then Place it in the Appropriate GlobalService Connection Variable.
    if (!string.IsNullOrWhiteSpace(apexDbConnectionSecret.Value))
        apexDbConnection = apexDbConnectionSecret.Value;

    if (!string.IsNullOrWhiteSpace(visionDbConnectionSecret.Value))
        visionDbConnection = visionDbConnectionSecret.Value;
}

}
//************************************************************************************************************

builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddDbContext<VisionSuiteAccounting.Data.ApexDbContext>(options =>
{
options.UseSqlServer(GlobalsService.visionDbConnection);
});
builder.Services.AddScoped();
builder.Services.AddDbContext<VisionSuiteAccounting.Data.VisionDbContext>(options =>
{
options.UseSqlServer(GlobalsService.visionDbConnection);
});
builder.Services.AddHttpClient("VisionSuiteAccounting").AddHeaderPropagation(o => o.Headers.Add("Cookie"));
builder.Services.AddHeaderPropagation(o => o.Headers.Add("Cookie"));
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();
builder.Services.AddScoped();
builder.Services.AddDbContext(options =>
{
options.UseSqlServer(GlobalsService.visionDbConnection);
});

In either case, there are no errors encountered when running the application in either Radzen Blazor Studion or Visual Studio 2022 Enterprise. Additionally, the Code in number 2 above loads noticeably faster in an Azure App Service than the 1st. Below, I am also attaching a listing of my project file:


CS0168,CS1998,BL9993,CS0649,CS0436,0436
net7.0
enable

all runtime; build; native; contentfiles; analyzers; buildtransitive

I am afraid I still cannot understand what the problem is. Please send us your project to info@radzen.com - if it is too big you can use a cloud storage service such as one drive or google drive. Once we reproduce the problem we will troubleshoot.

Ok then, I'll create 2 separate minimal programs to simulate my problem. My original program is very large and complex so, I think it would be much easier to send you 2 smaller ones.

I am not able to send these project examples to you via email because your mail server keeps rejecting my email so, I am going to send you an email with a Google Drive link to 2 zipped project files which should explain the problem.