Different ConnectorPools are created if you use connection strings that differ only in the order in which the parameters are defined, but not in their values.
See original GitHub issue(This problem is a bit like #3480 (#3476). But #3480 only affects EventCounters.)
If the application has two connection strings that are identical in composition, but differ in the order of defining values, e.g.:
var connString1 = "User Id=user;Password=password;Host=localhost;Application Name=test;Database=test;Pooling=true";
var connString2 = "Database=test;User Id=user;Password=password;Host=localhost;Application Name=test;Pooling=true";
If we create connections using these connection strings, we get a situation that for each connection string its own ConnectorPool is created (Not just entries in the _pools array of the PoolManager, as it was for # 3476, but really different pools).
The reason is that in NpgsqlConnection.GetPoolAndSettings (where it is decided whether to create a pool) the following “canonical connection string” computation is used:
// NpgsqlConnection.GetPoolAndSettings:
var settings = new NpgsqlConnectionStringBuilder(_connectionString);
settings.Validate();
Settings = settings;
// Maybe pooling is off
if (!Settings.Pooling)
return;
// The connection string may be equivalent to one that has already been seen though (e.g. different
// ordering). Have NpgsqlConnectionStringBuilder produce a canonical string representation
// and recheck.
var canonical = Settings.ConnectionString;
NpgsqlConnectionStringBuilder inherits System.Data.Common.DbConnectionStringBuilder, which defines ConnectionString’s getter as
public string ConnectionString
{
get
{
DataCommonEventSource.Log.Trace("<comm.DbConnectionStringBuilder.get_ConnectionString|API> {0}", ObjectID);
string? connectionString = _connectionString;
if (null == connectionString)
{
StringBuilder builder = new StringBuilder();
foreach (string keyword in Keys)
{
Debug.Assert(keyword != null);
object? value;
if (ShouldSerialize(keyword) && TryGetValue(keyword, out value))
{
string? keyvalue = ConvertValueToString(value);
AppendKeyValuePair(builder, keyword, keyvalue, _useOdbcRules);
}
}
connectionString = builder.ToString();
_connectionString = connectionString;
}
return connectionString;
}
Keys is a dictionary in which the keys are listed in the order in which they were added.
We could make a separate internal method NpgsqlConnectionStringBuilder.GetCanonicalConnectionString, which pre-sorts the keys during connection string generation and use it in NpgsqlConnection.GetPoolAndSettings.
@roji Do you think it is worth doing such a fix? Or is this behavior not a bug, but a feature?
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (6 by maintainers)
While I personally do not see a problem here, that’s not something I can say for other providers (don’t mind me, it’s just me being a little frustrated with some of the decisions for no apparent reason 🤣).
Closing this as a duplicate of dotnet/runtime#834, which is external to us.