Skip to content

Exception types for System.Net.Connections #39941

@scalablecory

Description

@scalablecory

Background and Motivation

We need an exception model for System.Net.Connections implementations, so that users can catch and react to common network events such as a connection reset.

Normally a SocketException would be used, but an abstracted connection may not be using a Socket and so that may not be appropriate. Furthermore it might confuse bugs in the connection's code versus events parsed from the protocol that the connection would like to communicate.

This proposes an exception that implementations should throw, when appropriate.

Proposed API

The API is a reduction of the existing SocketException and SocketError model.

Option A

We define two new exception types:

  • ConnectionException, with a ConnectionError enum, for exceptions from System.Net.Connections APIs
  • NetworkException, with a NetworkError enum, for exceptions from Stream.Read/Write[Async].

(We don't love the name NetworkException, but we don't have a better alternative. This is intended to be thrown from connection-oriented Streams like NetworkStream that would be returned from System.Net.Connections APIs. Note, however, that these exceptions are thrown regardless whether the Stream was created via System.Net.Connections or not -- we don't want different semantics based on how the Stream was created.)

namespace System.Net.Connections
{
    public class ConnectionException : IOException
    {
        public ConnectionException(string message, ConnectionError connectionError = ConnectionError.Unknown, Exception innerException = null);
        // serialization constructor as usual

        public ConnectionError ConnectionError { get; }
    }

    public enum ConnectionError
    {
        Unknown,
        AddressInUse,       // SocketError.AddressAlreadyInUse
        InvalidAddress,     // SocketError.AddressFamilyNotSupported, SocketError.AddressNotAvailable, etc
        ConnectionRefused,  // SocketError.ConnectionRefused
        HostNotFound,       // SocketError.HostNotFound, SocketError.HostUnreachable, etc
    }
}

namespace System.IO
{
    public class NetworkException : IOException
    {
        public NetworkException(string message, NetworkError error, Exception innerException = null);
        // serialization constructor as usual

        public NetworkError NetworkError { get; }
    }

    public enum NetworkError
    {
        Aborted,
        Reset,
    }
}

Option B

We define one new exception type: NetworkException, with NetworkError enum. System.Net.Connections APIs are expected to throw this exception, as are Stream.Read/Write[Async] in the case of a connection abort or reset. The various differentiated conditions from Option A are merged into a single NetworkError enum.

(Again, we don't love the name; see comments under Option A.)

namespace System.IO
{
    public class NetworkException : IOException
    {
        public NetworkException(string message, NetworkError error, Exception innerException = null);
        // serialization constructor as usual

        public NetworkError NetworkError { get; }
    }

    public enum NetworkError
    {
        Unknown,

        AddressInUse,       // SocketError.AddressAlreadyInUse
        InvalidAddress,     // SocketError.AddressFamilyNotSupported, SocketError.AddressNotAvailable, etc
        ConnectionRefused,  // SocketError.ConnectionRefused
        HostNotFound,       // SocketError.HostNotFound, SocketError.HostUnreachable, etc

        Aborted,
        Reset,
    }
}

Option C

We define no new exception type, but instead add an IOError enum property to IOException. System.Net.Connections APIs are expected to throw IOException with an appropriate IOError value, when applicable. Stream.Read/Write[Async] will continue to throw plain IOException, but set the IOError to the appropriate value in the case of a connection abort or reset.

The set of defined IOError values is currently focused on connection-oriented streams, but could be extended to other types of Streams (e.g. FileStream, MemoryStream) in the future.

namespace System.IO
{
    public class IOException : Exception
    {
        public IOException(string message, IOError error, Exception innerException = null);

        public IOError IOError { get; }
    }

    public enum IOError
    {
        Unknown,

        AddressInUse,       // SocketError.AddressAlreadyInUse
        InvalidAddress,     // SocketError.AddressFamilyNotSupported, SocketError.AddressNotAvailable, etc
        ConnectionRefused,  // SocketError.ConnectionRefused
        HostNotFound,       // SocketError.HostNotFound, SocketError.HostUnreachable, etc

        Aborted,
        Reset,
    }
}

Notes

NetworkStream currently throws IOException and would be updated to throw this.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions