Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/apicompat.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: API Compatibility

on:
pull_request: {}
push:
branches:
- main

permissions:
contents: read

jobs:
apicompat:
name: Check TFM API Compatibility
runs-on: ubuntu-latest
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.x

- name: Run API Compatibility Check
run: bash scripts/apicompat.sh --build
Comment thread Fixed
1 change: 1 addition & 0 deletions NATS.Net.sln
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
.github\workflows\test_linux.yml = .github\workflows\test_linux.yml
.github\workflows\test_linux_core.yml = .github\workflows\test_linux_core.yml
.github\workflows\test_windows.yml = .github\workflows\test_windows.yml
.github\workflows\apicompat.yml = .github\workflows\apicompat.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{5BF3C0C5-94CA-4008-8DF5-890ED8E06990}"
Expand Down
20 changes: 20 additions & 0 deletions apicompat.suppression.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<!-- These are intentional TFM-specific polyfill types that differ between netstandard2.0 and newer TFMs -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- SslClientAuthenticationOptions is a polyfill for netstandard2.0 where the BCL type doesn't exist -->
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:NATS.Client.Core.SslClientAuthenticationOptions</Target>
</Suppression>
<!-- ConfigureClientAuthentication uses the polyfill type in its signature -->
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:NATS.Client.Core.NatsTlsOpts.get_ConfigureClientAuthentication</Target>
</Suppression>
<!-- AddNats has an extra 'key' parameter in net8.0+ for keyed DI services -->
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:NATS.Client.Hosting.NatsHostingExtensions.AddNats(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Int32,System.Func{NATS.Client.Core.NatsOpts,NATS.Client.Core.NatsOpts},System.Action{NATS.Client.Core.NatsConnection})</Target>
</Suppression>
</Suppressions>
76 changes: 76 additions & 0 deletions scripts/apicompat.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/bin/bash
# API Compatibility Check Script
# Verifies that APIs are compatible across different TFMs
# Usage: ./scripts/apicompat.sh [--build]

set -e

# Get script directory (works on both Windows and Linux)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

PROJECTS="NATS.Client.Abstractions NATS.Client.Core NATS.Client.Hosting NATS.Client.JetStream NATS.Client.KeyValueStore NATS.Client.ObjectStore NATS.Client.Services NATS.Client.Serializers.Json NATS.Client.Simplified NATS.Net NATS.Extensions.Microsoft.DependencyInjection"

SUPPRESSION_FILE="$ROOT_DIR/apicompat.suppression.xml"

# Check if apicompat is installed
if ! command -v apicompat &> /dev/null; then
echo "Installing Microsoft.DotNet.ApiCompat.Tool..."
dotnet tool install --global Microsoft.DotNet.ApiCompat.Tool
fi

# Build if requested
if [ "$1" = "--build" ]; then
echo "Building solution..."
dotnet build -c Release "$ROOT_DIR/NATS.Net.sln"
fi

check_compat() {
local baseline_tfm=$1
local target_tfm=$2
local failed=0

echo ""
echo "=============================================="
echo "Checking: $baseline_tfm (baseline) vs $target_tfm"
echo "=============================================="

for project in $PROJECTS; do
left="$ROOT_DIR/src/$project/bin/Release/$baseline_tfm/$project.dll"
right="$ROOT_DIR/src/$project/bin/Release/$target_tfm/$project.dll"

if [ -f "$left" ] && [ -f "$right" ]; then
echo -n " $project: "
if apicompat --left "$left" --right "$right" --suppression-file "$SUPPRESSION_FILE" --permit-unnecessary-suppressions > /dev/null 2>&1; then
echo "OK"
else
echo "FAILED"
apicompat --left "$left" --right "$right" --suppression-file "$SUPPRESSION_FILE" --permit-unnecessary-suppressions 2>&1 | head -20
failed=1
fi
else
echo " $project: SKIPPED (assemblies not found)"
fi
done

return $failed
}

echo "API Compatibility Check"
echo "======================="

exit_code=0

# Only check against net8.0 as the target TFM
# net6.0 has known differences with init accessors
check_compat "netstandard2.0" "net8.0" || exit_code=1
check_compat "netstandard2.1" "net8.0" || exit_code=1

echo ""
if [ $exit_code -eq 0 ]; then
echo "All API compatibility checks passed!"
else
echo "Some API compatibility checks failed!"
fi

