Npgsql 10.0 Release Notes
Npgsql version 10.0 is out and available on nuget.org.
Note
We're considering to start dropping support for synchronous APIs (NpgsqlConnection.Open, NpgsqlCommand.ExecuteNonQuery, etc.) starting with Npgsql 11.0. The current plan is to deprecate the API by throwing a runtime exception by default (with a switch to re-enable synchronous I/O) for Npgsql 11.0, while possibly completely removing it for Npgsql 12.0. This is in line with ASP.NET Core and .NET APIs in general, which are moving in the direction of async I/O only (for example, System.IO.Pipelines doesn't have synchronous I/O). If you have any questions or want to share you experience/issues with async I/O, please feel free to post in the issue.
While this is a relatively minor release in terms of changes, it does contain new features and improvements. Notable changes:
Tracing and metrics improvements
Npgsql 10.0 brings multiple observability improvements:
- Command tracing has been changed to align with the stable OpenTelemetry tracing semantic conventions. This allows tracing any database driver using the same span and tags.
- Metrics support has also been changed to conform to the OpenTelemetry metrics semantic conventions. The stable
db.client.operation.durationmetric is now emitted, as well as the non-stabledb.client.connection.count,db.client.connection.max. The remaining Npgsql-specific metrics have been renamed for consistency. - COPY operations (binary, text and raw import/export) are now fully traced. Thanks to @manandre for contributing this feature!
- The opening of physical connections is now also traced, allowing you to observe and identify performance issues.
Note that these changes modify the metric names and tracing span tags, and so are breaking to anyone currently consuming Npgsql tracing/metrics.
GSSAPI session encryption
GSSAPI session encryption is an alternative to SSL/TLS session encryption, where special temporary tokens are used to encrypt traffic between the client and the server (MIT Kerberos is one of the GSSAPI providers that can be used for that), unlike SSL/TLS, where SSL certificate is used for the same purpose. You can use the GssEncryptionMode connection string parameter to control whether GSS session encryption is used; the default is Prefer, which will enable the feature if possible but proceed if it's not available. To learn more, see PostgreSQL docs.
Support for RequireAuth in connection string
RequireAuth is used to determine which authentication methods are allowed/required. For example, if you want to make sure that passwords aren't sent as cleartext or MD5, you can specify RequireAuth=!Password,!MD5. Or, if you want to make sure to always authenticate either via ScramSHA256 or GSS, then you can specify it as RequireAuth=ScramSHA256,GSS. To learn more, see PostgreSQL docs.
Support for the cube extension
PostgreSQL bundles the cube extension, which provides a multi-dimensional cube data type and associated operations. Npgsql 10 now fully supports the cube type out-of-the-box:
command.CommandText = """
CREATE EXTENSION IF NOT EXISTS cube;
CREATE TABLE data (my_cude CUBE);
""";
await command.ExecuteNonQueryAsync();
var cube = new NpgsqlCube([1.0, 2.0, 3.0], [4.0, 5.0, 6.0]);
command.CommandText = "INSERT INTO data (my_cude) VALUES ($1)";
command.Parameters.Add(new() { Value = cube });
await command.ExecuteNonQueryAsync();
command.CommandText = "SELECT my_cude FROM data";
var readCube = (NpgsqlCube)(await command.ExecuteScalarAsync())!;
Console.WriteLine($"Read cube: {readCube}");
Thanks to @kirkbrauer for contributing this feature!
Various other changes
- OpenTelemetry tracing now also included by default for whenever a physical connection to database is open.
- Added support for
PGAPPNAMEenvironment variable. It's mapped toApplicationNamefield of the connection string. - Added support for SHA3 hash algorithms with SASL authentication. Previously, Npgsql falled back to SCRAM-SHA-256 if the certificate, provided by the database, had SHA3 signature algorithm.
NpgsqlConnection.Opennow wrapsSocketExceptionwithNpgsqlExceptionwhen hostname can't be resolved.- Metrics names are now more aligned to the OpenTelemetry standard (see breaking change note below).
- The connection string now supports specifying
TargetSessionAttributeswhen used withNpgsqlDataSourceBuilder. This means that code creatingNpgsqlDataSourcedoesn't have to be aware that it's used with multiple hosts. - The built-in geometry types (e.g.
NpgsqlBox) can now be deconstructed. Thanks @ddas09 for contributing! - The new
IDbTypeResolvernow allows remapping DbType values to arbitrary PostgreSQL types.
Breaking changes
.NET 6 is no longer supported
With .NET 6 being out of support since November 2024, Npgsql 10.0 also drops support for .NET 6. This change allows us to have a much better capability parity between different versions of .NET, while also removing hundreds lines of compatibility-only code and simplifying the codebase.
date and time are now mapped to DateOnly and TimeOnly
The PostgreSQL date and time types are now read as .NET DateOnly and TimeOnly, instead of DateTime and TimeSpan by default, respectively. This affects non-generic read methods which return object, such as ExecuteScalarAsync and NpgsqlDataReader.GetValue; you can still read DateTime and TimeSpan via the generic GetFieldValue.
cidr is now mapped to IPNetwork
With .NET 6 no longer supported by Npgsql, the PostgreSQL cidr type is now mapped to IPNetwork by default instead of NpgsqlCidr. In addition, NpgsqlCidr is now obsolete and will be removed in the future.
Tracing and metrics have been changed to align with the OpenTelemetry standard
Npgsql emits metrics and tracing data that provide various information about commands and connections. Since these were designed when the OpenTelemetry specifications were in an earlier stage, they did not align with current standard naming. Npgsql 10 changes metrics names and tracing span tags to better align with the standard, allowing Npgsql observability data to be tracked in dashboards just like other standards-conforming database drivers. If you already have a dashboard set up to consume Npgsql observability data, its configuration will need to change to accomodate the new naming.
Only root CA certificate is used to validate TLS chain
While establishing TLS connection with PostgreSQL, Npgsql will now only use the provided root CA certificate to validate TLS chain instead of using it in addition to the system CA store. This behaviour aligns with libpq and prevents establishing unintended connections.
COPY operation's Timeout property now treats Timeout.InfiniteTimeSpan as an infinite timeout instead of TimeSpan.Zero
This is in line with other .NET API (like NetworkStream.ReadTimeout), where Timeout.InfiniteTimeSpan and Timeout.Infinite are treated as infinite.
PostgresException.BatchCommand is null by default
This prevents accidental leak of queries and parameters when exceptions are logged. To change this behavior you can set IncludeFailedBatchedCommand in connection string to true.
NpgsqlConnection.BeginText{Import,Export}Async now return NpgsqlCopyTextReader instead of TextWriter
The methods to start a text import/export operation have been changed to return a more specific NpgsqlCopyTextReader, rather than a general TextWriter; this was done since NpgsqlCopyTextReader exposes some additional APIs to allow cancelling and setting the timeout on a COPY operation. Since NpgsqlCopyTextReader extends TextWriter, this is a binary breaking change only - recompiling against the new version of Npgsql should work without any source changes.
NpgsqlParameter.DataTypeName now takes precedence over NpgsqlDbType
NpgsqlParameter allows configuring which PostgreSQL is sent to the database via several methods: DataTypeName (for a PostgreSQL type name as a string), NpgsqlDbType (PG-specific enum), or DbType (database-agnostic enum). Starting with Npgsql 10, setting DataTypeName takes precedence over NpgsqlDbType.
JSON mutable DOM mappings (e.g. JsonNode, JsonArray...) now require EnableJsonTypes on NpgsqlSlimDataSourceBuilder
NativeAOT applications which use NpgsqlSlimDataSourceBuilder and make use of mutable JSON types (JsonNode, JsonValue...) now have to call EnableJsonTypes(). Previously, calling EnableJsonDynamicTypes() added these mappings.