Skip to main content

SignalR not connecting? Things to check


SignalR is a websocket library for .NET. During setup and local development there are a number of issues I have encountered. In this post I’ll explain how to fix these.

I will assume you are using ASP.NET core, version 2.2 or later. And your client is just plain old vanilla JavaScript.

Obviously your first step should be reproducing your issue with new empty projects, where you can be sure nothing else is interfering. Beyond that, here are a few tips:

Client Scripts Updated

To use SignalR in JavaScript you should be using the official client-side library from Microsoft. This is usually a single file called signalr.js or signalr.min.js (the minified version). You can find basic HTML/JS example use here to check you are using it correctly.

If you have got the client scripts from a non-official source, or there is a chance they might be out-of-date, make sure you replace them with the latest version. You can get hold of the latest version of the scripts using Visual Studio or using a use a CDN, as explained in Microsoft's official documentation.

HTTPS client with HTTP server - ‘Mixed Content’ Error

My first mistake was accessing my client web app using ‘https’ and the SignalR server on ‘http’. Web browsers will not like sending an unencrypted ‘http’ request when visiting a ‘https’ page. For web browsers the ‘s’ in the URL is supposed to give the impression of security, so it expects all the linked content, including JavaScript web requests to be retrievable over secure TLS connections.

If you do this, your web brower should tell you something about the site not being secure. And it will likely block all of these requests, like those trying to establish a SignalR connection.

This is generally referred to as HTTPS mixed content.

The fix is simple. Either downgrade your website to use http, or a much better idea - upgrade your server to use https.

Set the correct URLs

This may seem obvious but you have to be very careful. Make sure your script has the correct URL of the SignalR server assigned.
Pay particular attention to whether it is ‘http’ or ‘https’, the path is the same as the route of the Hub in your ASP.NET Core app.

If you are using localhost, make sure you assign the correct port! You’re project settings of your ASP.NET core app will show this. I recommend using http when tesing locally, as development SSL certificates can be a nuisance.

It should look something like this:

var connection = new signalR.HubConnectionBuilder().withUrl("http://localhost:63205/myhub").build();

A Websever for your Website

Opening your website by literally opening a index.html file in your web browser is not a good idea. Most web browsers will block cross-origin requests when you do this, and normally log it as a CORS error.

If you are doing this, you’re address bar will display something like:

file:///C:/Users/.../index.html

To avoid this, you need to start a local webserver which will serve your files. Then access it using localhost or a local ip address such as 127.0.0.1 or something starting with 192 or 172. And you’ll usually have to provide a port number too like 8080.

http://127.0.0.1:8080/

How do you do this? My prefered method is to use node.js which you can install here. Then open a terminal and use the following command to install the http-server package:

npm install --global http-server

And from there it is simple. Every time your want to start a webserver, open a terminal to the directory containing your index.html, javascript files and whatever else. Simply type http-server. Then it will give you the address such as 127.0.0.1:8080 which you can open in a web browser to access your website.

Now take note of the address serving your website, you’ll need it to configure CORS correctly …

CORS

CORS can be a nightmare for web developers testing their work locally. But, it is a necessary evil.

You can check for errors these using the F12 developer tools in your web browser. Any red error message in the console which mentions CORS, means you haven’t configured it correctly. But first to explain what it is …

Suppose you are on example.com and the website wants to fetch something from another domain like jam-es.com. If that was allowed, anyone who visits example.com will be pinging jam-es.com. If example.com is your site, and it’s quite popular, you could easily get your visitors machines to flood jam-es.com with requests and perform a DDoS attack. For this reason, web browsers block visitors of one domain (example.com) from sending requests to another domain (jam-es.com), unless jam-es.com explicitly says it allows requests from visitors of example.com.

This is the exact scenaro you may have. You are visiting your web app on one domain example.com but it is trying to send requests to a different domain, the domain of your SignalR server jam-es.com (or even just a different subdomain like signalr.example.com). Those requests will be blocked unless you configure CORS correctly by ensuring OPTIONS requests to jam-es.com return a certain HTTP response header.

