Skip to main content

ASP.NET Core – CRUD With React.js And Entity Framework Core

Introduction

In this article, we are going to create a web application using ASP.NET Core 2.0 and React.js with the help of Entity Framework Core database first approach. We will be creating a sample Employee Record Management system and perform CRUD operations on it. To read the inputs from the user, we are using HTML Form element with required field validations on the client side. We are also going to bind a dropdown list in the HTML Form to a table in the database using EF Core.

We will be using Visual Studio 2017 and SQL Server 2014.

Prerequisites

  • Install .NET Core 2.0.0 or above SDK from here.
  • Install the latest version of Visual Studio 2017 Community Edition from here.
  • Download and install the latest version of Node.js from here.
  • SQL Server 2008 or above.

Source code

Before proceeding, I would recommend you to get the source code from GitHub.

Creating Table

We will be using two tables to store our data.

  1. tblEmployee
    Used to store the details of employee. It contains fields such as EmployeeID, Name, City, Department, and Gender.
  2. tblCities
    This contains the list of cities and used to populate the City field of tblEmployee table. It contains two fields CityID and CityName.

Execute the following commands to create both tables.

CREATE TABLE tblEmployee (      
EmployeeID int IDENTITY(1,1) NOT NULL PRIMARY KEY,      
Name varchar(20) NOT NULL ,      
City varchar(20) NOT NULL ,      
Department varchar(20) NOT NULL ,      
Gender varchar(6) NOT NULL       
)      
GO      
      
CREATE TABLE tblCities (      
CityID int IDENTITY(1,1) NOT NULL PRIMARY KEY,      
CityName varchar(20) NOT NULL       
)      
GO  

Now, we will put some data into the tblCities table. We will be using this table to bind a dropdown list in our web application from which the desired city can be selected. Use the following insert statements.

INSERT INTO tblCities VALUES('New Delhi');      
INSERT INTO tblCities VALUES('Mumbai');      
INSERT INTO tblCities VALUES('Hyderabad');      
INSERT INTO tblCities VALUES('Chennai');      
INSERT INTO tblCities VALUES('Bengaluru');

Now, our Database part has been completed. So, we will proceed to create the MVC application using Visual Studio 2017.

Create MVC Web Application

Open Visual Studio and select File >> New >> Project. After selecting the project, a “New Project” dialog will open. Select .NET Core inside Visual C# menu from the left panel.

Then, select “ASP.NET Core Web Application” from available project types. Put the name of the project as ReactCrudDemo and press OK. 

After clicking on OK, a new dialog will open asking you to select the project template. You can observe two drop-down menus at the top left of the template window. Select “.NET Core” and “ASP.NET Core 2.0” from these dropdowns. Then, select “React.js” template and press OK.

Now, our project will be created. You can observe the folder structure in Solution Explorer as shown in the below image.

Here, we have our Controllers and Views folders. We won’t be touching the Views folders for this tutorial since we will be using React.js to handle the UI. The Controllers folders will contain our Web API controller. The point of interest for us is the ClientApp folder where the client side of our application resides. Inside the ClientApp/components folder, we already have few components created which are provided by default with the React.js template in VS 2017. These components will not affect our application, but for the sake of this tutorial, we will delete fetchdata.tsx and counter.tsx files from ClientApp/app/components.

Adding the Model to the Application

We are using Entity Framework core database first approach to create our models. Navigate to Tools >> NuGet Package Manager >> Package Manager Console.

We have to install the package for the database provider that we are targeting which is SQL Server in this case. Hence, run the following command: 

Install-Package Microsoft.EntityFrameworkCore.SqlServer

Since we are using Entity Framework Tools to create a model from the existing database, we will install the tools package as well. Hence run the following command:

Install-Package Microsoft.EntityFrameworkCore.Tools

After you have installed both the packages, we will scaffold our model from the database tables using the following command:

Scaffold-DbContext "Your connection string here" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables tblEmployee, tblCities
Do not forget to put your own connection string (inside ” “). After this command is executed successfully you can observe a Models folder has been created and it contains three class files myTestDBContext.cs, TblCities.cs and TblEmployee.cs. The name of your DB Context class will be the name of your database suffixed with the word Context. Here my database name is myTestDB, hence the context class name is myTestDBContext.
Hence, we have successfully created our Models using EF core database first approach.

