Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
Mono organizations on
GitHub to continue tracking issues. Bugzilla will remain
available for reference in read-only mode. We will continue to work
on open Bugzilla bugs, copy them to the new locations
as needed for follow-up, and add the new items under Related
Our sincere thanks to everyone who has contributed on this bug
tracker over the years. Thanks also for your understanding as we
make these adjustments and improvements for the future.
Please create a new report on
GitHub or Developer Community with
your current version information, steps to reproduce, and relevant error
messages or log files if you are hitting an issue that looks similar to
this resolved bug and you do not yet see a matching new report.
After attempting to use the ClientWebSocket class on iOS/Android I was stumbled with so many issues that I ended up needing to re-write the class myself to fix the issues, and just use reflection hacks to access the internal stuff of HttpWebRequest and WebConnection classes.
I'm referring to these classes:
Here are the issues I faced:
- ClientWebSocket.ReceiveAsync and ClientWebSocket.SendAsync both use Task.Run to call synchronous methods on WebConnection when WebConnection offers async (Begin/End) methods that would do the job just fine. This causes unnecessary spinning up of Threadpool threads instead of using IO completion routines.
- WebConnection.BeginRead sometimes returns an instance of IAsyncResult who's concrete type is WebAsyncResult, depending on if chunking reads are enabled, but WebConnection.EndRead assumes WebAsyncResult is always passed in. This causes InvalidCastException's when calling EndRead when chunked reads are not enabled.
- ClientWebSocket.ReceiveAsync uses WebConnection.Read to get input which goes via the NetworkStream / SslStream inside WebConnection, but ClientWebSocket.SendAsync directly uses the raw Socket from WebConnection. This means that if SSL/TLS is enabled on the socket (e.g. for all wss:// connections) then writing raw unencrypted data to the socket will break the connection.
- ClientWebSocket.ReceiveAsync doesn't handle the "Ping" and "Pong" op-codes, and instead maps them to a "Close" message type resulting in the connection being disconnected. Since both "Ping" and "Pong" can be sent by the server unsolicited, the WebSocket connection will reliably drop whenever a keep alive Ping/Pong are sent by the server which is generally every 30 seconds or so.
I have no intention of writing any tests to assert these issues. They are too numerous and setting up a test project that hosts a secure websocket server isn't something I have time to do.
As I have worked around each of these issues already, this is more of a courtesy to the Mono team to take a serious look at just how broken this class is.
I would like to second this. I was filing a similar bug report when I found this one.
I am the developer of Websocket.Portable on Github / nuget and the Realtime.co websocket platfrom api for Xamarin. Currently the ClientWebSocket is sending close messages at incorrect times. Moreover, I have identical code running on standard dotnet which runs fine.
To replicate you should :
- Download Realtime.Xamarin
(Sorry my bug relates to chunking, and its easier to just test against a free hosted service)
- Acquire a realtime application key
-Add an application key here (free)
- Replace the Message with a call to BigChunk()
- Run the application (I debug on Droid)
When sending numerous large messages the WebSocketClient will issue a 'close frame' and end the websocket connection. This sucks.
I have identical code using non-mono (which works) here:
I third this!
I have just been porting the WebSocket transport for SignalR to Xamarin, and I'm almost there, but incoming messages just get chewed up. See the screenshot that I attached.
You can see that on multi-part messages, MessageType is set to "Closed" when it should be "Text", and the text content is dumped into the "CloseStatusDescription" field of the receive result! Argh!!
My code works perfectly on MS .net.
Created attachment 14958 [details]
Debug inspector showing incorrectly parsed incoming message
I've had some feedback from Xamarin. They have said that they're aware that the WebSocket implementation is broken - and is more of a 'proof of concept' than a 'full implementation'.
Personally I think proof of concept code should be provided as source only, and not distributed in the framework for us dev's to stumble painfully across... but there it is. Don't expect a fix any time soon as it doesn't appear to be a priority.
On the flip-side, I got my SignalR Websocket transport working using WebSocket-Sharp. Yay.
I can provide sample code that show 2 issues.
I also entered this info here (Xamarin Cross Platform form)
1) End Of Message not being handled correctly
2) Websocket Ping / Pong (Hearbeat) not being handled correctly
The sample code is here. 1 project is a simple WebSocket Android app and the other is a console WebSocket Server to demonstrate these two issues. Note to see issue #2 you must make sure to set the EndOfMessage flag to true.
This is blocking my Android app...I may have to try to use another library.
Oops, forgot to link my GitHub sample code for comment #5:
Should be fixed in master
"ClientWebSocket.ReceiveAsync uses WebConnection.Read to get input which goes via the NetworkStream / SslStream inside WebConnection, but ClientWebSocket.SendAsync directly uses the raw Socket from WebConnection. This means that if SSL/TLS is enabled on the socket (e.g. for all wss:// connections) then writing raw unencrypted data to the socket will break the connection."
this still representing for me on MonoAndroid 7.1 (mono 126.96.36.199, xamarin 188.8.131.521)
SSL Connection -> Connect -> SendAsync -> ReceiveAsync -/> Exception
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
at System.Net.WebConnection.Read (System.Net.HttpWebRequest request, System.Byte buffer, System.Int32 offset, System.Int32 size) [0x0002b] in <a547bd0d78184f26ab08d022f013c1e1>:0
at System.Net.WebSockets.ClientWebSocket+<>c__DisplayClass35_0.<ReceiveAsync>b__0 () [0x0016b] in <a547bd0d78184f26ab08d022f013c1e1>:0
at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in <3fd174ff54b146228c505f23cf75ce71>:0
at System.Threading.Tasks.Task.Execute () [0x00010] in <3fd174ff54b146228c505f23cf75ce71>:0
I ported the corefx implementation of ClientWebSocket and that's working fine. (tested on Android and desktop console)
Will mono adopt the corefx implementation in the future?
Mono is using CoreFX WebSocket's already
We seem to still be experiencing this issue in a Xamarin.iOS application. It has been pointed that it seems to be occurring at this specific line of code:
Additionally, the below is the error message we’re observing:
>ObjectDisposedExceptionCannot access a disposed object. Object name: 'System.Net.Sockets.Socket'.
>System.ObjectDisposedExceptionCannot access a disposed object. Object name: 'System.Net.Sockets.Socket'.
>System.Net.Sockets.Socket.Send(byte buffer, int offset, int size, SocketFlags socketFlags, ref SocketError errorCode)
>System.Net.Sockets.Socket.Send(byte buffer, int offset, int size, SocketFlags socketFlags)
>at IO.Ably.Transport.MsWebSocketConnection+<<StartSenderQueueConsumer>b__17_0>d.MoveNext () <0x1015def00 + 0x00267> in <c4e321e6fb8e41ab8e5d206c4e805416#dcddafa70bae31ffa9f620e4fc2a0a0b>:0
Visual Studio Enterprise 2017 for Mac
Version 7.0.1 (build 24)
Installation UUID: 5dd7b690-fda1-4097-af00-2c233739dd55
Mono 184.108.40.206 (2017-02/5077205) (64-bit)
GTK+ 2.24.23 (Raleigh theme)
Package version: 500010001
Apple Developer Tools
Xcode 8.3.2 (12175)
Version: 10.10.0.36 (Visual Studio Enterprise)
Build date: 2017-05-22 16:30:53-0400
Mac OS X 10.12.3
Darwin 16.4.0 Darwin Kernel Version 16.4.0
Thu Dec 22 22:53:21 PST 2016
This is different issue. Even if you can see WebSockets on the stack the issue look to be in Socket class. If you have a repro we can use to track this down, please fill a new bug report.