Learn how to deploy a React Native chat client against a SignalR hub on ASP.NET Core for Linux

Jonathan Zufi
The Startup
Published in
22 min readJun 24, 2020
Remember IE 6.0?

This screenshot is from a piece I published back in 2002 about improving the web experience by dealing with form data using XMLHTTPObject (a pattern later formally coined AJAX (Asynchronous JavaScript + XML) by Jesse James Garret in 2005). In the early 90’s I wrote a simple TCP socket client for a large supermarket chain to allow remote diagnostics into their POS terminals (remember the Winsock OCX for VB6?). I’ve always been interested in real time communication and this technology is now core to a user experience that we all expect regardless of the medium: desktop web browser, mobile app or even an IoT device — crisp, clear, real time feedback with the software we interact with.

Other examples: Dashboards that upgrade graphs/charts in real time, online gaming, and collaboration tools like Teams and Slack. Some more familiar examples include the animated chat bubbles in iMessage when someone else is typing, real time auction countdowns on eBay and real time stock prices on Robinhood.

Continuing on this journey of learning, I recently decided to dive into SignalR — a free and open source library for ASP.NET Core that simplifies embedding real-time communications into your apps. SignalR makes it quick and easy to enable your server code and client applications to provide the types of real time UX explained in the examples above. SignalR was created in 2011 by David Fowler and Damian Edwards who now play key roles in the direction and development of ASP.NET. It was released as part of ASP.NET in 2013 — at that time AJAX was the framework of choice for web developers and WebSockets was so new that many browsers didn’t support it. SignalR was designed to harmonize and better manage the myriad of these connection techniques such as polling, long polling and server-sent events. It solves these problems by providing a set of capabilities inside the ASP.NET stack via a set of powerful server- and client-side libraries. With it’s ease of use and comprehensive supporting developer tools (e.g. dedicated tracing tools, etc), ASP.NET developers quickly adopted SignalR and it’s now the de facto stack for real-time ASP.NET development.

Of course there are lots of alternative frameworks for real time bi-directional communication such as Firebase, Pusher, RabbitMQ, WebRTC, MQTT and others. I’ll leave it to you to research these and determine which one would ultimately suit your own use case.

The best way to learn is to build so I decided to leverage one of Microsoft’s sample SignalR applications to teach myself some new skills and see what new ideas might make themselves visible. In additional to my musings into hardware, I’ve also been dabbling in mobile frameworks such as Vue and React Native — so I thought it might be interesting to extend my experimentation with SignalR to a mobile app as well. If you’re interested in learning more about SignalR, Microsoft has fantastic resources to help you and you should definitely check out the Azure SignalR service — as always they provide rich examples and resources to get up and running.

In this walkthrough I’ll show you how to set up a simple chat app as a secure (HTTPS-based) SignalR hub running on ASP.NET Core for Linux. There are tons of chat samples for SignalR around the web but I wanted to pull together an end-to-end ‘story’ that could be a starter project for others to build something bigger. After that I’ll share a simple React Native client I wrote to communicate to the same hub. As a long time .NET fan, I also thought this would be a cool project to explore how ASP.NET Core works on Linux, learn more about Linux in general and of course improve my command line skills :) I learnt a ton during this process so I hope this helps or inspires others who are new/learning to build interesting applications that rely on real-time communications.

Step 1 — Create a Digital Ocean account

Azure is obviously a great place to host a SignalR chat app (they offer an extremely rich and powerful infrastructure for SignalR on Azure with a ton of samples) but for this exercise I went with DigitalOcean on the recommendation of a colleague. DigitalOcean offers highly configurable virtual servers called ‘droplets’ in 8 data center regions around the world. They offer tons of developer-friendly features wrapped in a simple, powerful portal. It’s also inexpensive — configurations start at $5 per month for a 1GB RAM, 1 vCPU instance with 25GB storage and 1TB traffic/month. Note that everything in this post from Step 3 onwards could easily be done on other cloud platforms like Azure, AWS, etc.

DigitalOcean actually has a great tutorial on setting up ASP.NET on their platform but I got tripped up quite a bit along the way — so hopefully my tweaks might help others who also might run into similar problems.

Head over to https://www.digitalocean.com and create an account and let’s create a new project. On the left nav bar click ‘+ New Project’

Create a new project in DigitalOcean

Now let’s create our instance, known as a ‘droplet’. From the top menu, select ‘Create’ then ‘Droplets’:

DigitalOcean is powerful but has a really simple UI. What’s not to love!