Now, we will create one more class file to handle database related operations.

Right click on Models folder and select Add >> Class. Name your class EmployeeDataAccessLayer.cs and click Add button. At this point in time, the Models folder will have the following structure.

 
 

Open EmployeeDataAccessLayer.cs and put the following code to handle database operations.

 

using Microsoft.EntityFrameworkCore;  
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Threading.Tasks;  
  
namespace ReactCrudDemo.Models  
{  
    public class EmployeeDataAccessLayer  
    {  
        myTestDBContext db = new myTestDBContext();  
  
        public IEnumerable<TblEmployee> GetAllEmployees()  
        {  
            try  
            {  
                return db.TblEmployee.ToList();  
            }  
            catch  
            {  
                throw;  
            }  
        }  
  
        //To Add new employee record     
        public int AddEmployee(TblEmployee employee)  
        {  
            try  
            {  
                db.TblEmployee.Add(employee);  
                db.SaveChanges();  
                return 1;  
            }  
            catch  
            {  
                throw;  
            }  
        }  
  
        //To Update the records of a particluar employee    
        public int UpdateEmployee(TblEmployee employee)  
        {  
            try  
            {  
                db.Entry(employee).State = EntityState.Modified;  
                db.SaveChanges();  
  
                return 1;  
            }  
            catch  
            {  
                throw;  
            }  
        }  
  
        //Get the details of a particular employee    
        public TblEmployee GetEmployeeData(int id)  
        {  
            try  
            {  
                TblEmployee employee = db.TblEmployee.Find(id);  
                return employee;  
            }  
            catch  
            {  
                throw;  
            }  
        }  
  
        //To Delete the record of a particular employee    
        public int DeleteEmployee(int id)  
        {  
            try  
            {  
                TblEmployee emp = db.TblEmployee.Find(id);  
                db.TblEmployee.Remove(emp);  
                db.SaveChanges();  
                return 1;  
            }  
            catch  
            {  
                throw;  
            }  
        }  
  
        //To Get the list of Cities    
        public List<TblCities> GetCities()  
        {  
            List<TblCities> lstCity = new List<TblCities>();  
            lstCity = (from CityList in db.TblCities select CityList).ToList();  
  
            return lstCity;  
        }  
  
    }  
} 

Now, we will proceed to create our Web API Controller.

Adding the Web API Controller to the Application 

Right click on Controllers folder and select Add >> New Item.

An “Add New Item” dialog box will open. Select ASP.NET from the left panel, then select “API Controller Class” from templates panel and put the name as EmployeeController.cs. Press OK.

This will create our Web API EmployeeController class. We will put all our business logic in this controller. We will call the methods of EmployeeDataAccessLayer to fetch data and pass on the data to the frontend.

Open EmployeeController.cs file and put the following code into it.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Threading.Tasks;  
using Microsoft.AspNetCore.Mvc;  
using ReactCrudDemo.Models;  
  
namespace ReactCrudDemo.Controllers  
{  
    public class EmployeeController : Controller  
    {  
        EmployeeDataAccessLayer objemployee = new EmployeeDataAccessLayer();  
  
        [HttpGet]  
        [Route("api/Employee/Index")]  
        public IEnumerable<TblEmployee> Index()  
        {  
            return objemployee.GetAllEmployees();  
        }  
  
        [HttpPost]  
        [Route("api/Employee/Create")]  
        public int Create(TblEmployee employee)  
        {  
            return objemployee.AddEmployee(employee);  
        }  
  
        [HttpGet]  
        [Route("api/Employee/Details/{id}")]  
        public TblEmployee Details(int id)  
        {  
            return objemployee.GetEmployeeData(id);  
        }  
  
        [HttpPut]  
        [Route("api/Employee/Edit")]  
        public int Edit(TblEmployee employee)  
        {  
            return objemployee.UpdateEmployee(employee);  
        }  
  
        [HttpDelete]  
        [Route("api/Employee/Delete/{id}")]  
        public int Delete(int id)  
        {  
            return objemployee.DeleteEmployee(id);  
        }  
  
