# Npgsql 9.0 Release Notes

Npgsql version 9.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 10.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 10.0, while possibly completely removing it for Npgsql 11.0. This is in line with ASP.NET Core and .NET runtime 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.

## Tracing improvements

Several quality-of-life improvements have been implemented for Npgsql's OpenTelemetry tracing support. You can now do the following via the new NpgsqlDataSourceBuilder.ConfigureTracing API:

- Specify a filter which determines which commands get traced
- Set the the tracing span name (e.g. use the command's SQL as the span name)
- Add arbitrary tags to the tracing span, based on the command
- Disable the time-to-first-read event that's emitted in spans

See the tracing documentation for more information.

## Mapping improvements

### Support System.Text.Json polymorphism with PostgreSQL `jsonb`

##### Note

If you're using EF Core, the below pertains to the EF provider's legacy POCO mapping, and not to the recommended ToJson mapping. Unfortunately, the latter does not yet support polymorphic serialization (support for this may be added in EF 10).

System.Text.Json has supported polymorphic serialization for a while, using a JSON `$type` property as the type discriminator. However, it was required that the `$type` property be at the top of the JSON document; this causes problems serializing to the PostgreSQL `jsonb` type, since that type does not preserve property order in JSON objects.

System.Text.Json 9.0 brings support for out-of-order metadata reads, which is an opt-in feature allowing the `$type` property to be anywhere in the JSON object. When using Npgsql, you can opt into this when configuring your NpgsqlDataSourceBuilder as follows:

    var builder = new NpgsqlDataSourceBuilder("<connection string>");
    builder
        .EnableDynamicJson()
        .ConfigureJsonOptions(new JsonSerializerOptions { AllowOutOfOrderMetadataProperties = true });
    await using var dataSource = builder.Build();

Once that's done, you can use JSON polymorphism with `jsonb`. If you're still targeting .NET 8.0, you can take a reference on System.Text.Json 9.0 in order to use `AllowOutOfOrderMetadataProperties`.

### Add support for cidr <-> IPNetwork mapping

.NET 8 added a new type IPNetwork which represents an IP network with an IPAddress containing the network prefix and an `int` defining the prefix length. This type seems to be a perfect fit for PostgreSQL's `cidr` type, which is why we added support to read and write it. The default when reading a `cidr` is still `NpgsqlCidr` in 9.0, though this will likely change in Npgsql 10.0. See this issue for more info.

### Add support for interval's infinity values via NodaTime's Period.MinValue/Period.MaxValue

PostgreSQL 17 added support for infinity values with `interval` type. In turn, Npgsql 9.0 adds native support to read and write them via NodaTime's `Period.MinValue` and `Period.MaxValue`. Note that while using this feature with previous versions of PostgreSQL, instead of infinity values you'll get the minimum and maximum values for `interval` type due to the way infinity values are implemented by PostgreSQL. See this issue for more info.

## Security-related improvements

- PostgreSQL 17 added support for direct SSL. Direct SSL allows clients to skip sending an SSL support request, which saves a roundtrip while opening a physical connection. This behavior is disabled by default (as it's not supported with previous versions of PostgreSQL), but you can enable it via the `SslNegotiation` property in connection string or environment variable `PGSSLNEGOTIATION`. See this issue for more info.
- The new NpgsqlDataSourceBuilder.UseSslClientAuthenticationOptionsCallback callback is called while connecting to PostgreSQL via `SslStream`, and allows users to modify SslClientAuthenticationOptions, e.g. to change the supported TLS ciphers. See this issue for more info.
- The new NpgsqlDataSourceBuilder.UseNegotiateOptionsCallback callback is called while performing GSSAPI authentication (such as Kerberos), and allows users to modify NegotiateAuthenticationClientOptions, e.g. to change the `Credential` property to implement password-based Kerberos authentication. See this issue for more info.

## Replication improvements

- Parallel in-progress transactions with logical streaming replication protocol V4 allow clients to handle multiple in-progress transactions in parallel instead of sequentially. See this issue for more info.
- ReplicationValue.GetFieldName() `ReplicationValue.GetFieldName` allows clients to receive the name of changed column while reading rows from replication stream. See this issue for more info.

## Breaking changes

### .NET Standard 2.0 (and .NET Framework) are no longer supported

Npgsql 9.0 drops support for .NET Standard 2.0, and in turn .NET Framework. Npgsql is a constantly evolving driver, which makes it problematic to add new features which use APIs that do not exist on older versions of .NET. This doesn't mean you can't use Npgsql with .NET Standard 2.0: we're still committed to supporting Npgsql 8.0 (which does support .NET Standard 2.0). See this issue for more info.

### Multiple SSL-related callbacks on NpgsqlDataSourceBuilder are deprecated

With the new `UseSslClientAuthenticationOptionsCallback` callback, users have much more control over the way Npgsql connects to PostgreSQL via `SslStream`. This makes other callbacks, like `UseUserCertificateValidationCallback` and `UseClientCertificate` less useful, which is why we're obsoleting them. See this issue for more info.

### Obsoleted the Server Compatibility Mode and Load Table Composites connection string parameters

Npgsql has supported disabling its initial type loading, as well as tweaking whether table composites are loaded, via the connection string. These have been obsoleted, and configuration APIs on NpgsqlDataSourceBuilder have been introduced. For example, to disable type loading, use the following code:

    var builder = new NpgsqlDataSourceBuilder("Host=localhost;Username=test;Password=test");
    builder.ConfigureTypeLoading(x => x.EnableTypeLoading(false));
    await using var dataSource = builder.Build();

### ConnectionLifetime now defaults to 1 hour

The `Connection Lifetime` connection string property determines the total maximum lifetime of connections. Previously, the default value of this property was set to 0, which made connections last indefinitely. The old behavior was problematic because each physical connection on PostgreSQL's side holds on certain caches, which can only grow over time. See this pull request for more info.

### Changes on PgOutputReplicationOptions

In order to support the new logical streaming replication protocol V4, the `ProtocolVersion` and `StreamingMode` properties on the `PgOutputReplicationOptions` were changed to an enum. See this issue for more info.