Let’s configure our droplet. I chose Ubuntu 18.04.3 (LTS) x64 with the Standard/Starter plan at $5/hour — that gives us a 1Gb single CPU instance with 25Gb disk and 1Tb transfer — that’s plenty for now. I’m based in Atlanta so I chose the New York data center and I left all the other options unchecked. I gave my droplet a hostname of ‘ubuntu-medium-signalrdemo’ but you can name it whatever you like.

You’ll also be given a couple of options for credentials: password or SSH key. I chose password — if you choose SSH Key just note that we’ll be creating a new user a little later so it might be easier to choose the ‘Password’ option for now.

Click ‘Create Droplet’ at the bottom of the page - this will take a few seconds and we’ll see our new droplet.

The new droplet you created appears pretty quickly in the DigitalOcean portal.

Make a note of our newly assigned IP address — we’ll need it to connect to our instance shortly. With our instance created we have a bunch of configuration to do before we can deploy an app. As I mentioned earlier, one of the goals of this exercise was to host a real domain name and make it secure (HTTPS). I purchased the domain name signalrdemo.com from my preferred registrar and so I’ll be referring to this domain throughout this tutorial so make sure you replace signalrdemo.com with your own domain name throughout the exercise.

On the left nav bar in our DigitalOcean dashboard, click ‘Networking’:

Create a new domain entry in DigitalOcean

Enter your domain name and click ‘Add Domain’. We’re taken straight to the domain configuration screen where we can now add our A records. An A Record connects a domain with the public IP address of a website. Let’s add two A records: ‘@’ (which will allow us to hit signalrdemo.com) and ‘www’ (www.signalrdemo.com) both with TTL values of 600. The TTL value determines the duration for which the server will cache these details.

We now have 5 entries in our DNS records list:

That’s it — the Ubuntu box is ready for configuration. Before start that process we need to configure our domain name at the registrar to point to our droplet.

Step 2 — Connect our domain to our droplet

My registrar of choice is Dotster. There are lots of domain registrars and they all have excellent tutorials on how to configure DNS records so this part will be short. I first added all three DigitalOcean nameservers:

I also added three ‘A’ records as follows:

That does it for our domain configuration. Now let’s log into our instance and start configuring it.

Step 3 — Log in to your new Ubuntu instance

To log into our new Linux instance, fire up your terminal of choice (I use Terminal on MacOS and the awesome app Termius on my iPad/iPhone) and log in using our assigned IP address from DigitalOcean. In this example it’s 68.182.98.72 but make sure you use the IP assigned to you:

# ssh root@68.183.98.72

NOTE: The root user is the administrative user in a Linux environment and has very broad privileges. If you plan on doing anything with your instance beyond experimenting here you should create a new, separate user with similar privileges. Being a Linux novice I decided to create a new user. Let’s call this user ‘signalr’.

# adduser signalr

Enter a password for the new user and select all the defaults.

Now let’s give the new user superuser privileges:

# usermod -aG sudo signalr

Logout of root (logout) and now SSH back in with our new signalr user.

# ssh signalr@68.183.98.72

Now let’s install Nginx.

Step 4 — Configure Nginx

Kestrel is the cross-platform web server that ships with for ASP.NET Core. Kestrel is the web server that’s included by default in ASP.NET Core project templates. Kestrel is great for serving dynamic content from an ASP.NET Core application as it provides better request-processing performance and was designed to make ASP.NET as fast as possible. However, Kestrel isn’t considered a full-featured web server because it can’t manage security and serve static files, which is why it is advisable to always run it behind a web server. We’re going to configure Nginx as a reverse proxy for our SignalR application. Nginx is one of Ubuntu’s default repositories so let’s install it using the apt packaging manager. First we tell apt to update itself with all recent packages. The first time you run a command with sudo you’ll be prompted for your password:

# sudo apt update

Now install the Nginx package:

# sudo apt install nginx

After installation is complete, let’s confirm Nginx is installed and running:

# sudo systemctl status nginx
Confirm Nginx is installed, active and running.

With the service running, let’s test it out by requesting a page from Nginx. Open up a browser and enter your server’s IP address in your browser’s address bar (you can get your IP address from your DigitalOcean dashboard) — for our example:

http://68.183.98.72       <-- change this to your own IP address

You should see the default Nginx landing page:

Nginx is running!

Our A records should have propagated by now so you should also be able to hit http://www.signalrdemo.com (try it with your own domain name).

