Skip to content

Commit b4272ba

Browse files
allow to choose between throwing if the WebSocket is in closed state or failing silently
1 parent 9fd527d commit b4272ba

File tree

1 file changed

+28
-19
lines changed

1 file changed

+28
-19
lines changed

src/WebSocket.cs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ public class WebSocket
3838
/// </summary>
3939
public SocketState State => socket.State;
4040

41+
/// <summary>
42+
/// Wether to throw an exception or fail silently when acting on a closed WebSocket.
43+
/// Defaults to <c>true</c>.
44+
/// </summary>
45+
public bool ThrowIfClosed { get; set; } = true;
46+
4147
/// <summary>
4248
/// The number of messages that are currently in the incoming queue.
4349
/// These messages can be retreived without delay using the <see cref="Receive"/> and <see cref="ReceiveAsync"/> methods.
@@ -84,15 +90,15 @@ public event EventHandler? OnConnected
8490
/// Queues a message to be sent to the peer.
8591
/// This method will return immediately.
8692
/// If the WebSocket is currently connecting, the message will be queued and sent once the WebSocket is connected.
87-
/// If the WebSocket is currently closing, the message will be discarded silently.
93+
/// If the WebSocket is currently closing or closed, the message will be discarded silently.
8894
/// </summary>
8995
/// <remarks>
9096
/// This method is thread-safe.
9197
/// </remarks>
92-
/// <exception cref="InvalidOperationException">The WebSocket is closed.</exception>
98+
/// <exception cref="InvalidOperationException">The WebSocket is closed and <see cref="ThrowIfClosed"/> == <c>true</c>.</exception>
9399
public void Send(Message message)
94100
{
95-
ThrowIfClosed();
101+
if (HandleClosed()) return;
96102
socket.SendRange(FramesFromMessage(message));
97103
}
98104

@@ -116,12 +122,12 @@ public void Send(Message message)
116122
/// Queues a message to be sent to the peer.
117123
/// This Task will complete immediately.
118124
/// If the WebSocket is currently connecting, the message will be queued and sent once the WebSocket is connected.
119-
/// If the WebSocket is currently closing, the message will be discarded silently.
125+
/// If the WebSocket is currently closing or closed, the message will be discarded silently.
120126
/// </summary>
121-
/// <exception cref="InvalidOperationException">The WebSocket is closed.</exception>
127+
/// <exception cref="InvalidOperationException">The WebSocket is closed and <see cref="ThrowIfClosed"/> == <c>true</c>.</exception>
122128
public async Task SendAsync(Message message)
123129
{
124-
ThrowIfClosed();
130+
if (HandleClosed()) return;
125131
await socket.SendRangeAsync(FramesFromMessage(message));
126132
}
127133

@@ -145,49 +151,55 @@ public async Task SendAsync(Message message)
145151
/// Return the next message from the peer.
146152
/// This method will block until a message is received.
147153
/// </summary>
154+
/// <remarks>
155+
/// This method is not affected by <see cref="ThrowIfClosed"/> and will always throw if called in closed state.
156+
/// </remarks>
148157
/// <exception cref="InvalidOperationException">The WebSocket is closed.</exception>
149158
/// <exception cref="OperationCanceledException">The WebSocket is being closed and thus this function could never return.</exception>
150159
/// <exception cref="OperationCanceledException">The operation has been canceled using the given token.</exception>
151160
public Message Receive(CancellationToken token = default)
152161
{
153-
ThrowIfClosed();
162+
if (State == SocketState.Closed) throw new InvalidOperationException("The WebSocket is closed.");
154163
return incoming.Dequeue(token);
155164
}
156165

157166
/// <summary>
158167
/// Return the next message from the peer.
159168
/// This Task will complete successfully once a message has been received.
160169
/// </summary>
170+
/// <remarks>
171+
/// This method is not affected by <see cref="ThrowIfClosed"/> and will always throw if called in closed state.
172+
/// </remarks>
161173
/// <exception cref="InvalidOperationException">The WebSocket is closed.</exception>
162174
/// <exception cref="OperationCanceledException">The WebSocket is being closed and thus this function could never return.</exception>
163175
/// <exception cref="OperationCanceledException">The operation has been canceled using the given token.</exception>
164176
public async Task<Message> ReceiveAsync(CancellationToken token = default)
165177
{
166-
ThrowIfClosed();
178+
if (State == SocketState.Closed) throw new InvalidOperationException("The WebSocket is closed.");
167179
return await incoming.DequeueAsync(token);
168180
}
169181

170182
/// <summary>
171183
/// Try to receive a message from the peer.
172184
/// This method will return immediately.
173185
/// </summary>
174-
/// <returns>The next message from the peer, or <c>null</c> if there were no messages or the WebSocket is being closed.</returns>
175-
/// <exception cref="InvalidOperationException">The WebSocket is closed.</exception>
186+
/// <returns>The next message from the peer, or <c>null</c> if there were no messages or the WebSocket is closing or closed.</returns>
187+
/// <exception cref="InvalidOperationException">The WebSocket is closed and <see cref="ThrowIfClosed"/> == <c>true</c>.</exception>
176188
public Message? TryReceive()
177189
{
178-
ThrowIfClosed();
190+
if (HandleClosed()) return null;
179191
return incoming.TryDequeue();
180192
}
181193

182194
/// <summary>
183195
/// Try to receive a message from the peer.
184196
/// This Task will complete immediately.
185197
/// </summary>
186-
/// <returns>The next message from the peer, or <c>null</c> if there were no messages or the WebSocket is being closed.</returns>
187-
/// <exception cref="InvalidOperationException">The WebSocket is closed.</exception>
198+
/// <returns>The next message from the peer, or <c>null</c> if there were no messages or the WebSocket is closing or closed.</returns>
199+
/// <exception cref="InvalidOperationException">The WebSocket is closed and <see cref="ThrowIfClosed"/> == <c>true</c>.</exception>
188200
public async Task<Message?> TryReceiveAsync()
189201
{
190-
ThrowIfClosed();
202+
if (HandleClosed()) return null;
191203
return await incoming.TryDequeueAsync();
192204
}
193205

@@ -262,9 +274,6 @@ private Message MessageFromFrames(Queue<Frame> queue)
262274
return message;
263275
}
264276

265-
private void ThrowIfClosed()
266-
{
267-
if (State == SocketState.Closed)
268-
throw new InvalidOperationException("The WebSocket is closed.");
269-
}
277+
private bool HandleClosed() => State == SocketState.Closed &&
278+
(ThrowIfClosed ? throw new InvalidOperationException("The WebSocket is closed.") : true);
270279
}

0 commit comments

Comments
 (0)