Building a web application using React and asp.net core(Part 01)

6 minute read

React is an open-source, javascript library for building UI components. It is the most popular front end framework. It is maintained by facebook. It can be used for SPA or mobile application development. On the other hand, .net core is an open-source, cross-platform supported framework. Now a days, it is also most popular for software development. In this article, I will show you, how to create a simple application with CRUD operation using asp.net core web api and react. I will show a simple employee profile of HRM application. Let’s start.

Tools and Technology used

  1. Visual Studio Code
  2. ASP.NET Core Web Api
  3. Visual C#
  4. React

Step 1: Create a new application

  • Visual Studio Code -> File -> Open Folder
  • Go to View -> Terminal
  • Type dotnet new react -o HRM in the terminal
  • Type cd HRM to enter into the HRM folder
  • In the application folder you will see another folder name ClientApp which is actually react application inside dotnet application.
  • Now run the application using donet run command

Step 2: Create model classes

  • Create a model class name Employee in Model folder as follows

Employee.cs

    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Designation {get; set;}
        public string FathersName{get; set;}
        public string MothersName{get; set;}
        public DateTime DateOfBirth{get; set;}
    }

Step 3: Install in memory database provider for entity framework core

  • Go to the terminal and type the following command
    dotnet add package Microsoft.EntityFrameworkCore.InMemory

Step 4: Create a dbContext class

  • Create HRMContext Class in Db folder as follows

HRMContext.cs

using HRM.Models;
using Microsoft.EntityFrameworkCore;

namespace HRM.Db
{
    public class HRMContext : DbContext
    {
        public HRMContext(DbContextOptions<HRMContext> options) : base(options)
        {

        }
        public DbSet<Employee> Employees { get; set; }
    }
}
  • Configure in memory database in the ConfigureService method of Startup class as follows.
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<HRMContext>(opt => opt.UseInMemoryDatabase("HRMDB"));
}

Step 5: Add some seed data

  • Create a class name SeedDataGenerator in Db folder as follows
using System;
using System.Linq;
using HRM.Db;
using HRM.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

public class SeedDataGenerator
{
    public static void Initialize(IServiceProvider serviceProvider)
    {
        using (var context = new HRMContext(
            serviceProvider.GetRequiredService<DbContextOptions<HRMContext>>()))
        {
            // Check any employee exists 
            if (context.Employees.Any())
            {
                return; // Data already exists no need to generate
            }

            context.Employees.AddRange(
                new Employee
                {
                    Name = "Md. Mahedee Hasan",
                    Designation = "Head of Software Development",
                    FathersName = "Yeasin Bhuiyan",
                    MothersName = "Moriom Begum",
                    DateOfBirth = new DateTime(1984, 12, 19, 00, 00, 00)
                },

                new Employee
                {
                    Name = "Khaleda Islam",
                    Designation = "Software Engineer",
                    FathersName = "Shahidul Islam",
                    MothersName = "Momtaz Begum",
                    DateOfBirth = new DateTime(1990, 10, 29, 00, 00, 00)
                },
                
                new Employee
                {
                    Name = "Tahiya Hasan Arisha",
                    Designation = "Jr. Software Engineer",
                    FathersName = "Md. Mahedee Hasan",
                    MothersName = "Khaleda Islam",
                    DateOfBirth = new DateTime(2017, 09, 17, 00, 00, 00)
                }
            );
            context.SaveChanges();

        }
    }
}
  • Call SeedDataGenerator from Program class to generate seed data as follows
