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.
Before proceeding, I would recommend you to get the source code from GitHub.
We will be using two tables to store our data.
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.
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.
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
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.
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.
We will be adding two React components to our application –
Now, our ClientApp folder will have following structure.
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 –
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.
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.
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
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.
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.
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.
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
Introduction Blazor is a .NET web framework that allows us to create client-side applications using…
Introduction In this article, we are going to create a sudoku solver with the help…
Introduction In this article, we will learn how to implement Azure serverless with Blazor web…
Introduction Angular is an open-source framework that allows us to create applications for multiple platforms…
Introduction In this article, we will create an optical character recognition (OCR) application using Angular…
Introduction In this article, we will create an optical character recognition (OCR) application using Blazor…
View Comments
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.
Thanks for reading my article. if you enjoyed this, do not forget to share it with your friends.
Can please you add a license to the github source?
For example Apache or MIT like https://github.com/aspnet/AspNetCore/blob/master/LICENSE.txt?
Thanks
Why do you need a license for this repo?? You are free to use/share the repo. I already mentioned this in the article.
Hello Ankit sir
I was trying to communicate with you over the ""https://dzone.com/articles/aspnet-core-crud-with-reactjs-and-entity-framework"" but didnot found any of your reply to any of my comment.
I was trying with the same method but i am facing the problem that when i run command
Scaffold-DbContext "Your connection string here" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables tblEmployee, tblCities
it says build failed can you please help me with this
I cannot help without proper error details. I suggest you to open an issue on Stack overflow.
Hi
In your tutorial you are using typescript but you do not explain how you got to that stage? When i do the beginning steps my dot.net core project uses js not ts. This has left me stuck at the beginning. Please can you expand on how you changed the project to use typescript.
Thanks
This project was created almost a year back. At that time the default react template was using ts, but now it has changed to js.
Thank you very much!
Hi
I followed same steps in the blog, but i am not able to run the project due to change in JS from TSX extension.
Could you please explain by creating new project in .js extension?