        [HttpGet]  
        [Route("api/Employee/GetCityList")]  
        public IEnumerable<TblCities> Details()  
        {  
            return objemployee.GetCities();  
        }  
    }  
}  

We are done with our backend logic. Therefore, we will now proceed to code our frontend using React.js.

Creating React.js Components

We will be adding two React components to our application –

  1. FetchEmployee component – to display all the employee data and delete an existing employee data.
  2. AddEmployee component – to add a new employee data and edit an existing employee data.
Right click on ClientApp/components folder and select Add >> New Item. An “Add New Item” dialog box will open. Select Scripts from the left panel, then select “TypeScript JSX File” from templates panel, and put the name as AddEmployee.tsx. Press OK. This will add a JSX file inside components folder. JSX stand for JavaScript XML. JSX is a preprocessor step that adds XML syntax to JavaScript.
 
 
Similarly, add FetchEmployee.tsx file insideClientApp/components folder.

Now, our ClientApp folder will have following structure.

FetchEmployee Component 

Open FetchEmployee.tsx file and put the following code to it.

import * as React from 'react';  
import { RouteComponentProps } from 'react-router';  
import { Link, NavLink } from 'react-router-dom';  
  
interface FetchEmployeeDataState {  
    empList: EmployeeData[];  
    loading: boolean;  
}  
  
export class FetchEmployee extends React.Component<RouteComponentProps<{}>, FetchEmployeeDataState> {  
    constructor() {  
        super();  
        this.state = { empList: [], loading: true };  
  
        fetch('api/Employee/Index')  
            .then(response => response.json() as Promise<EmployeeData[]>)  
            .then(data => {  
                this.setState({ empList: data, loading: false });  
            });  
  
       // This binding is necessary to make "this" work in the callback  
        this.handleDelete = this.handleDelete.bind(this);  
        this.handleEdit = this.handleEdit.bind(this);  
  
    }  
  
    public render() {  
        let contents = this.state.loading  
            ? <p><em>Loading...</em></p>  
            : this.renderEmployeeTable(this.state.empList);  
  
        return <div>  
            <h1>Employee Data</h1>  
            <p>This component demonstrates fetching Employee data from the server.</p>  
            <p>  
                <Link to="/addemployee">Create New</Link>  
            </p>  
            {contents}  
        </div>;  
    }  
  
    // Handle Delete request for an employee  
    private handleDelete(id: number) {  
        if (!confirm("Do you want to delete employee with Id: " + id))  
            return;  
        else {  
            fetch('api/Employee/Delete/' + id, {  
                method: 'delete'  
            }).then(data => {  
                this.setState(  
                    {  
                        empList: this.state.empList.filter((rec) => {  
                            return (rec.employeeId != id);  
                        })  
                    });  
            });  
        }  
    }  
  
    private handleEdit(id: number) {  
        this.props.history.push("/employee/edit/" + id);  
    }  
  
    // Returns the HTML table to the render() method.  
    private renderEmployeeTable(empList: EmployeeData[]) {  
        return <table className='table'>  
            <thead>  
                <tr>  
                    <th></th>  
                    <th>EmployeeId</th>  
                    <th>Name</th>  
                    <th>Gender</th>  
                    <th>Department</th>  
                    <th>City</th>  
                </tr>  
            </thead>  
            <tbody>  
                {empList.map(emp =>  
                    <tr key={emp.employeeId}>  
                        <td></td>  
                        <td>{emp.employeeId}</td>  
                        <td>{emp.name}</td>  
                        <td>{emp.gender}</td>  
                        <td>{emp.department}</td>  
                        <td>{emp.city}</td>  
                        <td>  
                            <a className="action" onClick={(id) => this.handleEdit(emp.employeeId)}>Edit</a>  |  
                            <a className="action" onClick={(id) => this.handleDelete(emp.employeeId)}>Delete</a>  
                        </td>  
                    </tr>  
                )}  
            </tbody>  
        </table>;  
    }  
}  
  
export class EmployeeData {  
    employeeId: number = 0;  
    name: string = "";  
    gender: string = "";  
    city: string = "";  
    department: string = "";  
}    

Let’s understand this code. At the top we have defined an interface “FetchEmployeeDataState” which has two properties –

  1. empList of type “EmployeeData” class to hold the employee data.
  2. loading of type “boolean” to indicate if the data is being loaded onto the page.

