Socket.End methods don't throw ObjectDisposedException

System.Net.Sockets.Socket.End* methods (for example, EndSend) throw a SocketException instead of an ObjectDisposedException if the socket is closed.

Previous behavior

Previously, the affected methods threw an ObjectDisposedException for closed sockets.

New behavior

Starting in .NET 7, the affected methods throw a SocketException with SocketErrorCode set to SocketError.OperationAborted for closed sockets.

Version introduced

.NET 7

Type of breaking change

This change can affect binary compatibility.

Reason for change

The asynchronous programming model (APM) APIs are those named Begin* and End*. Starting with .NET 6, these legacy APIs are backed with a Task-based implementation as part of an effort to consolidate and simplify the Socket codebase. Unfortunately, with the 6.0 implementation, unexpected events were sometimes raised on TaskScheduler.UnobservedTaskException. This happened even when the APIs were used correctly, meaning that the calling code always invoked the End* methods, including when the socket was closed.

The change to throw a SocketException was made to ensure that no unobserved exceptions are leaked in such cases.

If your code catches an ObjectDisposedException from any of the Socket.End* methods, change it to catch SocketException and refer to SocketException.SocketErrorCode to query the underlying reason.

Note

APM code should always make sure that End* methods are invoked after the corresponding Begin* methods, even if the socket is closed.

Affected APIs