build-react-app-with-dotnet-core-backend

React is a javascript library for building web apps and it doesn’t load itself in the browser. We need some kind of mechanism that loads the index.html (single page) of React with all the dependencies(CSS and js files) in the browser. In this post, we are using .NET Core Web API which loads React app and accepts any API calls from the React app.

In this post, I will show how to implement React  as UI with .NET Core as a Web API and how these interact with each others.

I am building a Demo project with name Students which user can add a student with name after name and email to store in a memory database in .NET Core, And he/she can retrieve all students and show them.

Architecture

Communication between React App and .NET Core shown in the bellow:

The web requests via .NET Web API will go to React routing. .NET Core API. handles data access (save/retrieve data)

before begin to work, you should have installed the followings in you computer:

After installation check the .NET Core version with the following command

dotnet --version

For React library, you can look to my previous post: Getting Started with React

In this post first I create a template for both React App and .NET Core App via command line which creates a Student project where React App as UI and .NET Core App as an API to communicate with React App and present the UI on the Browser.

We will have a basic app which we can add Students (First name, Last name, Email) and  then we want to retrieve  number of students, and display these at the website, when we want.

How To Build and Develop The Project

First we want to develop and build and after that we will run in production.

Now we began with development phase:

Generate whole project (React + .NET Core ) template with this command:

In my case: project name is Students.

You can choose a location in your computer (C disk) and start command line in the folder that you want to create the Students project.

In my case I am start command line in the path: C:/React.

dotnet new react -o Students

After running this command a template is created under C:/React/Students and this is just a template not more

If we open Students Folders in VS Code  then we see  the following structure:

AS we see there is a ClientApp folder which contains all React code for React App, under this folder there is src which contains the source code for this app. Pusblic folder is library which React needs to be build and Package.json, etc.
The rest is template for ASP.NET Core app.
The ClientApp subdirectory, will be used for all UI concerns to create the React App. The ASP.NET Core app is used  for data access, authorization, and other server-side matters.
First we want to Run this template without editing the template:
In the command line cd to the Students folder and  then run the following command.
dotnet run
After running we see there are two urls to start in the webbrowser.
first we start with https://localhost:7096
First runs and shows the following:

And then opens the browser and shows the following:

From the webbrowser we see the follwoing information:

Welcome to your new single-page application, built with:

And more description about the template project.

Now we want to change the UI of our Students application in the React app (ClientApp) as we want howt UI (user interface should be presented for Studenss).

Implementing React App

First we create the React app as UI for our students demo project.

First we need to create a Header component for our demo UI, and call it Header.js for the React application under ClientApp/src/components/

The code  for Header.js, is shown in the following:

import React from 'react';
export const Header = () => {
    const headerStyle = {
        width: '100%',
        padding: '2%',
        backgroundColor: "yellowgreen",
        color: 'black',
        textAlign: 'center'
    }
    return(
        <div style={headerStyle}>
            <h1>Demo .NET as backend for React</h1>
        </div>
    )
}

Header.js

The next component is to  create the Student Form: CreateStudent.js

Under : ClientApp/src/components/

The code for CreateStudent.js, is as following:

import React from 'react'
const CreateStudent = ({onChangeForm, createStudent }) => {
return(
<div className="container">
<div className="row">
<div className="col-md-7 mrgnbtm">
<h2>Create Student</h2>
<form>
<div className="row">
<div className="form-group col-md-6">
<label htmlFor="exampleInputEmail1">First Name</label>
<input type="text" onChange={(e) => onChangeForm(e)} className="form-control" name="firstname" id="firstname" aria-describedby="emailHelp" placeholder="First Name" />
</div>
<div className="form-group col-md-6">
<label htmlFor="exampleInputPassword1">Last Name</label>
<input type="text" onChange={(e) => onChangeForm(e)} className="form-control" name="lastname" id="lastname" placeholder="Last Name" />
</div>
</div>
<div className="row">
<div className="form-group col-md-12">
<label htmlFor="exampleInputEmail1">Email</label>
<input type="text" onChange={(e) => onChangeForm(e)} className="form-control" name="email" id="email" aria-describedby="emailHelp" placeholder="Email" />
</div>
</div>
<button type="button" onClick= {(e) => createStudent()} className="btn btn-danger">Create</button>
</form>
</div>
</div>
</div>
)
}
export default CreateStudent