If you’re not seeing this screen, go back and check your settings at your domain registrar and also the domain settings back in DigitalOcean. To learn more about how to manage your Nginx instance, visit the documentation at https://docs.nginx.com/nginx/admin-guide/ — there are also plenty of guides online.

Step 5 — Install .NET Core 3.1

Let’s kill the Nginx process for now by pressing CTRL-C. We’ll restart it later. Now that we know Nginx is working let’s use it to reverse proxy the built in ASP.NET Core web server we mentioned earlier — to do that we’ll need to install the .NET Core SDK (and runtime). If you’re interested in exploring this further there’s a super detailed tutorial on how to do that for Ubuntu over at Microsoft.

Let’s start by downloading the Microsoft .NET Core package for Ubuntu 18.04:

# wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb

Use dpkg with the -i flag to add the Microsoft package signing key to our list of trusted keys and add the package repository, then install it.

# sudo dpkg -i packages-microsoft-prod.deb

There are a couple of other packages we need to install:

# sudo add-apt-repository universe
# sudo apt install apt-transport-https

universe is a repository of community-maintained free and open-source software. apt-transport allows the use of repositories accessed via HTTPS. Now let’s make sure all our repositories are up to date with their newest versions and associated dependencies:

# sudo apt update

Now let’s install the .NET runtime. I’m opting for the latest version which is currently 3.1:

sudo apt install dotnet-sdk-3.1

We’re done installing .NET Core so let’s do some cleanup:

# rm packages-microsoft-prod.deb

Step 6 — Configure Nginx

I mentioned earlier that Nginx is going to reverse proxy our Kestrel instance so let’s set that up now. Create the directory for <yourdomain>.com using
the -p flag to create any necessary parent directories:

# sudo mkdir -p /var/www/signalrdemo.com

Next, assign ownership of the directory with the $USER environment variable and make sure the newly created folder that will house our web app has the right permissions:

# sudo chown -R $USER:$USER /var/www/signalrdemo.com
# sudo chmod -R 755 /var/www/signalrdemo.com

Now let’s create a sample index.html page using vi, nano or your favorite text editor:

# vi /var/www/signalrdemo.com/index.html

Inside, add the following sample HTML. If you’re new to vi, press i to start typing:

<html>
<body>
<h2>Welcome to signalrdemo.com</h2>
</body>
</html>

(Once again if you’re new to vi, save this snippet by pressing ESC then :wq to write/save the file). Before we can serve up this .html file, we need to create an Nginx server block. Just like virtual hosts in Apache or IIS, a server block encapsulates configuration details about how to host a domain. Nginx on Ubuntu 18.04 installs with one server block enabled by default that is configured to serve documents out of /var/www/html. We’re going to serve content out of the folder we just created by creating a new server block.

# sudo vi /etc/nginx/sites-available/signalrdemo.com

Paste in the following configuration block and remember to replace signalrdemo.com with your own domain name. You can learn more about server blocks at the Nginx documentation repo or over at DigitalOcean here):

Save this file. NOTE: You’ll notice the value for the proxy header ‘Connection’ is set to $http_connection instead of keep-alive. Special thanks to @raen over at Stack Overflow — my SignalR hub was erroring out with a ‘Not Found’ error and replacing keep-alive with $http_connection fixed the problem.

Now we need to enable the block by creating a symbolic link from it to the sites-enabled directory which Nginx reads from during startup:

# sudo ln -s /etc/nginx/sites-available/signalrdemo.com /etc/nginx/sites-enabled/

Our server block is now enabled and configured to respond to requests based on the listen and server_name directives inside the server block (you can read more about how Nginx processes these directives here). So now signalrdemo.com will respond to requests for signalrdemo.com and www.signalrdemo.com . Let’s restart Nginx to apply these changes:

# sudo service nginx restart

..and now visit www.signalrdemo.com in our browser:

We now have our domain directed to DigitalOcean and it’s serving up content.

Now would be a good time to think about security so let’s configure Nginx to serve up content over HTTPS.

Step 7 — Installing Certbot

To serve content securely via HTTPS, we need to obtain an SSL certificate for our domain from a registered certificate authority (CA). There are lots of CAs offering paid SSL certificates such as Comodo and Symantec but a new open-source provider called Let’s Encrypt has become popular because it provides an easy way to obtain and install TLS/SSL certificates — and they’re also free! It simplifies the process by providing a utility for Linux called Certbot that attempts to automate nearly all of the required steps. Certbot will fully automate the entire process of obtaining and installing a certificate.

Let’s make sure we are using the most up to date version of Certbot by installing the latest repository:

