If you're looking to improve the user experience in your ASP.NET application, dropping React in may sound like an easy fix. It turns out this might not be as straightforward as you'd think. Keep reading and I'll show you how adding a React app to an ASP.NET MVC application can be pretty easy once you know how.
Getting Started
For the purposes of this article I'll be using ASP.NET Core MVC version 3.1. The ideas in this post should also work with ASP.NET MVC 4.x as well as the upcoming ASP.NET 5 (which is supposed to be out later in 2020). Just know that if you're using ASP.NET MVC, you should be able to follow along with these steps.
For the React portion of this post I'll be setting up a new application using Create React App.
I've put the sample code from this article on my GitHub. I'll include a link to it at the end of the article as well.
Common Integration Problems
The first issue you're likely to encounter integrating a Create React App application is that it expects to be deployed to the root directory on a server. If you're deploying an ASP.NET MVC application it typically also expects to at the root directory so we'll need to be able to tell the React App that it is going to be deployed into a non-root sub-directory.
A second issue you'll likely encounter when building a Create React App is the javascript files created by the production build process include hashes that change every time the source code changes. This is good for optimization and caching, but can be tricky to deal with when building code and integrating it into your ASP.NET view.
Let's get started on how to configure a Create React App codebase, build, and then include the built assets into an ASP.NET MVC Razor view so that you can utilize React in your app.
Create React App
Getting started with Create React App is pretty straightforward. If it is new to you the React docs have a good walk through with the full details on getting started with Create React App. If you're not using Create React App for your React application, you should be able to follow along too, but there may be slight variations.
React App Details
For the purposes of this article, let's assume that we're making an "admin app" with React that we'll want to include into our ASP.NET MVC application and expose it at the URL - https://www.tonyranieri.com/admin.
This React application will make use of React Router (BrowserRouter
) to handle navigation between components. To make this work correctly within the context of the ASP.NET MVC page we'll need to make a few modifications.
Setting up Create React App to Deploy to a Sub-directory
The first thing you'll want to do is set router basename wherever you're setting up your routing.
<BrowserRouter basename="/admin">
This is the base URL for all locations listed in your router. Since we're planning to serve the app from a sub-directory you’ll set this to the name of the sub-directory that will contain your app.
Update Package.json in Your Create React App
Next we'll need to open up package.json
and set the homepage
property to the path where the app will be deployed.
"homepage": "https://www.tonyranieri.com/admin",
If the homepage
property doesn't exist in package.json you can manually add it. The homepage setting will only be used during the deployment steps (eg: npm run build
), so when you are working on your Create React App code you can still run npm start
and not have to worry about the homepage value messing you up.
Configure Your Create React App Build for ASP.NET
If you've worked with Create React App before you may know that when you build your code a few things happen. One step is the build process will embed a runtime script into the index.html that is built. This code changes with each build, and complicates inclusion into an ASP.NET application. To stop embedding this code into the index.html file you can set the INLINE_RUNTIME_CHUNK variable.
INLINE_RUNTIME_CHUNK=false
This will tell the Create React App build process to generate an additional javascript file that contains the code that would have previously been inlined into index.html. This is important because it allows us to have a static Razor view in our ASP.NET application.
In the sample code on my GitHub you'll notice that it contains a .env
file at the project root which sets INLINE_RUNTIME_CHUNK. If you prefer you can set an environment variable in your shell instead.
Now that we've turned off the inline runtime chunk it's time to build - npm run build
. This will generate a production build to the /build directory. After the build is complete we can get to work on the ASP.NET project.
Configuring ASP.NET Core MVC for React
I'll assume you already have an ASP.NET project you're working if, and if you don't that you can create one on your own. So let's get started by copying the built React assets to our ASP.NET application.
Copy the Built Create React App to ASP.NET MVC
The first step to integrate our React app into our ASP.NET app is to copy build/static
to the appropriate location in the wwwroot
directory. That location will vary depending on the value you gave the Create React App's package.json
homepage property earlier, but if you've been following along you'll recall that we set it to be deployed to "/admin". If you set your homepage to something else, you'll need to create the appropriate sub-directory within your wwwroot
.
Setting up ASP.NET Routing to Support React Routing
Remember we're setting up an "admin application" in this article, we'll need that to be reflected in the routing and links we use in the ASP.NET code. The routing change is important because you can go to https://www.tonyranieri.com/admin and it will work, but when you can't deep link to a component. For example https://www.tonyranieri.com/admin/users will work if you navigate to it via the app, but if you try to go directly to https://www.tonyranieri.com/admin/users via the address bar ASP.NET Routing gets confused and returns a 404.
Adding this fallback route will allow the ASP.NET Routing to direct the request to the React App for its routing to handle and return the proper view.
ASP.NET Core MVC 3.0+
endpoints.MapFallbackToController("Index", "Admin");
ASP.NET Core MVC Before 3.0
routes.MapSpaFallbackRoute(
name: "admin-react-app-fallback",
defaults: new { controller = "Admin", action = "Index" });
You wont need both of these code snippets, but depending on the version you're using you'll need to pick one of them.
Add a New Controller and View to Return Your React App
Now that we've got the routing set up, we need to make sure that the controller exists. Add AdminController
to the controllers folder and make sure it has an action "Index". This should be the default action for the controller and it is the one we specified in the routing earlier.
You'll also need to add an Index view. For now it should contain the contents from Create React App's build/index.html
. You may notice that at the bottom of the index there are several <script>
tags that reference hashed javascript file names - something along the lines of 2.87c47ae0.chunk.js
. The hash (eg: "87c47ae0") will change each time your code changes and you re-build the project. To deal with this we'll include the scripts, but use the asp-src-include
tag helper to include a wildcard file name for each javascript file.
<script asp-src-include="/admin/static/js/runtime-main.*.js"></script>
<script asp-src-include="/admin/static/js/2.*.chunk.js"></script>
<script asp-src-include="/admin/static/js/main.*.chunk.js"></script>
You could work around this by bundling these files into one new javascript file that will have a static name and then including that one file. This method has a few disadvantages, most importantly it will eliminate the possibility you'd get any benefits from code splitting. Code splitting helps out because we're able to cache chunks of code, rolling them all into one new file means we have to get all the code all the time, less-than-optimal caching for you!
You'll need to make a similar change for the CSS style closer to the top of the file:
<link asp-href-include="/admin/static/css/main.*.chunk.css" rel="stylesheet" />
You can remove other links that you're not using such as manifest.json
, etc.
Running the App
By this point you should be able to start up the ASP.NET application and navigate to the /admin path, then within your React admin application you should be able to navigate to different components and even use deep linked URLs to directly load a specific component/page.
Easy to Automate
Since we told the Create React App build process to not inline the runtime script, we're able to build the React app and copy the built resources to our ASP.NET app now. You should be able to automate these build steps to build & deploy the Create React App code with the rest of your ASP.NET application, you could even do so with the CI/CD tool of your choice.
Wrapping Up
If you've been following along with this blog post but don't have and code to work on, or simply would like to see it in action I've uploaded a sample repo that shows how to use a Create React App in ASP.NET Core MVC to my GitHub.
If you enjoyed this be sure to check out some of my other blog posts!