dotnet / EntityFramework.Docs

Documentation for Entity Framework Core and Entity Framework 6
https://docs.microsoft.com/ef/
Creative Commons Attribution 4.0 International
1.63k stars 1.96k forks source link

Example for lazy initialization of connectionstring does not work when using password in connectionstring #4101

Open stiankroknes opened 2 years ago

stiankroknes commented 2 years ago

Wasted some time debugging issue where sql login failed for user when using this approach for setting connection string.

When using connection string with a password it will be correct the first time the interceptor is invoked, but the next time we open connection the connection.ConnectionString is not empty - but the password is removed due to Persist Security Info is default false.

if (string.IsNullOrEmpty(connection.ConnectionString))
{
    connection.ConnectionString = (await _connectionStringFactory.GetConnectionStringAsync(cancellationToken));
}

Lazy initialization of a connection string

For this to work with password the connection string must be set each time and probably use some caching or change the default...

Maybe the docs should have a note about this?


Document Details

Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.

ajcvickers commented 2 years ago

@stiankroknes I don't see anywhere in the sample that takes the connection string from an existing DbConnection and attempts to use it. Is this something you added in your own code?

stiankroknes commented 2 years ago

@ajcvickers No, I experienced this when invoking MigrateAsync or EnsureCreatedAsync on my DbContext. The ConnectionOpeningAsync is invoked multiple times and when inspecting the connection.ConnectionString with a breakpoint the password is not present in the connection string anymore thus causing login failed.

When I added the Persist Security Info=True to the connection string the migration worked fine (or if I changed the code to always set the connection string using factory).

public override async ValueTask<InterceptionResult> ConnectionOpeningAsync(
        DbConnection connection, ConnectionEventData eventData, InterceptionResult result,
        CancellationToken cancellationToken = new())
    {
        if (string.IsNullOrEmpty(connection.ConnectionString))
        {
            connection.ConnectionString = (await _connectionStringFactory.GetConnectionStringAsync(cancellationToken));
        }

        return result;
    }

Hope this clarify the issue.