# sudo add-apt-repository ppa:certbot/certbot

Now install Certbot’s Nginx package:

# sudo apt install python-certbot-nginx

Certbot provides a variety of ways to obtain SSL certificates through plugins — the Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary:

sudo certbot --nginx -d signalrdemo.com -d www.signalrdemo.com

Since this is the first time running Certbot it will be prompt for an email address and ask to agree to the terms of service. After doing so, Certbot will communicate with the Let’s Encrypt server, then run a challenge to verify that we control the domain we’re requesting a certificate for — because signalrdemo.com is now live, we know this challenge will succeed. During the installation process, Certbot will ask how to handle redirects from HTTP automatically to HTTPS — I chose option 2. Here’s what the process should look like:

Certbot-auto will automatically generate the SSL certificate and key and store/install them in the directory /etc/letsencrypt. Certbot will also modify our server block (/etc/nginx/sites-enabled/signalrdemo.com) with some additional entries and has now basically HTTPS enabled our site:

NOTE: You may see an extra server block added to the end of the current one — if you see that, please remove the entire extra block and save the server block file. Let’s quickly test to make sure that there are no syntax errors in any of your Nginx files:

# sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Finally we need to restart Nginx to enable these changes:

# sudo systemctl restart nginx

Let’s confirm by reloading your website or just change the prefix from http to https to visit https://www.signalrdemo.com — notice your browser’s security indicator. It should indicate that the site is properly secured, usually with a green lock icon. Bingo — our site is serving content over HTTPS:

Our domain is up and running with HTTP and HTTPS. Remember when this used to be hard?

NOTE: If you’re interesting learning more about how to increase security for a site with Nginx and Let’s Encrypt, check out this blog which will show you how to further strengthen the security and reliability of your site.

Step 8— Create and deploy our first ASP.NET app

Everything is ready for us to start serving up a secure ASP.NET web app so let’s create that now. Let’s create a folder where we’ll host the app and use the dotnet CLI to create scaffolding to a simple web app.

# cd /var/www/signalrdemo.com
# dotnet new webapp

This will create a default ASP.NET web application and supporting files:

At this point I had to make a small tweak — the default setting for the WebApp we created includes a directive about redirection inside Startup.cs and this was tripped me up so I commented it out — so vi Startup.cs and comment this line out (line 43):

   // app.UseHttpsRedirection();

Let’s save our changes and now we can build the app.

# dotnet build

Now publish the app:

# dotnet publish

Our web app is ready to run. Now when it does, it will be running on localhost:5000 and localhost:5001 — so how do we see it from the outside world? We need make a small tweak to our server block to proxy port 80 to the ASP.NET application running on port 5000 (and vice verse for 443 which will redirect to 5001). Add the following line to the beginning of the ‘location’ section of the server block at /etc/nginx/sites-enabled/signalrdemo.com:

proxy_pass     http://localhost:5000;

The full server block now reads:

Save this change and restart Nginx:

# sudo systemctl restart nginx

Now we can start the app:

# dotnet bin/Debug/netcoreapp3.1/signalrdemo.com.dll

The CLI shows our app is running. Head back to your browser and refresh/visit https://www.signalrdemo.com:

We can now serve ASP.NET apps over HTTP/HTTPS on DigitalOcean so let’s stand up the chat app.

Step 9 — Create our server side SignalR app

Head over to the Microsoft SignalR site and check out their sample chat application:

I’ve based my sample chat app on this exact code from Microsoft but with a few important tweaks. The demo code appears to have been designed to run on a local development machine so many thanks to ASP.NET Core guru Ibrahim Šuta for helping me figure out a couple of key hurdles to resolving this. (If you need some deep-trench ASP.NET/Core work/consulting I strongly recommend you reach out to Ibrahim directly).

