Integrating React into a Visual Studio Web Application

Dimitris Vardalis
9 min readFeb 6, 2019

--

This article describes how React and a front-end build pipeline can be incorporated into Visual Studio. Hopefully this will be helpful to people who develop applications based on older MS web frameworks (e.g. Web Forms, MVC) and want to reap the benefits of modern front-end development with React, without having to migrate their entire codebase. For the rest of the article the application is assumed to be based on Web Forms; however, applying the given instructions to an MVC application should be fairly straightforward.

The main characteristics of the presented solution are:

  • Integration of the front-end build pipeline into the solution build: Automatic creation of the development or production front-end bundle when the respective Debug or Release solution configuration is built.
  • Separation of front-end development: Allow development of the front-end components outside Visual Studio, possibly using a separate web server with automatic build and refresh (webpack-dev-server with Hot Module Replacement).
  • Support for multiple pages with React components sharing code.
  • Integration of the front-end file packaging when the solution is published: The deployment package includes the produced front-end bundles, omitting the original sources.

There are multiple ways in which you can make use of this article. You may create a new application from scratch, you may start with an already existing application or you may just experiment with the provided solution. In all cases, it would be helpful to download the code on github so that you have locally all files of the solution. At various points you will need to copy and paste files from the sample solution to your own, so having them locally will come in handy.

Creating the Web Forms application

If you decide to create a Web Forms application with Web API support from scratch you may follow the instructions in this section. Folks who already have a Web Forms application may refer to the relevant documentation for enabling Web API functionality in their project and jump to the next section.

A new Web Forms application can be created by selecting File -> New Project and “ASP.NET Web Application (.NET Framework)”, as shown in the following figure.

Create new Web Forms application

On the next window select a Web Forms project with Web Forms and Web API as shown below.

Configure Web Forms project

Setting up the back-end

We now have a Web Forms application with support for Web API. In the following paragraphs we will demonstrate how two Web Form pages may host two React apps that share some common code. One page will display a list of parts and the other a list of products. Each React app will hit a different back-end controller, retrieve the sample data and display them using a common React component. This example can be generalized for any number of pages.

Let’s now create the two Web Forms by right-clicking on the Web Forms project and selecting Add -> New Item and then “Web Form with Master Page” as shown in the screenshot below.

Add a new Web Form

Name the Web Form PartsWebForm.aspx and select Site.Master as the master page for the Web Form. Edit the newly created page and add the following content (you may consult the provided solution on github).

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<!-- This is where the React application will be rendered -->
<div id="root"></div>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="PageScripts" runat="server">
<!-- We are passing the baseUrl to React. All Urls will be based on that. Helps as web app installation Url may vary -->
<script>
window.baseUrl = '<%= ResolveUrl ("~") %>';
</script>
<script src="React/dist/parts.bundle.js" type="text/javascript
</script>
</asp:Content>

Then create another Web Form, named ProductsWebForm.aspx, using the same master page. Add the same content as above only change the last script file from React/dist/parts.bundle.js to React/dist/products.bundle.js. These are the files that will be produced by webpack during the front-end build. Finally, add the links to those pages in the Site.Master to include them in the top page menu, so that they can be easily accessed for testing (see bold lines below).

<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a runat="server" href="~/">Home</a></li>
<li><a runat="server" href="~/About">About</a></li>
<li><a runat="server" href="~/Contact">Contact</a></li>
<li><a runat="server" href="~/PartsWebForm">Parts</a></li>
<li><a runat="server" href="~/ProductsWebForm">Products</a></li>

</ul>
</div>

Let’s now create one controller for the parts and another controller for the products page as shown below. The default route (api/Parts) of the PartsController returns a list of Part objects (defined in Models/Part.cs) and the default route (api/Products) of the ProductsController returns a list of Products objects (defined in Models/Product.cs). Please copy the code for the above files from the github repository.

Back-end files

Setting up Node.js packages

Let’s now add a React folder in our WebFormsReactSample project and start a command line window in that folder. If you are like me and find it extremely tedious to open a new command line window and switch to the desired folder, you may download the Open Command Line VS extension and enjoy opening a new command line window in the desired folder by right-clicking the folder in the solution explorer. Also, in order to proceed you need to have Node.js installed on your machine (it comes with npm which is also required). If necessary, you may download it on the official Node.js page.

The starting point for setting up React was the post Creating a React App… From Scratch. If you would like to learn more about what each command does please visit the above link (and links included therein). The following commands need to be executed inside the React folder:

  • npm init:Initializes an npm package. When prompted you may specify any value you like for the package description fields.
  • npm install --save-dev @babel/core@7.1.0 @babel/cli@7.1.0 @babel/preset-env@7.1.0 @babel/preset-react@7.0.0: Installs the Babel transpiler packages required to convert new ES6 syntax as well as React JSX code into mainstream Javascript, compatible with most browsers.
  • npm install --save-dev webpack@4.19.1 webpack-cli@3.1.1 webpack-dev-server@3.1.8 style-loader@0.23.0 css-loader@1.0.0 babel-loader@8.0.2: Installs the packages related to the webpack bundler.
  • npm install --save-dev react@16.5.2 react-dom@16.5.2: Installs the React packages.
  • npm install react-hot-loader: Installs the hot loader for webpack and React. This package allows for automatically building and refreshing the front-end when a file changes.
  • npm install --save-dev webpack-merge: Installs the package that enables merging webpack configuration files in order to maintain common code in a separate file and remain DRY (described in the documentation).

