dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.98k stars 4.66k forks source link

DbConnectionStringBuilder.ConnectionString should return identical strings for identical settings #834

Open roji opened 4 years ago

roji commented 4 years ago

DbConnectionStringBuilder internally uses a dictionary to keep key/value pairs, and the ConnectionString property iterates over the keys when building the string. Since Dictionary iteration order isn't stable, that means different strings can be returned for the same settings because keywords are ordered differently. This can lead to issues if resulting strings are used as keys to connection pools (or any other resource).

Simply applying a sort to ConnectionString's internal enumeration should fix this.

/cc @ajcvickers @bricelam

ajcvickers commented 4 years ago

@roji Certainly not against this, but experience has shown that, at least for SQL Server

Therefore using the connection string as a key for the connection is inherently problematic without some form of normalization.

roji commented 4 years ago

There are Many forms of what is essentially the same connection string. For example, there are multiple different key names that can be used for same option.

That is actually what I'd like to accomplish here. Npgsql already does connection normalization internally, as follows:

  1. When a connection is opened, Npgsql does a simple dictionary lookup from the given connection string (as given by the user) to a pool. If it's found we're done.
  2. If the connection string was not found, it is parsed by initializing an NpgsqlConnectionStringBuilder from it.
  3. A "normalized" string is extracted from that instance, via the ConnectionString property. This is where alias/synonyms are normalized to a single form.
  4. The normalized string is looked up again. If it is found, the original un-normalized string is inserted into the dictionary, pointing to the same value (pool) as the normalized string. So we have two keys with the same value (so next time lookup is very efficient).

The problem is that the normalization step currently yields different strings because of the ordering issue, which is what I'd like to fix. Hope that makes sense, the relevant code is here.