CreateStudent.js,

 

We need two functions as props:   onChangeForm and createStudent, that we could create our students in the UI.  We create these functions in the App.js  (under ClientApp/src/App.js). 

We import also the two files: Header.js and CreateStudent.js to the app.js (which is the main model in React).

The whole code of app.js shall be as following. Remove the content of app.js and paste the following code: app.js 

import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import './custom.css';
import { Header } from './components/Header'
import CreateStudent from './components/CreateStudent'
class App extends Component {
  state = {
    student: {},
    students: [],
    numberOfStudents: 0
  }
  createStudent = (e) => {
    createStudent(this.state.student)
      .then(response => {
        console.log(response);
        this.setState({numberOfStudents: this.state.numberOfStudents + 1})
    });
  }
  onChangeForm = (e) => {
    let student = this.state.student
    if (e.target.name === 'firstname') {
        student.firstName = e.target.value;
    } else if (e.target.name === 'lastname') {
        student.lastName = e.target.value;
    } else if (e.target.name === 'email') {
        student.email = e.target.value;
    }
    this.setState({student})
  }
  render() {
    return (
      <div className="App">
        <Header></Header>
        <div className="container mrgnbtm">
          <div className="row">
            <div className="col-md-8">
                <CreateStudent
                  onChangeForm={this.onChangeForm}
                  createStudent={this.createStudent}
                  >
                </CreateStudent>
            </div>
          </div>
        </div>
      </div>
    );
  }
}
export default App;

app.js 

 

We need to create Display Board component  to show the  number of Students that has been created before. We create the DisplayBoard.js under  ClientApp/src/components as follow:

import React from 'react'
export const DisplayBoard = ({numberOfStudents, getAllStudents}) => {
return(
<div style={{backgroundColor:'green'}} className="display-board">
<h4 style={{color: 'white'}}>Students Created</h4>
<div className="number">
{numberOfStudents}
</div>
<div className="btn">
<button type="button" onClick={(e) => getAllStudents()} className="btn btn-warning">Get all Students</button>
</div>
</div>
)
}

DisplayBoard.js

 

Update the App.js with DisplayBoard.js with importing of this file. then the App.js code shall be as follow:

import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import './custom.css';
import { Header } from './components/Header'
import CreateStudent from './components/CreateStudent'
import { DisplayBoard } from './components/DisplayBoard'
class App extends Component {
  state = {
    Student: {},
    Students: [],
    numberOfStudents: 0
  }
  createStudent= (e) => {
    createStudent(this.state.student)
      .then(response => {
        console.log(response);
        this.setState({numberOfStudents: this.state.numberOfStudens + 1})
    });
  }
  getAllStudents = () => {
    getAllStudents()
      .then(students => {
        console.log(students)
        this.setState({students: students, numberOfStudents: students.length})
      });
  }
  onChangeForm = (e) => {
    let student = this.state.student
    if (e.target.name === 'firstname') {
        student.firstName = e.target.value;
    } else if (e.target.name === 'lastname') {
        student.lastName = e.target.value;
    } else if (e.target.name === 'email') {
        student.email = e.target.value;
    }
    this.setState({student})
  }
  render() {
      return (
      <div className="App">
        <Header></Header>
        <div className="container mrgnbtm">
          <div className="row">
            <div className="col-md-8">
                <CreateStudent
                  onChangeForm={this.onChangeForm}
                  createStudent={this.createStudent}
                  >
                </CreateStudent>
            </div>
            <div className="col-md-4">
                <DisplayBoard
                  numberOfStudents={this.state.numberOfStudents}
                  getAllStudents={this.getAllStudents}
                >
                </DisplayBoard>
            </div>
          </div>
        </div>
      </div>
    );
  }
}
export default App;
app.js after importing DisplayBoard.js

In the last, we will add the Student.js as a table which can show student information such as first name, last name, etc. in the UI:

Student.js under ClientApp/src/components as following code:

import React from 'react'
export const Students = ({students}) => {
console.log('students length:::', students.length)
if (students.length === 0) return null
const StudentRow = (student,index) => {
return(
<tr key = {index} className={index%2 === 0?'odd':'even'}>
<td>{index + 1}</td>
<td>{student.firstName}</td>
<td>{student.lastName}</td>
<td>{student.email}</td>
</tr>
)
}
const studentTable = students.map((student,index) => StudentRow(student,index))
return(
<div className="container">
<h2>Students</h2>
<table className="table table-bordered">
<thead>
<tr>
<th>Student Id</th>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{studentTable}
</tbody>
</table>
</div>
)
}

Student.js

We need to create a Service (StudentService.js)   that takes care of the communication between the React application (frontend) and an API backend API. A single service provides multiple functions to retrieve data from or post data to an external service using the HTTP protocol.

First we need to create a folder: Services and under this folder we create the StudentService.js as following:

/* Get all students from the database */
export async function getAllStudents() {
const response = await fetch('/api/Students');
return await response.json();
}
/* Create a student in the database */
export async function createStudent(data) {
const response = await fetch(`/api/student`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
})
return await response.json();
}

StudentService.js

As we see from the code above there is two functions:  getAllStudents() wich can retrieve all studens from t he database and createStudent which user can create a new student in the database.

We should import this files: Student.js and  StudentService.js to app.js .

The final updated App Component (App.js)  is as following:

import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import './custom.css';
import { Header } from './components/Header'
import { Students } from './components/Students'
import CreateStudent from './components/CreateStudent'
import { DisplayBoard } from './components/DisplayBoard'
import { getAllStudents, createStudent } from './services/StudentService'
class App extends Component {
state = {
Student: {},
Students: [],
numberOfStudents: 0
}
createStudent= (e) => {
createStudent(this.state.student)
.then(response => {
console.log(response);
this.setState({numberOfStudents: this.state.numberOfStudens + 1})
});
}
getAllStudents = () => {
getAllStudents()
.then(students => {
console.log(students)
this.setState({students: students, numberOfStudents: students.length})
});
}
onChangeForm = (e) => {
let student = this.state.student
if (e.target.name === 'firstname') {
student.firstName = e.target.value;
} else if (e.target.name === 'lastname') {
student.lastName = e.target.value;
} else if (e.target.name === 'email') {
student.email = e.target.value;
}
this.setState({student})
}
render() {
return (
<div className="App">
<Header></Header>
<div className="container mrgnbtm">
<div className="row">
<div className="col-md-8">
<CreateStudent
onChangeForm={this.onChangeForm}
createStudent={this.createStudent}
>
</CreateStudent>
</div>
<div className="col-md-4">
<DisplayBoard
numberOfStudents={this.state.numberOfStudents}
getAllStudents={this.getAllStudents}
>
</DisplayBoard>
</div>
</div>
</div>
<div className="row mrgnbtm"> 
<Students students={this.state.students}></Students> 
</div>
</div>
);
}
}
export default App;

final app.js 

That was all for implementing of React App for our Student demo app..

 

Implementing .NET Web API

We have implemented UI (User Interface) in the  React app and now we  will create a Web API with ASP.NET Core.

First we need Install package Microsoft.AspNetCore.SpaServices.Extensions  which Provides types for hosting a Single Page Application (SPA).

This package make possible to integrate client-side SPA frameworks or libraries, such as Angular or React, with server-side frameworks such as ASP.NET Core can be difficult.  It enables seamless operation between the different client and server technology stacks.

Install this package with following command:

dotnet add package Microsoft.AspNetCore.SpaServices.Extensions

After running this command the package: Microsoft.AspNetCore.SpaServices.Extensions is created under dependencies.packages

Then we create a new folder:Models and under this folder we create StudentModel class as a data model for our Students Demo projec.  below.

Here is the code for StudentModel.cs class:

namespace Student.Models
{
    public class StudentModel
    {
        public int Id { get; set; }
         
      public string firstName { get; set; }
        public string lastName { get; set; }
        public string email { get; set; }
    }
}

 

We have to create a repository class that can store students data in memory. We will not use any database in this Project (Students).

StudentRepository.cs class Under Models Folder

