You Got A Friend In Me: Building A .Net Core Backend “Friend” For A React App

Jamie Taylor
You've Got a Friend In Me Header Image

A Quick Note From the Future

Hey everyone, this article originally appeared on The Reactionary back in November of 2016.

The Reactionary has closed its doors recently (as Zac is working on bigger and better things), but I’ve had a chat with him about posting my half of the two posts we worked on, and he said it wasn’t a problem at all.

if you don’t ask, you don’t get

So I’ve cross posted it here.

Something you need to know before reading this post is that it was written around the time of .NET Core 1.1. So there are some things which have changed

mainly in Startup.cs land

I decided to leave the code as it is, rather than change everything. Mainly because the GitHub repo is in the same state.

Anyway, on with the post.

Also, please forgive the moustache. I’m allowed to be wrong about some things, right?


A quick note from Zac at The Reactionary

This week at The Reactionary we’re shaking things up to try and help broaden your horizons. For this week I’ll be swapping blogs with Jamie Taylor at A Journey In .Net Core.

I’ll be guest authoring a post about using Create-React-App and isomorphic fetch on a Journey In .Net core in this linked article.

Below you’ll find an article authored by Jamie on how to create a .NET core back end which you can then use to receive messages from the React front end we build in my article. We really hope you enjoy this change of pace. So, without further ado…


Hey everyone, Jamie here.

So Zac and I discussed the idea of creating something together to show how React and .NET Core can forge a friendship that will last forever.

That came across a little more romantic than I’d thought it would.

… Or should that be Bromantic?

Bro As A Service

Bro As A Service was based on an example in one of Zac’s earlier posts, namely giving Hi 5s using React.

Because everyone loves Hi 5s right? I know I do.

So What’s The Problem You’re Solving?

Imagine that you have a Hi 5 addiction and a need, a drive, a want, to give them out every few seconds. Now imagine that all of your co-workers and loved ones are sick to their back teeth of Hi 5ing you 24 hours a day. People’s arms flop downwards whenever you walk into the room. Palms, when around you, run the risk of being slapped raw. You’ve had official warnings about unprofessional conduct from your boss, for shouting “Bro!” then Hi 5ing clients as they enter the board room.

What you need is some kind of service that you can utilise, one that’s on the web. Maybe a web service.

Now let’s pretend that you want to get this service up and running in as little time as possible.

That’s Where .NET Core Comes In.

What’s .NET Core, you ask? Luckily for you, I’ve written about it before, boom!

Go check out that link for a fuller description of what .NET Core is, but here comes a trimmed down, single paragraph version:

.NET Core is an open source implementation of the .NET Framework. It’s a subset (at the time of writing) of the .NET Framework, and precompiled binaries are available for many Operating Systems. The .NET Framework was released in early 2002 by Microsoft, as an application development framework that is designed to support RAD (Rapid Application Development).

Since .NET Core is an open source version of .NET, it’s inherently cross platform. This meant that I was able to build the web server for Bro As A Service on my Mac, or my work machine, or even a RaspberryPi if I wanted.

Well, RaspberryPi support is coming in version 1.10 according to this post by Damien Edwards

The Process

Zac and I discussed the app and came up with some implementation ideas, I even took some notes.

No, I wont share them here because they’re in my chicken scratch handwriting. And, quite frankly, it’s embarrassing that my handwriting stinks as much as it does.

From our discussions, we came up with the idea of a React front end  (what with him being an expert in it) that would talk to a .NET Core back end (that would be my job). The back end would have one endpoint (for simplicity) and would only accept HTTP GET and POST verbs. It would have to support CORS too.

So, we need:

  • A web server
  • Single end point
  • Just GET and POST

Simple

Here’s How I Did It

First thing I did was made sure that I had the .NET Core SDK, Visual Studio Code and a bunch of extensions set up on my machine. You can read about how to do that here.

My machine had all of that installed already, though

After I had that set up, I went and installed yeoman.

Heresy! This is an npm friendly blog!

Then I installed this aspnet generator for it.

Both yeoman and the aspnet generator where installed on my machine already, too

What’s great about this generator is that you can issue

yo aspnet

and have a .NET Core project set up in seconds.

