Friday, 14 October 2011

Getting to know System.Net.WebSockets: A simple ASP.NET echo server

The WebSockets offering for .NET 4.5 consists of several APIs that vary in granularity and purpose. The new System.Net.WebSockets namespace contains a set of types that are used regardless of whether you are hosting your WebSocket server in ASP.NET or if you are using the low level HttpListener class (WCF uses HttpListener when it needs to handle HTTP traffic in self-hosted mode). The goal of this set of types is to define a shared low-level WebSockets API that ASP.NET, WCF and .NET developers can build on top of.

System.Net.WebSockets is not to be confused with the new WinRT WebSocket APIs found in Windows.Networking.Sockets. The WinRT APIs provide client functionality only while the the System.Net.WebSockets types are designed for server side use.

The easiest way to get to know this new API is to look at a simple example. I’ve implemented a very basic WebSocket echo server in ASP.NET that demonstrates how to accept a WebSocket connection in ASP.NET, obtain an instance of System.Net.WebSockets.WebSocket and then begin send and receive operations using the methods on this type. Keep in mind that we do not expect most developers to use these low level APIs for every day applications – this is what our Microsoft.WebSockets NuGet package is for. Future posts will cover this package in more detail.

I’ve annotated the source code for this echo server and made it available in HTML format. Please check it out! Do you like samples presented in this style? Let me know in the comments.

If you want to download and run this example, it’s called AspNetWebSocketEcho and is part of my WebSocket Samples project on github. You will need to use the Windows 8 developer preview if you want to try this stuff out. See my earlier post for instructions on how to set up your development environment.

