diff --git a/src/NATS.Client.Abstractions/INatsSocketConnection.cs b/src/NATS.Client.Abstractions/INatsSocketConnection.cs
new file mode 100644
index 000000000..c71570000
--- /dev/null
+++ b/src/NATS.Client.Abstractions/INatsSocketConnection.cs
@@ -0,0 +1,43 @@
+using System.Net.Sockets;
+
+namespace NATS.Client.Core;
+
+///
+/// Represents a socket connection to a NATS server.
+///
+///
+/// This interface defines the contract for low-level socket connections to NATS servers,
+/// providing methods for sending and receiving data and disposing the socket.
+/// Disposing should attempt to perform graceful shutdown of the socket.
+///
+public interface INatsSocketConnection : IAsyncDisposable
+{
+ ///
+ /// Sends data asynchronously over the connection.
+ ///
+ /// The buffer containing the data to send.
+ /// A task representing the asynchronous send operation with the number of bytes sent.
+ ValueTask SendAsync(ReadOnlyMemory buffer);
+
+ ///
+ /// Receives data asynchronously from the connection.
+ ///
+ /// The buffer to store the received data.
+ /// A task representing the asynchronous receive operation with the number of bytes received.
+ ValueTask ReceiveAsync(Memory buffer);
+}
+
+///
+/// Represents a NATS socket connection that can be upgraded to use TLS.
+///
+///
+/// This interface extends to provide access to the underlying
+/// socket that is used to create a SslStream.
+///
+public interface INatsTlsUpgradeableSocketConnection : INatsSocketConnection
+{
+ ///
+ /// Gets the underlying Socket instance for the connection.
+ ///
+ Socket Socket { get; }
+}
diff --git a/src/NATS.Client.Abstractions/NATS.Client.Abstractions.csproj b/src/NATS.Client.Abstractions/NATS.Client.Abstractions.csproj
index e4e38515b..2fb09c6ff 100644
--- a/src/NATS.Client.Abstractions/NATS.Client.Abstractions.csproj
+++ b/src/NATS.Client.Abstractions/NATS.Client.Abstractions.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/NATS.Client.Core/INatsSocketConnection.cs b/src/NATS.Client.Core/INatsSocketConnection.cs
index 87386dc76..95f0861e9 100644
--- a/src/NATS.Client.Core/INatsSocketConnection.cs
+++ b/src/NATS.Client.Core/INatsSocketConnection.cs
@@ -1,32 +1,5 @@
-using System.Net.Sockets;
-
namespace NATS.Client.Core;
-///
-/// Represents a socket connection to a NATS server.
-///
-///
-/// This interface defines the contract for low-level socket connections to NATS servers,
-/// providing methods for sending and receiving data and disposing the socket.
-/// Disposing should attempt to perform graceful shutdown of the socket.
-///
-public interface INatsSocketConnection : IAsyncDisposable
-{
- ///
- /// Sends data asynchronously over the connection.
- ///
- /// The buffer containing the data to send.
- /// A task representing the asynchronous send operation with the number of bytes sent.
- ValueTask SendAsync(ReadOnlyMemory buffer);
-
- ///
- /// Receives data asynchronously from the connection.
- ///
- /// The buffer to store the received data.
- /// A task representing the asynchronous receive operation with the number of bytes received.
- ValueTask ReceiveAsync(Memory buffer);
-}
-
///
/// Obsolete, use instead
///
@@ -39,18 +12,3 @@ public interface ISocketConnection : INatsSocketConnection
ValueTask AbortConnectionAsync(CancellationToken cancellationToken);
}
-
-///
-/// Represents a NATS socket connection that can be upgraded to use TLS.
-///
-///
-/// This interface extends to provide access to the underlying
-/// socket that is used to create a SslStream.
-///
-public interface INatsTlsUpgradeableSocketConnection : INatsSocketConnection
-{
- ///
- /// Gets the underlying Socket instance for the connection.
- ///
- Socket Socket { get; }
-}
diff --git a/src/NATS.Client.Core/TypeForwarders.cs b/src/NATS.Client.Core/TypeForwarders.cs
index a565921ee..a9ff5cb35 100644
--- a/src/NATS.Client.Core/TypeForwarders.cs
+++ b/src/NATS.Client.Core/TypeForwarders.cs
@@ -5,3 +5,5 @@
[assembly: TypeForwardedTo(typeof(INatsSerialize<>))]
[assembly: TypeForwardedTo(typeof(INatsDeserialize<>))]
[assembly: TypeForwardedTo(typeof(INatsSerializerRegistry))]
+[assembly: TypeForwardedTo(typeof(INatsSocketConnection))]
+[assembly: TypeForwardedTo(typeof(INatsTlsUpgradeableSocketConnection))]
diff --git a/tests/NATS.Client.CheckAbi/Program.cs b/tests/NATS.Client.CheckAbi/Program.cs
index 433b42ed0..ed3b4ece6 100644
--- a/tests/NATS.Client.CheckAbi/Program.cs
+++ b/tests/NATS.Client.CheckAbi/Program.cs
@@ -23,10 +23,14 @@ void Check(string name, string expected, string actual)
Check("INatsSerializeWithContext<>", "NATS.Client.Abstractions", typeof(INatsSerializeWithContext<>).Assembly.GetName().Name!);
Check("INatsDeserializeWithContext<>", "NATS.Client.Abstractions", typeof(INatsDeserializeWithContext<>).Assembly.GetName().Name!);
Check("NatsMsgContext", "NATS.Client.Abstractions", typeof(NatsMsgContext).Assembly.GetName().Name!);
+Check("INatsSocketConnection", "NATS.Client.Abstractions", typeof(INatsSocketConnection).Assembly.GetName().Name!);
+Check("INatsTlsUpgradeableSocketConnection", "NATS.Client.Abstractions", typeof(INatsTlsUpgradeableSocketConnection).Assembly.GetName().Name!);
Console.WriteLine();
Console.WriteLine("Types as seen by TransientLib (compiled against 2.6.0):");
Check("INatsSerialize<> (transient)", "NATS.Client.Abstractions", MySerializer.GetSerializerInterfaceAssembly());
+Check("INatsSocketConnection (transient)", "NATS.Client.Abstractions", MySocketConnection.GetSocketConnectionInterfaceAssembly());
+Check("INatsTlsUpgradeableSocketConnection (transient)", "NATS.Client.Abstractions", MySocketConnection.GetTlsUpgradeableInterfaceAssembly());
Console.WriteLine();
Console.WriteLine("Assembly versions at runtime:");
@@ -54,6 +58,16 @@ void Check(string name, string expected, string actual)
Console.WriteLine();
+Console.WriteLine("Testing TransientLib.MySocketConnection (compiled against 2.6.0):");
+INatsSocketConnection connection = new MySocketConnection();
+var sent = await connection.SendAsync(new ReadOnlyMemory(new byte[7]));
+Console.WriteLine($" SendAsync reported {sent} bytes");
+if (sent != 7)
+ errors.Add($"SendAsync failed: got {sent}");
+await connection.DisposeAsync();
+
+Console.WriteLine();
+
if (errors.Count > 0)
{
Console.Error.WriteLine($"FAILED: {errors.Count} error(s):");
diff --git a/tests/NATS.Client.CheckAbiTransientLib/MySocketConnection.cs b/tests/NATS.Client.CheckAbiTransientLib/MySocketConnection.cs
new file mode 100644
index 000000000..43bab5812
--- /dev/null
+++ b/tests/NATS.Client.CheckAbiTransientLib/MySocketConnection.cs
@@ -0,0 +1,30 @@
+using System.Net.Sockets;
+using NATS.Client.Core;
+
+namespace NATS.Client.CheckAbiTransientLib;
+
+///
+/// Compiled against NATS.Net 2.6.0 where INatsSocketConnection and
+/// INatsTlsUpgradeableSocketConnection live in NATS.Client.Core. When used with a newer
+/// build, type forwarding should redirect both to NATS.Client.Abstractions.
+///
+public class MySocketConnection : INatsTlsUpgradeableSocketConnection
+{
+ public Socket Socket => throw new NotSupportedException();
+
+ public static string GetSocketConnectionInterfaceAssembly()
+ {
+ return typeof(INatsSocketConnection).Assembly.GetName().Name!;
+ }
+
+ public static string GetTlsUpgradeableInterfaceAssembly()
+ {
+ return typeof(INatsTlsUpgradeableSocketConnection).Assembly.GetName().Name!;
+ }
+
+ public ValueTask SendAsync(ReadOnlyMemory buffer) => new(buffer.Length);
+
+ public ValueTask ReceiveAsync(Memory buffer) => new(0);
+
+ public ValueTask DisposeAsync() => default;
+}