After this, we have defined a component class “FetchEmployee” which inherits the abstract class React.Component. Inside the constructor of this class, we are calling the base class constructor using Super() and then initializing the fields of the interface to their default values.

We are also calling our web API method using fetch and set the empList value and also set the loading to false. The fetch method is invoked inside the constructor so that the employee data will be displayed as the page loads.

At the end of constructor, we are binding handleDelete and handleEdit method. This binding is necessary to make “this” work in the callback.

Then we have our “render()” method which will render our HTML elements onto the DOM. We will check if the data has finished loading or not and then call renderEmployeeTable method which will return an HTML table to display all the employee data on the web page. Every row of the table also had two action method – Edit and Delete for editing and deleting the employee record.

Next, we have handleDelete method which accepts employeeID as a parameter. This will prompt the user with a confirmation box and if the user selects yes then it will delete the employee with this employeeID.

The handleEdit method will invoke an edit request on the employee record by passing the employee id in the URL parameter and redirects to AddEmployee component.

At the end, we have defined an EmployeeData class having the same properties as of our TblEmployee Model class to hold the employee data. 

AddEmployee Component 

Open AddEmployee.tsx file and put the following code into it:
 
import * as React from 'react';  
import { RouteComponentProps } from 'react-router';  
import { Link, NavLink } from 'react-router-dom';  
import { EmployeeData } from './FetchEmployee';  
  
interface AddEmployeeDataState {  
    title: string;  
    loading: boolean;  
    cityList: Array<any>;  
    empData: EmployeeData;  
}  
  
export class AddEmployee extends React.Component<RouteComponentProps<{}>, AddEmployeeDataState> {  
    constructor(props) {  
        super(props);  
  
        this.state = { title: "", loading: true, cityList: [], empData: new EmployeeData };  
  
        fetch('api/Employee/GetCityList')  
            .then(response => response.json() as Promise<Array<any>>)  
            .then(data => {  
                this.setState({ cityList: data });  
            });  
  
        var empid = this.props.match.params["empid"];  
  
        // This will set state for Edit employee  
        if (empid > 0) {  
            fetch('api/Employee/Details/' + empid)  
                .then(response => response.json() as Promise<EmployeeData>)  
                .then(data => {  
                    this.setState({ title: "Edit", loading: false, empData: data });  
                });  
        }  
  
        // This will set state for Add employee  
        else {  
            this.state = { title: "Create", loading: false, cityList: [], empData: new EmployeeData };  
        }  
  
        // This binding is necessary to make "this" work in the callback  
        this.handleSave = this.handleSave.bind(this);  
        this.handleCancel = this.handleCancel.bind(this);  
    }  
  
    public render() {  
        let contents = this.state.loading  
            ? <p><em>Loading...</em></p>  
            : this.renderCreateForm(this.state.cityList);  
  
        return <div>  
            <h1>{this.state.title}</h1>  
            <h3>Employee</h3>  
            <hr />  
            {contents}  
        </div>;  
    }  
  
    // This will handle the submit form event.  
    private handleSave(event) {  
        event.preventDefault();  
        const data = new FormData(event.target);  
  
        // PUT request for Edit employee.  
        if (this.state.empData.employeeId) {  
            fetch('api/Employee/Edit', {  
                method: 'PUT',  
                body: data,  
  
            }).then((response) => response.json())  
                .then((responseJson) => {  
                    this.props.history.push("/fetchemployee");  
                })  
        }  
  
        // POST request for Add employee.  
        else {  
            fetch('api/Employee/Create', {  
                method: 'POST',  
                body: data,  
  
            }).then((response) => response.json())  
                .then((responseJson) => {  
                    this.props.history.push("/fetchemployee");  
                })  
        }  
    }  
  
    // This will handle Cancel button click event.  
    private handleCancel(e) {  
        e.preventDefault();  
        this.props.history.push("/fetchemployee");  
    }  
  