I chose the WebApi Application option and gave it the name “HiFive-Server” and was ready to start throwing it together.

Project Layout

All of the code for Bro As A Service can be found at GitHub. The HiFive-Server code being here, so feel free to play along.

The default layout for a Web APi project is pretty much everything that we need. We have:

  • Program.cs  – which is the entry point to the application
  • Startup.cs – which sets up Kestrel (the .NET Core webserver)
  • Controllers – this contains all of out controllers, but we only need one
  • A bunch of json files – these are the config files for building and running the application
  • wwwroot – this contains css and JavaScript, but we don’t need these as it’s a headless server.

Pretty much everything else can be ditched. So I ditched it all, selectively. But you don’t have to.

Design

In order to build a back end that Zac’s front end would happily plug into

Ooh er. Cheeky.

We need one endpoint to contact, which will accept a GET and a POST. Let’s call that the HiFiveContoller, seeing as endpoints in WebApi are controllers. Here’s the basic version of the HiFiveController:

using System;
using Microsoft.AspNetCore.Mvc;
namespace HiFive.Controllers
{
[RouteAttribute("/")]
public class HiFiveController : Controller
{
[HttpGet]
public string Get()
{
return "Hey buddy! Hi 5?!";
}
[HttpPost]
public string Post()
{
return "YEAAAAH WOOOOOH!!!";
}
}
}
Attributes

Attributes are cool features of the C# language, and going into how they work is a little out of scope for this article. You can read up about them here though.

We have three attributes in this file:

  • [RouteAttribute(“/”)]
  • [HttpGet]
  • [HttpPost]

[RouteAttribute(“/”)] tells the C# compiler that this controller will respond to HTTP verbs sent to /, or the route of the web app.

[HttpGet] tells the C# compiler that our Get() method will be used to respond to the HTTP GET verb only. And the [HttpPost] attribute works in a similar way, except that it deals with the HTTP POST verb. This meant that Zac’s front end code had to do no more than send GET or POST requests to / for the server to respond correctly.

I fired up the server by running the following in the Terminal:

dotnet restore && dotnet run

This restored and installed all packages required to build and run the application (dotnet restore), then built and ran it (dotnet run). I was then given a port on localhost to send requests to, so I fired up Postman, and was able to send GET and POST requests to the server and get valid responses.

How To Make It Better

At this point, we have a perfectly working Hi 5 web service. But in real life, you can’t give an infinite amount of Hi 5s at once, can you? Neither should the server, users should have to wait in line to get their Hi 5. But how could we do this, if RESTful servers are meant to be stateless?

It’s a bit of a hack, but I decided to use a Singleton.

“A bit of a hack”, he says. Just a BIT of a hack?! That’s quite a hack. Considering that RESTful services are stateless, you just forced it to have a state, my friend.

Enter: The Bachelor

 Over in the models folder, you’ll find the Bachelor class

public sealed class Bachelor
{
private static Bachelor instance;
public DateTime? nextHiFive;
private Bachelor() {}
public static Bachelor Instance
{
get
{
if (instance == null)
{
instance = new Bachelor();
}
return instance;
}
}
}

Doing a deep dive on what a singleton is and why you would use one is definitely out of scope here, but you can read about them at Wikipedia.

The Bachelor class has a nullable DateTime, the idea here is to store the timestamp for when the next Hi 5 request can be dealt with, or NULL if the next Hi 5 request can be dealt with instantly.

When a POST comes in we’ll see whether we can accept the Hi 5 (if the nullable DateTime’s value is set to NULL), set a timeout value for the next time that we can accept one, and respond to the user. If we can’t accept the Hi 5 (if the nullable DateTime is not null), then we’ll return a commiseration message.

Here’s how the altered POST method looks

//declare the bachelor instance for this controller
private static HiFive.Bachelor bachelor = HiFive.Bachelor.Instance;
[HttpPost]
public string Post()
{
if (bachelor.nextHiFive.HasValue)
{
return "Can't Hi 5 right now, Bro!";
}
bachelor.nextHiFive = DateTime.Now.AddSeconds(5);
return "YEAAAAH WOOOOOH!!!";
}

We’re also going to use the time out to disable the Hi 5 button on the front end if the timer is ticking.

So we also need to change the GET method

