WebsocketClientLite.PCL
7.3.0
See the version list below for details.
dotnet add package WebsocketClientLite.PCL --version 7.3.0
NuGet\Install-Package WebsocketClientLite.PCL -Version 7.3.0
<PackageReference Include="WebsocketClientLite.PCL" Version="7.3.0" />
paket add WebsocketClientLite.PCL --version 7.3.0
#r "nuget: WebsocketClientLite.PCL, 7.3.0"
// Install WebsocketClientLite.PCL as a Cake Addin #addin nuget:?package=WebsocketClientLite.PCL&version=7.3.0 // Install WebsocketClientLite.PCL as a Cake Tool #tool nuget:?package=WebsocketClientLite.PCL&version=7.3.0
WebSocket Client Lite (Rx)
Please star this project if you find it useful. Thank you.
A Lightweight Cross Platform WebSocket Client
This library is a ground-up implementation of the WebSocket specification (RFC 6544) - i.e., this implementation does not rely on the build-in WebSocket libraries in .NET.
The library allows developers additional flexibility, including the ability to establish secure wss websocket connections to websocket servers that have self-signing certificates, expired certificates etc. This capability should be used with care for obvious reasons, however it is useful for testing environments, closed local networks, local IoT set-ups etc.
Furthermore, this library utilize ReactiveX (aka Rx or Reactive Extensions). Although taking this dependency introduces an added learning curve, it is a learning curve worthwhile investing in, as it IMHO makes using and creating a library like this much more elegant compared to using traditional call-back or events based patterns etc.
New in version 7.0
At writing time, this library has been around for more than 6 years. The work represented in this repo was mainly initiated on a desire to learn and play around with the technologies involved.
Unsurprisingly, over the years learning and insights grew and eventually maintaining and looking back at the aging code-base became more and more painful for the ever more trained eye, hence I decided to redo most of it.
Version 7 is more or less a rewrite of 90+ % of the original code.
The version 7 NuGet package includes both a .NET Standard 2.0 package and a .NET Standard 2.1, with e .NET Standard 2.1 package having a few less dependencies.
Version 7.3
Version 7.3 introduces a new feature. When passing an existing TCP Socket Client it is not possible to pass the life-cycle ownership of the socket, which means that when the observable WebSocket connection is disposed, so will the socket connection and the TCP Socket client be disposed and the connection closed.
new MessageWebsocketRx(tcpClient, hasTransferTcpSocketLifeCycleOwnership: true)
Now With Client Ping
Version 7 introduces a client ping feature, which enabling the WebSocket client to send a ping message with a constant interval.
The clientPingMessage
parameter is optional and the default value is null. The behavior for the null value is to not include any message, as part of the ping.
var websocketConnectionObservable =
client.WebsocketConnectWithStatusObservable(
uri: WebsocketServerUri,
hasClientPing: true, // default is false.
clientPingInterval: TimeSpan.FromSeconds(20), // default is 30 seconds.
clientPingMessage: "my ping message"); // default no message when set to null.
It is only possible to use a string
in this method. For more advanced scenarios, the ISender
has a SendPing
method that can be used for full control when sending client pings as string
or as byte[]
.
New in version 6.4
Successfully tested with .NET 6.0.
Previously the library only accepted the ws
and wss
scheme. Now http
and https
is also supported.
To further extend supported schemes override the IsSecureConnectionScheme
method of the MessageWebSocketRx
class.
The virtual method looks like this:
public virtual bool IsSecureConnectionScheme(Uri uri) =>
uri.Scheme switch
{
"ws" or "http" => false,
"https" or "wss"=> true,
_ => throw new ArgumentException("Unknown Uri type.")
};
New in version 6.3
- Fixed bug related to connecting to IPv6 endpoints.
- Updated System.Reactive to v5.0.0.
- Successfully tested with .NET 5.0.
- Updated Readme.
New in version 6.1.
Updates, stability and fundamental improvements to the library. See examples below for changes in usage.
New in version 6.0.
Simplifications and no longer relies on SocketLite but utilizes the cross-platform capabilities of .NET Standard 2.0+.
New in version 5.0.
From hereon and forward only .NET Standard 2.0+ is supported.
Usage
For a more detailed sample of using this library please see the console example app.
To instantiate WebSocket lite class
To use the WebSocket client create an instance of the class MessageWebsocketRx
:
var websocketClient = new MessageWebsocketRx()
{
IgnoreServerCertificateErrors = false,
Headers = new Dictionary<string, string> {{ "Pragma", "no-cache" }, { "Cache-Control", "no-cache" }}
};
... or use the alternative constructor to pass your own TcpClient for more control of the configuration and the management of your TCP socket connection.
MessageWebSocketRx(TcpClient tcpClient)
Note: If the TcpClient is not connected the library will connect it. Also, the TcpClient will not be disposed automatically when passed in using the constructor, as it will in the case when no TcpClient is supplied.
To connect client to WebSocket server
To connect and observe websocket connection use WebsocketConnectionObservable
:
var websocketConnectionObservable =
client.WebsocketConnectObservable(
new Uri(WebsocketTestServerUrl)
);
... or use WebsocketConnectionWithStatusObservable
to also observe connection status :
var websocketConnectionWithStatusObservable =
client.WebsocketConnectWithStatusObservable(
new Uri(WebsocketTestServerUrl)
);
To control TLS/SSL certificate validation behavior
To control TLS/SSL Server certificate behavior, either use the IgnoreServerCertificateErrors
parameter to ignore any issues with the certificate or override the ValidateServerCertificate
method to your liking.
The existing virtual method implementation looks like this:
public virtual bool ValidateServerCertificate(
object senderObject,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors tlsPolicyErrors)
{
if (IgnoreServerCertificateErrors) return true;
return tlsPolicyErrors switch
{
SslPolicyErrors.None => true,
SslPolicyErrors.RemoteCertificateChainErrors =>
throw new Exception($"SSL/TLS error: {SslPolicyErrors.RemoteCertificateChainErrors}"),
SslPolicyErrors.RemoteCertificateNameMismatch =>
throw new Exception($"SSL/TLS error: {SslPolicyErrors.RemoteCertificateNameMismatch}"),
SslPolicyErrors.RemoteCertificateNotAvailable =>
throw new Exception($"SSL/TLS error: {SslPolicyErrors.RemoteCertificateNotAvailable}"),
_ => throw new ArgumentOutOfRangeException(nameof(tlsPolicyErrors), tlsPolicyErrors, null),
};
}
Working With Slack (And maybe also other WebSocket server implementations)
The RFC 6455 section defining how ping/pong works seems to be ambiguous on the question whether or not a pong must include the byte defining the length of data-frame, in the special case when there is no data and the length of the data is zero.
When testing against for instance the Postman WebSocket test server Postman WebSocket Server the data-frame byte is expected and should have the value 0 (zero), when there's no data in the data-frame.
However, when used with the slack.rtm API the byte should not be there at all in the case of no data in the data-frame, and if it is, the slack WebSocket server will disconnect.
To manage this length byte-issue the following property can be set to true
, in which case the byte with the zero value will NOT be added to the pong. For instance like this:
var websocketClient = new MessageWebSocketRx
{
ExcludeZeroApplicationDataInPong = true
}
To further complicate matters the slack.rtm api seems to require a ping at the Slack application layer too.
A simplified implementation of this could look like this, which obviously would need to be repeated in some interval to keep the slack connection going:
await _webSocket.SendText("{\"id\": 1234, // ID, see \"sending messages\" above\"type\": \"ping\",...}");
For details read the Ping and Pong section of the slack.rtm API documentation
Working with socket.io
This library has also been tested with socket.io.
A typical connection will look like this:
var websocketConnectionObservable =
client.WebsocketConnectWithStatusObservable(
new Uri($"http://{url}:{port}/socket.io/?EIO=4&transport=websocket"));
This will connect on the WebSocket layer with socket.io server.
To further connect on socket.io level see documentation. For instance, typically a text message with the content 40
needs to be sent right after the connection have been established. Also, some socket.io server implementations seem to be very sensitive to the encoding of the messages that are being send, and will disconnect immediately if receiving a data-frame with a text message that does not comply with the expected socket.io encoding protocol.
For more see here: WebSocket client not connecting to the socket.io server.
References:
The following documentation was utilized when writing this library:
- RFC 6544
- Writing WebSocket Servers
- Writing WebSocket Server in C#
- Writing WebSocket client applications
Thank you !
Thank you to all the developers who've been using this library through the years, many of which that have reported issues or bugs, or made contributions and pull requests to make the library better and/or more capable. It is this interaction with all of you that makes sharing and learning fun.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- HttpMachine.PCL (>= 4.0.3)
- IWebsocketClientLite (>= 7.3.0)
- Microsoft.Bcl.AsyncInterfaces (>= 6.0.0)
- System.Memory (>= 4.5.5)
- System.Reactive (>= 5.0.0)
-
.NETStandard 2.1
- HttpMachine.PCL (>= 4.0.3)
- IWebsocketClientLite (>= 7.3.0)
- System.Reactive (>= 5.0.0)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on WebsocketClientLite.PCL:
Package | Downloads |
---|---|
CryptoExchangeClient
Clients for multiple cryptocurrency exchanges. All clients have a shared interface for common actions. |
|
SlackConnector_Demo
Demo version of SlackConnector initiates an open connection between you and the Slack api servers. SlackConnector uses web-sockets to allow real-time messages to be received and handled within your application. |
|
PureWebSockets_WebsocketLite
A cross platform WebSocket client library for .NET NetStandard core (backed by WebsocketClientLite). |
|
WebRTCme.Middleware
WebRTC middleware for .NET MAUI and Blazor applications. |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on WebsocketClientLite.PCL:
Repository | Stars |
---|---|
melihercan/WebRTCme
A cross-platform framework for adding WebRTC support to .NET MAUI, Blazor, and Desktop applications by using a single unified .NET/C# API.
|
Version | Downloads | Last updated |
---|---|---|
7.3.2 | 1,316 | 1/5/2023 |
7.3.0 | 1,134 | 5/28/2022 |
7.2.2 | 1,027 | 4/24/2022 |
7.2.1 | 966 | 4/24/2022 |
7.1.1 | 933 | 4/22/2022 |
7.1.0 | 917 | 4/21/2022 |
7.0.7 | 939 | 4/20/2022 |
7.0.6 | 1,362 | 4/18/2022 |
7.0.5 | 923 | 4/18/2022 |
7.0.4 | 944 | 4/18/2022 |
6.4.0 | 1,411 | 3/20/2022 |
6.3.0 | 2,189 | 9/25/2021 |
6.2.0 | 20,321 | 10/27/2018 |
6.1.1 | 9,288 | 9/9/2018 |
6.1.0 | 1,311 | 9/7/2018 |
6.0.0 | 1,338 | 9/3/2018 |
5.1.1 | 1,496 | 8/24/2018 |
5.0.0 | 25,916 | 6/2/2018 |
4.2.5 | 3,138 | 4/8/2018 |
4.2.5-beta1 | 1,459 | 4/7/2018 |
4.2.3 | 1,929 | 3/23/2018 |
4.2.1 | 1,837 | 2/15/2018 |
4.2.0 | 1,502 | 2/11/2018 |
4.1.4 | 1,696 | 2/1/2018 |
4.1.2 | 1,756 | 10/23/2017 |
4.1.1 | 13,089 | 9/22/2017 |
4.0.6 | 9,271 | 5/13/2017 |
3.7.8 | 1,548 | 4/17/2017 |
3.7.4 | 1,523 | 4/17/2017 |
3.7.3 | 1,521 | 4/15/2017 |
3.7.0 | 1,604 | 3/12/2017 |
3.6.8 | 1,582 | 3/2/2017 |
3.6.6 | 1,713 | 2/14/2017 |
3.6.2 | 1,682 | 12/10/2016 |
3.6.0 | 1,786 | 11/24/2016 |
2.0.11 | 1,667 | 11/6/2016 |
1.6.2 | 1,699 | 10/15/2016 |
1.5.2 | 1,735 | 6/29/2016 |
Removed PCL in assembly name.
New feature: hasTransferTcpSocketLifeCycleOwnership.