    // Returns the HTML Form to the render() method.  
    private renderCreateForm(cityList: Array<any>) {  
        return (  
            <form onSubmit={this.handleSave} >  
                <div className="form-group row" >  
                    <input type="hidden" name="employeeId" value={this.state.empData.employeeId} />  
                </div>  
                < div className="form-group row" >  
                    <label className=" control-label col-md-12" htmlFor="Name">Name</label>  
                    <div className="col-md-4">  
                        <input className="form-control" type="text" name="name" defaultValue={this.state.empData.name} required />  
                    </div>  
                </div >  
                <div className="form-group row">  
                    <label className="control-label col-md-12" htmlFor="Gender">Gender</label>  
                    <div className="col-md-4">  
                        <select className="form-control" data-val="true" name="gender" defaultValue={this.state.empData.gender} required>  
                            <option value="">-- Select Gender --</option>  
                            <option value="Male">Male</option>  
                            <option value="Female">Female</option>  
                        </select>  
                    </div>  
                </div >  
                <div className="form-group row">  
                    <label className="control-label col-md-12" htmlFor="Department" >Department</label>  
                    <div className="col-md-4">  
                        <input className="form-control" type="text" name="Department" defaultValue={this.state.empData.department} required />  
                    </div>  
                </div>  
                <div className="form-group row">  
                    <label className="control-label col-md-12" htmlFor="City">City</label>  
                    <div className="col-md-4">  
                        <select className="form-control" data-val="true" name="City" defaultValue={this.state.empData.city} required>  
                            <option value="">-- Select City --</option>  
                            {cityList.map(city =>  
                                <option key={city.cityId} value={city.cityName}>{city.cityName}</option>  
                            )}  
                        </select>  
                    </div>  
                </div >  
                <div className="form-group">  
                    <button type="submit" className="btn btn-default">Save</button>  
                    <button className="btn" onClick={this.handleCancel}>Cancel</button>  
                </div >  
            </form >  
        )  
    }  
} 

This component will be used for both adding and editing the employee data. Since we will use EmployeeData class to hold the data, we have imported it from FetchEmployee component.

The interface AddEmployeeDataState has four properties.

  1. title – to show “Create” or “Edit” on the top of the page
  2. loading – to check if the page has finished loading data
  3. cityList – to hold the list of cities from tblCities table
  4. empData – to hold the employee data to bind it to the HTML form

Inside the constructor of component class “AddEmployee” we are initializing the fields of the interface to their default value and then setting the value of CityList property by fetching the data from tblCitiestable. We will use this to bind a dropdown in our HTML form. Since we are fetching the city list inside our constructor, the dropdown list will be populated as the page loads.

This component will handle both Add and Edit request. So how will the system differentiate between both requests? The answer is routing. We need to define two different route parameters, one for Add employee record and another to edit employee record. We will be defining these in routes.tsx file shortly.

If an edit request is made then the employee id will be passed in the parameter. Inside the constructor, we will read the value of URL parameter empid. If the value of empid is greater than zero then this is an edit request and we will set the value of title to “Edit”, fill the data in empData property and set loading to false.

If the empid value is not set then it is an add request and we will set the value of title to “Create” and set loading to false.

The handleSave method will handle the save event on the form. Based on whether the URL has empid parameter or not we will send a request for PUT or POST and upon success, redirect the user back to FectchEmployee component.

The renderCreateForm method will return an HTML form to be displayed on the webpage. We have set the default value in all the fields of the Form. If an Add request is made then all the fields will empty. If an edit request is made then it will fill the data of the corresponding employee in the fields. We bind the select element using cityList property that we have populated in our constructor.

At this point in time, you might get an error “Parameter ‘props’ implicitly has an ‘any’ type” in AddEmployee.tsx file.

If you encounter this issue, then add the following line inside tsconfig.json file.

“noImplicitAny”: false

Defining route and navigation menu for our Application

Open ClientApp/routes.tsx file and put the following code in to it.

import * as React from 'react';  
import { Route } from 'react-router-dom';  
import { Layout } from './components/Layout';  
import { Home } from './components/Home';  
import { FetchEmployee } from './components/FetchEmployee';  
import { AddEmployee } from './components/AddEmployee';  
  
export const routes = <Layout>  
    <Route exact path='/' component={Home} />  
    <Route path='/fetchemployee' component={FetchEmployee} />  
    <Route path='/addemployee' component={AddEmployee} />  
    <Route path='/employee/edit/:empid' component={AddEmployee} />  