using HRM.Db;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace HRM
{
    public class Program
    {
        public static void Main(string[] args)
        {
            //CreateHostBuilder(args).Build().Run();

            // 1. Get the IHost which will host this application
            var host = CreateHostBuilder(args).Build();

            // 2. Find the service within the scope to use
            using (var scope = host.Services.CreateScope())
            {
                // 3. Get the instance of HRMContext in our service layer
                var services = scope.ServiceProvider;
                var context = services.GetRequiredService<HRMContext>();

                // 4. Call the SeedDataGenerator to generate seed data
                SeedDataGenerator.Initialize(services);  
            }

            // Run the application 
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

Step 6: Create IRepository and Repository class in the Repository folder as follows

IEmployeeRepository.cs


using System.Collections.Generic;
using System.Threading.Tasks;
using HRM.Models;

namespace HRM.Repository
{
    public interface IEmployeeRepository
    {
        public Task<IEnumerable<Employee>> SelectAllEmployees();
        public Task<Employee> SelectEmployee(int id);
        public Task<string> UpdateEmployee(int id, Employee employee);
        public Task<string> SaveEmployee(Employee employee);
        public Task<string> DeleteEmployee(int id);
    }
}


EmployeeRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using HRM.Db;
using HRM.Models;
using Microsoft.EntityFrameworkCore;

namespace HRM.Repository
{
    public class EmployeeRepository : IEmployeeRepository
    {
        private readonly HRMContext _context;

        public EmployeeRepository(HRMContext context)
        {
            _context = context;
        }

        public async Task<IEnumerable<Employee>> SelectAllEmployees()
        {
            try
            {
                var allemployess = _context.Employees.ToListAsync();
                return await allemployess;
            }
            catch (Exception exp)
            {
                throw (exp);
            }
        }

        public async Task<Employee> SelectEmployee(int id)
        {
            try
            {
                var employee = _context.Employees.FindAsync(id);
                return await employee;
            }
            catch (Exception exp)
            {
                throw (exp);
            }
        }

        public async Task<string> UpdateEmployee(int id, Employee employee)
        {
            if (id != employee.Id)
            {
                return "Cannot be updated!";
            }

            _context.Entry(employee).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
                return "Data updated successfully!";
            }
            catch (DbUpdateConcurrencyException exp)
            {
                if (!EmployeeExists(id))
                {
                    return "Data not found!";
                }
                else
                {
                    throw (exp);
                }
            }
        }

        public async Task<string> SaveEmployee(Employee employee)
        {
            _context.Employees.Add(employee);
            try
            {
                await _context.SaveChangesAsync();
                return "Data saved successfully!";
            }
            catch (Exception exp)
            {
                throw (exp);
            }
        }

        public async Task<string> DeleteEmployee(int id)
        {
            var employee = await _context.Employees.FindAsync(id);
            if (employee == null)
            {
                return "Data not found!";
            }

            _context.Employees.Remove(employee);
            await _context.SaveChangesAsync();

            return "Data deleted successfully!";
        }

        private bool EmployeeExists(int id)
        {
            return _context.Employees.Any(e => e.Id == id);
        }

    }
}

Step 7: Create IEmployeeService and EmployeeService class in the Services folder as follows

IEmployeeService.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using HRM.Models;

namespace HRM.Services
{
    public interface IEmployeeService
    {
        public Task<IEnumerable<Employee>> GetEmployees();
        public Task<Employee> GetEmployee(int id);
        public Task<string> EditEmployee(int id, Employee employee);
        public Task<string> AddEmployee(Employee employee);
        public Task<string> RemoveEmployee(int id);

    }
}

EmployeeService.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using HRM.Models;
using HRM.Repository;

namespace HRM.Services
{
    public class EmployeeService : IEmployeeService
    {
        IEmployeeRepository _employeeRepository;
        public EmployeeService(IEmployeeRepository repository)
        {
            _employeeRepository = repository;
        }

        public async Task<IEnumerable<Employee>> GetEmployees()
        {
            try
            {
                return await _employeeRepository.SelectAllEmployees();
            }
            catch(Exception exp)
            {
                throw (exp);
            }
        }

        public async Task<Employee> GetEmployee(int id)
        {
            try
            {
                return await _employeeRepository.SelectEmployee(id);
            }
            catch(Exception exp)
            {
                throw(exp);
            }
        }

        public async Task<string> EditEmployee(int id, Employee employee)
        {
            try
            {
                return await _employeeRepository.UpdateEmployee(id, employee);
            }
            catch(Exception exp)
            {
                throw(exp);
            }
        }

        public async Task<string> AddEmployee(Employee employee)
        {
            try
            {
                return await _employeeRepository.SaveEmployee(employee);
            }
            catch(Exception exp)
            {
                throw(exp);
            }
        }

        public async Task<string> RemoveEmployee(int id)
        {
            try
            {
                return await _employeeRepository.DeleteEmployee(id);
            }
            catch(Exception exp)
            {
                throw(exp);
            }
        }

    }
}

Step 7: Register interfaces and corresponding concrete class in the ConfigureServic method

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<HRMContext>(opt => opt.UseInMemoryDatabase("HRMDB"));
    

    services.AddControllersWithViews();

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

    //Register 
    services.AddScoped<IEmployeeRepository, EmployeeRepository>();
    services.AddScoped<IEmployeeService, EmployeeService>();
}

Step 8: Add controller

  • Add a controller class name - EmployeesController in Controllers folder as follows.

EmployeesController.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using HRM.Db;
using HRM.Models;
using HRM.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

[Route("api/[controller]")]
public class EmployeesController : Controller
{

    private readonly IEmployeeService _employeeService;

    public EmployeesController(IEmployeeService employeeService)
    {
        _employeeService = employeeService;
    }

    [HttpGet("[action]")]
    public async Task<ActionResult<IEnumerable<Employee>>> GetEmployees()
    {
        try
        {
             var allemployess = await _employeeService.GetEmployees();
             return Ok(allemployess);
        }
        catch(Exception exp)
        {
            return BadRequest(exp.Message);
        }
        //return await _context.Employees.ToListAsync();
    }

    
    [HttpGet("Employee/{id}")]
    public async Task<ActionResult<Employee>> GetEmployeeById(int id)
    {
        try
        {
            var employee = await _employeeService.GetEmployee(id);
            return Ok(employee);
        }
        catch(Exception exp)
        {
            return BadRequest(exp.Message);
        }
    }

    [HttpPost("AddEmployee")]
    public async Task<ActionResult> AddEmployee([FromBody]Employee employee)
    {
        try
        {
            string result = string.Empty;
            if(employee != null)
            {
                result = await _employeeService.AddEmployee(employee);
            }
            return Ok(result);
        }
        catch(Exception exp)
        {
            return BadRequest(exp.Message);
            //
        }
    }

    [HttpPut("EditEmployee/{id}")]
    public async Task<ActionResult> EditEmployee(int id, [FromBody]Employee employee)
    {
        try
        {
            string result = string.Empty;
            result = await _employeeService.EditEmployee(id, employee);
            return Ok(result);
        }
        catch(Exception exp)
        {
            return BadRequest(exp.Message);
        }
    }

    [HttpDelete("DeleteEmployee/{id}")]
    public async Task<ActionResult> DeleteEmployee(int id)
    {
        try
        {
            string result = string.Empty;
            result = await _employeeService.RemoveEmployee(id);
            return Ok(result);
        }
        catch(Exception exp)
        {
            return BadRequest(exp.Message);
        }
    }

}

Step 9: Test the application using postman

  • Go to terminal and type dotnet run to run the application
  • Test api end point using postman as follows.