exit $exit_code
1 change: 1 addition & 0 deletions tools/site_src/documentation/advanced/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,4 @@ essentially sent back to back after they're picked up from internal queues and b
- [Serialization](serialization.md) is the process of converting an object into a format that can be stored or transmitted.
- [Security](security.md) is an important aspect of any distributed system. NATS provides a number of security features to help you secure your applications.
- [AOT Deployment](aot.md) is a way to deploy your applications as native platform executables, which produces faster startup times and better performance in most cases.
- [Platform Compatibility](platform-compatibility.md) documents API differences across target frameworks (.NET Standard, .NET 6, .NET 8).
93 changes: 93 additions & 0 deletions tools/site_src/documentation/advanced/platform-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Platform Compatibility

NATS.Net targets multiple .NET platforms to provide broad compatibility:

- `netstandard2.0` - .NET Framework 4.6.1+, .NET Core 2.0+, Mono, Xamarin, Unity
- `netstandard2.1` - .NET Core 3.0+
- `net6.0` - .NET 6
- `net8.0` - .NET 8

While the API surface is designed to be consistent across all target frameworks, there are some
intentional differences due to platform capabilities. This page documents these differences.

## TLS Configuration

### SslClientAuthenticationOptions

The [`NatsTlsOpts.ConfigureClientAuthentication`](xref:NATS.Client.Core.NatsTlsOpts.ConfigureClientAuthentication)
property allows you to configure TLS client authentication options.

| Target Framework | Type |
|-----------------|------|
| `netstandard2.0` | `NATS.Client.Core.SslClientAuthenticationOptions` (polyfill) |
| `netstandard2.1`, `net6.0`, `net8.0` | `System.Net.Security.SslClientAuthenticationOptions` (BCL) |

On `netstandard2.0`, the library provides a polyfill type `NATS.Client.Core.SslClientAuthenticationOptions`
because the BCL type doesn't exist in that target framework. The polyfill provides a subset of the
properties available in the BCL type:

- `TargetHost`
- `EnabledSslProtocols`
- `ClientCertificates`
- `CertificateRevocationCheckMode`
- `RemoteCertificateValidationCallback`
- `LocalCertificateSelectionCallback`

If you need the full `SslClientAuthenticationOptions` functionality, consider targeting `netstandard2.1` or later.

## Dependency Injection

### Keyed Services

The [`AddNats`](xref:NATS.Client.Hosting.NatsHostingExtensions.AddNats*) extension method has different
signatures depending on the target framework:

**netstandard2.0, netstandard2.1, net6.0:**
```csharp
public static IServiceCollection AddNats(
this IServiceCollection services,
int poolSize = 1,
Func<NatsOpts, NatsOpts>? configureOpts = null,
Action<NatsConnection>? configureConnection = null)
```

**net8.0:**
```csharp
public static IServiceCollection AddNats(
this IServiceCollection services,
int poolSize = 1,
Func<NatsOpts, NatsOpts>? configureOpts = null,
Action<NatsConnection>? configureConnection = null,
object? key = null) // Additional parameter for keyed services
```

[Keyed dependency injection services](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#keyed-services)
were introduced in .NET 8. The `key` parameter allows you to register multiple NATS connections
with different keys:

```csharp
// .NET 8+ only
services.AddNats(key: "primary", configureOpts: opts => opts with { Url = "nats://primary:4222" });
services.AddNats(key: "secondary", configureOpts: opts => opts with { Url = "nats://secondary:4222" });

// Inject with [FromKeyedServices("primary")]
public class MyService([FromKeyedServices("primary")] INatsConnection primaryNats) { }
```

## API Compatibility Checking

The repository includes an API compatibility check that runs in CI to ensure APIs remain consistent
across target frameworks. Known intentional differences are documented in `apicompat.suppression.xml`
at the repository root.

To run the compatibility check locally:

```bash
./scripts/apicompat.sh --build
```

## What's Next

- [Serialization](serialization.md) is the process of converting an object into a format that can be stored or transmitted.
- [Security](security.md) is an important aspect of any distributed system. NATS provides a number of security features to help you secure your applications.
- [AOT Deployment](aot.md) is a way to deploy your applications as native platform executables.
2 changes: 2 additions & 0 deletions tools/site_src/documentation/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
href: advanced/security.md
- name: AOT Deployments
href: advanced/aot.md
- name: Platform Compatibility
href: advanced/platform-compatibility.md

- name: Updating Documentation
href: update-docs.md
Loading