</Layout>; 

In this file, we have defined the routes for our application as below.

  • / – if base URL is hit then it will redirect to Home component
  • /fetchemployee – It will redirect to FetchEmployee component
  • /addemployee – it will redirect to AddEmployee component to add a new employee record
  • /employee/edit/:empid – we are passing the employee id in the parameter. it will redirect to AddEmployee component to edit the exisiting employee data 

The last thing remaining is to define navigation menu for our application. Open ClientApp/components/NavMenu.tsx file and put the following code to it.

import * as React from 'react';  
import { Link, NavLink } from 'react-router-dom';  
  
export class NavMenu extends React.Component<{}, {}> {  
    public render() {  
        return <div className='main-nav'>  
            <div className='navbar navbar-inverse'>  
                <div className='navbar-header'>  
                    <button type='button' className='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>  
                        <span className='sr-only'>Toggle navigation</span>  
                        <span className='icon-bar'></span>  
                        <span className='icon-bar'></span>  
                        <span className='icon-bar'></span>  
                    </button>  
                    <Link className='navbar-brand' to={'/'}>ReactCrudDemo</Link>  
                </div>  
                <div className='clearfix'></div>  
                <div className='navbar-collapse collapse'>  
                    <ul className='nav navbar-nav'>  
                        <li>  
                            <NavLink to={'/'} exact activeClassName='active'>  
                                <span className='glyphicon glyphicon-home'></span> Home  
                            </NavLink>  
                        </li>  
                        <li>  
                            <NavLink to={'/fetchemployee'} activeClassName='active'>  
                                <span className='glyphicon glyphicon-th-list'></span> Fetch employee  
                            </NavLink>  
                        </li>  
                    </ul>  
                </div>  
            </div>  
        </div>;  
    }  
}  

And that’s it. We have created our ASP.NET Core application using React.js and Entity Framework core database first approach.

Execution Demo

Press F5 to launch the application.

A web page will open as shown in the image below. Notice the navigation menu on the left showing navigation link for Home and Fetch Employee pages.

Click on Fetch Employee in the navigation menu. It will redirect to FetchEmployee component and displays all the employee data on the page. Notice the URL has “/fetchemployee” appended to it as we have defined in our routes.tsx file.

Since we have not added any data, hence it is empty.

Click on CreateNew to navigate to /addemployee page. Add a new Employee record as shown in the image below. You can observe that the City field is a dropdown list, containing all the city names that we have inserted into tblCities table.

After inserting the data in all the fields, click on “Save” button. The new employee record will be created and you will be redirected to the /fetchemployee page, displaying records of all the employees. Here, we can also see action methods Edit and Delete.

If we want to edit an existing employee record, then click Edit action link. It will open Edit page as shown below where we can change the employee data. Notice that we have passed employee id in the URL parameter.

Here, we have changed the City of employee Neha from Bengaluru to Mumbai. Click on “Save” to return to the fetch-employee page to see the updated changes as highlighted in the image below.

Now, we will perform Delete operation on an employee named Rajesh having Employee ID 2. Click on Delete action link. It will open a JavaScript confirmation box asking for a confirmation to delete.

Once we click on “OK” the employee with name Rajesh will be removed from our record and you can see the updated list of the employee as shown below.

Conclusion

We have successfully created an ASP.NET Core application using React.js and Entity Framework core database first approach with the help of Visual Studio 2017 and SQL Server 2014. We have used HTML forms to get data from the user and bind the dropdown list to the database table using Entity framework.

Fork this application on GitHub and let me know your valuable feedback in the comments section below.

You can also find this article at C# Corner.

You can check my other articles on ASP .NET Core here 

See Also

Ankit Sharma

Software engineer having more than 4 years of extensive experience in MS technologies including but not limited to C#, ASP.NET MVC and MSSQL. I am also an author at C# corner and currently working on ASP.NET Core and Angular 5.

2 thoughts to “ASP.NET Core – CRUD With React.js And Entity Framework Core”

  1. Thank you for this very good and working example it was kind of hard to follow a lot of new things, A suggestion would have been to make it longer to explain more in detail for people starting the react part of it.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.