I tried to analyse your issue and based on my reaserch I found primarly many similar problems to yours.
First thing, I think that the error you are having is because of the AAD authentication is being in conjunction with the AccessToken
property in Microsoft.Data.SqlClient
because you set the AccessToken
property programmatically, the Authentication
keyword in your connection string should not be used.
You can remove it dynamically :
if (useAccessToken)
{
var builder = new SqlConnectionStringBuilder(connectionString);
builder.Remove("Authentication"); // Remove conflicting property
connectionString = builder.ToString();
}
Don't forget that you can have this issue if your token is expiring and in this case you need to use Microsoft.Identity.Client
to fetch and cache tokens since it better handle token renewal.
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
var token = await app.AcquireTokenForClient(scopes).ExecuteAsync();
var accessToken = token.AccessToken;
Another behaviour you can get is the AccessToken
property being not compatible with connection pooling because tokens are tied to a single connection lifespan so you may need to disable it :
options.UseSqlServer(connectionString, sqlOptions =>
{
sqlOptions.EnableRetryOnFailure();
sqlOptions.CommandTimeout(60); // Adjust as necessary
sqlOptions.UseConnectionPooling(false);
})
;
One last point, if you have multiple threads attemping to use or renew the same token so you can use the below :
private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
public async Task<string> GetAccessTokenAsync()
{
await semaphore.WaitAsync();
try
{
// Token acquisition logic
}
finally
{
semaphore.Release();
}
}
What I highly recommend is you need to have a retry catch mechanism to better understand the issue :
services.AddDbContext<MyDbContext>((serviceProvider, options) =>
{
options.UseSqlServer(connectionString, sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(10),
errorNumbersToAdd: null);
});
});