Adding the required files

At this point you may paste into your solution the following sets of files:

React source code in the src folder

  • The file itemInfo.js in the components folder: A lower level component used by the top-level components.
  • Files in the parts and products folders: Each of them contains the entry point (index.js) and the top-level React component (parts.js and products.js respectively). Both the parts and products components utilize the itemInfo component.

Webpack-dev-server open page in the public folder

  • The file index.html will host a React page app for debugging with the webpack-dev-server. The file contains the “root” div where the application will be rendered, a baseUrl that corresponds to the base URL of the backend and includes the bundle we are interested in debugging.

Configuration files

  • .babelrc: The babel configuration where the transpilation presets are set.
  • wepback.common.js: The common part of the webpack configuration (for both development and production). The common file is included from both the dev and prod files so that common configuration need only set once and maintained in a single place (https://webpack.js.org/guides/production/).
  • webpack.dev.js: The development-specific part of the webpack configuration. It enables full source maps so that the original ES6 code can be debugged.
  • webpack.prod.js: The production specific part of the webpack configuration. It enables minification of the produced bundles.

A couple of things to note with respect to the common webpack configuration:

  • The entry points are defined in the relevant section of the configuration file as shown below. Adding more pages would require adding more entry points.
entry: {
parts: "./src/parts/index.js",
products: "./src/products/index.js"
}
  • It is possible to improve the user experience by extracting the common code of the two entry points to a separate file using the webpack SplitChunks plugin. The common file would include the React-related dependencies as well as the common components (in this case only ItemInfo). If setup that way, the common file would contain most of the code (it would be a few orders of magnitude larger than the individual files) and it would only need to be downloaded once, the first time any of the pages would be loaded. This feature was omitted due to the further complexity it would introduce (it would complicate how scripts are included in the page).
  • The devServer configuration uses “../” as the content base. This is helpful in case you would want to include styles or scripts outside the React directory.
  • The publicPath option in the output section must be the same as the publicPath in the devServer section.
  • The HotModuleReplacementPlugin must be enabled in the plugins section.
React files

Additional configuration

You will also need to do the following additional configuration:

  • Add the three required script entries to the npm configuration in the package.json file, by adding a “scripts” property to the configuration object. The scripts are used to start the webpack-dev-server for debugging, build the development version and build the production version of the front-end respectively. The json snippet is as follows:
"scripts": {
"start": "webpack-dev-server --mode development --config webpack.dev.js",
"build-dev": "webpack --config webpack.dev.js",
"build-prod": "webpack --config webpack.prod.js"
}
  • Integrate the front-end build pipeline into the solution build, by adding in the “Pre-build event command line” of your top-level project the script below. The script calls the build-dev or build-prod scripts defined above for the Debug and Release solution configuration build respectively. The Build Events can be accessed by right-clicking the top-level project -> Properties -> Build Events.
cd "$(ProjectDir)React"
if $(ConfigurationName) == Debug (
call npm run build-dev
)
if $(ConfigurationName) == Release (
call npm run build-prod
)
  • Enable CORS so as to allow the front-end served by the webpack-dev-server to connect to the Web Forms back-end. You may do this by entering the following snippet in the system.webServer section of your web.config:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Headers" value="content-type" />
</customHeaders>
</httpProtocol>
  • Setup deployment packaging by pasting the WebFormReactSample.wpp.targets file to your solution. This file defines a build target that excludes from the deployment package all files in the React folder except for the files in the React\dist (where webpack stores the produced bundles).

Using the functionality

At this point your solution should be ready for separate front- and back-end development. When you start debugging your solution the front-end will be automatically built. The following options are available for your debugging cycle:

  • Make changes to your files and restart the solution debugging in Visual Studio. This corresponds to the traditional debugging cycle and it works because the front-end is automatically rebuilt. Changes made that way are not reflected in the application until debugging is restarted.
  • While the solution is debugging make changes to the React source files, run “npm run build-dev” in the React folder command line and then refresh the browser. The changes will be reflected in your front-end.
  • While your solution is debugging run “npm run start” in the React folder command line. The webpack-dev-server will start and Chrome will automatically open to the index.html file in the React\public folder. Any change made to the React source files from now on will trigger a rebuild of the front-end and an automatic reload of the React modules (https://webpack.js.org/concepts/hot-module-replacement/). Note that the default index.html file includes the parts script. If you would like to develop the products page you will need to point that to the products bundle. I generally use a single html file for working with the webpack-dev-server and edit it accordingly depending on the page I want to work on. You may follow a different strategy and have multiple files and change the server opening page instead.
  • If you are using IIS instead of IIS Express then you may follow the above cycles even if the solution is not debugging (i.e. IIS will be serving your back-end even when you are not debugging).

Finally, if you opt for publishing your solution (right-click your top-level project and select “Publish”), the resulting files will only contain the bundles produced by webpack in the dist folder and not your source files.

--

--