32 comments:

  1. great example! was looking for this info. thanks! Rick

    ReplyDelete
  2. The very bad thing with .NET 4.5 WebSocket feature is the requirement of IIS 8.0 which is you can't install it on previous Server 2008 R2 etc systems.

    ReplyDelete
  3. @^: Try Socket.io, a library for NodeJS. NodeJS supports any modern version of Windows, and Unix/Linux as well. I believe it is possible to install it into IIS 7 :)

    ReplyDelete
  4. Yes you can use socket.io with IIS 7 via iisnode, but WebSockets won't work in this case. You can use socket.io and node on Windows without running in IIS (without iisnode) and then WebSockets will work.

    Another alternative is to use SignalR (https://github.com/SignalR/SignalR). This means you can continue using ASP.NET and IIS. Once you then deploy your SignalR based app on a IIS 8.0 machine, WebSockets will become available. In the meantime, SignalR can use long polling, forever frames, server sent events, etc.

    ReplyDelete
  5. can i use System.Net.websocket as a server talking to a node js based client with socket.io ?

    ReplyDelete
  6. You would have to do additional work to allow socket.io to talk to your .NET websocket server because socket.io layers on top of various transports (including WebSockets) and defines its own protocol (https://github.com/LearnBoost/socket.io-spec).

    If you instead used a pure WebSocket node client such as 'ws' (https://github.com/einaros/ws) then this would work.

    ReplyDelete
  7. Thank you for the information, Paul.

    One thing that is very disappointing in how .NET websockets are implemented is that HttpContext.AcceptWebSocketRequest() method is IIS7-specific and expects HttpWorkerRequest to be of IIS7WorkerRequest type, which makes it impossible for other HttpListener-based web server vendors to expose the same functionality without supplying proprietary APIs to access HttpListenerRequest which has all the websocket goodies in it. Microsoft should have added new members to HttpWorkerRequest to get access to websockets, and then in turn they should have implemented HttpContext.AcceptWebSocketRequest() so that it would rely on these new standard HttpWorkerRequest members instead of the non-public IIS7WorkerRequest.

    ReplyDelete
  8. If you want to use websockets on HttpListener, why not use it directly? Why bother with the ASP.NET types (HttpContext) at all?

    Here's the HttpListener equivalent of the above sample:
    http://paulbatum.github.com/WebSocket-Samples/HttpListenerWebSocketEcho/

    ReplyDelete
    Replies
    1. Thanks! Most of the examples I've found at IIS-specific. This link was very helpful!

      Delete
  9. Paul,

    I went through your samples first time around and they were very helpful.

    The reason for that is we make http.sys-based web server for ASP.NET applications (http://ultidev.com/products/UWS/), and we simply need to expose WebSockets access to ASP.NET applications in the same way as IIS does.

    However, ASP.NET team chose perplexing way of getting to WebSockets - instead of expanding the long-standing interface between ASP.NET and a web server, the HttpWorkerRequest class, ASP.NET team uses IIS7WorkerRequest.

    It's been impossible to make Microsoft aware that there life on ASP.NET planet besides IIS, despite us having almost a million installations of our web server. We were unable to get onto WebPI despite being the only redistributable ASP.NET web server, got cold shoulder from WCF team when we found IIS dependencies there, and now WebSockets...

    ReplyDelete
  10. Hi,

    I have windows 8 & .net4.5 installed in the web server.
    im trying to achieve pushing system in the website.
    looked into html5 websocket, which is not compatibly with lower version of browsers, so from client side, need to use socket.io/nodejs or SignalR, those js lib to enable the client to use websocket.
    I get a bit confused, if i use Signal R or socket.io in the client side. what's the option for server side ? does the choice I made for client side effect what to use on server side ?

    and I still not sure what exactly the code should look like in the server side.
    if from server side, it's a aspx page, then what is the link, called by client looks like ?

    Regards,
    Coco

    ReplyDelete
  11. Ideally , for me, the server side should be implemented in a windows service. and in client side, should be compatibly with IE 7+.

    so what should I use ? SignalR on server & client side ?

    ReplyDelete
  12. Hi Coco,

    It sounds like SignalR or socket.io would be a good choice for your scenario. The important thing to note is that SignalR and socket.io are not just client side technologies - they both have client and server side components. SignalR has a .NET based server component while socket.io runs on node.js.

    If you are comfortable developing for .NET, I suggest you look at SignalR. If you would prefer to work with JavaScript as your server side programming language then you should look at using socket.io. There are other options too, but I think these are worthwhile starting points.

    Scott Hanselman has a good introductory post on SignalR here:
    http://www.hanselman.com/blog/AsynchronousScalableWebApplicationsWithRealtimePersistentLongrunningConnectionsWithSignalR.aspx

    ReplyDelete
  13. Hi Coco,

    To answer your second post, yes I would start with SignalR (on both client and server). This page here has some information about selfhosting SignalR and this would be applicable to running in a Windows Service:
    https://github.com/SignalR/SignalR/wiki/Self-host

    The SignalR room on Jabbr is a great way to connect with other SignalR users. You should try that here:
    http://jabbr.net/#/rooms/signalr

    ReplyDelete
  14. Paul
    I have lots of machine that are running .net 4.0 and won't upgrade for some time, question: what libraries do you recommend for windows sockets client / server?
    thanks.

    ReplyDelete
  15. Hi Tamer,

    It really depends on your scenario. If you are talking about LOB desktop applications it might be simpler to just use WCF. If you're talking about web applications then I would look at SignalR.

    Paul

    ReplyDelete
  16. It is possible to create a websocket server without having to use some http listener (either IIS on asp.net or HttpListener outside iis)? So, simply connecting to the ws:// instead of upgrading an http connection.

    ReplyDelete
  17. The WebSocket protocol is designed around a HTTP upgrade mechanism, so it makes sense for it to be implemented on top of a webserver. If you take a look at a standalone WebSocket server (such as Fleck - https://github.com/statianzo/Fleck), it will still have some code to do the HTTP based handshake for establishing a WebSocket connection, but it won't serve normal HTTP requests. This is as close as you can get.

    ReplyDelete
  18. I have been trying for a while to get a C# websocket server running in Azure... as far as I understand this should now be possible (because Azure provides Windows Server 2012). However, I have a hard time getting it to work. Are there any samples for this scenario?

    I am using a worker role that runs the server coder from your sample, and it seems to start o.k. in Azure. Unfortunately, when I connect from a client, it appears that the request is not recognized as a websocket request (the listenerContext.Request.IsWebSocketRequest returns false). Am I missing some configuration?

    ReplyDelete
  19. Hi Sebastian,

    Have you made sure that your .cscfg is specifying osFamily="3" ? This is necessary to ensure that Windows Server 2012 is used.

    Paul

    ReplyDelete
  20. Yes. I now got this to work, after a bit more tinkering:

    - using a web role instead of a worker role. I used a WCF web role template, ignored the service it specifies, and just start my own http listener, exactly as in your sample
    - adding "" to ServiceDefinition.csdef
    - not using port 80... for some reason, the problem described above (websocket requests are not recognized as such, but appear like normal http requests) still happens when I use port 80.

    So it's not perfect yet since I would like to use port 80 but at least it runs.

    ReplyDelete
  21. I think the reason your above approach did not work on port 80 is that IIS has got control over port 80 (you picked web role). In this configuration, you could use the ASP.NET support for WebSockets instead of http listener (see my other sample) and that would work on port 80 (you will have to enable the WebSocket module in your IIS configuration).

    Given that you want to use http listener, worker role would be best. Assuming you have the os family set correctly, you have an input endpoint setup in your role config, and you are using an up to date websocket client, I am struggling to think what else could be missing.

    ReplyDelete
  22. Thanks Paul!

    I agree it may work if I try a worker role one more time. However: it appears that websockets on port 80 get blocked quite often for a number of reasons beyond my control, like firewalls (https://github.com/LearnBoost/socket.io/wiki/Socket.IO-and-firewall-software) so I will stick with port 843 which seems to work just fine.

    ReplyDelete
  23. Yes, WebSocket connectivity on port 80 isn't particularly good. In practice I would recommend that you run the WebSocket traffic over SSL (and use default port of 443) because it makes a huge improvement to the connectivity success rate - the connection just looks like a standard SSL connection, and the intermediary can't tell that you're running WebSockets over it.

    ReplyDelete
  24. Thanks Paul,

    I want to know in System.Net.WebSockets(.net 4.5) whether websocket client supports passing authentication header during handshaking.

    regards,
    shiva

    ReplyDelete
  25. Yes, you would do this using a HTTP header, which can be set using:
    http://msdn.microsoft.com/en-us/library/system.net.websockets.clientwebsocketoptions.setrequestheader.aspx

    ReplyDelete
  26. Paul,
    Thanks for the post.

    System.Net.Websockets provides a WebSocket Server funcctionality for a .NET application.

    However, in a WINRT environment, I didn't see anything that will allow me to create a web sockcte server. In WINRT environment, we just have a Windows.Networking namespace which provides "WebSocket CLient" functionality.

    DO u know if WINRT has any websocket server capability?

    If not, how can we use System.Net.WebSockets namespace and implement a websocket server and bring that to a winrt environment (any hack?).

    Thanks

    ReplyDelete
  27. Unfortunately, I am not sure how you would bring websocket server capabilities to WinRT. You wouldn't be able to reuse the .NET 4.5 implementation because it requires either HttpListener or ASP.NET, neither of which are part of WinRT. If you were going to try to hack it together, I think the best way would be to take an open source .NET websocket implementation (there are a few out there), and modify it to use the WinRT socket API. I am not sure how feasible this is but that is what I would try.

    ReplyDelete
  28. Hello Paul,

    I got your email address from your blog i am trying to develop webrtc video chat conference in traditional asp.net
    so i have took help form this link

    http://www.codeproject.com/Articles/618032/Using-WebSocket-in-NET-4-5-Part-2

    But it gives me error some random error in my console( do not know what to do with it i already installed websocket in my IIS 8.0.

    Please help to over come this problem

    WebSocket connection to 'ws://localhost/DemoRtc/WSHandler.ashx' failed: Error during WebSocket handshake: Unexpected response code: 500

    ReplyDelete
  29. Hi Vivek,

    I'm not familiar with the code project you linked to. If you'd like to get started with websockets I suggest you try out my samples:
    https://github.com/paulbatum/WebSocket-Samples

    ReplyDelete
  30. Hi Paul,
    I have seen your video and downloaded the BasicAppNetChat application. I ran the code the way it is instructed in video. But in the chrome, I am getting an error as;
    error during WebSocket handshake: Unexpected response code: 200

    Am I missing anything ?

    ReplyDelete
  31. I think you might be using an older sample, try the ones here: https://github.com/paulbatum/WebSocket-Samples

    ReplyDelete