5

Someone is building a native chat app for us, and Websockets seem to be the way to go for synchronicity between the app and our server (which uses Web API).

We looked into SignalR, but it seems to require jQuery and thus will be cumbersome in a native app.

Is there a "pure" and simple way to use Websockets in C# that is scalable? By "easy" I mean as easy as getting started with Web API for example (I've seen examples where you have to create a TCP listener and comply with latest RFC specifications et.c. - not simple in my opinion), and by "scalable" I mean not blocking threads.

Edit: question title renamed to amplify the importance of the implementation of the websocket server

Scarabas
  • 103
  • 1
  • 1
  • 7
  • "I've seen examples where you have to create a TCP listener and comply with latest RFC specifications et.c. - not simple in my opinion" - there are libraries that do this for you, though. Web-socket support is now backed into the main .NET web APIs, and would be the "simplest" approach, but it really depends on how high it needs to scale, and how often you deploy (if you run the web-sockets inside the main web-server, then you will tear down all the connections whenever you deploy, or whenever the app-pool recycles) – Marc Gravell Apr 20 '18 at 09:36
  • if "someone" is building a native chat app for you - leave them to it, none of this would be relevant as that someones not you – BugFinder Apr 20 '18 at 09:38
  • 2
    `We looked into SignalR, but it seems to require jQuery` this is incorrect – TheGeneral Apr 20 '18 at 09:38
  • 1
    Why do you think SignalR will be cumbersome in a native app? I've used it with mobile apps (Xamarin), MVC and WinForms and it's incredibly easy to integrate. – Frauke Apr 20 '18 at 09:39
  • @MarcGravell how is this integrated into Web API? I can't find any examples? – Scarabas Apr 20 '18 at 09:44
  • @TheGeneral - I can't seem to find any examples of SignalR usage without jQuery or any "not traditional" approaches from the client. Do yo have any? Ideally, the client just needs to use the websocket protocol and not have to deal with the fact that we chose SignalR. – Scarabas Apr 20 '18 at 09:47
  • 1
    @Scarabas there is plenty of documentation, https://stackoverflow.com/questions/11140164/signalr-console-app-example or https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-net-client – TheGeneral Apr 20 '18 at 09:49
  • 1
    You could have a simple signalR chat app up and running in minutes. its fairly scalable but its also limited in certain ways. It really does depend how many people are using this, and what for. you could also have a simple wcf duplex and reliable messaging system set up quickly too. however if you want to create the next skype or flock, then you need to start nailing down your requirements and domain and doing a lot of research – TheGeneral Apr 20 '18 at 09:52
  • @TheGeneral It's about 10k users who are sending a message every 1½ minute, so it's by no means Skype. I'll look at SignalR again - this doc seems relevant (found it thanks to you - I found it hard to find the right doc for my purpose): https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server If you write an answer I'll mark it – Scarabas Apr 20 '18 at 10:01

2 Answers2

5

SignalR is great for cases where:

1) You need a fallback in case websockets aren't available

AND

2) You have control over the implementation of the client (there's a specific protocol that has to be followed by the client)

The easiest way I can think of, from what you tell us about the project (limited control of the implementation of the client, websocket server implementation only, Web API) is Microsoft.WebSockets.

You can install Microsoft.WebSockets from NuGet and be up and running with a websocket server in minutes. There a few tutorials out there (ex.: https://dejanstojanovic.net/aspnet/2014/june/database-change-notifications-in-aspnet-using-websocket/), but essentially:

1) make sure your IIS has websockets enabled

2) create a Web API controller that handles websocket requests. Ex.:

using System;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using Microsoft.Web.WebSockets;

public class SomeController : ApiController
{
    // Has to be called something starting with "Get"
    public HttpResponseMessage Get()
    {
        HttpContext.Current.AcceptWebSocketRequest(new SomeWebSocketHandler());
        return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);
    }

    class SomeWebSocketHandler : WebSocketHandler
    {
        public SomeWebSocketHandler() { SetupNotifier(); }
        protected void SetupNotifier()
        {
            // Call a method to handle whichever change you want to broadcast
            var messageToBroadcast = "Hello world";
            broadcast(messageToBroadcast);
        }

        private static WebSocketCollection _someClients = new WebSocketCollection();

        public override void OnOpen()
        {
            _someClients.Add(this);
        }

        public override void OnMessage(string message)
        {

        }

        private void broadcast(string message)
        {
            _someClients.Broadcast(msg);
            SetupNotifier();
        }
    }

}

The SetupNotifier() method should contain logic that catches the change you want to react upon. broadcast(string message) (can be renamed of course) contains the logic that "returns" data to the client(s) - this example sends the same message to all clients.

Make sure to test this with a proper websocket client (there are Chrome extenstions for this, if you want the ease of use) - you can't do ws:// requests in a browser as-is.

The_Torst
  • 401
  • 3
  • 10
  • Works like a charm, and it took two minutes! Perfect! I found it hard to find Microsoft.WebSockets from all the SignalR mentions and tutorials. I guess my case is an odd one. – Scarabas Apr 25 '18 at 08:12
3

This is not fully addressing your question, however

We looked into SignalR, but it seems to require jQuery and thus will be cumbersome in a native app

This is not correct, it actually supports self hosted and clients of various platforms

Someone is building a native chat app for us, and Websockets seem to be the way to go for synchronicity between the app and our server (which uses Web API).

SignalR and WebSocket

SignalR uses the new WebSocket transport where available, and falls back to older transports where necessary. While you could certainly write your application using WebSocket directly, using SignalR means that a lot of the extra functionality you would need to implement will already have been done for you. Most importantly, this means that you can code your application to take advantage of WebSocket without having to worry about creating a separate code path for older clients. SignalR also shields you from having to worry about updates to WebSocket, since SignalR will continue to be updated to support changes in the underlying transport, providing your application a consistent interface across versions of WebSocket.

Though just as a last thought, SignalR is not the saviour of humanity, however it is very light and robust, and suited for what it is. Though, you have mentioned you want to have a chat setup targeting 10000 uses. You should probably weigh up all the options first, including third party solutions and also traditional services like WCF.

Further Reading

SignalR Console app example

ASP.NET SignalR Hubs API Guide - .NET Client (C#)

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • I've been through the docs and many examples, but I still can't find examples of how to use SignalR as a pure websocket server, which works with clients that don't know SignalR. Can you guide me in the right direction? – Scarabas Apr 23 '18 at 08:44
  • @Scarabas you cant just use it as a websocket. the clients need to talk signalR, however there are C# java and javscript examples as clients – TheGeneral Apr 23 '18 at 11:17
  • 2
    This means that my comment "the client just needs to use the websocket protocol and not have to deal with the fact that we chose SignalR" invalidates SignalR for this purpose, and we're back to using somehting else - hence the question remains. – Scarabas Apr 23 '18 at 12:28