using System;
using System.Collections.Generic;
namespace Students.Models
{
public class StudentRepository: IStudentRepository
{
private List<StudentModel> students = new List<StudentModel>();
private int _nextId = 1;
public StudentRepository()
{
Add(new StudentModel { firstName= "first1", lastName="last1", email="email1@gmail.com"});
Add(new StudentModel { firstName= "first2", lastName="last2", email="email2@gmail.com"});
Add(new StudentModel { firstName= "first3", lastName="last3", email="email3@gmail.com"});
}
public IEnumerable<StudentModel> GetAll()
{
return students;
}
public StudentModel Add(StudentModel item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
item.Id = _nextId++;
students.Add(item);
return item;
}
}
}

We need also to createInterface IStudentRepository.cs Class under Models folder:

using System;
using System.Collections.Generic;
namespace Students.Models
{
public interface IStudentRepository
{
IEnumerable<StudentModel> GetAll();
StudentModel Add(StudentModel student);
}
}

We should create the  Startup.cs class (.NET 6 doesn’t create startup class by default.

We should app.UseSpa to interact from .NET Core app to React app by this we gives the SourcePath to the “ClientApp”   folder in the React app, by adding following code:

app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{ spa.UseReactDevelopmentServer(npmScript: "start");
}
});

The whole code for Startup.cs is as following:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Students
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
}

Creating the Controller class: StudentsController.cs

Under Controller, change the name of  WeatherForecast to StudentsController and past the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Students.Models;
namespace Students.Controllers
{
[ApiController]
public class StudentsController : ControllerBase
{
private readonly ILogger<StudentsController> _logger;
static readonly IStudentRepository repository = new Students.Models.StudentRepository();
public StudentsController(ILogger<StudentsController> logger)
{
_logger = logger;
}
// GetAllStudents() method to retrieve all Students

[HttpGet]
[Route("api/students")]
public IEnumerable<StudentModel> GetAllStudents()
{
return repository.GetAll();
}
// PostStudent() method to create a new student.

[HttpPost]
[Route("api/student")]
[Consumes("application/json")]
public Models.StudentModel PostStudent(Models.StudentModel item)
{
return repository.Add(item);
}
}
}
StudentsController.cs
That is all to create our Students Demo project in .NET Core app.

How to run this application?

You can run and test the application both via Visual Studio 2022 (even VS code) or by command line.

Here is how to run and test it via command line.

When you run this command dotnet run, you can access the APIs as below.
First show the URLs:

As you see in the above there are two url: https://localhost:5001 and http://localhost:5000

If you open a browser and paste https://localhost:5001 then you should access to the React API  (UI) as follow:

How does Interaction works Between .NET API and React?

When you run the command dotnet run,you can access the React App with the two URIs as we sow above.

https://localhost:5001

http://localhost:5000

You can access  APIs with the same port with the context path /api.

This feature is provide by .NET as default if  template is generated  with the following command as we done in the beginning of this  post.

dotnet new react -o <project name>

The interact between React and API has been done, in Startup.cs (  line 58, we are using the UseSpa method to give the React folder ClientApp.

app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";

By this way, we can access the  React app on ports 5000 (http) and 5001(HTTPS), to access to the UI.

How to publish For Production

Publish can be done to package the whole app for production by the following command.

This command first 

If you got the following Error:

error MSB3073: The command "npm install" exited with code 1.

Then remove the npm install from the project file.

published folder contains the whole app packaged

The configuration is done in the Startup.cs file  that built React code is under the folder ClientApp/build:

// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});

The published folder contains the follwoings:

Run the following command to start the application.

dotnet published/Student.dll

Now start browse with https://localhost:5001

 

Conclusion

In this post I have explained how to build React App with ASP.NET Core, I have create a project template via command line which create us an ASP.NET Core app and a React app. The React app code is  in the ClientApp subdirectory,  and it is  used for UI. The ASP.NET Core app is used for data access, authorization, and other server-side. I have modified this template to adapt our Demo project.

In this project is used some kind of mechanism that loads the index.html (single page) of React with all the dependencies(CSS and js files) in the browser, by .NET core API.

This post is part of React-Step by step.

Back to home page