[HttpGet]
public string Get()
{
if (bachelor.nextHiFive.HasValue)
{
while(bachelor.nextHiFive.Value > DateTime.Now)
{
System.Threading.Thread.Sleep(5000);
}
}
// reset datetime for next HiFive
bachelor.nextHiFive = (DateTime?)null;
return "Hey buddy! Hi 5?!";
}

Both the GET and POST methods will now wait for the timeout value (which defaults to 5 seconds) to pass before allowing further requests.

CORS

This was the big requirement (after getting the server working, of course), because my backend would be on a different port to Zac’s front end but both applications will still be on the same host thus making CORS a problem.

Story of my life…

As such CORS would be a problem for us.

Turns out that .NET Core has a really simple way to deal with CORS. Here’s the standard Startup.cs file (remember, this one sets up our instance of the Ketstrel web server):

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
 
namespace HiFive
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMvcWithDefaultRoute();
}
}
}

There’s a lot going on here, but the two methods we’re interested in are Configure and ConfigureServices. Adding CORS support into Kestrel is as simple as taking these two methods, Configure and ConfigureServices, and adding a line of code to each)

Seriously, a single line of code. It’s not as easy as that in .NET classic

// Simplified both methods to only include the relevant changes
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors(builder => builder.AllowAnyOrigin());
app.UseMvcWithDefaultRoute();
}

The first change (in ConfigureServices) adds the CORS middleware. The ordering here is important, because its a pipeline. This means that, in our altered ConfigureServices method, all incoming requests will go through the CORS service BEFORE they go through the MVC service.

ASP.NET Core tidbit: unlike ASP.NET classic, responses will take the reverse of the journey taken by their request when being generated.

So our generated responses will go through the MVC service BEFORE the CORS service.

The second change tells the application builder to use CORS and passes a delegate into its constructor with the option of AllowAnyOrigin(). This means that ANY server can make a request to ours and it will be accepted by our server. This comes with security risks, and you should read up about .NET Core’s CORS middleware here, before you use it in production applications.

It’s fine to use AllowAnyOrigin() here, because it’s an extremely simple app for demonstration purposes, and the chances of a malicious user coming along are pretty slim.

NEVER make this assumption is production code, though.

Retrospective

Together we’ve:

  • Built a WebAPI web server in .NET Core
  • Added a controller method to it
  • Ensured that the controller only responds to GET and POST methods
  • Added a Singleton (invalidating the RESTful nature of the server)
  • Enabled CORS (at a security risk)

This will be, pretty much, perfect as a back end for Zac to plug in his front end into.

What did I say earlier about the double entendres?

There is an issue with this web server code, though. I was going to leave you , dear reader, to ponder on it and see if you could figure it out. But that’s not fair.

So here’s the reproduction steps for the issue:

  • User A connects to the React front end and “BROOOOO!” is displayed along with an active button
  • User A clicks “Give Hi5” (this sends a POST to the back end)
  • User A receives “YEAAAAH WOOOOOH!!!” via the front end
  • User B connects to the front end and “BROOOOO!” is displayed along with an active button
  • User B clicks “Give Hi5”, before the server timeout for User A is reached
  • User B receives “Can’t Hi 5 right now, Bro!” and button is disabled
  • User B never receives an active button after the timeout has ended
  • User B has to refresh their view of the front end, to be able to interact with the button.

This will happen whenever the number of users connected to the front end is greater than one. However, for our use case (creating an example so that Zac and I can discuss how to get React and .NET Core to communicate, and how easy it is), it’s not really worth worrying about.

How about you take a look at the entire codebase, here a link to the repo, see if you can come up with an elegant solution and submit a pull request? Maybe let us know in the comments, too.

More Information

As Zac mentioned at the top, for the rest of the story you can read his article about the front end development here.

If this post has helped you out, please consider   Buy me a coffeeBuying me a coffee
Jamie Taylor
A .NET developer specialising in ASP.NET MVC websites and services, with a background in WinForms and Games Development. When not programming using .NET, he is either learning about .NET Core (and usually building something cross platform with it), speaking Japanese to anyone who'll listen, learning about languages, writing for his non-dev blog, or writing for a blog about video games (which he runs with his brother)