So we have here two versions of this app — one to host on signalrdemo.com (SignalRWebServer https://github.com/jonathanzufi/SignalRWebServer) and one to run locally for testing/verification (SignalRWebClient https://github.com/jonathanzufi/SignalRWebClient). They’re split into two projects even though they are 99% similar for reasons I’ll explain in a moment.

Let’s start with the server app: the code provided by Microsoft works great on your local development machine, but as soon as we host it on a public IP in order to communicate over the open web, there are security related considerations that we need to address in order to allow traffic to hit our SignalR hub. Browser security prevents a web page from making requests to a different domain than the one that served the web page. This restriction is called the same-origin policy. The same-origin policy prevents a malicious site from reading sensitive data from another site. In our case we want to allow our chat client to make cross-origin requests to our app. To do this, we need to enable CORS (Cross Origin Resource Sharing) middleware to allow this to happen. To read up more about this, check out Microsoft’s detailed blog.

So back in our server app in Startup.cs we set our CORS policy name:

private string CorsPolicyName = “MyCorsPolicy”;

Further down inside ConfigureServices we define the CORS policy:

services.AddCors(options => options.AddPolicy(CorsPolicyName, builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.WithOrigins(
https://localhost:5001”,
https://localhost:44390”,
http://localhost:5000”);
}));

This code will allows a SignalR browser client running on our local machine in dev (i.e. inside Visual Studio) to access our SignalR app hosted on https://www.signalrdemo.com. This is important if we decide to tinker with the client Visual Studio project connected to our live hub.

Finally for our server app, remember that we’re using Nginx to reverse proxy calls from the outside to the .NET Kestrel engine. For this reason we need some additional glue code to handle the forwarding of these requests. From the Microsoft docs:

Because requests are forwarded by reverse proxy, use the Forwarded Headers Middleware from the Microsoft.AspNetCore.HttpOverrides package. The middleware updates the Request.Scheme, using the X-Forwarded-Proto header, so that redirect URIs and other security policies work correctly.

Any component that depends on the scheme, such as authentication, link generation, redirects, and geolocation, must be placed after invoking the Forwarded Headers Middleware. As a general rule, Forwarded Headers Middleware should run before other middleware except diagnostics and error handling middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing.

Invoke the UseForwardedHeaders method at the top of Startup.Configure before calling other middleware. Configure the middleware to forward the X-Forwarded-For and X-Forwarded-Proto headers:

So that’s exactly what we do inside Startup.cs:

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseAuthentication();

(Also note we define the Microsoft.AspNetCore.HttpOverrides framework at the top of the Startup.cs).

So this explains the tweaks required to get that sample working on the open web. Back in our terminal, press CTRL-C to stop .NET. Now let’s install this server chat hub app on to our server by cloning the repo, build, publish and the run the app:

# cd /var/www/signalrdemo.com
# git clone https://github.com/jonathanzufi/SignalRWebServer .
# dotnet build
# dotnet publish
# cd SignalRWebServer
# dotnet bin/Debug/netcoreapp3.1/SignalRWebServer.dll

The chat app should now be running — bring up two browser windows side by side pointing to our domain and we can see the chat app in action:

Our SignalR chat hub in action!

Now to the SignalRWebClient project —I spun this project out as a separate app so that we can load it into Visual Studio to learn more about how it works and still communicate with the openly hosted hub at signalrdemo.com. This project only has a single change from the Microsoft demo code — it’s minor but obvious — we need to change the endpoint to the fully qualified domain name of where the server is hosted. So we change the endpoint in wwwroot\js\chat.js to:

var connection = new signalR.HubConnectionBuilder().withUrl(“https://signalrdemo.com/chatHub").build(); 

‘/chatHub’ is the name of the route we defined in the server app so this gets added to our fully qualified domain name as the endpoint for any client applications that want to communicate with the SignalR hub. Make sure you change this to your own domain name. Pull the code down for the SignalRWebClient project from GitHub on to your local Visual Studio environment and run it and you’ll be able to successfully talk to the live hub.

On the left is the client app running in Visual Studio as localhost

We’re nearly done. The last step is to configure Nginx to automatically run our server app in the background without having to leave a terminal window open. Let’s create a new service file:

# sudo vi /etc/systemd/system/signalrdemo.service

Add the following content and remember to plug in your own domain name:

Nginx service definition file for our server app

This service configuration file specifies the location of the project’s folder with WorkingDirectory and the command to execute at the start of the process in ExecStart. This also specifies using the RestartSec directive to restart the systemd service if the .NET runtime service crashes. Save this file and let’s enable the new service created:

# sudo systemctl enable signalrdemo.service

Now start the service:

# sudo systemctl start signalrdemo.service

Finally let’s check it’s status:

# sudo systemctl status signalrdemo.service
Output showing our service is running.

This means our .NET server app is running in the background so we can close the terminal session. We are pretty much done — we can now hit our server app from anywhere:

IMPORTANT: Don’t forget about your running service! Make sure you stop the running service with sudo systemctl stop signalrdemo.service when/if you’re done so you don’t incur any unwanted charges. You can also easily destroy the droplet as well.

Step 10— Create our React Native app

When SignalR was originally released, almost every Web application used jQuery, so it was an easy decision for the SignalR JavaScript client to depend on jQuery as well. Today a lot of jQuery’s functionality can be achieved with plain JavaScript allowing a frictionless developer experience integrating into mature frameworks such as Angular, React/React Native, and Vue. I’ve recently taken an interest with React Native so I chose that framework for this example. WebSockets are also now available in all major browsers and are now the standard for real-time Web communications and the SignalR Javascript client is available via npm and Content Delivery Networks (CDNs) which makes it easy to ingest into React Native (or other mobile frameworks).

Let’s examine a simple, single page React Native client to talk to our SignalR hub — take a look at https://github.com/jonathanzufi/SignalR-react-native-client.

A simple SignalR chat client built with React Native

I built this against iOS as my screenshots reflect, but this should run just fine on Android as well although I have not tested it (if you hit a problem please let me know).

Here are the instructions for building this code with the React Native CLI — if you prefer Expo, use expo init with the Expo CLI to make a new project, and then copy over all the JavaScript source code from this project, and then repeat the same below to install npm/Cocoapod dependencies. I was a fan of Expo for a while but I’ve come to prefer the iOS simulator as I feel like it will be a shorter path to publishing something to the App Store.

Let’s pull down the repo, install the npm/Cocoapod dependencies and run it in the iOS simulator (this assumes you have the React Native CLI installed along with XCode):

# git clone https://github.com/jonathanzufi/SignalR-ReactNativeClient 
# cd SignalR-ReactNativeClient
# yarn install
# cd ios && pod install
# cd ..
# npx react-native run-ios

Some areas of interest:

const errorHandler = (e, isFatal) => { 
console.log(‘Global error handler’);
}
setJSExceptionHandler(errorHandler, true);

It took me some time to learn about the lifecycle of a connection event in SignalR and along the way I saw some runtime errors that were hard to catch so I used the react-native-exception-handler package as a catch-all to help narrow things down. This isn’t very elegant but it helped me continue developer and I’m looking forward to learning more about debugging tools in React Native.

const hub_endpoint = ‘https://signalrdemo.com/chatHub';

Here we’re hardcoding the hub endpoint. It would be nice to harden the example to work with any endpoint but make sure you change this to your own URL.

I use a useEffect React hook to initialize a SignalR connection object and then create/start a connection — during this initialization (of a HubConnectionBuilder object) I initialize it with a logging level of LogLevel.Debug which was really helpful in terms of understanding what SignalR does in the background.

I also set up some event handlers for disconnects, reconnects and what to do with incoming messages. I use a state array called messageLog to house all incoming messages and a FlatList to render them with a simple MessageItem functional component to render each item of the message log as new messages are sent and received (I love the simplicity and power of the the FlatList component). For incoming messages we use the on method of the HubConnection object:

connection.on("ReceiveMessage", function (user, message) {      
setMessageLog(messageLog => [...messageLog.concat({
id: Date.now().toString(),
user: user,
message: message
})]);
});

This is an important concept to understand with SignalR — back on the server, hubs are created by declaring a class that inherits from Hub, and then we add public methods to it. Clients (i.e. our mobile app) can call those methods that are defined as public.

We specify a return type and parameters, including complex types and arrays, as you would in any C# method, and SignalR handles the serialization and deserialization of complex objects and arrays in your parameters and return values (our parameters user and message are very simple). So in our case, we defined the method name ReceiveMessage which is why we use it when we initialize the connection inside the mobile app.

The app tries to gracefully handle server side disconnects — you can see below when I stop the ASP.NET service, the app reflects a disconnected state and allows manual reconnection. My code is primitive — see here for a deep dive discussion about connection events and how SignalR works under the covers when a connection is interrupted or broken. One simple tweak is to add the .withAutomaticReconnect() method when initializing HubConnectionBuilder but I’ll leave this to you as an exercise.

That wraps it all up! Stepping back, we’ve effectively created simple scaffolding for what could be extended for any kind of real time communications use case — hopefully this will accelerate any ideas you might have!

If you’ve made it this far — thank you! Documenting this walkthrough really cemented many of the concepts in this post for me personally and I hope they do the same for you, or at least inspire you to build something cool. If you have any comments or suggestions please post them below or contact me directly — I’d love to know what I could have done better.

A special shout out to Ibrahim Šut, Rodhan Hickey, Nimesh Neema and Stefan Georg for their guidance and advice.

Keep coding.

--

--

Jonathan Zufi
The Startup

CTO at Equity Estates. Lifelong Learner. Curious tinkerer. @shrineofapple. Atlanta, GA.