This header has the name Access-Control-Allow-Origin and it must be returned by your SignalR server. This only applies when your client sends requests with an Origin header (to tell the server which domain the visitor making the request is coming from), which all web browsers include by default (and it is hard to disable).

The Access-Control-Allow-Origin header may return 3 different values. Either the wildcard * to allow all domains, or null (which you should never use), or it should be set to the domain the vistor’s is making the request from like example.com.

Note: With SignalR you cannot use *, because SignalR requires the use of credentials, and requests using * with credentials will all be blocked by your web browser too 🙄.

Therefore, we need to change our ASP.NET Core SignalR server to return this header with the value set to the domain the requests are coming from. If you are testing locally and read the previous section this will be a local IP address with a port like 127.0.0.1:8080, otherwise it is the domain of your website example.com.

Within Startup.cs inside ConfigureServices add the following line:

services.AddCors();

And within Configure add:

app.UseCors(builder =>
{
    builder.WithOrigins("http://127.0.0.1:8080", "https://example.com")
        .AllowAnyHeader()
        .WithMethods("GET", "POST")
        .AllowCredentials();
});

Notice here, we’ve provided two allowed origins, one which we can use for development, and the other for production. But the method will accept as many as you like, or even just one. Make sure you include the ‘http’ or ‘https’ correctly.

Now build and run your webserver, and hopefully you will not get any more issues with CORS … but you might …

Deployment issues … CORS again?

By this point, you should be able to get things working locally. But you might still have issues when deployed to your site example.com (when using it as an origin above).

You’re going to have to go through all the settings on your server or cloud dashboard, until you find what is set wrong.

For example, if using a server or cloud VM, make sure your firewall is open to all sources on ports 80 and 443.

For the Azure Web App users, I recommend you check this first. Navigate to your web app (App Service resource) in the Azure Portal and look for the section called ‘CORS’ in the left-hand menu. If enabled this will enable CORS at an App Service level and override everything you set in the set above … and break your SignalR connections. So make sure this is DISABLED, i.e. remove anything from the ‘Allowed Origins’ list, especially remove the wildcard * if it appears.

Hopefully all your issues are fixed now … or at least those relating to SignalR conenctions 🙂

Comments

Popular posts from this blog

Terminals in Sublime Text 3

If you need a quick answer on how to create terminals in Sublime Text 3, watch the following video, or read the instructions below it. How to set up Terminals in Sublime Text 3 Open Sublime Text. Open the Command Palette with Crtl+Shift+P Type  'Package Control: Install Package' until the option appears and select it [You'll need to install package control if you are using it for the first time] Type 'Terminus' and select it. Now the package Terminus will install. Wait for this to complete. Then restart Sublime Text. Next we will add Commands to the Command Palette. So you can open terminals using Crtl+Shift+P then typing a command. To do this open the Command Palette (Ctrl+Shift+P) and type 'Terminus: Command Palette' and open it. You'll be greeted by a split view. Basically there are settings defined in the code on the left panel and you can override them or add your own by typing code in the right panel. Copy ...

Generating a MSI Installer for a WPF Application

This post serves as a tutorial for creating a MSI installer for your WPF Applications in Visual Studio. For this we use WiX (recommended by Microsoft). Prerequisites I assume you already have a Visual Studio solution containing a WPF Project. And I assume you have some experience with Visual Studio and XML. You do not need any prior knowledge of WiX. Step 1: Install Wix We are going to need WiX to generate our MSI. If you don't already have Wix installed, go ahead and download it from here . You'll be redirected to the relevant GitHub releases page where you can download the .exe file to install WiX.

Fill your GitHub activity heatmap with the image of your choice

Taking 12 months to upload a 52x7 pixel image, through thousands of git commits, ... that's completely reasonable right?